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

# Database integration with nestrs

> nestrs supports SQL via SqlxDatabaseModule for direct AnyPool queries or nestrs-prisma for Prisma-style schema-driven access. MongoDB support is also available.

nestrs gives you SQL paths depending on how much structure you want:

* **`nestrs-sea-orm` (recommended ORM)** — SeaORM `Repo`, ambient transactions, `RowAuthz` / `AbilityAuthz`. See [adapters/sea-orm](/adapters/sea-orm).
* **`SqlxDatabaseModule`** (feature `database-sqlx`) — SQLx `AnyPool` + `CrudService` when you want direct SQL.
* **`nestrs-prisma`** — `PrismaModule` / `prisma_model!` for a Prisma-style DX.
* **`MongoModule`** — document store path.

For a TypeORM/Sequelize-style Active Record layer, prefer [`nestrs-sea-orm`](/adapters/sea-orm).

## Path 1: SqlxDatabaseModule (direct SQLx)

`SqlxDatabaseModule` manages a single `AnyPool` shared across all injected consumers. Call `for_root` before `NestFactory::create` to register the URL, then import the module.

### Cargo.toml

```toml theme={null}
[dependencies]
nestrs = { version = "1.5.0", features = ["database-sqlx"] }
sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio", "macros", "postgres"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```

### Environment variable

```bash theme={null}
export DATABASE_URL="postgresql://user:password@127.0.0.1:5432/myapp"
# or for SQLite:
# export DATABASE_URL="sqlite:./dev.db"
```

### Module registration

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

#[tokio::main]
async fn main() {
    let db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let _ = SqlxDatabaseModule::for_root(db_url);

    NestFactory::create::<AppModule>()
        .listen(3000)
        .await;
}

#[module(
    imports = [SqlxDatabaseModule],
    providers = [UserService],
    controllers = [UserController],
)]
struct AppModule;
```

### Injecting SqlxDatabaseService

`SqlxDatabaseService` exposes the pool via `pool()` and a `ping()` health check. Use `pool()` to run any SQLx query directly.

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

#[injectable]
pub struct UserService {
    db: Arc<SqlxDatabaseService>,
}

impl UserService {
    pub async fn health(&self) -> &'static str {
        match self.db.ping().await {
            Ok(_) => "up",
            Err(_) => "degraded",
        }
    }

    pub async fn user_count(&self) -> Result<i64, String> {
        let pool = self.db.pool().await?;
        let row: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM users")
            .fetch_one(pool)
            .await
            .map_err(|e| e.to_string())?;
        Ok(row.0)
    }
}
```

***

## Migrations and seeding (`nestrs-cli db`)

Both SQL paths compose with the built-in migrations CLI (the `db` feature of `nestrs-scaffold`). It works on plain SQL migration files — there is no DDL-diff engine or entity auto-discovery.

```bash theme={null}
cargo install nestrs-scaffold --features db

nestrs-cli db migrate add create_posts_table --reversible
# migrations/001_create_posts_table.up.sql
# migrations/001_create_posts_table.down.sql

nestrs-cli db migrate run          # apply pending
nestrs-cli db migrate info        # list applied/pending
nestrs-cli db migrate revert      # walk down (--target-version 0 for full)

nestrs-cli db seed --bin seed_posts        # cargo run --bin seed_posts
nestrs-cli db seed --seed-file dev.sql      # transactional raw SQL
```

Key details:

* **URL resolution** — `--database-url` > `DATABASE_URL` > `NESTRS_DB__URL`.
* **File naming** — sequence-numbered (`<NNN>_<name>.sql`, zero-padded 3 digits), not timestamped: deterministic, greppable, sortable, hand-writable.
* **Reversible migrations** — `--reversible` writes paired `.up.sql` / `.down.sql` files; the sqlx backend records history in `_sqlx_migrations` via `sqlx::migrate::Migrator`.
* **Seeding** — `--bin` passes through to a Cargo seed binary (the common case: a bin that composes with `CrudService<T>`); `--seed-file` runs a SQL file inside an explicit transaction so a mid-file failure rolls back.
* **Prisma pass-through** — `--backend prisma` shells out to `npx prisma …`. Prisma records its own history and has **no revert**; use the sqlx backend with `--reversible` if you need downgrades.

See the [CLI reference](/cli/overview) for the full flag table.

***

## Path 2: nestrs-prisma

