#[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:
re_exports:
Composing feature modules
1
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.
2
Import the feature module from your root module
List the feature module in
imports. Exported providers are absorbed into the importing module’s registry.3
Bootstrap the application
Pass the root module to
NestFactory::create. nestrs builds the full provider registry and Axum router automatically.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:
1
eager_init_singletons()
Constructs every singleton in the registry synchronously. This is where circular provider dependency panics surface.
2
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.3
run_on_application_bootstrap().await
Calls
on_application_bootstrap on every singleton. Use this for tasks that depend on all modules being fully initialized.4
Server accepts requests
The Axum TCP listener opens and the application begins serving traffic.
5
Shutdown: run_on_application_shutdown().await
On SIGTERM or graceful shutdown,
on_application_shutdown is called on every singleton.6
Shutdown: run_on_module_destroy().await
on_module_destroy is called last. Use this to close connections and flush buffers.Circular module imports
If two modules import each other, nestrs detects the cycle and panics with:forward_ref to break the cycle: