Lazy-Loaded Modules and Feature Toggles
Load optional feature modules on demand with LazyModuleLoader to shrink startup cost.
Why Eager Loading Hurts Startup
By default, NestJS instantiates every module in your imports graph at bootstrap. For an enterprise API with dozens of optional features — a PDF exporter, a payment gateway, an AI scoring engine — that means paying the full provider-instantiation and connection-warmup cost before the app even accepts a request.
- Heavy SDKs (Stripe, AWS, gRPC clients) run their constructors eagerly.
- Modules a given deployment never uses still load.
- Cold-start latency grows linearly with the module graph.
The fix: load select feature modules lazily, only when first invoked.
The LazyModuleLoader
Nest ships a built-in LazyModuleLoader (from @nestjs/core). You inject it like any provider, then call load() with a factory that returns the module. Nest registers the module's providers on demand and caches the resulting reference for subsequent calls.
Key traits:
- Lazy modules are not listed in any
importsarray. - They do not register controllers, resolvers, or enhancers — only providers.
- The first
load()instantiates; later calls return the cachedModuleRef.
import { Injectable } from '@nestjs/common';
import { LazyModuleLoader } from '@nestjs/core';
@Injectable()
export class ReportsService {
constructor(private readonly lazyModuleLoader: LazyModuleLoader) {}
async generate(): Promise<void> {
const { PdfModule } = await import('./pdf/pdf.module');
const moduleRef = await this.lazyModuleLoader.load(() => PdfModule);
// moduleRef now exposes PdfModule's providers
}
}All lessons in this course
- Ports and Adapters for Domain Isolation
- Dynamic Provider Registration with DiscoveryService
- Lazy-Loaded Modules and Feature Toggles
- Extension Points with the Module Reference API