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

# Providers and services in nestrs

> Mark types as injectable with #[injectable], register them in modules, inject via State<Arc<T>>, and use custom factory providers for advanced construction.

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:

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

#[injectable]
pub struct AppService {
    prisma: Arc<PrismaService>,
}
```

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.

<Note>
  `construct` is **synchronous**. Do not call `block_on` or perform I/O inside it — use `on_module_init` for async setup.
</Note>

## Provider scopes

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

```rust theme={null}
// Default: one shared instance per application
#[injectable]
pub struct SingletonService;

// New instance on every injection site / registry.get() call
#[injectable(scope = "transient")]
pub struct TransientService;

// One instance per HTTP request (requires use_request_scope())
#[injectable(scope = "request")]
pub struct RequestScopedService;
```

| Scope | Lifetime | NestJS equivalent |
| - | - | - |
| `"singleton"` (default) | One per application container | `Scope.DEFAULT` |
| `"transient"` | New instance per resolution | `Scope.TRANSIENT` |
| `"request"` | One per HTTP request | `Scope.REQUEST` |

## 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`:

```rust theme={null}
#[module(
    controllers = [AppController, AppControllerV2],
    providers   = [AppService],
)]
pub struct AppModule;
```

To share a provider across modules:

```rust theme={null}
#[module(
    controllers = [UserController],
    providers   = [UserService],
    exports     = [UserService],
)]
pub struct UserModule;

#[module(
    imports  = [UserModule],
    providers = [AppService],
)]
pub struct AppModule;
```

## 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:

```rust theme={null}
#[routes(state = AppService)]
impl AppController {
    #[get("/")]
    pub async fn root(service: Arc<AppService>) -> &'static str {
        service.get_hello()
    }

    #[get("/db-health")]
    pub async fn db_health(
        service: Arc<AppService>,
    ) -> Json<DbHealthResponse> {
        Json(service.db_health().await)
    }
}
```

### Multiple providers per controller (tuple state)

If a controller needs multiple services, specify a tuple in `state`:

```rust theme={null}
#[routes(state = (AppService, UserService))]
impl AppController {
    #[get("/profile")]
    pub async fn profile(
        app: Arc<AppService>,
        users: Arc<UserService>,
    ) -> Json<UserProfile> {
        Json(users.get_profile(app.default_tenant()).await)
    }
}
```

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):

```rust theme={null}
#[injectable]
pub struct AppService {
    prisma: Arc<PrismaService>,
}

impl AppService {
    pub async fn list_users(&self) -> Result<Vec<UserRow>, String> {
        self.prisma
            .query_all_as(r#"SELECT "id", "email", "name" FROM "User""#)
            .await
    }
}
```

## 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`.

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

#[injectable]
pub struct DatabaseService {
    // fields ...
}

#[async_trait]
impl Injectable for DatabaseService {
    fn construct(registry: &ProviderRegistry) -> Arc<Self> {
        Arc::new(Self { /* wire fields */ })
    }

    async fn on_module_init(&self) {
        // Run after all singletons are constructed; safe to do async I/O here.
    }

    async fn on_before_application_shutdown(&self) {
        // NestJS `beforeApplicationShutdown`: flush caches while dependents are still alive.
    }

    async fn on_application_shutdown(&self) {
        // Close connections, flush buffers.
    }
}
```

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.

<Warning>
  Lifecycle hooks only run for **singleton** providers. Transient providers are constructed on demand and do not receive hook calls.
</Warning>

## 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`:

```rust theme={null}
use nestrs::core::{ProviderRegistry, ProviderScope};
use std::sync::Arc;

fn register_heavy(registry: &mut ProviderRegistry) {
    registry.register_use_factory::<HeavyService>(ProviderScope::Singleton, |reg| {
        let light = reg.get::<LightService>();
        Arc::new(HeavyService::new(light))
    });
}
```

### All custom provider variants

| Method | NestJS analogue | Notes |
| - | - | - |
| `register_use_value::<T>(Arc<T>)` | `useValue` | Pre-built singleton; lifecycle hooks are **not** run — any `T` is accepted, so there is no hook impl to call |
| `register_use_value_with_lifecycle::<T>(Arc<T>)` | `useValue` + `OnModuleInit` & friends | Requires `T: ProviderLifecycle`; the framework drives `T`'s five hooks like an `Injectable` |
| `register_use_factory::<T>(scope, \|reg\| Arc<T>)` | `useFactory` | Sync closure; call `reg.get()` for dependencies; lifecycle hooks are **not** run |
| `register_use_factory_with_lifecycle::<T>(scope, \|reg\| Arc<T>)` | `useFactory` + lifecycle | Requires `T: ProviderLifecycle`; hooks run while `T` is singleton-scoped |
| `register_use_class::<T>()` | `useClass` | Same as `register::<T>()` for normal `#[injectable]` types |

<Tip>
  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.
</Tip>
