NestJS Dynamic Modules
Dynamic modules return module definitions at runtime so callers can pass configuration—like TypeOrmModule.forRoot(). This lesson shows building your own.
What Makes a Module Dynamic? A static module is a class with fixed @Module() metadata. A dynamic module method (forRoot, register) returns { module, imports, providers, exports } so configuration can be supplied by the application.
@Module({})
export class MetricsModule {
static forRoot(options: MetricsOptions): DynamicModule {
return {
module: MetricsModule,
providers: [
{ provide: METRICS_OPTIONS, useValue: options },
MetricsService,
],
exports: [MetricsService],
};
}
} Consumers call MetricsModule.forRoot({ apiKey }) in their imports array.
Async Configuration static forRootAsync(options: MetricsAsyncOptions): DynamicModule {
return {
module: MetricsModule,
imports: options.imports || [],
providers: [
{
provide: METRICS_OPTIONS,
useFactory: options.useFactory,
inject: options.inject || [],
},
MetricsService,
],
exports: [MetricsService],
};
} forRoot is typically used once for global configuration. forFeature style methods register per-feature providers. forRootAsync integrates ConfigService and other DI factories. Mark configurable library modules @Global() only when widely needed. Dynamic Module Cheatsheet Conventions used across Nest ecosystem packages.
Method Meaning forRoot Configure once at app root forRootAsync Configure with injected factories forFeature Register feature-specific providers register General-purpose configurable import
Options Injection Token Provide options via a constant token (METRICS_OPTIONS) and inject it into services with @Inject(METRICS_OPTIONS) for clean typing.
Authoring Shared Libraries If you publish an internal Nest library, dynamic modules are how consumers supply API keys and endpoints without forking your code.
Common Mistakes Mutating static module metadata instead of returning a DynamicModule object. Forgetting to export providers that consumers need. Making everything global and creating hidden coupling. Not supporting async registration when secrets come from ConfigService. Key Takeaways Dynamic modules return configured module definitions at runtime. forRoot / forRootAsync / forFeature are common conventions. Pass options through dedicated DI tokens. Use dynamic modules to build reusable Nest libraries.
Pro Tip
Mirror the async options shape used by official Nest packages (useFactory, inject, imports) so your module feels familiar to Nest developers.
NestJS Lifecycle Events Go to next item