Skip to content

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.