`nestrs-prisma` ships `PrismaModule` and `PrismaService` with higher-level helpers: `query_all_as` for typed row mapping, `execute` for DDL and DML, and `prisma_model!` for declarative repositories that generate `find_unique`, `find_many`, `create`, `update`, `delete`, and more.

### Cargo.toml

```toml theme={null}
[dependencies]
nestrs = "1.5.0"
nestrs-prisma = { version = "1.5.0", features = ["sqlx", "sqlx-postgres"] }
async-trait = "0.1"
sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio", "macros", "postgres"] }
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```

Enable exactly one SQLx backend feature: `sqlx-postgres`, `sqlx-mysql`, or `sqlx-sqlite`. `async-trait` must be a direct dependency of any crate that uses `prisma_model!`.

<Tabs>
  <Tab title="PostgreSQL">
    ```toml theme={null}
    nestrs-prisma = { version = "1.5.0", features = ["sqlx", "sqlx-postgres"] }
    ```

    ```bash theme={null}
    export DATABASE_URL="postgresql://user:password@127.0.0.1:5432/myapp"
    ```
  </Tab>

  <Tab title="MySQL">
    ```toml theme={null}
    nestrs-prisma = { version = "1.5.0", features = ["sqlx", "sqlx-mysql"] }
    ```

    ```bash theme={null}
    export DATABASE_URL="mysql://user:password@127.0.0.1:3306/myapp"
    ```
  </Tab>

  <Tab title="SQLite">
    ```toml theme={null}
    nestrs-prisma = { version = "1.5.0", features = ["sqlx", "sqlx-sqlite"] }
    sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio", "macros", "sqlite"] }
    ```

    ```bash theme={null}
    export DATABASE_URL="sqlite:./dev.db"
    # or for tests:
    # DATABASE_URL="sqlite::memory:?cache=shared"
    ```
  </Tab>
</Tabs>

### Schema

Create a Prisma schema file at `prisma/schema.prisma`. nestrs-prisma reads the schema for optional sync but does not require the Prisma CLI at runtime.

```prisma theme={null}
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  name  String
}
```

Apply the schema to your database — `nestrs-cli db --backend prisma migrate run` is the nestrs-native pass-through, or use Prisma directly:

```bash theme={null}
nestrs-cli db --backend prisma migrate run   # pass-through to npx prisma
# or for quick local work:
npx prisma db push
```

### Bootstrap PrismaModule

Call `PrismaModule::for_root_with_options` before `NestFactory::create` so the pool is ready before DI builds providers.

```rust theme={null}
use nestrs::prelude::*;
use nestrs_prisma::{PrismaModule, PrismaOptions};

#[tokio::main]
async fn main() {
    let db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");

    let _ = PrismaModule::for_root_with_options(
        PrismaOptions::from_url(db_url)
            .pool_min(1)
            .pool_max(10),
    );

    NestFactory::create::<AppModule>()
        .listen(3000)
        .await;
}

#[module(
    imports = [PrismaModule],
    re_exports = [PrismaModule],
)]
pub struct DataModule;

#[module(
    imports = [DataModule],
    controllers = [UserController],
    providers = [UserService],
)]
pub struct AppModule;
```

### Raw queries with PrismaService

`query_all_as` maps rows to any type that implements `sqlx::FromRow`. `execute` runs DDL or parameterless DML. `query_scalar` is useful for health checks.

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

#[derive(Debug, serde::Serialize, sqlx::FromRow)]
pub struct UserRow {
    pub id: i64,
    pub email: String,
    pub name: String,
}

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

impl UserService {
    pub async fn health(&self) -> &'static str {
        match self.prisma.query_scalar("SELECT 1").await {
            Ok(_) => "up",
            Err(_) => "degraded",
        }
    }

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

### Declarative repositories with prisma\_model!

`prisma_model!` generates a full repository from a table declaration. The macro expands a struct, `CreateInput`, `Where`, `Update`, `OrderBy`, and a `PrismaUserRepository` trait — all accessible via `prisma.user()`.

```rust theme={null}
nestrs_prisma::prisma_model!(User => "users", {
    id: i64,
    email: String,
    name: String,
});
```

After the macro expands, you can use the full repository API:

```rust theme={null}
impl UserService {
    pub async fn create_user(&self, email: &str, name: &str) -> Result<UserRow, HttpException> {
        let row = self
            .prisma
            .user()
            .create(UserCreateInput {
                email: email.into(),
                name: name.into(),
            })
            .await
            .map_err(HttpException::from)?;
        Ok(UserRow { id: row.id, email: row.email, name: row.name })
    }

    pub async fn find_by_id(&self, id: i64) -> Result<UserRow, HttpException> {
        let u = self
            .prisma
            .user()
            .find_unique(user::id::equals(id))
            .await
            .map_err(HttpException::from)?
            .ok_or_else(|| NotFoundException::new("user"))?;
        Ok(UserRow { id: u.id, email: u.email, name: u.name })
    }
}
```

<Note>
  `PrismaError` implements `Into<HttpException>`. Map errors with `.map_err(HttpException::from)` or `?` when the return type is `Result<_, HttpException>`.
</Note>

### HTTP controller

```rust theme={null}
#[controller(prefix = "/users", version = "v1")]
pub struct UserController;

#[routes(state = UserService)]
impl UserController {
    #[get("/")]
    pub async fn list(State(s): State<Arc<UserService>>) -> Result<Json<Vec<UserRow>>, HttpException> {
        s.list_users().await.map(Json).map_err(InternalServerErrorException::new)
    }

    #[get("/health/db")]
    pub async fn db_health(State(s): State<Arc<UserService>>) -> &'static str {
        s.health().await
    }
}
```

### Run the quickstart example

The nestrs-prisma crate ships a full end-to-end example with two related models, CRUD operations, and schema sync:

```bash theme={null}
cargo run -p nestrs-prisma --example quickstart --features "sqlx,sqlx-sqlite"
```

***

## Path 3: MongoModule

`MongoModule` wraps the official `mongodb` driver. Call `for_root` (or
`for_root_async` for vault / env factories) with a connection URI before
`NestFactory::create`, then inject `MongoService` to access databases and
collections. `MongoService::model::<T>()` is the NestJS `@InjectModel`
analogue over `MongoRepository::for_feature`.

### Cargo.toml

```toml theme={null}
[dependencies]
nestrs = { version = "1.5.0", features = ["mongo"] }
mongodb = "3"
bson = "3"
futures-util = { version = "0.3", features = ["sink"] }
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```

### Bootstrap and inject

```rust theme={null}
#[tokio::main]
async fn main() {
    let _ = nestrs::MongoModule::for_root(
        std::env::var("MONGODB_URI").unwrap_or_else(|_| "mongodb://127.0.0.1:27017".into()),
    );

    NestFactory::create::<AppModule>()
        .listen(3000)
        .await
        .expect("server");
}

// Async factory (vault / ConfigService) — must complete before create:
// MongoModule::for_root_async(|| async {
//     Ok(nestrs::mongo::MongoOptions::new(std::env::var("MONGO_URI")?))
// }).await?;

#[module(imports = [MongoModule], controllers = [ProfileController], providers = [ProfileStore])]
pub struct AppModule;
```

### Service with typed collections

```rust theme={null}
use bson::doc;
use futures_util::TryStreamExt;
use nestrs::prelude::*;
use serde::{Deserialize, Serialize};
use std::sync::Arc;

#[derive(Debug, Serialize, Deserialize)]
pub struct ProfileDoc {
    pub email: String,
    pub display_name: String,
}

#[injectable]
pub struct ProfileStore {
    mongo: nestrs::MongoService,
}

impl ProfileStore {
    pub async fn find_by_email(&self, email: &str) -> Result<Option<ProfileDoc>, String> {
        let db = self.mongo.database("app").await?;
        let col = db.collection::<ProfileDoc>("profiles");
        col.find_one(doc! { "email": email })
            .await
            .map_err(|e| e.to_string())
    }
}
```

`MongoService::model::<T>()` is the NestJS `@InjectModel` analogue: it
returns `MongoRepository<T>` for a type that implements `Document`
(`#[derive(Document)]`) after `MongoModule::for_feature("db_name")`.
See the [MongoDB recipe](/recipes/mongodb).

### Troubleshooting

| Symptom | What to check |
| - | - |
| `sqlx` pool / TLS errors | `DATABASE_URL` scheme matches the `sqlx-*` feature; Postgres often needs `sslmode` in the URL. |
| "feature not enabled" | Exactly one of `sqlx-postgres`, `sqlx-mysql`, or `sqlx-sqlite` on `nestrs-prisma`. |
| In-memory SQLite flaky | Set `pool_max(1)` — in-memory SQLite works most reliably on a single connection. |
| Macro / trait errors on `prisma_model!` | Add `async-trait` as a direct dependency in your `Cargo.toml`. |
| "MongoModule must be called…" | `MongoModule::for_root` must run before `NestFactory::create` in the same process. |
