> ## Documentation Index
> Fetch the complete documentation index at: https://nestrs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# nestrs-core: DI container and module runtime

> Reference for nestrs-core: ProviderRegistry, ModuleRef, DiscoveryService, ExecutionContext, RouteRegistry, MetadataRegistry, and all core traits.

`nestrs-core` is the foundational crate that every nestrs crate depends on. It provides the compile-time DI container, the runtime module graph, route and metadata registries, and all core traits that guards, pipes, interceptors, and filters implement. You rarely use `nestrs-core` directly—`nestrs` re-exports everything under `nestrs::core` and `nestrs::prelude`—but understanding the types here helps you extend the framework.

```toml theme={null}
# Cargo.toml (usually not needed directly; nestrs re-exports everything)
[dependencies]
nestrs-core = "*"
```

## `ProviderRegistry`

The DI container. Built by `#[module]`-generated code, it stores one entry per registered type and resolves instances by `TypeId`.

```rust theme={null}
pub struct ProviderRegistry { /* private */ }
```

### Registration methods

| Method                                         | NestJS analogue                        |
| ---------------------------------------------- | -------------------------------------- |
| `register::<T>()`                              | `useClass` (derives from `Injectable`) |
| `register_use_value::<T>(Arc<T>)`              | `useValue`                             |
| `register_use_factory::<T, F>(scope, factory)` | `useFactory`                           |
| `register_use_class::<T>()`                    | Same as `register::<T>()`              |
| `override_provider::<T>(Arc<T>)`               | Testing override / mock                |

### Resolution

```rust theme={null}
// Returns Arc<T> — panics if T is not registered
pub fn get<T: Send + Sync + 'static>(&self) -> Arc<T>
```

### Lifecycle methods

The framework calls these in order inside `listen` / `listen_graceful`:

```rust theme={null}
pub fn eager_init_singletons(&self)
pub async fn run_on_module_init(&self)
pub async fn run_on_application_bootstrap(&self)
pub async fn run_on_application_shutdown(&self)
pub async fn run_on_module_destroy(&self)
```

### Introspection

```rust theme={null}
pub fn registered_type_ids(&self) -> Vec<TypeId>
pub fn registered_type_names(&self) -> Vec<&'static str>
```

### Cross-module absorption

```rust theme={null}
// Absorb all providers from another registry
pub fn absorb(&mut self, other: ProviderRegistry)

// Absorb only exported provider types from another registry
pub fn absorb_exported(&mut self, other: ProviderRegistry, exported: &[TypeId])
```

## `ProviderScope`

Controls the lifetime of a provider instance.

```rust theme={null}
pub enum ProviderScope {
    Singleton,  // One instance per application container (default)
    Transient,  // New instance on every resolution
    Request,    // One instance per request (requires use_request_scope middleware)
}
```

Set scope via the macro:

```rust theme={null}
#[injectable(scope = "singleton")]  // default
#[injectable(scope = "transient")]
#[injectable(scope = "request")]
```

Or programmatically when using `register_use_factory`:

```rust theme={null}
registry.register_use_factory::<MyService, _>(
    ProviderScope::Transient,
    |_registry| Arc::new(MyService::new()),
);
```

## `Injectable` trait

Every provider type implements this trait (usually generated by `#[injectable]`).

```rust theme={null}
#[async_trait]
pub trait Injectable: Send + Sync + 'static {
    fn construct(registry: &ProviderRegistry) -> Arc<Self>;

    fn scope() -> ProviderScope {
        ProviderScope::Singleton
    }

    async fn on_module_init(&self) {}
    async fn on_module_destroy(&self) {}
    async fn on_application_bootstrap(&self) {}
    async fn on_application_shutdown(&self) {}
}
```

<Note>
  `construct` is always synchronous. Perform async initialization in `on_module_init`, which runs before the server accepts traffic.
</Note>

## `Module` trait

Generated by `#[module]`. Called once by `NestFactory::create` to build the full provider and router graph.

```rust theme={null}
pub trait Module {
    fn build() -> (ProviderRegistry, Router);
    fn exports() -> Vec<TypeId> { Vec::new() }
}
```

## `Controller` trait

Generated by `#[controller]` + `#[routes]`. Registers Axum routes into the router for a module.

```rust theme={null}
pub trait Controller {
    fn register(router: Router, registry: &ProviderRegistry) -> Router;
}
```

## `ModuleRef`

The NestJS `ModuleRef` analogue. Provides typed access to the root `ProviderRegistry` after the application graph is built. Obtain it from `NestApplication::module_ref()`.

```rust theme={null}
pub struct ModuleRef { /* private */ }

impl ModuleRef {
    pub fn get<T: Send + Sync + 'static>(&self) -> Arc<T>
    pub fn registry(&self) -> &ProviderRegistry
    pub fn registry_arc(&self) -> &Arc<ProviderRegistry>
    pub fn into_inner(self) -> Arc<ProviderRegistry>
}
```

```rust theme={null}
use nestrs::prelude::*;

#[derive(Default)]
#[injectable]
struct AppState;

#[module(providers = [AppState])]
struct AppModule;

fn main() {
    let app = NestFactory::create::<AppModule>();
    let mref = app.module_ref();
    let state: std::sync::Arc<AppState> = mref.get::<AppState>();
    let _router = app.into_router();
}
```

## `DiscoveryService`

The NestJS `DiscoveryService` analogue. Introspects registered providers and compiled HTTP routes.

```rust theme={null}
pub struct DiscoveryService { /* private */ }

impl DiscoveryService {
    pub fn new(module: ModuleRef) -> Self
    pub fn module_ref(&self) -> ModuleRef
    pub fn get_providers(&self) -> Vec<TypeId>
    pub fn get_provider_type_names(&self) -> Vec<&'static str>
    pub fn get_routes(&self) -> Vec<RouteInfo>
}
```

```rust theme={null}
let mref = app.module_ref();
let discovery = DiscoveryService::new(mref);

for name in discovery.get_provider_type_names() {
    tracing::info!("registered provider: {name}");
}

for route in discovery.get_routes() {
    tracing::info!("{} {}", route.method, route.path);
}
```

<Note>
  Unlike NestJS, there is no reflection over arbitrary class metadata. You get `TypeId` keys, type name strings, and whatever is in the global `RouteRegistry`. There is no runtime annotation discovery for arbitrary field metadata.
</Note>

## `RouteRegistry`

A process-wide registry populated by `impl_routes!` / `#[routes]` expansion at startup. Used by `nestrs-openapi` to generate the OpenAPI spec.

```rust theme={null}
pub struct RouteRegistry; // static methods only

impl RouteRegistry {
    pub fn list() -> Vec<RouteInfo>
}

pub struct RouteInfo {
    pub method: &'static str,
    pub path: &'static str,
    pub handler: &'static str,
    pub openapi: Option<&'static OpenApiRouteSpec>,
}
```

## `MetadataRegistry`

A process-wide key-value store for handler string metadata set by `#[set_metadata]` and `#[roles]`.

```rust theme={null}
pub struct MetadataRegistry; // static methods only

impl MetadataRegistry {
    pub fn set(handler: &'static str, key: &str, value: &str)
    pub fn get(handler: &str, key: &str) -> Option<String>
}
```

```rust theme={null}
use nestrs::core::MetadataRegistry;

MetadataRegistry::set(
    "my_app::controllers::UserController::list",
    "roles",
    "admin",
);

let value = MetadataRegistry::get(
    "my_app::controllers::UserController::list",
    "roles",
);
```

Access the current handler key from a guard via `HandlerKey` in request extensions:

```rust theme={null}
pub struct HandlerKey(pub &'static str);

// Inside CanActivate::can_activate:
if let Some(key) = parts.extensions.get::<HandlerKey>() {
    let roles = MetadataRegistry::get(key.0, "roles");
}
```

## `ExecutionContext`

The NestJS `ArgumentsHost` analogue for HTTP requests. Available via the `HttpExecutionContext` extractor when `NestApplication::use_execution_context()` is enabled.

```rust theme={null}
pub struct ExecutionContext { /* private */ }

pub enum HostType {
    Http,
    Microservice,
    WebSocket,
}
```

## `CanActivate` trait

The guard contract. Implement this on any unit struct (must be `Default`) and apply with `#[use_guards]`.

```rust theme={null}
#[async_trait]
pub trait CanActivate: Default + Send + Sync + 'static {
    async fn can_activate(&self, parts: &Parts) -> Result<(), GuardError>;
}

pub enum GuardError {
    Unauthorized(String),  // → 401
    Forbidden(String),     // → 403
}
```

## `PipeTransform` trait

The pipe contract. `ValidationPipe` is the built-in implementation.

```rust theme={null}
#[async_trait]
pub trait PipeTransform: Default + Send + Sync + 'static {
    async fn transform(&self, value: serde_json::Value) -> Result<serde_json::Value, GuardError>;
}
```

## `AuthStrategy` trait

Pluggable authentication strategy for `AuthStrategyGuard`. Implement this to verify tokens, sessions, or API keys.

```rust theme={null}
#[async_trait]
pub trait AuthStrategy: Send + Sync + 'static {
    async fn authenticate(&self, parts: &Parts) -> Result<(), AuthError>;
}

pub enum AuthError {
    Unauthorized(String),
    Forbidden(String),
}
```

## `DynamicModule` and `DynamicModuleBuilder`

Runtime-composed module units for conditional imports, feature flags, and configurable modules.

```rust theme={null}
pub struct DynamicModule {
    pub registry: ProviderRegistry,
    pub router: Router,
    pub exports: Vec<TypeId>,
}

impl DynamicModule {
    pub fn from_module<M: Module>() -> Self
    pub fn from_router(router: Router) -> Self
    pub fn from_parts(registry: ProviderRegistry, router: Router, exports: Vec<TypeId>) -> Self
    pub fn lazy<M: Module + 'static>() -> Self  // initialized at most once per process
}
```

`DynamicModuleBuilder` allows provider overrides before controllers are registered (useful for configurable modules and test setups):

```rust theme={null}
let module = DynamicModuleBuilder::<MyModule>::new()
    .override_provider::<MyService>(Arc::new(MockService))
    .build();
```

`ConfigurableModuleBuilder` is the NestJS `forRoot` / `forRootAsync` pattern:

```rust theme={null}
// Synchronous options
let module = ConfigurableModuleBuilder::<MyOptions>::for_root::<MyModule>(options);

// Async options (e.g. await a vault client)
let module = ConfigurableModuleBuilder::<MyOptions>::for_root_async::<MyModule>(|| async {
    load_options_from_vault().await
}).await;
```
