#[module] proc-macro generates the Module and ModuleGraph trait implementations that NestFactory uses to build the provider registry and Axum router.
The #[module] macro
Annotate a plain struct with #[module] to define a module. The macro accepts four optional fields:
| Field | Type | Description |
|---|---|---|
imports | array of module types or DynamicModule expressions | Modules whose exported providers this module can use |
controllers | array of controller types | Axum route sets registered under this module |
providers | array of injectable types | Services available to controllers in this module |
exports | array of injectable types | Providers this module re-exports to importing modules |
re_exports:
Composing feature modules
Define a feature module
Create a module for a focused area of your application. List only the providers and controllers that belong to that feature.
Import the feature module from your root module
List the feature module in
imports. Exported providers are absorbed into the importing module’s registry.Dynamic modules
Static#[module] declarations cover most use cases. When you need to configure a module at runtime — loading options from environment variables, a remote secrets store, or feature flags — use a DynamicModule.
DynamicModule::from_module
Converts any static module into a DynamicModule at call time:
ConfigurableModuleBuilder
The ConfigurableModuleBuilder pattern mirrors NestJS’s forRoot / forRootAsync:
- Synchronous options
- Async options
Lazy modules
DynamicModule::lazy::<M>() runs M::build() at most once per process and shares the singleton cells across all callers. This is useful for shared infrastructure modules (databases, caches) that multiple feature modules import independently.
Lifecycle sequence
When you callNestFactory::create and then listen or listen_graceful, nestrs drives the provider registry through the following sequence for all singleton providers:
eager_init_singletons()
Constructs every singleton in the registry synchronously. This is where circular provider dependency panics surface.
run_on_module_init().await
Calls
on_module_init on every singleton. Use this hook for async setup (opening database pools, warming caches) that must complete before the server accepts traffic.run_on_application_bootstrap().await
Calls
on_application_bootstrap on every singleton. Use this for tasks that depend on all modules being fully initialized.Shutdown: run_on_application_shutdown().await
On SIGTERM or graceful shutdown,
on_application_shutdown is called on every singleton.Circular module imports
If two modules import each other, nestrs detects the cycle and panics with:forward_ref to break the cycle: