Skip to main content
Providers are the services, repositories, and utilities that your application logic depends on. In nestrs, any type can become a provider by implementing the Injectable trait — the #[injectable] proc-macro generates that implementation for you. The framework constructs and caches providers in the ProviderRegistry, then makes them available to controllers and other providers through Axum’s State extractor.

Marking a type as injectable

Apply #[injectable] to a struct to generate the Injectable trait implementation. nestrs calls construct to build the type, injecting any dependencies it finds in the registry:
nestrs infers dependencies from the struct fields. Any field of type Arc<T> where T is a registered provider is resolved from the registry automatically.
construct is synchronous. Do not call block_on or perform I/O inside it — use on_module_init for async setup.

Provider scopes

Control how long a provider instance lives with the scope argument:

Registering providers in a module

List your providers in the providers field of the enclosing module. Providers that other modules need must also appear in exports:
To share a provider across modules:

Injecting providers into controllers

Controllers access their providers via Axum’s State extractor. The #[routes(state = T)] macro wires the service type into the router, and handler functions can take service: Arc<T> directly:

Multiple providers per controller (tuple state)

If a controller needs multiple services, specify a tuple in state:
nestrs stitches the composite state from the ProviderRegistry via RouteStateFromRegistry. Handlers only receive the services they declare. Explicit State(service): State<Arc<T>> remains supported as well.

Injecting providers into other providers

When one provider depends on another, declare the dependency as an Arc<T> field and ensure both types are registered in the same module (or that the dependency is exported from an imported module):

Lifecycle hooks

Injectable provides five async hooks (all default to no-ops): on_module_init, on_application_bootstrap, on_before_application_shutdown, on_application_shutdown, and on_module_destroy.
On startup, listen() first eagerly constructs all singleton providers (in registration order), then runs on_module_init across all singletons, then on_application_bootstrap, and only then binds the listener — hooks run before the server accepts traffic. Within each hook phase, providers run in dependency order (construction dependencies first, ties broken by registration order). On graceful shutdown the phases run in reverse: on_before_application_shutdown → on_application_shutdown → on_module_destroy, each in reverse initialization order so dependencies are torn down after their dependents.
Lifecycle hooks only run for singleton providers. Transient providers are constructed on demand and do not receive hook calls.

Custom factory providers

Use register_use_factory when construction order must be explicit or when you need to close a provider dependency cycle without calling registry.get() eagerly inside another type’s construct:

All custom provider variants

Keep factory closures non-async. Defer I/O to on_module_init on the produced type (which requires a hook-driving registration — the *_with_lifecycle variants, or a plain #[injectable] type registered with register), or to ConfigurableModuleBuilder::for_root_async for module-level configuration.