Bird
Raised Fist0
NestJSframework~10 mins

Dynamic modules in NestJS - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Dynamic modules
Define Dynamic Module Class
↓
Create static forRoot() method
↓
Accept config/options parameter
↓
Return Module with providers based on config
↓
Import Dynamic Module in AppModule
↓
NestJS loads module with custom providers
↓
Use injected providers in app
Dynamic modules let you create NestJS modules that can change their providers and configuration when imported.
Execution Sample
NestJS
import { Module } from '@nestjs/common';

@Module({})
export class DynamicModule {
  static forRoot(options) {
    return {
      module: DynamicModule,
      providers: [{ provide: 'CONFIG', useValue: options }],
      exports: ['CONFIG'],
    };
  }
}
Defines a dynamic module with a static forRoot method that accepts options and returns a module with providers.
Execution Table
StepActionInput/StateOutput/Result
1Call DynamicModule.forRoot({debug: true})options = {debug: true}Returns module object with providers using options
2AppModule imports DynamicModule.forRoot({debug: true})Module imports listDynamicModule loaded with providers configured
3NestJS creates provider 'CONFIG' with value {debug: true}Provider setupProvider available for injection
4Inject 'CONFIG' in serviceInjection requestService receives {debug: true} config
5Use config in service logicConfig = {debug: true}Service behaves according to config
6Application runs with dynamic configApp runningDynamic behavior based on injected config
💡 Dynamic module setup completes after providers are created and injected based on options.
Variable Tracker
VariableStartAfter Step 1After Step 3Final
optionsundefined{debug: true}{debug: true}{debug: true}
moduleObjectundefined{module: DynamicModule, providers: [...], exports: [...]}{module: DynamicModule, providers: [...], exports: [...]}{module: DynamicModule, providers: [...], exports: [...]}
provider 'CONFIG'undefinedundefined{useValue: {debug: true}}{useValue: {debug: true}}
Key Moments - 3 Insights
Why do we use a static forRoot() method in dynamic modules?
The static forRoot() method allows passing configuration options when importing the module, as shown in execution_table step 1 and 2.
How does NestJS know what providers to create from the dynamic module?
NestJS uses the returned module object from forRoot() which includes the providers array, as seen in execution_table step 3.
Can the dynamic module change behavior based on different options?
Yes, because the providers use the passed options, so injecting 'CONFIG' gives different values depending on what was passed, shown in steps 4 and 5.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the value of 'options' after step 1?
Aundefined
B{debug: true}
C{}
Dnull
💡 Hint
Check the 'Input/State' column at step 1 in the execution_table.
At which step does NestJS create the provider 'CONFIG'?
AStep 3
BStep 4
CStep 2
DStep 5
💡 Hint
Look for the step mentioning provider setup in the execution_table.
If we change options to {debug: false}, what changes in the variable_tracker?
AThe provider 'CONFIG' is removed
BThe 'moduleObject' becomes undefined
CThe 'options' variable value changes to {debug: false}
DNo variables change
💡 Hint
Refer to the 'options' row in variable_tracker and how it updates after step 1.
Concept Snapshot
Dynamic modules in NestJS use a static forRoot() method.
This method accepts options and returns a module with configured providers.
Importing the dynamic module with forRoot() passes config to providers.
Providers can then be injected with the passed config.
This allows modules to change behavior based on import-time options.
Full Transcript
Dynamic modules in NestJS allow modules to be configured dynamically when imported. This is done by defining a static forRoot() method on the module class. The forRoot() method accepts configuration options and returns a module object with providers that use those options. When the app imports the dynamic module using forRoot(), NestJS creates providers based on the passed options. These providers can then be injected into services to customize behavior. The execution table shows the step-by-step process: calling forRoot(), importing the module, creating providers, injecting config, and running the app with dynamic behavior. Variables like options and provider values update as the module loads. Key moments include understanding why forRoot() is static, how providers are created, and how config changes behavior. The visual quiz tests understanding of these steps and variable changes. Overall, dynamic modules enable flexible, configurable NestJS modules.

Practice

(1/5)
1. What is the main purpose of a dynamic module in NestJS?
easy
A. To automatically generate database schemas
B. To create modules without any providers or exports
C. To replace the need for controllers in an application
D. To allow configuration of modules with custom options at runtime

Solution

  1. Step 1: Understand dynamic module concept

    Dynamic modules let you pass custom options to configure the module when importing it.
  2. Step 2: Identify the main purpose

    This flexibility helps reuse modules with different settings instead of hardcoding them.
  3. Final Answer:

    To allow configuration of modules with custom options at runtime -> Option D
  4. Quick Check:

    Dynamic modules = configurable modules [OK]
Hint: Dynamic modules customize modules with options [OK]
Common Mistakes:
  • Thinking dynamic modules remove controllers
  • Believing dynamic modules auto-generate schemas
  • Assuming dynamic modules have no providers
2. Which of the following is the correct way to define a dynamic module method in NestJS?
easy
A. constructor(options: ModuleOptions): void { ... }
B. static forRoot(options: ModuleOptions): DynamicModule { ... }
C. export function createModule(options: ModuleOptions) { ... }
D. async initialize(options: ModuleOptions): Promise<void> { ... }

Solution

  1. Step 1: Recall dynamic module pattern

    Dynamic modules use a static method, commonly named forRoot, returning a DynamicModule object.
  2. Step 2: Match method signature

    Only a static method can be called without creating an instance, fitting the dynamic module pattern.
  3. Final Answer:

    static forRoot(options: ModuleOptions): DynamicModule { ... } -> Option B
  4. Quick Check:

    Dynamic module method = static forRoot [OK]
Hint: Dynamic modules use static forRoot method [OK]
Common Mistakes:
  • Using constructor instead of static method
  • Defining dynamic module as a normal function
  • Making dynamic module method async without returning DynamicModule
3. Given this dynamic module code, what will be the value of the exported provider's token?
export class LoggerModule {
  static forRoot(prefix: string): DynamicModule {
    return {
      module: LoggerModule,
      providers: [
        { provide: 'LOGGER_PREFIX', useValue: prefix },
      ],
      exports: ['LOGGER_PREFIX'],
    };
  }
}
medium
A. 'prefix'
B. 'LoggerModule'
C. 'LOGGER_PREFIX'
D. 'useValue'

Solution

  1. Step 1: Identify provider token

    The provider uses the key 'provide' with value 'LOGGER_PREFIX' which is the token for injection.
  2. Step 2: Confirm exported token

    The exports array includes 'LOGGER_PREFIX', so this token is available outside the module.
  3. Final Answer:

    'LOGGER_PREFIX' -> Option C
  4. Quick Check:

    Provider token = 'LOGGER_PREFIX' [OK]
Hint: Provider token is the 'provide' string value [OK]
Common Mistakes:
  • Confusing module name with provider token
  • Using variable name 'prefix' as token
  • Thinking useValue is the token
4. Identify the error in this dynamic module definition:
export class CacheModule {
  static forRoot(options: { ttl: number }): DynamicModule {
    return {
      module: CacheModule,
      providers: [
        { provide: 'CACHE_TTL', useFactory: (options) => options.ttl },
      ],
      exports: ['CACHE_TTL'],
    };
  }
}
medium
A. The useFactory function cannot access options parameter directly
B. The module property should be a string, not a class
C. Exports array must include providers, not strings
D. Static methods cannot return DynamicModule

Solution

  1. Step 1: Analyze useFactory context

    The useFactory function runs later and cannot directly access the outer options variable without injection.
  2. Step 2: Identify correct pattern

    To use options inside useFactory, it must be passed via inject or closure properly; direct access causes runtime error.
  3. Final Answer:

    The useFactory function cannot access options parameter directly -> Option A
  4. Quick Check:

    useFactory needs inject or closure for options [OK]
Hint: useFactory can't directly use outer variables [OK]
Common Mistakes:
  • Thinking module property must be string
  • Believing exports must list provider objects
  • Assuming static methods can't return DynamicModule
5. You want to create a dynamic module that accepts a configuration object and provides two services using that config. Which approach correctly implements this pattern?
hard
A. Use a static forRoot method returning a DynamicModule with providers using useValue for config and export both services
B. Create a constructor in the module class that sets config and exports services directly
C. Define services inside the module without any configuration and import them normally
D. Use a global module without any providers and configure services externally

Solution

  1. Step 1: Understand dynamic module pattern for config

    Dynamic modules use a static method (like forRoot) to accept config and return a DynamicModule object with providers.
  2. Step 2: Provide config and services properly

    Use useValue or useFactory to inject config into providers, and export services to make them available outside.
  3. Final Answer:

    Use a static forRoot method returning a DynamicModule with providers using useValue for config and export both services -> Option A
  4. Quick Check:

    Dynamic module with static forRoot and providers = Use a static forRoot method returning a DynamicModule with providers using useValue for config and export both services [OK]
Hint: Use static forRoot with providers and exports [OK]
Common Mistakes:
  • Trying to configure modules via constructor
  • Not exporting services after providing them
  • Using global module without providers for config
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard