Dynamic Modules
Dynamic modules are configured at import time with a static method like forRoot or register.
Syntax
static forRoot(options): DynamicModuleA dynamic module is a module you configure when you import it. Instead of importing the class directly, you call a static method that returns the module with your options baked in.
Common conventions
forRoot(options)- configure a module once at the app root, e.g. a database connection.forFeature(options)- register per-feature pieces, e.g. specific entities.register(options)- general configurable import.
These methods return a DynamicModule object describing the providers and exports for that configuration.
Example
import { Module, DynamicModule } from '@nestjs/common';
@Module({})
export class ConfigModule {
static forRoot(options: { folder: string }): DynamicModule {
return {
module: ConfigModule,
providers: [
{ provide: 'CONFIG_OPTIONS', useValue: options },
],
exports: ['CONFIG_OPTIONS'],
};
}
}
// Usage: imports: [ConfigModule.forRoot({ folder: './config' })]When to use it
- A developer configures the ConfigModule once at the root with ConfigModule.forRoot({ envFilePath: ".env" }) so all other modules can inject ConfigService.
- A team uses TypeOrmModule.forRootAsync() to asynchronously load database credentials from ConfigService before establishing the connection.
- A library author writes a custom SmsModule.register({ apiKey }) pattern so consumers can pass credentials at import time.
More examples
forRoot static method pattern
Implements the forRoot/register pattern: consumers call SmsModule.register({ apiKey: "..." }) to pass config at import time.
import { Module, DynamicModule } from '@nestjs/common';
@Module({})
export class SmsModule {
static register(options: { apiKey: string }): DynamicModule {
return {
module: SmsModule,
providers: [
{ provide: 'SMS_OPTIONS', useValue: options },
],
exports: ['SMS_OPTIONS'],
};
}
}Consuming a dynamic module
Shows how a consuming module calls the static register method to pass runtime configuration to the dynamic module.
import { Module } from '@nestjs/common';
import { SmsModule } from './sms/sms.module';
@Module({
imports: [
SmsModule.register({ apiKey: process.env.SMS_API_KEY! }),
],
})
export class AppModule {}forRootAsync with ConfigService
Uses forRootAsync to delay TypeORM configuration until ConfigService is available, enabling async environment variable loading.
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (cfg: ConfigService) => ({
type: 'postgres',
url: cfg.get('DATABASE_URL'),
autoLoadEntities: true,
}),
}),
],
})
export class AppModule {}
Discussion