# Prisma Documentation - Full Content Feed

This file contains the current Prisma documentation in machine-readable format.
Legacy Prisma ORM v6 content is not included here; fetch any v6 page directly by
appending `.md` to its URL (for example, https://www.prisma.io/docs/orm/v6/....md).
For the documentation index, see https://www.prisma.io/docs/llms.txt.

---

# Deploy the full Prisma stack (/docs/full-stack-tutorial)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.

Location: Deploy the full Prisma stack

This tutorial takes you through the whole recommended stack in one sitting. [Prisma Composer](https://www.prisma.io/docs/composer) declares your app: its services, its databases, and how they connect. [Prisma ORM](https://www.prisma.io/docs/orm) types your data. [Prisma Postgres](https://www.prisma.io/docs/postgres) stores it, locally while you develop and on the platform when you deploy. One declaration drives everything: the same `module.ts` runs the app on your machine and deploys it to [Prisma Compute](https://www.prisma.io/docs/compute). Plan on about 15 minutes.

It uses the `hono` template so you get a small API you can verify with curl at every step. The same journey works for the other templates; the [framework guides](https://www.prisma.io/docs/guides) cover each one.

## Prerequisites [#prerequisites]

* Node.js 22.18 or newer (on the 24 line, 24.11 or newer; 24 recommended), or Bun
* A [Prisma Data Platform account](https://pris.ly/pdp) for the deploy step, free to create
* No database needed: local runs provision a local Prisma Postgres, and deploys provision a real one, both from your Composer declaration

## Use with your agent [#use-with-your-agent]

If you would rather hand the work to a coding agent, this prompt runs the same journey as the one on the [getting started page](https://www.prisma.io/docs), with the `hono` template chosen for you:

The prompt uses npm and Node.js. On Bun, replace `npm create prisma@latest --` with `bun create prisma@latest`, `npx` with `bunx`, and `npm run` with `bun run`.

```text
Create a new Hono API composed with Prisma Composer and Prisma ORM, run it locally, and deploy it to Prisma Compute.

1. Scaffold: `npm create prisma@latest -- my-app --template hono --provider postgres --yes`. Then run `npx prisma@latest init` in `my-app` to confirm the Prisma agent skills the scaffold installed are current, and use them.
2. Read `module.ts` and `service.ts` first: the Composer module provisions the database and the service, and it is what `dev` and `deploy` operate on.
3. Build and run locally: `npm run build`, then `npx prisma dev module.ts`. This provisions a local Prisma Postgres database and applies the contract; no DATABASE_URL is needed. Sample users are seeded on the app's first query. Verify the local URL that `dev` prints: its /users endpoint returns the seeded users.
4. Deploy: check `npx prisma auth whoami`; if I am not signed in, stop and ask me to run `npx prisma auth login` (it opens a browser). The scaffold already wrote the baseline migration under `migrations/app/`; note its directory name, which ends in `_init`. Then run `npx prisma deploy module.ts` and verify the live URL's /users endpoint with curl. The deploy creates the project and provisions the database from the module declaration; do not pass a DATABASE_URL.
5. Evolve the schema: add `role String @default("member")` to the User model in `src/prisma/contract.prisma`, run `npx prisma contract emit`, add `"role"` to the typed select and the returned object in `src/prisma/users.ts`, and plan the migration with `npx prisma migration plan --name add-user-role --from <the init migration directory>`. Then run `npm run build` and `npx prisma deploy module.ts` again, and verify the live /users now returns `role: "member"` with the same createdAt values as before.
```

## 1. Scaffold the app [#1-scaffold-the-app]

One command creates a Composer-declared app with Prisma ORM wired in:

  

#### bun

```bash
bun create prisma@latest my-app --template hono --provider postgres --no-deploy
```

#### pnpm

```bash
pnpm create prisma@latest my-app --template hono --provider postgres --no-deploy
```

#### yarn

```bash
yarn create prisma@latest my-app --template hono --provider postgres --no-deploy
```

#### npm

```bash
npm create prisma@latest -- my-app --template hono --provider postgres --no-deploy
```

Answer the prompts for contract authoring style, package manager, and agent skills, or pass the `--authoring`, `--package-manager`, and `--skills` flags to skip them (see the [create-prisma reference](https://www.prisma.io/docs/prisma-orm/create-prisma); Deno projects cannot deploy to Prisma Compute yet, so this tutorial uses Node.js or Bun). Then enter the project:

  

#### bun

```bash
cd my-app
```

#### pnpm

```bash
cd my-app
```

#### yarn

```bash
cd my-app
```

#### npm

```bash
cd my-app
```

If you work with a coding agent, run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once. The scaffold ran it already, so on a fresh project `init` confirms the setup and reports each step as already done: the [Prisma agent skills](https://www.prisma.io/docs/ai/tools/skills) that ship inside the Prisma packages are synced, and `package.json` has a `postinstall` hook (`prisma skills sync || exit 0`) that resyncs them on every install, plus a `skills:sync` script for refreshing them by hand. Running `init` again is what repairs the setup after you upgrade a Prisma package. See [`skills`](https://www.prisma.io/docs/cli/skills).

## 2. The Composer app [#2-the-composer-app]

Start with the declaration, because it is what every later command operates on. The scaffold declares the whole app in two files. `module.ts` is the app: it provisions a Prisma Postgres database and the service, and wires one to the other:

```ts title="module.ts"
import { module } from "@prisma/composer";
import { postgres } from "@prisma/composer-prisma-cloud/orm";

import { appContract } from "./src/prisma/composer.ts";
import app from "./service.ts";

export default module("my-app", ({ provision }) => {
  const database = provision(
    postgres({
      name: "database",
      contract: appContract,
      config: "./prisma.config.ts",
    }),
    { id: "database" },
  );

  provision(app, { deps: { database } });
});
```

`service.ts` declares the service itself: its name, its dependency on the database, and how it is built:

```ts title="service.ts"
import node from "@prisma/composer/node";
import { compute } from "@prisma/composer-prisma-cloud";
import { postgres } from "@prisma/composer-prisma-cloud/orm";

import { appContract } from "./src/prisma/composer.ts";

export default compute({
  name: "app",
  deps: {
    database: postgres(appContract),
  },
  build: node({ module: import.meta.url, entry: "./dist/server.mjs" }),
});
```

Notice there is no connection string anywhere. The database is a declared dependency, typed by your contract, and Composer injects the connection wherever the app runs. The declaration is ordinary TypeScript: `npx tsc --noEmit` checks the wiring, and mistakes fail the compile instead of a deploy. [Composer](https://www.prisma.io/docs/composer) covers the model in full: modules, services, dependencies, and the first-party building blocks.

## 3. The Prisma ORM data model [#3-the-prisma-orm-data-model]

The data side lives under `src/prisma/`. Your schema is the starter contract in `src/prisma/contract.prisma`; `npm run contract:emit` compiles it into the contract artifacts your queries are type-checked against, and `src/prisma/db.ts` is the typed client the route handlers import. The `/users` route in `src/index.ts` is ordinary Hono code calling an ordinary Prisma ORM query.

Change the contract when you are ready to model your own data, re-emit it, and the compiler walks you through every query the change touches. The [fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data) cover the query patterns.

## 4. Run it locally on Prisma Postgres [#4-run-it-locally-on-prisma-postgres]

Build the server, then bring the whole declaration up on your machine:

  

#### bun

```bash
bun run build
bunx prisma dev module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma dev module.ts
```

#### yarn

```bash
yarn build
yarn prisma dev module.ts
```

#### npm

```bash
npm run build
npx prisma dev module.ts
```

`dev` provisions a local Prisma Postgres database, applies the contract to it, starts the service, and prints the app's local URL when everything is ready. No account, credentials, or connection string are involved; see [Local development](https://www.prisma.io/docs/local-development) for how the local platform works.

Sample users are seeded automatically the first time the app queries the database. Confirm the API serves the seeded rows. `dev` picks a free port and prints the URL, so use the one it printed if it differs from the `3000` shown here:

```bash
curl http://localhost:3000/users
```

```json no-copy
[
  { "id": "1", "email": "alice@prisma.io", "username": "alice", "name": "Alice", "createdAt": "2026-08-24 13:51:34.797+00" },
  { "id": "2", "email": "bob@prisma.io", "username": "bob", "name": "Bob", "createdAt": "2026-08-24 13:51:34.803+00" },
  { "id": "3", "email": "carol@prisma.io", "username": "carol", "name": "Carol", "createdAt": "2026-08-24 13:51:34.804+00" }
]
```

If you prefer the framework's own dev server, `npm run dev` runs it directly. Composer does not manage that mode, so the app needs a database of your own in `DATABASE_URL`. Create one inside your project with the CLI:

  

#### bun

```bash
bunx prisma auth login
bunx prisma project create my-app
bunx prisma postgres create mydb
```

#### pnpm

```bash
pnpm prisma auth login
pnpm prisma project create my-app
pnpm prisma postgres create mydb
```

#### yarn

```bash
yarn prisma auth login
yarn prisma project create my-app
yarn prisma postgres create mydb
```

#### npm

```bash
npx prisma auth login
npx prisma project create my-app
npx prisma postgres create mydb
```

`postgres create` prints the connection string once; export it as `DATABASE_URL`, and mint another later with `npx prisma postgres connection create mydb` if you need one. The `db:*` scripts in `package.json` initialize and verify that database. See [`postgres`](https://www.prisma.io/docs/cli/postgres).

## 5. Deploy app and database to Prisma Compute [#5-deploy-app-and-database-to-prisma-compute]

Sign in once (it opens your browser):

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

Deployed databases evolve through the migrations you commit, so the first migration must create your starting schema. The scaffold already planned it for you as `migrations/app/<timestamp>_init`; commit it with your code. You will chain the next migration from it in [step 7](#7-evolve-the-data-model).

Build and deploy the same declaration:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

Composer creates a project named after your module, provisions the Prisma Postgres database declared in `module.ts`, wires it to the service, and starts the app. There is nothing to configure and no environment file to pass, because the deployed database comes from the declaration exactly as the local one did. When everything is up, the deploy prints what it made, each part of your app next to the platform resource it became, along with the public URL:

```text no-copy
my-app
├─ database   postgres-database db_abc123
└─ app        compute-service cps_abc123
              https://xyz.ewr.prisma.build
```

> [!WARNING]
> The module name must be unique in your workspace
> 
> `deploy` looks the module name up in your workspace and reuses the project this module deployed before rather than creating another. If a `my-app` project exists whose hosted state the CLI cannot verify (one deployed from a different checkout, for example), the deploy stops with `HostedStateBootstrapError` and names a project id you did not choose. Deploy under a different name with [`--name`](https://www.prisma.io/docs/cli/deploy#flags), or rename the module in `module.ts`:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bunx prisma deploy module.ts --name my-app-tutorial
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm prisma deploy module.ts --name my-app-tutorial
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn prisma deploy module.ts --name my-app-tutorial
>     ```
>
> 
>   #### npm

>     ```bash
>     npx prisma deploy module.ts --name my-app-tutorial
>     ```
>
> 

## 6. Verify the live URL [#6-verify-the-live-url]

```bash
curl https://xyz.ewr.prisma.build/users
```

The same three users come back, now served from production next to your database, seeded on the deployed app's first query. Re-deploying is idempotent: build again, deploy again, and the platform applies only the difference. That includes removals, because your module is the source of truth: delete a provision from `module.ts`, deploy again, and the resource disappears from the platform. See [Removing resources](https://www.prisma.io/docs/composer/deploying#removing-resources).

## 7. Evolve the data model [#7-evolve-the-data-model]

Live apps outgrow their starter schema, so give users a role. Add one line to the contract:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  username  String?
  name      String?
  role      String   @default("member")
  posts     Post[]
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}
```

Re-emit the contract, then plan the migration that carries the change, chaining from the baseline migration you committed in [step 5](#5-deploy-app-and-database-to-prisma-compute):

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add-user-role --from <timestamp>_init
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add-user-role --from <timestamp>_init
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add-user-role --from <timestamp>_init
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add-user-role --from <timestamp>_init
```

`--from` names the migration you are building on, and here it is required: a Composer deploy never sets the `db` ref that `migration plan` chains from by default, so a plan without it would describe every table again. The [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) and [`migration ref`](https://www.prisma.io/docs/cli/migration-ref) references cover the default, the ref, and how to keep plans chaining on their own.

The plan is your change and nothing else. Review it like any other diff, with [`migration show`](https://www.prisma.io/docs/cli/migration-show) or by reading the generated package:

```text no-copy
ALTER TABLE "public"."User" ADD COLUMN "role" text DEFAULT 'member' NOT NULL
```

Emitting also updated the query types, so surface the new field in the route's typed select in `src/prisma/users.ts`, adding `"role"` to the `.select(...)` list and `role: user.role` to the returned object:

```ts title="src/prisma/users.ts"
const users = await db.orm.public.User.select("id", "email", "username", "name", "role", "createdAt").limit(limit).all();
```

This is the Prisma ORM loop: the contract is the source of truth, the emit step regenerates the types, and the compiler points at every query the change touches.

If you want to see the change on your machine first, run `npm run build` and `npx prisma dev module.ts` again; the local database applies the new migration on start and `/users` returns the role there too. Then build and deploy again:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

The deploy applies the committed migration to the deployed database in place. The same users come back with `role: "member"`, backfilled by the column default, and their `createdAt` timestamps unchanged; nothing was dropped or recreated:

```bash
curl https://xyz.ewr.prisma.build/users
```

```json no-copy
[
  { "id": "1", "email": "alice@prisma.io", "username": "alice", "name": "Alice", "role": "member", "createdAt": "2026-08-24 18:40:06.375+00" }
]
```

## 8. Clean up (optional) [#8-clean-up-optional]

The project keeps running until you remove it. Deleting it removes the service and the database, so the command asks you to repeat the project id (find it with `npx prisma project list`):

  

#### bun

```bash
bunx prisma project delete <project-id> --confirm <project-id>
```

#### pnpm

```bash
pnpm prisma project delete <project-id> --confirm <project-id>
```

#### yarn

```bash
yarn prisma project delete <project-id> --confirm <project-id>
```

#### npm

```bash
npx prisma project delete <project-id> --confirm <project-id>
```

## Next steps [#next-steps]

* [Learn Composer](https://www.prisma.io/docs/composer/getting-started): typed contracts between services, databases, storage, and scheduled jobs.
* [Pick your framework](https://www.prisma.io/docs/guides): the same journey for Next.js, Nuxt, Astro, NestJS, TanStack Start, and more.
* [Branching and previews](https://www.prisma.io/docs/compute/branching): how each branch gets its own isolated environment.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): reading, writing, relations, and transactions.
* [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push): connect GitHub and add a deploy workflow so every push deploys, with a preview environment per branch.

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.
- [`Overview`](https://www.prisma.io/docs/cli): Prisma CLI reference

# Choose a Prisma ORM setup path (/docs/getting-started)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Choose the fastest path to try Prisma ORM in a new or existing project.

Location: Choose a Prisma ORM setup path

Start with a quickstart if you want [Prisma ORM](https://www.prisma.io/docs/orm) to create the app. Use the existing-project path if you already have an app and database.

Coming from an earlier version? [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) maps every Prisma ORM 7 API to its Prisma ORM 8 form, and [Release status](https://www.prisma.io/docs/orm/release-status) says where Prisma ORM 8 stands today.

## Start a new project [#start-a-new-project]

  

#### bun

```bash
bun create prisma@latest
```

#### pnpm

```bash
pnpm create prisma@latest
```

#### yarn

```bash
yarn create prisma@latest
```

#### npm

```bash
npm create prisma@latest
```

The [create-prisma reference](https://www.prisma.io/docs/prisma-orm/create-prisma) lists every template and flag.

- [Deploy the full Prisma stack](https://www.prisma.io/docs/full-stack-tutorial): The whole journey in one sitting: scaffold, Prisma Postgres, first query, and a Prisma Compute deploy.

- [Quickstart with PostgreSQL](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql): Create the app, run it against a local Prisma Postgres from Composer or your own PostgreSQL, and run the first query.

- [Quickstart with MongoDB](https://www.prisma.io/docs/prisma-orm/quickstart/mongodb): Create the app, connect a MongoDB deployment, apply the first migration, and run the first query.

```text
Create a new [framework] application with Prisma ORM, seed it, and run it locally.

If I have not told you which framework, stop and ask before scaffolding. Valid --template values: minimal (the default), next, hono, nuxt, astro, nest, svelte, tanstack-start, elysia.

1. Scaffold the app: `npm create prisma@latest -- my-app --template [framework] --provider postgres --yes`.
2. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
3. From the project directory, apply the starter contract: `npm run db:init`. Sample users are seeded automatically on the app's first query; there is no separate seed script.
4. Edit the starter contract under `src/prisma/` into a small schema for my use case, then run `npm run contract:emit` and plan and apply the migration: `npx prisma migration plan`, then `npx prisma db migrate --yes`. Migration planning diffs the emitted contract, so the emit step is required.
5. Update the seed script under `src/prisma/` and the app routes to query the new schema, start `npm run dev` in the background (with `DATABASE_URL` exported), and verify with a request against the running app. For the `nest` template, if routes return 500s with `reading 'findAll'` in the logs, add explicit `@Inject()` tokens as shown in https://www.prisma.io/docs/guides/frameworks/nestjs.md.

Use the installed Prisma ORM skills and the current Prisma docs: https://www.prisma.io/docs/llms.txt (append `.md` to any docs URL for a markdown version).
```

## Add to an existing project [#add-to-an-existing-project]

  

#### bun

```bash
bunx prisma@latest orm init
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init
```

#### yarn

```bash
yarn dlx prisma@latest orm init
```

#### npm

```bash
npx prisma@latest orm init
```

- [Add to PostgreSQL](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql): Add Prisma ORM to an existing PostgreSQL app and infer a starter contract from the live schema.

- [Add to MongoDB](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/mongodb): Add Prisma ORM to an existing MongoDB app and model the collections you want to query first.

```text
Add Prisma ORM to this existing project.

This flow is for PostgreSQL. If the project uses MongoDB, follow https://www.prisma.io/docs/prisma-orm/add-to-existing-project/mongodb.md instead; for other databases, stop and tell me.

1. Run `npx prisma@latest orm init --yes --target postgres --authoring psl` (the flags are required when the CLI cannot prompt). It writes `prisma.config.ts`, a starter contract and `db.ts` under `src/prisma/`, and installs dependencies. Then run `npx prisma skills sync` to install the Prisma ORM skills.
2. Set `DATABASE_URL` in `.env` to my database. If I did not give you one, create a Prisma Postgres database with `npx create-db@latest`, put its connection string in `.env`, and show me the claim URL it prints so I can keep the database.
3. If the database already has tables, infer the contract from it: `npx prisma contract infer`, then `npx prisma contract emit`, then sign it with `npx prisma db sign`. If the database is empty, keep the starter contract and run `npx prisma db init`.
4. Write one query with the generated `db` client in an existing code path, run it, and show me the returned rows.

Follow https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql.md and the installed Prisma ORM skills.
```

## After setup [#after-setup]

* Use the generated app scripts for the first run.
* Open `prisma-8.md` or the installed Prisma ORM skills when you want agent-ready guidance inside the project.
* Change the starter contract when you are ready to model your own data.
* Open the [Prisma ORM overview](https://www.prisma.io/docs/orm) when you want the concepts behind the setup.

## Related pages

- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.
- [`Overview`](https://www.prisma.io/docs/cli): Prisma CLI reference

# Get started with Prisma (/docs)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma is a complete TypeScript stack with one workflow: **build** your app and run all of it on your machine, then **deploy** it to the Prisma platform with one command. Check out the [full-stack tutorial](https://www.prisma.io/docs/full-stack-tutorial).
  <span className="mt-2 block">Here for the ORM? Jump straight to [Prisma ORM 7](https://www.prisma.io/docs/orm/v7) or [Prisma ORM 8](https://www.prisma.io/docs/orm), or check the [release status](https://www.prisma.io/docs/orm/release-status) first.</span>

  
## Build

Define the app in TypeScript and run everything locally before you ship.

- **[Local development](https://www.prisma.io/docs/local-development)**: One command runs your whole app on your machine, with your services on Bun wired to local Postgres and local storage, and no cloud credentials.

- **[Composer](https://www.prisma.io/docs/composer)** (Early Access): Declare your services and the resources they depend on: databases, jobs, buckets, secrets.

- **[ORM](https://www.prisma.io/docs/orm)**: Model your data and query it with type safety, end to end.

## Deploy

One deploy provisions everything on the Prisma platform and connects it.

- **[Compute](https://www.prisma.io/docs/compute)**: Hosting for your services, next to your data.

- **[Storage](https://www.prisma.io/docs/storage)**: S3-compatible object storage inside your project.

- **[Postgres](https://www.prisma.io/docs/postgres)**: Managed PostgreSQL, provisioned during setup.

- **[Deploy](https://www.prisma.io/docs/prisma-compute/deploy)**: Ship from your terminal with Composer, from the Console, or on every push from a connected repository with a deploy workflow. Every branch gets its own environment.
  

  One CLI serves the whole stack: `npx prisma@latest` drives the ORM and the Prisma platform, from migrations and local dev to deploys, databases, and buckets, for you and your coding agent. See the [CLI reference](https://www.prisma.io/docs/cli).

## Pick your framework

Every guide runs the same journey with the same commands: scaffold, connect Prisma Postgres, run a real query, and deploy. SvelteKit and Deno don't deploy to Compute yet; their guides stop at a verified local run.

- [Next.js](https://www.prisma.io/docs/guides/frameworks/nextjs)

- [Hono](https://www.prisma.io/docs/guides/frameworks/hono)

- [TanStack Start](https://www.prisma.io/docs/guides/frameworks/tanstack-start)

- [NestJS](https://www.prisma.io/docs/guides/frameworks/nestjs)

- [Astro](https://www.prisma.io/docs/guides/frameworks/astro)

- [Nuxt](https://www.prisma.io/docs/guides/frameworks/nuxt)

- [SvelteKit](https://www.prisma.io/docs/guides/frameworks/sveltekit)

- [Bun](https://www.prisma.io/docs/guides/runtimes/bun)

- [Elysia](https://www.prisma.io/docs/guides/frameworks/elysia)

- [Deno](https://www.prisma.io/docs/guides/runtimes/deno)

If you're using Express or another Node.js server, follow the [existing-project path](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql) instead.

## Prisma ORM 7

Prisma ORM 7 remains fully supported. Scaffold it with `npx create-prisma@stable`, or add it to an existing project with `npx prisma@prev init`. It pairs with Prisma Postgres and Prisma Compute the same way. When you're ready, Prisma ORM 8 is the upgrade path.

- [Prisma ORM 7 setup paths](https://www.prisma.io/docs/v7/getting-started): All database quickstarts, plus the agent prompt

- [Prisma ORM 7 quickstart](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres): With Prisma Postgres, 5 min

## Other setups

If you already have an app or a database, or need a single Prisma product on its own, each path below has a guide to follow and a prompt to hand to your agent.

**Existing project, your own database, or a single product on its own**

### Add Prisma to an existing project

Follow the guide: [PostgreSQL guide](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql)

```text
Add Prisma ORM to this existing project.

This flow is for PostgreSQL. If the project uses MongoDB, follow https://www.prisma.io/docs/prisma-orm/add-to-existing-project/mongodb.md instead; for other databases, stop and tell me.

1. Run `npx prisma@latest orm init --yes --target postgres --authoring psl` (the flags are required when the CLI cannot prompt). It writes `prisma.config.ts`, a starter contract and `db.ts` under `src/prisma/`, and installs dependencies. Then run `npx prisma skills sync` to install the Prisma ORM skills.
2. Set `DATABASE_URL` in `.env` to my database. If I did not give you one, create a Prisma Postgres database with `npx create-db@latest`, put its connection string in `.env`, and show me the claim URL it prints so I can keep the database.
3. If the database already has tables, infer the contract from it: `npx prisma contract infer`, then `npx prisma contract emit`, then sign it with `npx prisma db sign`. If the database is empty, keep the starter contract and run `npx prisma db init`.
4. Write one query with the generated `db` client in an existing code path, run it, and show me the returned rows.

Follow https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql.md and the installed Prisma ORM skills.
```

### Prisma ORM with your own PostgreSQL database

Follow the guide: [Quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql)

```text
Create a new [framework] application with Prisma ORM against my existing PostgreSQL database.

If I have not given you a connection string, stop and ask; do not invent one. Valid --template values: minimal (the default), next, hono, nuxt, astro, nest, svelte, tanstack-start, elysia.

1. Scaffold: `npm create prisma@latest -- my-app --template [framework] --provider postgres --yes`.
2. Export my connection string as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`. From the project directory: `npm run db:init`, then start `npm run dev` in the background and verify the sample query returns data. Sample users are seeded automatically on the app's first query; there is no separate seed script.
3. Evolve the starter contract under `src/prisma/` into my schema, then run `npm run contract:emit`, `npx prisma migration plan`, and `npx prisma db migrate --yes`.

Do not provision any hosted database. Use the installed Prisma ORM skills and https://www.prisma.io/docs/llms.txt for current docs.
```

### Prisma ORM only (Prisma ORM 7)

Follow the guide: [Quickstart](https://www.prisma.io/docs/v7/prisma-postgres/quickstart/prisma-orm)

```text
Add Prisma ORM 7 to this project with my existing database.

If I have not given you a database connection string and none exists in the project, stop and ask.

1. Run `npx prisma@prev init` (Prisma ORM 7). For an existing database, set DATABASE_URL in `.env` and introspect it with `npx prisma@prev db pull`; for a new schema, define models in `prisma/schema.prisma` and run `npx prisma@prev migrate dev --name init`. If migrate dev asks to reset the database, stop and ask me first.
2. Install the driver adapter for the database (Prisma ORM 7 requires one), e.g. `npm install @prisma/adapter-pg` for PostgreSQL, and pass it to `new PrismaClient({ adapter })`. Generate the client with `npx prisma@prev generate` and write one query in an existing code path.
3. Run the query (e.g. with `npx tsx`) and show me the output, the schema, and the query you added.

Current docs: https://www.prisma.io/docs/orm/v7.md and https://www.prisma.io/docs/llms.txt.
```

### Prisma Postgres only

Follow the guide: [create-db guide](https://www.prisma.io/docs/postgres/npx-create-db)

```text
Create a Prisma Postgres database for this project.

1. Run `npx create-db@latest`. It creates a temporary Prisma Postgres database without an account and prints a connection string plus a claim URL.
2. Put the connection string in `.env` as DATABASE_URL and wire it into whichever of Prisma ORM, Kysely, Drizzle, TypeORM, or node-postgres the project already uses (detect it from package.json; if none, ask me). Verify the connection with one trivial query such as `select 1`.
3. Remind me to open the claim URL to keep the database in my Prisma workspace.

Current docs: https://www.prisma.io/docs/postgres.md.
```

### Prisma Compute only

Follow the guide: [Deploy guide](https://www.prisma.io/docs/prisma-compute/deploy)

```text
Deploy this app to Prisma Compute using `npx prisma@latest`.

Compute runs apps declared with Prisma Composer: your server code plus a small TypeScript declaration. Port the app following https://www.prisma.io/docs/composer/porting-an-app.md. SvelteKit and Deno are not supported yet; if the app is one of those, stop and tell me.

1. Install `@prisma/composer` and `@prisma/composer-prisma-cloud`, and pin `effect` in package.json to the exact version in `node_modules/@prisma/composer/package.json` (`"overrides": { "effect": "<that version>" }`). Then install the Composer skill with `npx prisma skills sync`, and use it.
2. Declare the app: a `service.ts` with `compute({ name, deps, build })`, a `module.ts` that provisions it, and a `prisma-composer.config.ts`. Read the port from `service.port()` and bind 0.0.0.0. Replace other `process.env` reads with the service input schema, binding credentials like DATABASE_URL with `envSecret`. Composer does not build: produce one self-contained entry file per service (for example `esbuild <server> --bundle --platform=node --format=esm --outfile=dist/server.mjs`), or use the framework build adapter (Next.js needs the `nextjs` adapter and `output: "standalone"`).
3. Verify locally: run the build, then `npx prisma dev module.ts`, and curl the printed local URL.
4. Confirm I am signed in with `npx prisma auth whoami`; if not, stop and ask me to run `npx prisma auth login` (it opens a browser).
5. Deploy: run the build, then `npx prisma deploy module.ts` with the app's env values (like DATABASE_URL) exported in the shell; the first deploy copies input values up to the deployment. Verify the printed public URL with curl.

Current docs: https://www.prisma.io/docs/composer/porting-an-app.md and https://www.prisma.io/docs/prisma-compute/deploy.md.
```

    If you're using MongoDB, follow the [MongoDB quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/mongodb) or [add Prisma ORM to an existing MongoDB app](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/mongodb). If you work with [Kysely](https://www.prisma.io/docs/prisma-postgres/quickstart/kysely), [Drizzle](https://www.prisma.io/docs/prisma-postgres/quickstart/drizzle-orm), or [TypeORM](https://www.prisma.io/docs/prisma-postgres/quickstart/typeorm), follow the Prisma Postgres quickstart for that tool.

## Browse the docs

This page hides the full navigation to keep the first run focused. These links open the full docs for each product.

- [Prisma ORM](https://www.prisma.io/docs/orm): Prisma ORM 8, with Prisma ORM 7 docs

- [Prisma Postgres](https://www.prisma.io/docs/postgres): The managed database

- [Prisma Compute](https://www.prisma.io/docs/compute): Hosting and branching

- [CLI reference](https://www.prisma.io/docs/cli): Every command and flag

- [Guides](https://www.prisma.io/docs/guides): Frameworks and workflows

- [AI tools](https://www.prisma.io/docs/ai): Skills, MCP, and prompts

# Prisma with AI coding tools (/docs/ai)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Use Prisma with AI coding tools like Cursor, Codex, and ChatGPT

Location: Prisma with AI coding tools

Prisma ORM and Prisma Postgres work with AI coding agents through installable skills, an MCP server, and editor integrations. This page collects the setup guides, prompts, and tutorials for using them together.

## Get started [#get-started]

Run the following command to bootstrap your database with a prompt:

  

#### bun

```bash
bunx --bun prisma@prev init --prompt "Create a habit tracker application"
```

#### pnpm

```bash
pnpm dlx prisma@prev init --prompt "Create a habit tracker application"
```

#### yarn

```bash
yarn dlx prisma@prev init --prompt "Create a habit tracker application"
```

#### npm

```bash
npx prisma@prev init --prompt "Create a habit tracker application"
```

## AI Coding Tools [#ai-coding-tools]

Each guide covers setup and prompts for using Prisma in a specific AI editor or agent.

* [Cursor](https://www.prisma.io/docs/ai/tools/cursor) - Define project-specific rules and use your schema as context to generate accurate queries and code.
* [Codex](https://www.prisma.io/docs/ai/tools/codex) - Install the Prisma Codex plugin with Prisma ORM skills and the remote Prisma MCP server.
* [Windsurf](https://www.prisma.io/docs/ai/tools/windsurf) - Automate your database workflows by generating schemas, queries, and seed data in this AI-powered editor.
* [Github Copilot](https://www.prisma.io/docs/ai/tools/github-copilot) - Get Prisma-aware code suggestions, run CLI commands from chat, and query the Prisma docs.
* [ChatGPT](https://www.prisma.io/docs/ai/tools/chatgpt) - Learn how to connect the Prisma MCP server to ChatGPT to manage your databases with natural language.

## Agent Skills [#agent-skills]

AI agents often generate outdated Prisma v6 code. Install Prisma Skills to give your agent accurate, up-to-date v7 knowledge: CLI commands, Client API, upgrade guides, database setup, and Prisma Postgres workflows.

  

#### bun

```bash
bunx skills add prisma/skills
```

#### pnpm

```bash
pnpm dlx skills add prisma/skills
```

#### yarn

```bash
yarn dlx skills add prisma/skills
```

#### npm

```bash
npx skills add prisma/skills
```

* [Available skills and setup](https://www.prisma.io/docs/ai/tools/skills) - See all available skills and learn how to install them.

## MCP server [#mcp-server]

With Prisma's MCP server, your AI tool can create Prisma Postgres databases, run SQL queries, restore automated backups, and manage Object Storage. It can also manage Prisma Compute deployments, read app logs, set environment variables, and inspect how your [Composer](https://www.prisma.io/docs/composer) services connect.

```json title="Integrate in AI tool"
{
  "mcpServers": {
    "Prisma": {
      "url": "https://mcp.prisma.io/mcp"
    }
  }
}
```

* [Available tools](https://www.prisma.io/docs/ai/mcp-tools) - The full list of tools the Prisma MCP server exposes.
* [Integrating in AI tools](https://www.prisma.io/docs/ai/tools/mcp-server#integrating-in-ai-tools) - Configuration for Cursor, Claude, Warp, and other AI tools.
* [How we built it](https://www.prisma.io/blog/about-mcp-servers-and-how-we-built-one-for-prisma) - How the MCP protocol works and how the Prisma MCP server was built.

## Vibe Coding Tutorials [#vibe-coding-tutorials]

Tutorials that build a full application from scratch with an AI coding assistant.

* [Build a Linktree Clone SaaS](https://www.prisma.io/docs/ai/tutorials/linktree-clone) - Build a Linktree clone SaaS with Next.js, Prisma Postgres, and Clerk auth using AI assistance.

## Resources [#resources]

* [Vibe Coding with Limits](https://www.prisma.io/blog/vibe-coding-with-limits-how-to-build-apps-in-the-age-of-ai) - How to Build Apps in the Age of AI
* [Vibe Coding an E-commerce App](https://www.prisma.io/blog/vibe-coding-with-prisma-mcp-and-nextjs) - with Prisma MCP and Next.js
* [Integrating the Vercel AI SDK](https://www.prisma.io/docs/guides/integrations/ai-sdk) - in a Next.js application

## Integrations [#integrations]

* [Automate with Pipedream](https://pipedream.com/apps/prisma-management-api) - Connect Prisma Postgres to 2,800+ apps in automated workflows
* [Firebase Studio](https://www.prisma.io/docs/guides/postgres/idx) - Prompt your application with Firebase Studio & Prisma Postgres

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# MCP tools (/docs/ai/mcp-tools)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Available Prisma MCP tools for databases, Compute deployments, Object Storage, and Composer projects.

Location: AI > MCP tools

These tools are available through the [Prisma MCP server](https://www.prisma.io/docs/ai/tools/mcp-server) in your selected workspace. Your AI client lists each tool's input parameters when it connects.

> [!WARNING]
> Tools that change or delete resources can cause data loss or interrupt live traffic. Check the target workspace and resources before approving an operation in your AI tool.

## Workspace and databases [#workspace-and-databases]

* `fetch_workspace_details`: Fetch the details of a Prisma Postgres workspace.
* `list_prisma_postgres_databases`: Fetch a list of available Prisma Postgres databases for the user's workspace.
* `create_prisma_postgres_database`: Create a managed Prisma Postgres database and a new project.
* `delete_prisma_postgres_database`: Permanently delete a Prisma Postgres database by ID. This tool cannot delete a project's default database.

## Connection strings [#connection-strings]

* `list_prisma_postgres_connection_strings`: Fetch a list of available connection strings for the given database id.
* `create_prisma_postgres_connection_string`: Create a new connection string for a Prisma Postgres database with the given id.
* `delete_prisma_postgres_connection_string`: Delete a connection string with the given connection string id.

## Backups and recovery [#backups-and-recovery]

* `list_prisma_postgres_backups`: List available automated backups for a Prisma Postgres database.
* `create_prisma_postgres_recovery`: Restore a Prisma Postgres database to a new database with the given backup id.

## Schema and queries [#schema-and-queries]

* `introspect_database_schema`: Read the schema of a Prisma Postgres database to show its structure.
* `execute_sql_query`: Run SQL to read, modify, or delete data in a Prisma Postgres database, without changing its schema.
* `execute_prisma_postgres_schema_update`: Execute a schema update on a Prisma Postgres database with the given id.

## Object Storage [#object-storage]

* `list_object_store_buckets`: List object-store buckets in the workspace, optionally filtered by project id.
* `create_object_store_bucket`: Create a new object-store bucket in the given project.
* `delete_object_store_bucket`: Permanently delete an object-store bucket, all objects stored in it, and all its access keys.
* `create_object_store_bucket_key`: Create an S3-compatible access key for an object-store bucket.
* `delete_object_store_bucket_key`: Delete an object-store bucket access key. The key stops working immediately.

## Documentation [#documentation]

* `search_prisma_documentation`: Answer a natural-language question about Prisma using the official Prisma documentation, returning a cited answer with links back to the docs.

## Compute apps and builds [#compute-apps-and-builds]

* `list_prisma_compute_apps`: List Prisma Compute apps in the selected workspace, optionally filtered by project.
* `list_prisma_compute_builds`: List builds, newest first, with optional project, branch, and state filters.
* `list_prisma_compute_deployments`: List deployments for a Prisma Compute app, newest first.
* `get_prisma_compute_deployment_logs`: Read runtime logs for a deployment, one page at a time.

## Compute deployment management [#compute-deployment-management]

* `promote_prisma_compute_deployment`: Make a running deployment the live version of an app.
* `rollback_prisma_compute_app`: Make an existing deployment live, starting it first if it is stopped.
* `start_prisma_compute_deployment`: Start an existing deployment from an already uploaded build. This tool does not build or upload the app.
* `stop_prisma_compute_deployment`: Stop a deployment, disconnecting it from the app's public URL if it is the live version.
* `delete_prisma_compute_deployment`: Permanently delete a deployment, stopping it first if needed.
* `delete_prisma_compute_app`: Permanently delete an app. To stop and delete its deployments too, set `deleteDeployments` to true; otherwise, active deployments block deletion.

## Compute environment variables [#compute-environment-variables]

* `set_prisma_compute_env_var`: Set an environment variable for a project's production or preview environment, or override it for one preview branch. Values are encrypted and never returned.
* `delete_prisma_compute_env_var`: Permanently delete an environment variable by ID.

## Composer projects [#composer-projects]

[Composer](https://www.prisma.io/docs/composer) defines your application's services, databases, and other resources in TypeScript.

* `get_prisma_composer_topology`: Show the saved connections between a project's Composer services and resources, with Console links and stored app URLs. The result may be out of date and does not check whether apps are running.

The Compute tools manage existing apps and deployments; they do not build or upload your source code. To deploy a new app, follow the [Prisma Compute guide](https://www.prisma.io/docs/compute).

# Apps and Modules (/docs/composer/apps-and-modules)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.

Location: Composer > Apps and Modules

A **Prisma App** is a tree of Modules composed in TypeScript. At the leaves are **services**, the units that run your code, and **resources**, stateful things like a Postgres database. A parent Module wires them together; your code never participates in the wiring, it only receives the results.

For example, a store app might be one root module containing a `catalog` Module (an API service plus its own database), an `orders` Module, and a `storefront` Next.js service that calls both. Each piece declares what it needs, and the root wires the pieces together.

This matters because the wiring is data the compiler can check. A dependency wired to the wrong producer, or a missing one, fails `tsc` and fails the deploy, instead of failing at runtime in production.

## The service declaration [#the-service-declaration]

A service declares everything about itself in one `compute()` call. It is pure data, with no behavior:

```ts
compute({
  name: 'auth',                  // the service's name in the app graph
  deps: { db: postgres() },      // what it needs         -> read via service.load()
  input: authInput,              // its incoming config   -> read via service.input()
  build: node({ module: import.meta.url, entry: '../dist/server.mjs' }),
  expose: { rpc: authContract }, // what it offers to other services
});
```

Dependencies and input are two deliberately separate channels with two separate accessors. A dependency is a live connection to another node; input is data, plain values and credentials together, declared as one schema (see [Service input](https://www.prisma.io/docs/composer/service-input)). Your code contains no configuration reads and no URLs, which is what makes every environment (production, a stage, a test) a different set of injected values and nothing more.

## The root module [#the-root-module]

The root module is the app. The Composer CLI loads its default export:

```ts title="module.ts"
import { module } from '@prisma/composer';
import authModule from './src/auth/module.ts';
import storefrontService from './src/storefront/service.ts';

export default module('my-app', ({ provision }) => {
  const auth = provision(authModule);
  provision(storefrontService, { deps: { auth: auth.rpc } });
});
```

`provision(node, opts?)` places a node in the graph and returns a ref carrying one port per exposed contract. Its options:

* `id`: the node's name in the graph, defaulting to its own `name`. Set it explicitly when the default stutters; a service named `auth` inside a module named `auth` would read as `auth.auth`.
* `deps`: a value for each declared dependency slot, either another provisioned ref or an exposed port.
* `input`: the service's input binding, required exactly when the service declares an input schema. See [Service input](https://www.prisma.io/docs/composer/service-input).
* `secrets`: for a Module boundary, a binding for each forwarded secret need.

Two naming rules the platform enforces: provision names must be at least three characters (call a database `'database'`, not `'db'`; the wiring key on the service side can still be `db`), and ids must be unique within their module.

## Reusable Modules [#reusable-modules]

When a service and its database belong together, package them as a **Module**: a unit that owns its internals and offers only typed ports. A consumer provisions the Module and wires its exposed contract; it never sees, and can never reach, the database inside.

A Module declares its boundary (what it needs, what it offers) in the second argument, wires its internals in the builder function, and returns the ports it promised:

```ts title="src/auth/module.ts"
import { module, secret } from '@prisma/composer';
import { postgres } from '@prisma/composer-prisma-cloud';
import { authContract } from './contract.ts';
import authService from './service.ts';

export default module(
  'auth',
  { secrets: { signingKey: secret() }, expose: { rpc: authContract } },
  ({ secrets, provision }) => {
    const db = provision(postgres({ name: 'database' }));
    const service = provision(authService, {
      id: 'service',
      deps: { db },
      input: { signingKey: secrets.signingKey },
    });
    return { rpc: service.rpc };
  },
);
```

The boundary declares `secrets: { signingKey: secret() }`: a nameless need the Module forwards without ever learning the platform variable's name. The root binds it:

```ts title="module.ts"
const auth = provision(authModule, {
  secrets: { signingKey: envSecret('AUTH_SIGNING_SECRET') },
});
provision(storefrontService, { deps: { auth: auth.rpc } });
```

A Module can also declare boundary `deps`: inputs its parent must supply, wired exactly like a service's. The root module you already have is the outermost Module, with no boundary at all.

## When to reach for a Module [#when-to-reach-for-a-module]

* **Compose before you write.** Ready-made Modules for scheduled jobs, blob storage, and event streams ship with the framework; wiring one in is a couple of lines. See [Building blocks](https://www.prisma.io/docs/composer/building-blocks).
* **Package what belongs together.** A service that owns a database, or a pair of services that only make sense as a unit, is a Module.
* **Keep the app graph readable.** The deploy prints the module tree with dotted addresses (`auth.service`), so the structure you author is the structure you operate.

## Next steps [#next-steps]

* [Services and contracts](https://www.prisma.io/docs/composer/services-and-contracts): what happens on the wire between services.
* [Service input](https://www.prisma.io/docs/composer/service-input): configuration and secrets as one schema.
* [Building blocks](https://www.prisma.io/docs/composer/building-blocks): the Modules that ship with the framework.

## Related pages

- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.
- [`Getting started`](https://www.prisma.io/docs/composer/getting-started): Build a two-service Prisma App from an empty directory and run it on your machine with one command.

# Building blocks (/docs/composer/building-blocks)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.

Location: Composer > Building blocks

Building blocks are Modules you compose instead of implementing a capability yourself. Each owns its internals and hands you a typed port, so adding one is a couple of lines. The first-party set ships inside `@prisma/composer-prisma-cloud`. It is small, and growing:

| Import                                                 | What you get                                                    | Exposes   |
| ------------------------------------------------------ | --------------------------------------------------------------- | --------- |
| `cron` from `@prisma/composer-prisma-cloud/cron`       | A scheduler that fires your jobs at your service on an interval | nothing   |
| `storage` from `@prisma/composer-prisma-cloud/storage` | An S3-backed blob store, credentials included                   | `store`   |
| `streams` from `@prisma/composer-prisma-cloud/streams` | Durable append-only event streams, backed by a `store`          | `streams` |

Before implementing a capability by hand, check whether a block already owns it. Wiring one in takes a few lines, while an integration you write yourself is code you maintain.

## Cron [#cron]

Cron is the block most apps want first. You supply two things, a schedule and a runner service that exposes the `trigger` contract, and the Module does the rest.

The schedule is the single source of truth for job ids and intervals:

```ts title="src/promotions/service.ts"
import { defineSchedule, triggerContract } from '@prisma/composer-prisma-cloud/cron';

export const schedule = defineSchedule({ rotateSpecial: '30s' });

export default compute({
  name: 'promotions',
  deps: { catalog: rpc(catalogContract) },
  build: node({ module: import.meta.url, entry: '../dist/server.mjs' }),
  expose: { trigger: triggerContract },
});
```

In the server, map each job id to work. `serveSchedule` checks the map against the schedule, so an unhandled job does not compile:

```ts title="src/promotions/server.ts"
import { serveSchedule } from '@prisma/composer-prisma-cloud/cron';

const handler = serveSchedule(service, schedule, {
  rotateSpecial: (deps) => deps.catalog.rotateSpecial({}),
});
```

In the module, the cron Module's boundary deps mirror the runner's own, so the root wires it like any other edge:

```ts title="module.ts"
provision(cron({ schedule, runner: promotionsService }), {
  deps: { catalog: catalog.rpc },
});
```

A runner that declares an `input` schema (see [Service input](https://www.prisma.io/docs/composer/service-input)) takes its binding on `cron()` itself, with `envSecret(...)` where the schema expects a secret. It is required exactly when the runner declares a schema, the same rule `provision()` applies:

```ts title="module.ts"
provision(
  cron({
    schedule,
    runner: ingestService,
    input: { token: envSecret('INGEST_TOKEN') },
  }),
  { deps: { catalog: catalog.rpc } },
);
```

The scheduler is the one service in your app that never sleeps. Compute scales an idle service to zero, and the scheduler receives no requests of its own, so it holds the platform's keep-awake guard for its whole lifetime. One warm instance per app is the cost of the clock; the runner sleeps like any other service and wakes when the scheduler calls it.

## Storage and streams [#storage-and-streams]

The `storage` Module provisions an S3-backed blob store, with its own Postgres and minted credentials, and exposes a `store` port. The `streams` Module builds durable append-only event streams on top of a `store`. For working versions, including the streams Module's secret binding, see [`examples/storage`](https://github.com/prisma/composer/tree/main/examples/storage) and [`examples/streams`](https://github.com/prisma/composer/tree/main/examples/streams) in the Composer repository.

If you want the raw S3 surface without the Module, provision a [`bucket` resource](https://www.prisma.io/docs/composer/object-storage) instead; the two share a contract kind, so a service wired to `s3()` can be rewired to a `bucket` without changing its declaration.

## Where new blocks come from [#where-new-blocks-come-from]

An **extension** is a package that brings its own Modules, resources, or deploy target, using the same mechanism `@prisma/composer-prisma-cloud` itself uses. The convention is an npm package named `prisma-composer-*`, which is how you and your agent find one. An extension is installed like any dependency and enters the deploy through the `extensions` array in `prisma-composer.config.ts`.

The ecosystem is new: today the three Modules above plus the ones you write are the whole set. Treat `prisma-composer-*` as the place to look, and check that a package actually exists on npm before depending on it.

## Next steps [#next-steps]

* [Apps and Modules](https://www.prisma.io/docs/composer/apps-and-modules): write a reusable Module of your own.
* [Object storage](https://www.prisma.io/docs/composer/object-storage): the raw bucket resource.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.
- [`Getting started`](https://www.prisma.io/docs/composer/getting-started): Build a two-service Prisma App from an empty directory and run it on your machine with one command.

# Core concepts (/docs/composer/core-concepts)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.

Location: Composer > Core concepts

Prisma Composer is a TypeScript framework for applications made of several services. You touch two things: the `@prisma/composer` library, which you use to declare your services and what they depend on, and the `dev` and `deploy` commands in the Prisma CLI, which run and provision what you declared on [Prisma Compute](https://www.prisma.io/docs/compute) and [Prisma Postgres](https://www.prisma.io/docs/postgres). The declarations use a small vocabulary that repeats everywhere: in the authoring API, in deploy output, and in error messages. The sections below define each term in plain language, and each links to the page that goes deeper.

## Declarations are data [#declarations-are-data]

Everything you author in Composer is a declaration: a plain TypeScript value that describes a piece of your application without running it. A service declaration says what the service is, what it depends on, and how it was built:

```ts title="src/storefront/service.ts"
import nextjs from '@prisma/composer/nextjs';
import { rpc } from '@prisma/composer/service-rpc';
import { compute } from '@prisma/composer-prisma-cloud';
import { catalogContract } from '../catalog/contract.ts';

export default compute({
  name: 'storefront',
  deps: { catalog: rpc(catalogContract) },
  build: nextjs({ module: import.meta.url, appDir: '..' }),
});
```

The `deps` line says the storefront calls the catalog service's API, named by a [contract](#contracts) defined further down this page. Importing this file starts no service and provisions nothing: `compute()` returns a plain description. The declaration is data that three different consumers read: the TypeScript compiler checks the wiring, the deploy provisions what it describes, and the runtime injects the declared dependencies into your code. That is why a mistake, such as a dependency wired to a producer with a different contract, fails `tsc` in seconds instead of failing a deploy.

Two rules follow from this design and shape everything else:

1. **Your code never reads its environment.** No `process.env`, no hardcoded URLs. Every dependency and config value arrives typed, through injection.
2. **Composer never bundles or transforms your code.** You build with your own tooling; the deploy assembles what you built.

## The three node kinds [#the-three-node-kinds]

A Composer application is a tree of nodes. There are three kinds, and each answers a different question:

| Kind         | What it is                                                               | Declared with         |
| ------------ | ------------------------------------------------------------------------ | --------------------- |
| **Service**  | A unit that runs your code: an API, a web app, a worker                  | `compute()`           |
| **Resource** | A stateful dependency the platform manages for you: a database, a bucket | `postgres()`, storage |
| **Module**   | A boundary that groups services and resources and exposes typed ports    | `module()`            |

A service is atomic: Composer sees its ports and nothing inside. A Module is the opposite: it runs no code of its own; its behaviour is the composition of what it wraps. A Module owns its internals, so a consumer can use its exposed port but can never reach the database inside it.

The **App** is not a fourth kind. It is the outermost Module, the one whose file you hand to the CLI. It wires the top-level pieces together, and deploying it deploys everything it contains. On the platform, the App becomes one Prisma [project](https://www.prisma.io/docs/compute#the-model): services land on [Prisma Compute](https://www.prisma.io/docs/compute) and databases on [Prisma Postgres](https://www.prisma.io/docs/postgres).

What is deliberately not a node: plain values. An API key, a region name, or a feature flag has no lifecycle to manage, so it is **configuration**, and it travels through a different channel ([below](#two-channels-dependencies-and-input)). The test for whether something is a node is whether the deploy can create, update, and destroy it.

See [Apps and Modules](https://www.prisma.io/docs/composer/apps-and-modules) for the full authoring surface.

## Ports and wiring [#ports-and-wiring]

Every node has typed connection points, called ports. A `deps` entry is a port where the node requires something; an `expose` entry is a port where it offers something. Wiring means connecting a required port to an offered one that satisfies it, and it happens in exactly one place: a Module's builder function, using `provision()`:

```ts title="module.ts"
import { module } from '@prisma/composer';
import catalogModule from './src/catalog/module.ts';
import ordersModule from './src/orders/module.ts';
import storefrontService from './src/storefront/service.ts';

export default module('store', ({ provision }) => {
  const catalog = provision(catalogModule);
  const orders = provision(ordersModule, { deps: { catalog: catalog.rpc } });
  provision(storefrontService, { deps: { catalog: catalog.rpc, orders: orders.rpc } });
});
```

`provision()` places a node in the graph and returns a ref carrying one port per exposed contract. Because ports are typed, the compiler verifies every wire: each declared dependency must be bound, and bound to a producer whose contract matches. The wired graph as a whole is the application's **topology**, and the deploy prints it as a tree with dotted addresses (`auth.service`), so the structure you author is the structure you operate.

## Two channels: dependencies and input [#two-channels-dependencies-and-input]

A service receives things from outside through two deliberately separate channels, with two separate accessors in your code.

**Dependencies** are live connections to other nodes: another service's API, a database. They are declared in `deps` and arrive in code through `service.load()`, already typed and already authenticated:

```ts title="src/storefront/data.ts"
import service from './service.ts';

const { catalog } = service.load();
const { products } = await catalog.listProducts({});
```

**Input** is configuration: plain values and credentials, declared together as one [Standard Schema](https://standardschema.dev) and read through `service.input()`. The service declares what shapes are legal; the place that provisions it decides where each value comes from. There are three bindings:

1. A **literal**: the value is written at the provision site and travels with the deployment.
2. **`envParam(NAME)`**: the value is read from a named platform variable per environment, so the same app reads different values in production and in a staging copy.
3. **`envSecret(NAME)`**: like `envParam`, but the value is a credential: redacted in output and never stored in deploy state. This is the only thing Composer calls a secret.

The split is what makes environments cheap: production, a staging stage, a local run, and a test all execute the same code with different injected values. See [Service input](https://www.prisma.io/docs/composer/service-input).

## Contracts [#contracts]

A **contract** is the typed interface through which services communicate. You write it once as a set of method signatures with Standard Schema message types (arktype, zod, and valibot all work), then both sides use it: the providing service serves it, and a consuming service declares `rpc(contract)` as a dependency and gets a typed client from `service.load()`. On the wire, calls are RPC over HTTP, authenticated with per-consumer service keys Composer provisions for you, and retried safely. See [Services and contracts](https://www.prisma.io/docs/composer/services-and-contracts).

Databases have a contract story of their own: a `postgres()` resource is typed by a [Prisma ORM data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract), and its migrations run as part of the deploy. Every database belongs to exactly one Module, which is what makes migration ownership unambiguous: the Module that owns the database owns its schema. See [Databases](https://www.prisma.io/docs/composer/databases).

## The deploy model [#the-deploy-model]

A deploy is not a script of steps you wrote; it is a comparison. `deploy` loads your root module, compares the topology it describes with the **deploy state** recorded for that environment, and applies only the difference: create what is new, update what changed, leave the rest alone. Re-running a deploy with nothing changed is a no-op, and re-running after a failure converges what the deploy state already tracks rather than starting over. One edge sits outside that guarantee: if an environment's very first deploy fails before its state is written, resources created up to that point are untracked, and neither a retry nor a destroy will manage them.

  

#### bun

```bash
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn prisma deploy module.ts
```

#### npm

```bash
npx prisma deploy module.ts
```

Two consequences of convergence are worth naming. Removing a node from your module removes the deployed thing on the next deploy, because the topology is the source of truth. And tearing a whole environment down works through the same mechanism, via the `destroy` operation in `@prisma/composer/control`. See [Deploying](https://www.prisma.io/docs/composer/deploying) and the [`deploy` reference](https://www.prisma.io/docs/cli/deploy).

## Stages [#stages]

A **stage** is an environment name chosen at deploy time, never written in the topology. The same graph deploys anywhere:

  

#### bun

```bash
bunx prisma deploy module.ts                  # production
bunx prisma deploy module.ts --stage staging  # a persistent staging environment
bunx prisma deploy module.ts --stage pr-42    # one environment per PR
```

#### pnpm

```bash
pnpm prisma deploy module.ts                  # production
pnpm prisma deploy module.ts --stage staging  # a persistent staging environment
pnpm prisma deploy module.ts --stage pr-42    # one environment per PR
```

#### yarn

```bash
yarn prisma deploy module.ts                  # production
yarn prisma deploy module.ts --stage staging  # a persistent staging environment
yarn prisma deploy module.ts --stage pr-42    # one environment per PR
```

#### npm

```bash
npx prisma deploy module.ts                  # production
npx prisma deploy module.ts --stage staging  # a persistent staging environment
npx prisma deploy module.ts --stage pr-42    # one environment per PR
```

Deploying with no `--stage` targets production, which lives at the project level. A named stage is a complete, isolated copy of the app, deployed as a [preview branch](https://www.prisma.io/docs/compute/branching) of the same project: its own services, its own databases, its own configuration. The only thing a stage shares with production is the code, which is exactly what the two-channel design promises: same topology, different injected values.

## Local development [#local-development]

`dev` brings the whole app up on your machine by running the same deploy pipeline against local emulators standing in for Prisma Compute and Prisma Postgres. No credentials, no network. Your services, databases, and wiring are real; only the providers underneath are swapped, so behaviour like service-key authentication works locally exactly as it does deployed:

  

#### bun

```bash
bunx prisma dev module.ts
```

#### pnpm

```bash
pnpm prisma dev module.ts
```

#### yarn

```bash
yarn prisma dev module.ts
```

#### npm

```bash
npx prisma dev module.ts
```

See [Local development](https://www.prisma.io/docs/composer/local-development) for what persists between runs and the [`dev` reference](https://www.prisma.io/docs/cli/dev).

## Building blocks and extensions [#building-blocks-and-extensions]

A Module is also the unit of reuse. A **building block** is a ready-made Module that ships with the framework and composes in a couple of lines: `cron` for scheduled jobs, `storage` for S3-backed blobs, and `streams` for durable event streams. Because a block is an ordinary Module, wiring one in is the same `provision()` call you use for your own.

An **extension** is a package that brings its own Modules, resources, or deploy target, published under the `prisma-composer-*` naming convention. The first-party blocks above are the whole catalogue today. See [Building blocks](https://www.prisma.io/docs/composer/building-blocks) and [Object storage](https://www.prisma.io/docs/composer/object-storage).

## Testing [#testing]

Because your code receives everything through `service.load()` and `service.input()`, a test is another environment: one where you decide what those calls return. `mockService` substitutes a fake for a unit test; `bootstrapService` hydrates a service with real local dependencies for an integration test. Nothing is provisioned and no code changes. See [Testing](https://www.prisma.io/docs/composer/testing).

## Next steps [#next-steps]

* [Apps and Modules](https://www.prisma.io/docs/composer/apps-and-modules): the authoring surface behind the node kinds and `provision()`.
* [Getting started](https://www.prisma.io/docs/composer/getting-started): build and run a two-service app from an empty directory.
* [Limitations](https://www.prisma.io/docs/composer/limitations): what Composer does not do yet, before you commit to a design.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.
- [`Getting started`](https://www.prisma.io/docs/composer/getting-started): Build a two-service Prisma App from an empty directory and run it on your machine with one command.

# Databases (/docs/composer/databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.

Location: Composer > Databases

There are two ways for a service to get a [Prisma Postgres](https://www.prisma.io/docs/postgres) database, depending on how much you want the framework to do. Both are dependencies: the service declares the need, the module provisions the resource, and your code receives the result from `service.load()`.

> [!NOTE]
> Two kinds of contract
> 
> Composer's [service contracts](https://www.prisma.io/docs/composer/services-and-contracts) describe an RPC API between services. A Prisma ORM **data contract** describes a database schema. This page uses both: `postgres()` ties a database dependency to a Prisma ORM data contract.

## `rawPostgres()`: bring your own client [#rawpostgres-bring-your-own-client]

Declare `rawPostgres()` when you want to build the client yourself. The dependency delivers connection config, `{ url }`, and nothing else. In your server entry, build the client you already know (`pg`, Bun's `SQL`, an ORM):

```ts title="src/auth/service.ts"
import { compute, rawPostgres } from '@prisma/composer-prisma-cloud';

export default compute({
  name: 'auth',
  deps: { db: rawPostgres() },
  // ...
});
```

```ts title="src/auth/server.ts"
import { SQL } from 'bun';

const { db } = service.load();
const sql = new SQL({ url: db.url, max: 1, idleTimeout: 10 });
```

Those pool settings matter. Prisma Compute scales to zero and closes idle connections, so keep the pool small and reconnect-friendly. See [Deploying](https://www.prisma.io/docs/composer/deploying#production-behavior).

The module that owns the database provisions it:

```ts title="module.ts"
const db = provision(rawPostgres({ name: 'database' }));
provision(authService, { deps: { db } });
```

## `postgres()`: a Prisma ORM-typed database [#postgres-a-prisma-orm-typed-database]

If you want typed queries and managed migrations, make the database a [Prisma ORM](https://www.prisma.io/docs/prisma-orm) one. `load()` then returns `{ url, client }`: the raw connection string, plus a client generated from your data contract. Queries like `db.client.orm.public.Product.where({ id }).first()` are compile-time checked, with no SQL strings and no row mapping. The client is constructed only on first access, so a service that brings its own Postgres client can still read `db.url` and keep contract-checked wiring and deploy-time migrations.

The schema workflow runs once per schema change, using the [Prisma ORM CLI commands](https://www.prisma.io/docs/cli):

1. Edit `contract.prisma`, your schema.
2. Run `contract emit` to regenerate `contract.json` and `contract.d.ts` from it.
3. Run `migration plan` to author the migration into `migrations/`.
4. Deploy. The deploy applies `migrations/` before the service starts. There is no `CREATE TABLE IF NOT EXISTS` anywhere in app code.

In your app, wrap the emitted contract once. Both the resource and every service that queries it reference that one value:

```ts title="src/data.ts"
import { dataContract } from '@prisma/composer-prisma-cloud/orm';
import type { Contract } from '../contract.d.ts';
import contractJson from '../contract.json' with { type: 'json' };

export const catalogData = dataContract<Contract>(contractJson);
```

You call `postgres()` on both sides of the wiring, and what you pass it tells the two apart. Passing the contract alone declares the dependency, the service saying what it queries:

```ts
deps: { db: postgres(catalogData) }
```

Passing an options object declares the resource. The module that owns the database provisions it, naming the `prisma.config.ts` path (relative to the module file) so the deploy can reload the emitted `contract.json` and find `migrations/`:

```ts
const db = provision(
  postgres({ name: 'database', contract: catalogData, config: './prisma.config.ts' }),
);
```

Because both ends share the contract value, the deploy refuses to wire a service against a database whose schema does not match. Deploy state records only the contract's identity; the full emitted contract is reloaded through `prisma.config.ts` at deploy time, and if `contract.json` is missing, unreadable, or no longer matches the declared contract, the deploy fails before touching the database.

For complete working versions, see [`examples/orm-demo`](https://github.com/prisma/composer/tree/main/examples/orm-demo) (one service, one typed database) and [`examples/store`](https://github.com/prisma/composer/tree/main/examples/store) (the full pattern inside a reusable Module) in the Composer repository.

## Local databases [#local-databases]

`dev` provisions real local Postgres instances for both kinds, so you can migrate and query them exactly as you would in production, with no cloud credentials. The data persists across restarts until you pass `--fresh`. See [Local development](https://www.prisma.io/docs/composer/local-development).

## Next steps [#next-steps]

* [Object storage](https://www.prisma.io/docs/composer/object-storage): the other stateful resource, an S3-compatible bucket.
* [Apps and Modules](https://www.prisma.io/docs/composer/apps-and-modules): keep a database private inside a Module.
* [Prisma ORM CLI reference](https://www.prisma.io/docs/cli): the contract and migration commands in detail.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.
- [`Getting started`](https://www.prisma.io/docs/composer/getting-started): Build a two-service Prisma App from an empty directory and run it on your machine with one command.

# Deploying (/docs/composer/deploying)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.

Location: Composer > Deploying

`deploy` takes your entry file (the one whose default export is the root module) and stands the whole app up on [Prisma Compute](https://www.prisma.io/docs/compute) and [Prisma Postgres](https://www.prisma.io/docs/postgres). You choose the target environment, production or an isolated **stage**, on the command line rather than in your code. Tearing an environment down is the `destroy` operation of the [control API](#driving-deploys-from-code).

| You want to...                    | Run                                          |
| --------------------------------- | -------------------------------------------- |
| Deploy to production              | `npx prisma deploy module.ts`                |
| Deploy an isolated environment    | `npx prisma deploy module.ts --stage <name>` |
| Deploy under a different app name | `npx prisma deploy module.ts --name demo-42` |

## Credentials [#credentials]

On your machine, `deploy` uses the session stored by `auth login`, the same sign-in every other CLI command uses:

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

In CI or any headless environment, use a service token instead. Set two environment variables:

* `PRISMA_SERVICE_TOKEN`: create a service token for your workspace in the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=composer).
* `PRISMA_WORKSPACE_ID`: in the workspace's settings.

A fresh checkout with those two variables set deploys successfully once the app's project exists. The very first deploy creates that project, and a new project needs a region: set it in the deploy config or in the environment, as described in the [`deploy` reference](https://www.prisma.io/docs/cli/deploy). Once the project exists it keeps its region, and later deploys, stages included, inherit it. The CLI finds or creates everything else. Keep the values out of the repo (an `.env` you source at deploy time, or CI secrets). When `PRISMA_SERVICE_TOKEN` is set it takes priority over any stored session.

## Build first [#build-first]

`deploy` does not build for you. It assembles what your build produced:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

Deploy state records what is already provisioned, so a re-deploy applies the difference instead of recreating everything. The platform stores this state with the environment it describes, scoped to that environment's branch inside the app's project. It is not stored on your machine, so your laptop and CI see the same state. Concurrent deploys of the same environment take turns through a lease on that state. While one deploy holds the lease, a second deploy fails immediately with a message naming the holder. If a deploy crashes, its lease expires after about a minute, and the next deploy takes over.

## Production and stages [#production-and-stages]

Deploying with no `--stage` targets **production**. In platform terms, the app is a project (named after your root module), and production lives at the project level. The name is looked up in your workspace: a project this module deployed before is reused, and redeploying converges it. A project with the same name whose hosted state the CLI cannot identify or verify (one created outside this module's deploys, for example) stops the command with `HostedStateBootstrapError`. Use `--name` to deploy under a different name, or rename the module.

`--stage <name>` deploys a complete, isolated copy of the app as a [preview branch](https://www.prisma.io/docs/compute/branching) of that same project: its own services, its own databases, its own configuration. The only thing a stage shares with production is the code. Composer's *stage* and Compute's *preview branch* are the same object seen from two tools, which is why the stage's variables are the branch's [environment variables](https://www.prisma.io/docs/compute/environment-variables):

  

#### bun

```bash
bunx prisma deploy module.ts                  # production
bunx prisma deploy module.ts --stage staging  # a persistent staging environment
bunx prisma deploy module.ts --stage pr-42    # one environment per PR
```

#### pnpm

```bash
pnpm prisma deploy module.ts                  # production
pnpm prisma deploy module.ts --stage staging  # a persistent staging environment
pnpm prisma deploy module.ts --stage pr-42    # one environment per PR
```

#### yarn

```bash
yarn prisma deploy module.ts                  # production
yarn prisma deploy module.ts --stage staging  # a persistent staging environment
yarn prisma deploy module.ts --stage pr-42    # one environment per PR
```

#### npm

```bash
npx prisma deploy module.ts                  # production
npx prisma deploy module.ts --stage staging  # a persistent staging environment
npx prisma deploy module.ts --stage pr-42    # one environment per PR
```

Re-deploying any environment is idempotent: it updates the resources in place. A stage name must be a valid git ref name. An invalid name fails the deploy rather than being renamed.

## What a deploy prints [#what-a-deploy-prints]

A deploy ends by printing what it made, in your own terms: the names you authored, what each one became on the platform, and the public URLs:

```text no-copy
storefront-auth
├─ auth
│  └─ api   compute-service cps_abc123
│           https://xyz.ewr.prisma.build
├─ db       postgres-database db_def456
└─ web      compute-service cps_ghi789
            https://uvw.ewr.prisma.build
```

The tree is your module structure: `auth.api` is the `api` service inside the `auth` Module. Under each name is the platform resource it became and its ID, the thing to search for in the Console when you need it.

URLs appear for publicly reachable endpoints. That is why a Compute service prints one and a database does not: a database has a connection string, not a public endpoint. Secrets are left out entirely, so a node whose only output is a keypair prints no resource line. A node that deployed but published nothing reportable still appears in the tree, marked `(no entities reported)`.

## Removing resources [#removing-resources]

Your module is the source of truth for what exists. To remove a resource, delete its provision from the code and deploy again: the deploy compares the declaration against the environment's deploy state and deletes whatever is no longer declared, alongside any creates and updates the same deploy needs.

```text no-copy
Plan: 3 to update, 4 to delete, 1 to noop
[web2-deploy] deleted
[COMPOSER_WEB2_PORT-var] deleted
[COMPOSER_WEB2_ORIGIN-var] deleted
[web2-svc] deleted
```

A removed service takes its deployment and its wiring with it, and the resources that remain are untouched: a two-service app whose second service is deleted from the module keeps serving from the first without interruption.

Two things a deploy never removes:

1. **The last service.** An app is at least one service; a module that provisions nothing fails with `ASSEMBLE.SERVICE_MISSING` before anything runs, so you cannot empty an environment by emptying the module.
2. **The project and its branches.** Those are the containers an environment deploys into: created if absent on deploy, and never deleted by one. Tearing down a whole environment is the [`destroy` operation](#destroying); deleting an entire project is [`project delete`](https://www.prisma.io/docs/cli/project), which asks you to repeat the project id with `--confirm <project-id>` because it destroys the project's databases too.

## Destroying [#destroying]

The unified CLI has no `destroy` command. Tear an environment down with the `destroy` operation from `@prisma/composer/control` (see [Driving deploys from code](#driving-deploys-from-code)). It requires an explicit target, `{ kind: 'stage', stage }` or `{ kind: 'production' }`, and there is no default, so a teardown always names what it destroys. Unlike the CLI, the control API does not read the session stored by `auth login`. Export `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` (see [Credentials](#credentials)) before running the script, or it stops with `environment variable PRISMA_WORKSPACE_ID is required`:

```ts title="destroy-staging.ts"
import { destroy } from '@prisma/composer/control';

const result = await destroy({ entry: 'module.ts', target: { kind: 'stage', stage: 'staging' } });
if (!result.ok) throw new Error(`${result.failure.code}: ${result.failure.message}`);
```

If you deployed under a different name with `--name`, pass the same `name` here so the operation finds the right project.

Destroying a stage removes its resources, then deletes its branch along with the stage's deploy state. Destroying production removes the resources and, if the project is empty afterwards, deletes the project too, so empty projects do not pile up in your workspace. A project still holding another stage's resources stays in place. Tearing down a stage that was never deployed fails with "nothing deployed". It does not provision one first.

## CI [#ci]

On GitHub, connect the repository and add [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action) to a workflow instead of scripting the deploy yourself. The action derives the target from the branch: the default branch deploys production, and every other branch deploys a stage named after it. Connected repositories authenticate through GitHub's OIDC tokens, without a stored secret. [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push) walks through the setup.

Any other CI runs the same commands as your machine: set the two credential variables as CI secrets, build, and deploy. The per-PR environment pattern:

  

#### bun

```bash
bunx prisma deploy module.ts --stage "pr-$PR_NUMBER"    # on push
```

#### pnpm

```bash
pnpm prisma deploy module.ts --stage "pr-$PR_NUMBER"    # on push
```

#### yarn

```bash
yarn prisma deploy module.ts --stage "pr-$PR_NUMBER"    # on push
```

#### npm

```bash
npx prisma deploy module.ts --stage "pr-$PR_NUMBER"    # on push
```

When the PR closes, tear the stage down with the `destroy` operation, targeting `{ kind: 'stage', stage: 'pr-<number>' }` from a small script.

One extra step applies if your app binds input fields with `envSecret` or `envParam` (see [Service input](https://www.prisma.io/docs/composer/service-input)). Each stage stores its own copy of those platform variables. The deploying shell only seeds them. A fresh stage, such as a new `pr-42`, starts with none of them, so CI must export the values alongside the two credential variables. The first deploy then copies any missing values from the shell up to the stage. If a name is absent from both the platform and the shell, the deploy fails early and names the missing variable.

## When a deploy stops on an effect version conflict [#when-a-deploy-stops-on-an-effect-version-conflict]

Before doing anything else, every Composer command verifies that the installed dependency tree gives the deploy engine the exact `effect` version `@prisma/composer` pins. When it does not, the command stops immediately:

```text no-copy
Error: Dependency conflict: alchemy resolves effect@<found>, but
@prisma/composer requires effect@<required>.
```

This happens when your app, or another dependency of it, pins a different `effect` than `@prisma/composer` does and your package manager hoists that copy where the deploy engine resolves it. A plain Composer app never hits it: `@prisma/composer` and `@prisma/composer-prisma-cloud` pin every `effect`-family package the engine would otherwise float, so a fresh install resolves a single `effect`. The fix is to use the same `effect` as Composer: match your own `effect` dependency to the exact version the error names (`dependencies.effect` in `@prisma/composer`), or, when a dependency you cannot change pins another version, force Composer's with an `overrides` entry for `effect` in your `package.json` (`resolutions` in Yarn, under `"pnpm"` for pnpm) and reinstall. The pin goes stale when you upgrade `@prisma/composer`; the error names the new version each time.

## When a deploy stops on a missing connection value [#when-a-deploy-stops-on-a-missing-connection-value]

A dependency's connection declares the values it needs, by name, and the node on the other end has to supply them. When one does not, the deploy stops and names the edge rather than standing the app up:

```text no-copy
Connection input "auth.db" declares param "url", but its producer "db" did not
supply it — the producer's outputs carry [host].
```

Fix it at whichever end is wrong: add the name to the outputs the producer returns, or mark the param `optional` on the connection if absent is a valid value (the consumer then reads `undefined`). Do not make the param optional just to route around the error: that reinstates a silent `undefined`. You will only meet this error if you authored the connection or an extension on one side of the wire. Every block that ships with the framework supplies what it declares.

## Production behavior [#production-behavior]

Behavior you will run into once the app is deployed, and what to do about it:

* **Compute scales to zero, and idle database connections get closed.** A long-lived client that treats a dropped connection as fatal will crash-loop through 502s. Keep the pool small and reconnect-friendly, and do not let an async error kill the process:

  ```ts
  const sql = new SQL({ url: db.url, max: 1, idleTimeout: 10 });
  process.on('uncaughtException', (err) => console.error('uncaughtException', err));
  process.on('unhandledRejection', (err) => console.error('unhandledRejection', err));
  ```

* **Bind `0.0.0.0`, not loopback.** Compute routes external HTTP to the VM; a `localhost` listener is unreachable from outside.

* **A deployed `/rpc/<method>` returns `401` to you.** Calls are [authenticated for you](https://www.prisma.io/docs/composer/services-and-contracts#calls-are-authenticated-for-you), and your `curl` is not one of the services the app connected. Reach it through a consumer instead.

* **Calls into a sleeping service can get `ECONNRESET`** while it cold-starts. Retry them; the generated RPC client already does.

* **The `cron` scheduler stays awake on purpose.** It holds Compute's keep-awake guard for its whole lifetime, so it never scales to zero: one warm instance per app is the cost of the clock. Every other service, the runner included, sleeps as usual.

* **The `COMPOSER_*` variables in your project belong to the deploy.** Config, secret pointers, and service keys all land there, and every deploy rewrites them. An edit made by hand does not survive the next deploy.

* **Streaming responses stream, but the first bytes have a 60-second deadline.** Compute's ingress forwards your response as your service sends it; it does not hold it back until the response completes. What it bounds is the wait for the response to start: send nothing for 60 seconds and the client gets `504 Gateway Time-out` and the request is cancelled. Send the first bytes early, keep data flowing rather than letting a started stream sit idle, and have a long-lived client reconnect instead of holding one connection open. See [Request timeout](https://www.prisma.io/docs/compute/request-timeout).

* **Next.js pages that call `service.load()` need `export const dynamic = 'force-dynamic'`.** The runtime environment does not exist at build time, and Next.js will not re-read it for prerendered routes.

## Driving deploys from code [#driving-deploys-from-code]

Everything the CLI does is also callable in-process, from `@prisma/composer/control`: typed `deploy`, `destroy`, `dev`, and `log` operations that return structured results instead of printing and exiting. The operations and their result shapes are documented in [the control API](https://www.prisma.io/docs/cli/deploy#the-control-api) on the `deploy` command reference.

## Next steps [#next-steps]

* [Local development](https://www.prisma.io/docs/composer/local-development): the same pipeline, no credentials.
* [Service input](https://www.prisma.io/docs/composer/service-input): how per-stage configuration and secrets travel.
* [`deploy` command reference](https://www.prisma.io/docs/cli/deploy): every flag, plus the control API for destroy and log.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Getting started`](https://www.prisma.io/docs/composer/getting-started): Build a two-service Prisma App from an empty directory and run it on your machine with one command.

# Getting started (/docs/composer/getting-started)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Build a two-service Prisma App from an empty directory and run it on your machine with one command.

Location: Composer > Getting started

By the end of this page you will have a working Prisma App: a `quotes` API and a public `gateway` that calls it. A typed contract wires the two together, and one command runs them on your machine. Along the way you will meet every core Composer idea once: a contract, a service, a root module, a build, and a local run.

The app is deliberately tiny, with no database, so you can see the whole shape at once. Adding a Postgres is the natural next step. See [Databases](https://www.prisma.io/docs/composer/databases) when you are ready.

> [!NOTE]
> Working with a coding agent
> 
> Add the Composer skill first, even if you plan to write every line yourself. It ships inside the `@prisma/composer` package, and one command, run after step 1 installs the packages, copies it into the directories your agent reads and stops the agent from inventing an API that does not exist:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bunx --bun prisma@latest init
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm dlx prisma@latest init
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn dlx prisma@latest init
>     ```
>
> 
>   #### npm

>     ```bash
>     npx prisma@latest init
>     ```
>
> 
> 
> `init` also adds a `postinstall` hook that keeps the skill matching the installed version; see [`skills`](https://www.prisma.io/docs/cli/skills).

## Prerequisites [#prerequisites]

* **Node.js 22.18 or newer.** Check with `node --version`. Composer hands your TypeScript entry file straight to Node. Node runs `.ts` files directly only from 22.18.0, the release that turns type stripping on by default. On any older version, including 22.17, Composer commands stop at `ERR_UNKNOWN_FILE_EXTENSION` naming your own entry file.
* **[Bun](https://bun.sh).** Prisma Compute runs Bun, so the server code targets it (`Bun.serve`). This guide also uses `bun build` to produce the built output.
* **npm, pnpm, or Bun.** Bun workspaces need two extra direct dependencies; see the note in step 1.

You do not need a Prisma account for this page. Local runs never talk to the platform. You only need credentials when you [deploy](https://www.prisma.io/docs/composer/deploying).

## 1. Set up the project [#1-set-up-the-project]

Create a directory and install the two Composer packages, plus [arktype](https://arktype.io) for the contract schemas:

  

#### bun

```bash
bun init
npm pkg set type module
# couldn't auto-convert command
bun add @prisma/composer @prisma/composer-prisma-cloud arktype
bun add --dev typescript @types/bun
```

#### pnpm

```bash
pnpm init
npm pkg set type=module
# couldn't auto-convert command
pnpm add @prisma/composer @prisma/composer-prisma-cloud arktype
pnpm add -D typescript @types/bun
```

#### yarn

```bash
yarn init
npm pkg set type=module
# couldn't auto-convert command
yarn add @prisma/composer @prisma/composer-prisma-cloud arktype
yarn add --dev typescript @types/bun
```

#### npm

```bash
npm init
npm pkg set type=module
npm install @prisma/composer @prisma/composer-prisma-cloud arktype
npm install -D typescript @types/bun
```

`"type": "module"` matters: Composer loads your entry file as an ES module, and without it every Composer command stops at `COMPOSE.ENTRY_UNLOADABLE` ("Cannot use import statement outside a module").

You do not need to pin `effect` yourself. `@prisma/composer` and `@prisma/composer-prisma-cloud` pin every `effect`-family package their deploy engine needs, so a fresh install resolves a single copy. `DEPS.EFFECT_VERSION_CONFLICT` only appears when something in your dependency tree, your own `effect` pin or another dependency's, hoists a different `effect` where the deploy engine resolves it; see [When a deploy stops on an effect version conflict](https://www.prisma.io/docs/composer/deploying#when-a-deploy-stops-on-an-effect-version-conflict).

> [!NOTE]
> Bun workspaces
> 
> In a Bun workspace (a monorepo with isolated installs), two of Composer's indirect dependencies must also be direct ones, because Bun does not expose transitive packages or their bins to your app:
> 
> ```bash
> bun add alchemy
> bun add -d @prisma/dev
> ```
>
> Without `alchemy`, `dev` and `deploy` stop at `DEPLOY.ALCHEMY_BIN_MISSING`; without `@prisma/dev`, local dev stops with "local dev needs @prisma/dev". A single-package Bun project is not affected.

Add a `tsconfig.json` so the compiler checks your wiring the same way the deploy will:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Preserve",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "noEmit": true,
    "strict": true,
    "skipLibCheck": true,
    "types": ["bun"]
  },
  "include": ["module.ts", "src"]
}
```

This is what you are about to create:

```text no-copy
my-app/
├── module.ts                  # the root module: the app itself
├── prisma-composer.config.ts  # deploy config (read only by the CLI)
└── src/
    ├── quotes/
    │   ├── contract.ts        # the quotes service's public API, as types
    │   ├── service.ts         # what quotes is: deps + build + what it exposes
    │   └── server.ts          # the code that actually runs
    └── gateway/
        ├── service.ts
        └── server.ts
```

## 2. Create the quotes service [#2-create-the-quotes-service]

A service is three files. First, the **contract**: the API other services will call, written as schemas. It lives with the service that owns it. Any [Standard Schema](https://standardschema.dev) validator works (arktype, zod, valibot); these examples use arktype:

```ts title="src/quotes/contract.ts"
import { contract, rpc } from '@prisma/composer/service-rpc';
import { type } from 'arktype';

export const quotesContract = contract({
  random: rpc({ input: type({}), output: type({ quote: 'string' }) }),
});
```

Second, the **service declaration**. This is pure data with no behavior. It says what the service is called, what it depends on (nothing yet), how it is built, and which contract it exposes:

```ts title="src/quotes/service.ts"
import node from '@prisma/composer/node';
import { compute } from '@prisma/composer-prisma-cloud';
import { quotesContract } from './contract.ts';

export default compute({
  name: 'quotes',
  deps: {},
  build: node({ module: import.meta.url, entry: '../../dist/quotes/server.mjs' }),
  expose: { rpc: quotesContract },
});
```

Third, the **server**: the code your build turns into `dist/quotes/server.mjs` and the platform boots. `serve()` generates the HTTP handler from the contract. If you forget a handler or return the wrong shape, the code does not compile:

```ts title="src/quotes/server.ts"
import { serve } from '@prisma/composer/service-rpc';
import service from './service.ts';

const port = service.port(); // the reserved port, resolved (default 3000)

const QUOTES = [
  'Simplicity is prerequisite for reliability.',
  'Make it work, make it right, make it fast.',
];

const handler = serve(service, {
  rpc: {
    random: async () => ({ quote: QUOTES[Math.floor(Math.random() * QUOTES.length)]! }),
  },
});
export default handler;

// Bind all interfaces. Compute routes external HTTP to the VM, so a
// loopback-only listener would be unreachable.
Bun.serve({ port, hostname: '0.0.0.0', fetch: handler });
```

Notice what is missing: no URL of anything and no `process.env`. Every service gets a port for free, read through `service.port()`. Dependencies arrive through `service.load()`. Any configuration of your own arrives through `service.input()` (see [Service input](https://www.prisma.io/docs/composer/service-input)). Those three typed accessors are the whole framework contract with your code.

## 3. Create the gateway service [#3-create-the-gateway-service]

The gateway depends on the quotes contract. Note the asymmetry with step 2: the quotes service *exposed* the bare contract (what it provides), while the gateway wraps it in `rpc()` (what it needs: a client of this contract). Declaring `deps: { quotes: rpc(quotesContract) }` means `service.load()` hands the server a ready-made typed client:

```ts title="src/gateway/service.ts"
import node from '@prisma/composer/node';
import { rpc } from '@prisma/composer/service-rpc';
import { compute } from '@prisma/composer-prisma-cloud';
import { quotesContract } from '../quotes/contract.ts';

export default compute({
  name: 'gateway',
  deps: { quotes: rpc(quotesContract) },
  build: node({ module: import.meta.url, entry: '../../dist/gateway/server.mjs' }),
});
```

```ts title="src/gateway/server.ts"
import service from './service.ts';

const { quotes } = service.load();
const port = service.port();

Bun.serve({
  port,
  hostname: '0.0.0.0',
  fetch: async () => {
    const { quote } = await quotes.random({});
    return new Response(quote);
  },
});
```

The gateway exposes no contract of its own, so there is no `serve()` here. It is an ordinary HTTP server that happens to receive a typed client, and calling `quotes.random({})` is an ordinary async function call.

## 4. Compose the app [#4-compose-the-app]

The root module is the app. It provisions both services and wires the quotes service's exposed port into the gateway's dependency slot. `provision()` returns a ref carrying one port per exposed contract, so `quotes.rpc` exists because the service declared `expose: { rpc: ... }`:

```ts title="module.ts"
import { module } from '@prisma/composer';
import gatewayService from './src/gateway/service.ts';
import quotesService from './src/quotes/service.ts';

export default module('my-app', ({ provision }) => {
  const quotes = provision(quotesService);
  provision(gatewayService, { deps: { quotes: quotes.rpc } });
});
```

Next to it goes the deploy config. Only the Composer CLI reads this file; your app code never imports it:

```ts title="prisma-composer.config.ts"
import { defineConfig } from '@prisma/composer/config';
import { nodeBuild } from '@prisma/composer/node/control';
import { prismaCloud, prismaState } from '@prisma/composer-prisma-cloud/control';

export default defineConfig({
  extensions: [prismaCloud(), nodeBuild()],
  state: prismaState(),
});
```

## 5. Build [#5-build]

You own the build. The framework only assembles what you built, and it has one requirement: each entry must be a single self-contained file, with everything inlined except the runtime's own built-ins (`bun`, `bun:*`, `node:*`). Any bundler that produces such a file works. This guide uses Bun. Build the two services separately, because a multi-entry build would split the shared contract code into a chunk neither output contains:

```json title="package.json"
{
  "scripts": {
    "build": "bun build src/quotes/server.ts --target=bun --outfile dist/quotes/server.mjs && bun build src/gateway/server.ts --target=bun --outfile dist/gateway/server.mjs"
  }
}
```

  

#### bun

```bash
bun run build
```

#### pnpm

```bash
pnpm run build
```

#### yarn

```bash
yarn build
```

#### npm

```bash
npm run build
```

This is also a good moment to typecheck. The compiler checks the whole wiring, so a dependency wired to the wrong producer or a missing RPC handler fails here, in seconds:

  

#### bun

```bash
bunx tsc --noEmit
```

#### pnpm

```bash
pnpm tsc --noEmit
```

#### yarn

```bash
yarn tsc --noEmit
```

#### npm

```bash
npx tsc --noEmit
```

## 6. Run it locally [#6-run-it-locally]

One command brings the whole app up on your machine, both services wired together, with no cloud credentials:

  

#### bun

```bash
bunx prisma dev module.ts
```

#### pnpm

```bash
pnpm prisma dev module.ts
```

#### yarn

```bash
yarn prisma dev module.ts
```

#### npm

```bash
npx prisma dev module.ts
```

It runs the same pipeline a deploy runs, against local stand-ins for Prisma Compute and Prisma Postgres, and prints each service's local URL:

```text no-copy
dev: ready
gateway: http://localhost:3001
quotes: http://localhost:3000
```

Verify it works by calling the gateway:

```bash
curl localhost:3001
```

```text no-copy
Make it work, make it right, make it fast.
```

That response traveled over one typed RPC hop: the gateway received your request, called `quotes.random({})` through its injected client, and returned the result.

`dev` keeps running, watches your built output, and restarts a service when its build changes (run `npm run build` in another terminal and the affected service restarts). `Ctrl-C` stops it. Your local data stays, so the next start is warm. See [Local development](https://www.prisma.io/docs/composer/local-development) for logs, `--fresh`, and what persists.

Now try the quotes service directly:

```bash
curl -X POST localhost:3000/rpc/random -H 'content-type: application/json' -d '{}'
```

You get `401 Unauthorized`. That is deliberate: Composer mints a **service key** for each dependency edge and the quotes service accepts only calls from the gateway. Neither service's code mentions a key. See [Services and contracts](https://www.prisma.io/docs/composer/services-and-contracts#calls-are-authenticated-for-you) for how this works.

## 7. Deploy it (optional) [#7-deploy-it-optional]

Local dev needed no account. Deploying the same app to [Prisma Compute](https://www.prisma.io/docs/compute) needs a signed-in session:

  

#### bun

```bash
bunx prisma auth login
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm prisma auth login
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn prisma auth login
yarn prisma deploy module.ts
```

#### npm

```bash
npx prisma auth login
npx prisma deploy module.ts
```

(In CI, where the browser sign-in is not an option, set `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` from the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=composer) instead; see [Deploying](https://www.prisma.io/docs/composer/deploying#credentials).)

A new project needs a region, so give it one before the first deploy, in the deploy config or in the environment. The [`deploy` reference](https://www.prisma.io/docs/cli/deploy) shows both ways.

The CLI creates a project named `my-app` in your workspace (a project this module deployed before is reused; one whose hosted state the CLI cannot verify stops the deploy with `HostedStateBootstrapError`, so pass `--name <unique-name>` in that case), provisions both services on Prisma Compute, points the gateway's `quotes` dependency at the deployed quotes service, and starts everything. The deploy finishes by printing what it made: your module names, the platform resource each became, and the public URLs. Open the gateway's URL and you get a quote.

Re-deploying is idempotent. For an isolated copy of the whole app, deploy a stage:

  

#### bun

```bash
bunx prisma deploy module.ts --stage demo
```

#### pnpm

```bash
pnpm prisma deploy module.ts --stage demo
```

#### yarn

```bash
yarn prisma deploy module.ts --stage demo
```

#### npm

```bash
npx prisma deploy module.ts --stage demo
```

Tearing a stage down is the `destroy` operation of the [control API](https://www.prisma.io/docs/cli/deploy#the-control-api). That operation does not read your `auth login` session: it needs `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` in the environment, the same service-token credentials CI uses. Without them, delete the stage's branch in the [Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=composer) instead. See [Deploying](https://www.prisma.io/docs/composer/deploying) for stages, CI, and teardown in full.

## Where to go next [#where-to-go-next]

* [Apps and Modules](https://www.prisma.io/docs/composer/apps-and-modules): package a service and its database as a reusable Module.
* [Databases](https://www.prisma.io/docs/composer/databases): add a Postgres, plain or typed by a Prisma ORM contract.
* [Building blocks](https://www.prisma.io/docs/composer/building-blocks): compose the ready-made cron, storage, and streams Modules.
* [Testing](https://www.prisma.io/docs/composer/testing): unit tests with `mockService`, integration tests with `bootstrapService`.
* [Porting an existing app](https://www.prisma.io/docs/composer/porting-an-app): keep your server code and declare the app around it.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.

# Prisma Composer (/docs/composer)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A TypeScript framework for defining applications composed of multiple services and resources, and deploying them to Prisma Compute and Prisma Postgres.

Location: Prisma Composer

With Prisma Composer, you describe your whole application in TypeScript: each service, plus whatever it depends on, such as other services, [Prisma Postgres](https://www.prisma.io/docs/postgres) databases, scheduled jobs, object storage, and secrets. One deploy command then provisions the services on [Prisma Compute](https://www.prisma.io/docs/compute), the databases on Prisma Postgres, and the authenticated connections between them.

You do not need Composer to deploy to Prisma Compute. If your application is a single service, you can deploy it to Compute directly. See [Deployments](https://www.prisma.io/docs/compute/deployments) for those paths.

> [!NOTE]
> Early Access
> 
> Prisma Composer is in [Early Access](https://www.prisma.io/docs/console/more/feature-maturity#early-access). APIs and commands can change between releases. Composer ships inside the [Prisma CLI](https://www.prisma.io/docs/cli/deploy) as the root-level `dev` and `deploy` commands: run them with `npx prisma dev module.ts` and `npx prisma deploy module.ts`.

## What a Composer application is [#what-a-composer-application-is]

A Composer application is a tree of services and resources. Each service declares the resources it needs, such as a database. Services call each other through typed contracts. Step through how the pieces relate:

<ConceptAnimation name="composer-app-graph" />

## A minimal example [#a-minimal-example]

You declare a service as data instead of writing deployment scripts. The declaration below says the `storefront` service calls the `catalog` service's API and is built as a Next.js app:

```ts title="src/storefront/service.ts"
import nextjs from '@prisma/composer/nextjs';
import { rpc } from '@prisma/composer/service-rpc';
import { compute } from '@prisma/composer-prisma-cloud';
import { catalogContract } from '../catalog/contract.ts';

export default compute({
  name: 'storefront',
  deps: { catalog: rpc(catalogContract) },
  build: nextjs({ module: import.meta.url, appDir: '..' }),
});
```

At runtime, the service receives a typed client for each declared dependency from `service.load()`. The contract determines which methods that client exposes and their TypeScript types, and calling one is an ordinary async function call:

```ts title="src/storefront/data.ts"
import service from './service.ts';

const { catalog } = service.load();
const { products } = await catalog.listProducts({});
```

The root module ties the application together, wiring each declared dependency to the service or resource that provides it:

```ts title="module.ts"
import { module } from '@prisma/composer';
import catalogModule from './src/catalog/module.ts';
import ordersModule from './src/orders/module.ts';
import storefrontService from './src/storefront/service.ts';

export default module('store', ({ provision }) => {
  const catalog = provision(catalogModule);
  const orders = provision(ordersModule, { deps: { catalog: catalog.rpc } });
  provision(storefrontService, { deps: { catalog: catalog.rpc, orders: orders.rpc } });
});
```

TypeScript checks the wiring: a dependency bound to a producer with a different contract, a missing RPC handler, or a config value of the wrong shape is a compile error, not a failed deploy.

## From declaration to deployment [#from-declaration-to-deployment]

`npx prisma deploy module.ts` loads the root module, compares it with the deploy state stored for that environment, and creates or updates the services on Prisma Compute and the databases on Prisma Postgres. Re-running a deploy applies only the difference:

<ConceptAnimation name="composer-deploy-flow" />

## Core concepts [#core-concepts]

* **App**: the complete deployable application, defined by the root module. Deployed as one Prisma [project](https://www.prisma.io/docs/compute#the-model).
* **Service**: a running application component, declared with `compute()`. Deployed as one Prisma Compute service.
* **Resource**: something a service depends on that is not a service: a Prisma Postgres database, a bucket, or a secret.
* **Contract**: the typed interface through which services communicate, written as [Standard Schema](https://standardschema.dev) definitions.
* **Module**: a reusable unit that provisions services and resources behind a typed boundary, such as a service packaged with its own database.

[Apps and Modules](https://www.prisma.io/docs/composer/apps-and-modules) covers each in depth.

## Design principles [#design-principles]

Two choices shape the rest of the framework. First, application code does not read `process.env` or hardcode URLs. Dependencies arrive typed through `service.load()`, so production, an isolated stage, and a test all run the same code with different injected values. Second, Composer does not bundle or transform your code. You build with your own bundler, and the deploy assembles what you built.

## Get started [#get-started]

- [Getting started](https://www.prisma.io/docs/composer/getting-started): Build and run a two-service application locally, then deploy it.

- [Port an existing app](https://www.prisma.io/docs/composer/porting-an-app): Keep your server code and add the declarations around it.

## Use Composer with an AI coding agent [#use-composer-with-an-ai-coding-agent]

Composer's declaration-based API works well with coding agents because mistakes fail the TypeScript compile instead of a deploy. The Composer skill ships inside the `@prisma/composer` package, so it always matches the version you installed. Before your agent writes Composer code, install it:

  

#### bun

```bash
bunx prisma skills sync
```

#### pnpm

```bash
pnpm prisma skills sync
```

#### yarn

```bash
yarn prisma skills sync
```

#### npm

```bash
npx prisma skills sync
```

The `prisma-composer` skill documents the full authoring API, the CLI commands, and the first-party Modules for scheduled jobs, object storage, and event streams. It is one of several [Prisma agent skills](https://www.prisma.io/docs/ai/tools/skills). Review the generated declarations like any other TypeScript: `npx tsc --noEmit` checks the wiring before you deploy.

## What to read next [#what-to-read-next]

Start with [Apps and Modules](https://www.prisma.io/docs/composer/apps-and-modules) for how services, resources, and Modules compose into an app, then [Services and contracts](https://www.prisma.io/docs/composer/services-and-contracts) for the typed RPC between them. When you're ready to run something, [Local development](https://www.prisma.io/docs/composer/local-development) works with no cloud credentials, and [Deploying](https://www.prisma.io/docs/composer/deploying) covers production, stages, and CI. Check [Limitations](https://www.prisma.io/docs/composer/limitations) before committing to a design.

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# Limitations (/docs/composer/limitations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

What Prisma Composer does not do yet, so you can name the gap instead of working around it blind.

Location: Composer > Limitations

Prisma Composer is in [Early Access](https://www.prisma.io/docs/console/more/feature-maturity#early-access). This page lists what it does not do yet, so you can plan around a gap instead of discovering it mid-build. If something you need is missing here and below, check the [examples](https://github.com/prisma/composer/tree/main/examples) and design docs in the [Composer repository](https://github.com/prisma/composer), then file an issue there rather than guessing at an API.

## Contracts and communication [#contracts-and-communication]

* **RPC over HTTP is the only contract kind.** No gRPC, WebSocket, or streaming contracts.
* **No in-memory contract bindings.** A dependency cannot yet be wired to a co-located handler without HTTP; use [`bootstrapService`](https://www.prisma.io/docs/composer/testing#integration-tests-bootstrapservice) with a loopback fake in tests.

## Deploys and auth [#deploys-and-auth]

* **No interactive login for deploys.** Deploys authenticate only via a static `PRISMA_SERVICE_TOKEN`; there is no browser flow.
* **Deploys do not build.** `deploy` assembles your built output; the build is always yours to run first.
* **The `effect` family must be pinned** in your app's `package.json` until an upstream dependency fixes its version ranges; see [Getting started](https://www.prisma.io/docs/composer/getting-started#1-set-up-the-project). Every Composer command checks this and stops with a fix-naming error when the pin is missing.

## Platforms [#platforms]

* **Windows is not supported yet** for local development (`dev`).
* **Node.js 22.18 or newer is required.** Composer hands your TypeScript entry file straight to Node, and earlier versions cannot run `.ts` files directly.

## Runtime behavior to design around [#runtime-behavior-to-design-around]

These are properties of running on [Prisma Compute](https://www.prisma.io/docs/compute) rather than missing features; [Deploying](https://www.prisma.io/docs/composer/deploying#production-behavior) covers each with the fix:

* Compute scales to zero, so idle database connections get closed and cold calls can see `ECONNRESET`.
* A deployed RPC endpoint answers only its wired consumers; hand-rolled probes get `401`.
* Environment variables prefixed `COMPOSER_*` belong to the deploy and are rewritten on every deploy.
* Streaming responses are delivered as your service sends them, but the service has 60 seconds to send the first bytes before the ingress returns `504 Gateway Time-out`; see [Request timeout](https://www.prisma.io/docs/compute/request-timeout).

## Next steps [#next-steps]

* [Deploying](https://www.prisma.io/docs/composer/deploying): operational behavior in full.
* [Building blocks](https://www.prisma.io/docs/composer/building-blocks): what ships today, and how extensions arrive.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.

# Local development (/docs/composer/local-development)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Run the whole app on your machine with prisma dev, with no cloud credentials, and tail its logs through the control API.

Location: Composer > Local development

One command brings your whole app up on your machine, every service, its databases and buckets, wired together, with no cloud credentials. `dev` runs the same pipeline a deploy runs, but against local stand-ins for Prisma Compute and Prisma Postgres, so what you run locally is what you ship. Logs are read separately, through the control API's `log` operation.

| You want to...                      | Run                                                                                                                                    |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Bring the app up locally            | `npx prisma dev module.ts`                                                                                                             |
| Start clean (wipe local data first) | `npx prisma dev module.ts --fresh` (fails for apps with a database in this release; see [the reset steps](#whats-local-vs-whats-real)) |

`module.ts` is your entry file, the one whose default export is the root module, the same file you pass to `deploy`. No `PRISMA_*` variables are needed. Local dev never talks to the platform.

## Bring it up [#bring-it-up]

Like deploy, `dev` runs your *built* output, so build first:

  

#### bun

```bash
bun run build
bunx prisma dev module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma dev module.ts
```

#### yarn

```bash
yarn build
yarn prisma dev module.ts
```

#### npm

```bash
npm run build
npx prisma dev module.ts
```

It stands the app up and prints each service's local URL:

```text no-copy
dev: ready
gateway: http://localhost:3001
quotes: http://localhost:3000
```

From here `dev` keeps running: it watches your built output and, when a service's build changes, restarts only that service. Rebuild in another terminal and the affected service picks up the change.

`Ctrl-C` stops your app's service processes and exits. The local databases, buckets, and their data stay up, so the next `dev` is a warm start: same ports, same data. `--fresh` wipes this app's local instances and data before starting.

`dev` does not print service logs. With several services running, streaming them all inline would bury the URL list and the restart notices, so logs are read separately.

## Logs [#logs]

The unified CLI has no `log` command. Tail the merged logs of the already-running app with the `log` operation from `@prisma/composer/control`, the same in-process API that backs `deploy` and `dev` (see [the control API](https://www.prisma.io/docs/cli/deploy#the-control-api)):

```ts title="logs.ts"
import { log } from '@prisma/composer/control';

const result = await log({ entry: 'module.ts', tail: 20, signal: AbortSignal.timeout(60_000) });
if (!result.ok) throw new Error(result.failure.message);

for await (const { service, line } of result.value.lines) {
  console.log(`[${service}] ${line}`);
}
```

Run it with `node logs.ts` next to a running `dev`. `log` attaches to the running app and hands back the merged stream as `lines`, an async iterable, so nothing prints until you iterate it. The `signal` ends the stream, here after a minute, so the script exits on its own; leave it out and stop with `Ctrl-C`. Each line carries the service it came from:

```text no-copy
[quotes] serving a quote
[quotes] serving a quote
```

It follows live, like `tail -f`. It only reads the running app. It never builds, provisions, starts, or stops anything, so you can start and stop it freely alongside a running `dev`.

* **One service:** pass its dotted address, for example `cron.runner`, exactly as the startup output prints it.
* **How much history:** a tail option sets how many recent lines to show before going live (default 20; `0` for live-only). Each service's log is cleared when it starts fresh, so you are never scrolling back through past sessions.
* **No running app:** if you have not run `dev` (or you stopped it), the operation says so and points you at `dev`.

## What's local vs. what's real [#whats-local-vs-whats-real]

Everything above the cloud boundary is real: your actual service code, real databases you can migrate and query, real object storage, and the same wiring a deploy creates, including [service keys](https://www.prisma.io/docs/composer/services-and-contracts#calls-are-authenticated-for-you). What is swapped are the providers underneath: local emulators stand in for Prisma Compute and Prisma Postgres, so no token, workspace, or network is involved. Three consequences worth knowing:

* **Direct RPC probes get `401` here too.** `dev` runs the deploy pipeline, so providers only accept their wired consumers, exactly as in production. Exercise a provider through a consumer, or in [tests](https://www.prisma.io/docs/composer/testing), where nothing is provisioned and every call passes through.
* **Unset secrets do not stop the app.** A secret you have not set in your shell gets a local placeholder and a one-line warning. The app boots and serves. Only the code path that actually uses that secret fails, at the real external service it calls. Set the secret in your shell to exercise that path.
* **The emulators outlive a session.** They are shared, machine-wide daemons, so your data survives `Ctrl-C` and even a reboot until you pass `--fresh`. That is what makes restarts warm. Because they are shared, `dev` currently lists every app the emulators know about, including apps you started earlier and stopped, so ignore endpoints whose names are not in your `module.ts`.
* **`--fresh` currently fails for an app with a database.** The Postgres emulator declines to close the app's local server, the recreate step cannot connect, and a plain `dev` afterwards waits forever on the missing database. To recover, stop the stuck `dev`, remove the app's local server with `npx prisma dev rm pcdev-<app>-<database>` (run it from a directory without a Prisma ORM config), delete `.prisma-composer/dev` and `.alchemy` in the project, and run `dev` again. It re-provisions from scratch. The same reset fixes a `dev` that reports ready with none of its services listed, which happens when the emulators were restarted underneath a project.

Windows is not supported yet; see [Limitations](https://www.prisma.io/docs/composer/limitations).

## Next steps [#next-steps]

* [Deploying](https://www.prisma.io/docs/composer/deploying): the same app, on Prisma Compute.
* [Testing](https://www.prisma.io/docs/composer/testing): drive a service in-process instead of running the whole app.
* [Local development across the Prisma stack](https://www.prisma.io/docs/local-development): the app runtime, local Postgres, and local storage.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.

# Object storage (/docs/composer/object-storage)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Provision an S3-compatible object-store bucket and use it from a service with any S3 client.

Location: Composer > Object storage

`bucket` is a raw S3-compatible object-store bucket: a flat key-value store with no higher-level abstractions attached. Like [`postgres()`](https://www.prisma.io/docs/composer/databases), it is a resource with two ends: the service declares the need, and the module that owns the bucket provisions it.

```ts title="src/uploads/service.ts"
import { bucket, compute } from '@prisma/composer-prisma-cloud';

export default compute({
  name: 'uploads',
  deps: { store: bucket() }, // dependency end: receives credentials
  // ...
});
```

```ts title="module.ts"
const store = provision(bucket({ name: 'uploads' })); // resource end: provisions + mints a keypair
provision(uploadsService, { deps: { store } });
```

Inside the service entry, `load()` hands back `{ url, bucket, accessKeyId, secretAccessKey }`, the standard S3 config set. Use any S3-compatible client (`@aws-sdk/client-s3`, `minio`, Bun's S3 API):

```ts title="src/uploads/server.ts"
import { S3Client } from '@aws-sdk/client-s3';

const { store } = service.load();
const s3 = new S3Client({
  endpoint: store.url,
  bucket: store.bucket,
  credentials: { accessKeyId: store.accessKeyId, secretAccessKey: store.secretAccessKey },
});
```

## Buckets and the storage Module [#buckets-and-the-storage-module]

A bucket resource uses the same S3 contract kind as the [`storage` Module's](https://www.prisma.io/docs/composer/building-blocks) blob store. A service declared with `deps: { store: s3() }`, where `s3` is imported from `@prisma/composer-prisma-cloud/storage`, can be rewired to a `bucket` resource without changing the service declaration. Reach for the `storage` Module when you want a managed blob store with its own internals; reach for `bucket` when you want the raw S3 surface.

`dev` provisions a local stand-in bucket with working credentials, so upload code runs locally without an account. See [Local development](https://www.prisma.io/docs/composer/local-development).

## Next steps [#next-steps]

* [Building blocks](https://www.prisma.io/docs/composer/building-blocks): the storage and streams Modules built on the same contract.
* [Service input](https://www.prisma.io/docs/composer/service-input): when a credential should be input instead of a dependency.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.

# Port an existing app (/docs/composer/porting-an-app)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Bring an app you already have to Prisma Composer by declaring it, keeping your server code and your build.

Location: Composer > Port an existing app

Bringing an existing app to Composer does not mean rewriting it. The server code you already have stays the server, and you add a service declaration around it. This page covers the three common cases.

## Use with your agent [#use-with-your-agent]

To delegate the port, run this from your project's root and hand the prompt to your coding agent:

```text
Port this app to Prisma Composer.

1. Install the Composer skill with `npx skills add prisma/composer`, then read https://www.prisma.io/docs/composer/porting-an-app.md and follow it for this repository.
2. Survey the repo before changing anything and report back: every deployable server, its runtime (Node, Bun, or Next.js), its build command and entry file, every `process.env` read, and any database it connects to. Ask me about anything ambiguous.
3. Declare each server as a service with `compute()`, using the `node` or `nextjs` build adapter as appropriate, and compose them in a single `module.ts`.
4. Replace the `process.env` reads: the listen port becomes `service.port()` bound to `0.0.0.0`, config and credentials become fields of the service input schema, and anything another service provides becomes a typed dependency. Replace the URLs services use to reach each other with contracts.
5. If the app talks to Postgres, declare `postgres()` as a dependency and build the existing client from the injected `db.url` instead of a connection-string variable.
6. Verify with `npx tsc --noEmit`, then build and run `npx prisma dev module.ts` and confirm every service boots with a local URL. Do not deploy; show me the diff first.
```

## A Node.js or Bun service [#a-nodejs-or-bun-service]

Add a `service.ts` with `compute({ name, deps, build: node({ module, entry }) })` pointing `entry` at your built server file, then make three changes to the server itself:

1. **Read the port from `service.port()`**, never `process.env`, and bind `0.0.0.0`:

   ```ts
   Bun.serve({ port: service.port(), hostname: '0.0.0.0', fetch: handler });
   ```

2. **Replace every other `process.env` read.** Config and credentials become fields of the service's [input schema](https://www.prisma.io/docs/composer/service-input). Anything another service provides becomes a [dependency](https://www.prisma.io/docs/composer/services-and-contracts). If a value differs per stage (an app origin, an external URL), bind it with `envParam`. Bind a credential with `envSecret`.

3. **If it talks to Postgres**: declare `deps: { db: postgres() }` and build your existing client (`pg`, Bun's `SQL`, whatever you use today) from the injected `db.url` instead of a connection-string env var. See [Databases](https://www.prisma.io/docs/composer/databases).

Your build must produce a self-contained entry file, with everything inlined except runtime built-ins. Keep your own build if it already does this. Otherwise, a one-line `bun build --target=bun` produces one. See [Getting started](https://www.prisma.io/docs/composer/getting-started#5-build).

## A Next.js app [#a-nextjs-app]

Use the `nextjs` build adapter instead of `node`. With `output: 'standalone'` set, `next build` is the whole build:

```ts title="src/service.ts"
import nextjs from '@prisma/composer/nextjs';
import { rpc } from '@prisma/composer/service-rpc';
import { compute } from '@prisma/composer-prisma-cloud';
import { apiContract } from '../api/contract.ts';

export default compute({
  name: 'web',
  deps: { api: rpc(apiContract) },
  build: nextjs({ module: import.meta.url, appDir: '..' }),
});
```

```ts title="next.config.ts"
export default { output: 'standalone' };
```

Add `nextjsBuild()` from `@prisma/composer/nextjs/control` to the deploy config's `extensions`:

```ts title="prisma-composer.config.ts"
import { defineConfig } from '@prisma/composer/config';
import { nextjsBuild } from '@prisma/composer/nextjs/control';
import { nodeBuild } from '@prisma/composer/node/control';
import { prismaCloud, prismaState } from '@prisma/composer-prisma-cloud/control';

export default defineConfig({
  extensions: [prismaCloud(), nodeBuild(), nextjsBuild()],
  state: prismaState(),
});
```

Add `export const dynamic = 'force-dynamic'` to any page or server action that calls `service.load()`. The runtime environment does not exist at build time, and Next.js will not re-read it for prerendered routes.

[`examples/storefront-auth`](https://github.com/prisma/composer/tree/main/examples/storefront-auth) in the Composer repository is a complete example of a ported app: a Next.js frontend calling a Bun API service that owns a Postgres.

## More than one service [#more-than-one-service]

Port them into one `module.ts` and replace the URLs they used to reach each other with [contracts](https://www.prisma.io/docs/composer/services-and-contracts). The payoff is that the calls between services become typed, and every environment (production, stages, tests) gets the wiring for free.

## Verify the port [#verify-the-port]

Build, then run the app locally before you deploy:

  

#### bun

```bash
bun run build
bunx prisma dev module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma dev module.ts
```

#### yarn

```bash
yarn build
yarn prisma dev module.ts
```

#### npm

```bash
npm run build
npx prisma dev module.ts
```

Every service should appear in the startup output with a local URL. If a service fails at boot with a module-resolution error, its build left something un-inlined. Check that the entry file is self-contained.

## Next steps [#next-steps]

* [Getting started](https://www.prisma.io/docs/composer/getting-started): the same shape, built from scratch.
* [Deploying](https://www.prisma.io/docs/composer/deploying): take the ported app to production.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.

# Service input (/docs/composer/service-input)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Declare a service's configuration and credentials as one schema, bind values at provision time, and read them back typed.

Location: Composer > Service input

Everything a running service receives arrives through one of two channels, and choosing the channel is most of the decision:

| The value is...                                            | Declare it as                             | Provide it                                                          | Read it           |
| ---------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------- | ----------------- |
| Produced by another node (a database, another service)     | a dependency: `deps: { db: postgres() }`  | wire it at `provision()`                                            | `service.load()`  |
| Anything else (a region, a flag, a job list, a credential) | one field of the service's `input` schema | bind it at `provision()`: a literal, `envParam()`, or `envSecret()` | `service.input()` |

Dependencies are covered in [Services and contracts](https://www.prisma.io/docs/composer/services-and-contracts) and [Databases](https://www.prisma.io/docs/composer/databases). This page is the second row.

## Declare the input schema [#declare-the-input-schema]

A service declares its whole incoming configuration, plain values and credentials together, as one [Standard Schema](https://standardschema.dev). The schema gives you the TypeScript type and validates the assembled input at deploy and again at boot, so garbage config is a loud failure, not a runtime surprise. A credential is a field typed as the redacting `SecretString` box:

```ts title="src/scheduler/service.ts"
import { secretString } from '@prisma/composer/arktype';
import { type } from 'arktype';

const schedulerInput = type({
  jobs: type({ jobId: 'string', every: 'string' }).array(),
  'region?': 'string',
  apiKey: secretString(),
});

export default compute({ name: 'scheduler', input: schedulerInput /* ... */ });
```

Because the input is a real schema, legality can be conditional. "No Stripe key unless billing is on" is an ordinary union, not a framework feature, and `service.input()` narrows it like any other TypeScript union:

```ts
const chatInput = type({ stripeEnabled: 'false' }).or(
  type({ stripeEnabled: 'true', stripeSecretKey: secretString() }),
);
```

## Bind values at provision [#bind-values-at-provision]

The service declares what shapes are legal; the place that provisions it decides where each value comes from. The binding is a plain object mirroring the schema's shape, whose leaves are literals, `envParam(...)`, or `envSecret(...)`:

```ts title="module.ts"
import { envParam, envSecret } from '@prisma/composer-prisma-cloud';

provision(scheduler, {
  input: {
    jobs: [{ jobId: 'tick', every: '60s' }],  // a literal
    region: envParam('REGION'),               // a per-stage platform variable
    apiKey: envSecret('SCHEDULER_API_KEY'),   // a credential: name only, never the value
  },
});
```

Secretness is enforced by validation, not annotation: binding a plain literal where the schema expects a `SecretString` fails the deploy (a credential almost landed in plain config), and binding `envSecret` where the schema expects a plain string fails the same way. Neither side can silently misclassify a credential.

### `envParam`: plain values the code cannot know [#envparam-plain-values-the-code-cannot-know]

An app origin is the canonical case: it differs between production and every preview stage, and a stage's public URL does not exist until that stage first deploys. Each stage keeps its own copy of the variable, so one topology serves them all.

How the value travels: &#x2A;*the stage's platform variable is the store; the deploying shell only seeds it.** At deploy, preflight checks the name exists for the target stage, and a name the stage is missing is copied up from the deploying shell's environment. Once the stage has it, your shell no longer matters. To change the value later, set it on the platform and redeploy; a running instance's environment is frozen when the instance is created.

`envParam` values arrive as raw strings, so bind them to string fields.

### `envSecret`: credentials [#envsecret-credentials]

Seeded exactly the same way, with one rule: **the value never enters framework config**. The framework carries only the variable's name; the platform injects the value straight into the running instance. What your code gets is a `SecretString` box that redacts on logging, rendering, and JSON serialization. Leaking it takes a deliberate `.expose()`:

```ts
const input = service.input();
if (input.stripeEnabled) stripe(input.stripeSecretKey.expose());
```

A reusable Module forwards a secret need to its parent without ever learning the platform name (see [Apps and Modules](https://www.prisma.io/docs/composer/apps-and-modules#reusable-modules)), which is what lets a Module require credentials without dictating your naming.

## Absence is the schema's call [#absence-is-the-schemas-call]

An env-bound field whose variable is unset (or empty) resolves to *key omitted*. Whether that is legal is the schema's call: an optional field, a union arm, or a validation error that fails the deploy. A credential for an off-by-default feature is an ordinary optional `SecretString` field, not a framework flag. Because an omitted key can also be a typo'd variable name, the deploy report prints every key that resolved absent; check it when a value goes missing.

## The reserved port [#the-reserved-port]

Every service also gets a `port` (default 3000), outside the input schema and read through its own typed accessor:

```ts
Bun.serve({ port: service.port(), hostname: '0.0.0.0', fetch: handler });
```

`service.port()` is a sibling of `service.origin()`. Never read `process.env.PORT` yourself; the framework exports `PORT` only for a server it does not write and cannot call, Next.js's standalone `server.js`, which binds it itself.

## What travels [#what-travels]

The deploy validates the resolved binding, applies the schema's defaults, and serializes the result into one document, with each secret as a pointer naming the platform variable that holds the value, never the value itself:

```json no-copy
{ "stripeEnabled": true, "stripeSecretKey": { "$secret": "STRIPE_SECRET_KEY" } }
```

At boot the framework swaps each pointer for a redacting box over the named variable, validates against the schema again, and `service.input()` returns the typed object. The document is secret-free by construction, which is why the deploy report can print it verbatim.

## Next steps [#next-steps]

* [Deploying](https://www.prisma.io/docs/composer/deploying): how a fresh stage gets its variables in CI.
* [Testing](https://www.prisma.io/docs/composer/testing): supply an input double under the reserved `input` key.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.

# Services and contracts (/docs/composer/services-and-contracts)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Define a service's API as a typed contract, serve it, and call it from other services with authentication and retries handled for you.

Location: Composer > Services and contracts

A **contract** is a service's API written as schemas, and it types both ends of the edge: the producer's handlers and the consumer's client. Define it once, in the package of the service that owns it.

For example, an `auth` service that verifies tokens declares one `verify` method:

```ts title="src/auth/contract.ts"
import { contract, rpc } from '@prisma/composer/service-rpc';
import { type } from 'arktype';

export const authContract = contract({
  verify: rpc({ input: type({ token: 'string' }), output: type({ ok: 'boolean' }) }),
});
```

Any [Standard Schema](https://standardschema.dev) validator types the messages; arktype, zod, and valibot all work. The only contract kind today is RPC over HTTP; there are no gRPC, WebSocket, or streaming contracts yet (see [Limitations](https://www.prisma.io/docs/composer/limitations)).

## Serve a contract [#serve-a-contract]

On the producer, declare the contract under `expose` and turn it into an HTTP handler with `serve()`. The handler map must cover every method; a missing or wrong-shaped handler does not compile:

```ts title="src/auth/server.ts"
import { serve } from '@prisma/composer/service-rpc';
import service from './service.ts';

const handler = serve(service, {
  rpc: {
    verify: async ({ token }) => ({ ok: await check(token) }),
  },
});
export default handler;

Bun.serve({ port: service.port(), hostname: '0.0.0.0', fetch: handler });
```

Each handler receives the validated input, the service's own loaded deps as a second argument, and an optional third argument carrying the call's [idempotency key](#calls-retry-safely-for-you). Most handlers only use the first.

## Call a contract [#call-a-contract]

On the consumer, declare the dependency as `rpc(contract)`. `service.load()` then returns a ready-made typed client, and calling it is an async function call:

```ts title="src/storefront/service.ts"
import { rpc } from '@prisma/composer/service-rpc';

export default compute({
  name: 'storefront',
  deps: { auth: rpc(authContract) },
  // ...
});
```

```ts
const { auth } = service.load();
const { ok } = await auth.verify({ token });
```

Note the asymmetry: the producer exposes the bare contract (its offer), while the consumer wraps it in `rpc()` (its need, "a client of this contract"). Inputs and outputs are validated at runtime at the boundary, against the same schemas that typed them.

## Calls are authenticated for you [#calls-are-authenticated-for-you]

You do not write anything for this. When you deploy, the framework mints a distinct, unguessable **service key** for each consumer-to-provider edge you declared, gives it to the consumer's client, and tells the provider to accept it. Every call carries the key, and `serve()` answers anything else with `401` before your handler runs. A deployed service has a public URL; the key is what makes it answer only the services your app connected to it.

Two rules follow:

* **Do not build your own service-to-service auth** on top of this.
* **Do not `curl` a deployed `/rpc/<method>` to check it works.** You are not one of the services wired to it, so you always get `401`. That looks like a broken deploy and is not. Debug through a consumer instead.

`dev` runs the same pipeline as a deploy, so local runs enforce the keys too: a direct `curl` to a provider's RPC endpoint returns `401` even on `localhost`. Only bare runs and [tests](https://www.prisma.io/docs/composer/testing) skip enforcement, because nothing is provisioned there.

The details that matter operationally:

|          |                                                                                                                     |
| -------- | ------------------------------------------------------------------------------------------------------------------- |
| Scope    | Service-level: any valid key reaches every method that service exposes. Split into two services to gate separately. |
| Per edge | Two consumers of one provider hold different keys, so one leaking cannot impersonate the other.                     |
| Rotation | Remove the dependency (or destroy the stack) and redeploy. A plain redeploy keeps the same keys.                    |
| Storage  | `COMPOSER_*` variables the deploy owns and rewrites. Never hand-edit one.                                           |

## Calls retry safely for you [#calls-retry-safely-for-you]

You do not write anything for this either. A provider that has scaled to zero has to boot before it answers, and a first call can be dropped while it does. The generated client absorbs that: every call carries an idempotency key, a dropped call is retried with a backoff, and `serve()` runs one call per key. A retry that arrives after the first call already ran gets the first answer back instead of running your handler twice. So `await auth.verify(...)` works across a cold start, whether or not the call changes state.

The deduplication rides on the key, so a hand-rolled request without one is served once without deduplication rather than rejected. Do not add an "is this idempotent" flag to a contract; the framework does not have one. If a handler needs exactly-once guarantees beyond one instance's memory (surviving a crash mid-call), its optional third argument carries the key to write into its own transaction:

```ts
verify: async (input, deps, ctx) => {
  // ctx.idempotencyKey: string | undefined (absent for keyless callers)
},
```

## Next steps [#next-steps]

* [Service input](https://www.prisma.io/docs/composer/service-input): the other channel, for configuration and credentials.
* [Testing](https://www.prisma.io/docs/composer/testing): fake a contract in unit tests, or boot the real entry against a stand-in.
* [Apps and Modules](https://www.prisma.io/docs/composer/apps-and-modules): wire contracts across Module boundaries.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.

# Testing (/docs/composer/testing)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Test composed services by deciding what service.load() returns, with mockService for unit tests and bootstrapService for integration tests.

Location: Composer > Testing

Your app's code gets every dependency from one call, `service.load()`, and nothing from arguments or globals. That makes testing a matter of deciding what `load()` returns; the code under test is never modified. There are two tools, and you pick by how much of the real path you want to exercise:

| You want to...                                               | Use                | From                                    |
| ------------------------------------------------------------ | ------------------ | --------------------------------------- |
| Call a page, action, or handler directly, dependencies faked | `mockService`      | `@prisma/composer/testing`              |
| Boot the real built entry and drive it over real HTTP        | `bootstrapService` | `@prisma/composer-prisma-cloud/testing` |

Most tests are the first kind. Reach for the second when the thing you are proving is the wiring itself: that the service boots, reads its config, builds its clients, and answers requests.

## Unit tests: `mockService` [#unit-tests-mockservice]

`mockService(service, overrides)` returns a copy of the service whose `load()` yields your fakes and whose `input()` yields the object you pass under the reserved `input` key. Everything goes in one flat object: dependency names route to `load()`, and `input` routes to `input()` (required exactly when the service declares an input schema; the input double is handed over as-is, not validated). The fakes are type-checked against the service's declared dependencies, so a double with the wrong shape does not compile.

Substituting the mocked service for the real one is your test runner's job: `vi.mock` in Vitest, `mock.module` in `bun test`. A Vitest example, testing a Next.js page:

```tsx title="app/page.test.tsx"
import { renderToString } from 'react-dom/server';
import { mockService } from '@prisma/composer/testing';
import realService from '../src/service.ts';

vi.mock('../src/service.ts', () => ({
  default: mockService(realService, {
    auth: { verify: async () => ({ ok: true }) }, // wrong shape = compile error
  }),
}));

import Page from './page.tsx';

it('renders the verified state', async () => {
  expect(renderToString(await Page())).toContain('Signed in: true');
});
```

No server, no database, no environment; the page renders against the fake.

## Integration tests: `bootstrapService` [#integration-tests-bootstrapservice]

`bootstrapService` boots the service's real built entry in-process, fed the same way a deployed boot is fed, except you choose the values. Point a dependency at a stand-in you run on a loopback port, then make real HTTP requests. Run these under `bun test`:

```ts title="service.integration.test.ts"
import { bootstrapService } from '@prisma/composer-prisma-cloud/testing';
import fakeAuth from '@my-app/auth/fake'; // an in-memory handler, no db
import storefront from '../src/service.ts';

const fake = Bun.serve({ port: 0, fetch: fakeAuth });

const app = await bootstrapService(storefront, {
  service: { port: 4310 },
  inputs: { auth: { url: fake.url.href } },
});

const res = await app.fetch(new Request(app.url));
expect(await res.text()).toContain('Signed in: true');
```

Five things to know:

* **Build first.** It boots the *built* entry, so the test task must depend on the build.
* **Pass a concrete `service.port`.** The entry listens itself; no OS-assigned port is reported back.
* **There is no `close()`.** Run each integration-test file in its own process (`bun test` does this per file) and the server dies with it.
* **The service's code is untouched.** If you find yourself editing `server.ts` to make it testable, something upstream is wrong.
* **You do not need a service key.** Only a deploy (or `dev`) provisions keys; in a test nothing checks, every call reaches your handler, and there is nothing to put in `inputs`.

A service with an input schema takes `input` in the config, a binding exactly like `provision()`'s, run through the real serialize and read path, so `input()` in the booted entry sees what a deploy would produce.

**Next.js services need a third argument**, a boot function, because the built entry lives inside Next's standalone output. Resolve it with `standaloneServerPath`; `bootstrapService` exports the resolved port as `process.env.PORT` before booting, which is exactly what Next's standalone server binds:

```ts
import { pathToFileURL } from 'node:url';
import { standaloneServerPath } from '@prisma/composer/nextjs/control';

await bootstrapService(storefront, config, async () => {
  await import(pathToFileURL(standaloneServerPath(storefront.build)).href);
});
```

The complete working version is [`examples/storefront-auth`](https://github.com/prisma/composer/tree/main/examples/storefront-auth) in the Composer repository.

## Writing good fakes [#writing-good-fakes]

A dependency's type *is* its contract, so anything of that shape is a valid fake, and the compiler holds it to that. In increasing order of realism:

* **A bare object**: `{ verify: async () => ({ ok: true }) }`. Right for most unit tests.
* **The real client over an in-memory handler**: exercises JSON encoding and schema validation, still no socket.
* **A real local server**: the fake served over actual HTTP, which is what `bootstrapService` drives.

One habit pays for all of this. Ship each service's fake from its own package as a `/fake` entry point, outside `src/`, so it cannot reach production code. Fake and service then share one contract; when the contract changes, both stop compiling at once, and every consumer's tests find out immediately.

## Next steps [#next-steps]

* [Services and contracts](https://www.prisma.io/docs/composer/services-and-contracts): what the contract types on each end.
* [Local development](https://www.prisma.io/docs/composer/local-development): run the real app instead of booting one service.

## Related pages

- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.

# Alchemy (/docs/compute/alchemy)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.

Location: Compute > Alchemy

Use [Alchemy](https://alchemy.run/) to create Prisma Postgres databases and deploy applications to Prisma Compute from one `alchemy.run.ts` file.

[Alchemy docs](https://alchemy.run/prisma/) · [GitHub](https://github.com/alchemy-run/alchemy) · [Provider source](https://github.com/alchemy-run/alchemy/tree/main/packages/alchemy/src/Prisma) · [TanStack Start example](https://github.com/alchemy-run/alchemy/tree/main/examples/prisma-tanstack-start) · [npm](https://www.npmjs.com/package/alchemy)

## Deploy Postgres and Compute [#deploy-postgres-and-compute]

### 1. Install and authenticate [#1-install-and-authenticate]

  

#### bun

```bash title="Terminal"
bun add alchemy@next effect@beta @effect/platform-bun@beta @effect/platform-node@beta
printf '\n.alchemy/\n' >> .gitignore
```

#### pnpm

```bash title="Terminal"
pnpm add alchemy@next effect@beta @effect/platform-bun@beta @effect/platform-node@beta
printf '\n.alchemy/\n' >> .gitignore
```

#### yarn

```bash title="Terminal"
yarn add alchemy@next effect@beta @effect/platform-bun@beta @effect/platform-node@beta
printf '\n.alchemy/\n' >> .gitignore
```

#### npm

```bash title="Terminal"
npm install alchemy@next effect@beta @effect/platform-bun@beta @effect/platform-node@beta
printf '\n.alchemy/\n' >> .gitignore
```

Create a Prisma [service token](https://www.prisma.io/docs/rest-api/authentication#service-tokens), then choose how Alchemy should read it.

To store the token in your local Alchemy profile:

  

#### bun

```bash title="Terminal"
bunx alchemy login --configure
```

#### pnpm

```bash title="Terminal"
pnpm dlx alchemy login --configure
```

#### yarn

```bash title="Terminal"
yarn dlx alchemy login --configure
```

#### npm

```bash title="Terminal"
npx alchemy login --configure
```

Choose **Service Token** for Prisma and paste the token when prompted. Alchemy stores it under `~/.alchemy/credentials/<profile>/`.

For CI or an ephemeral shell, choose **Environment Variable** and export the token before running Alchemy:

```bash title="Terminal"
export PRISMA_SERVICE_TOKEN="<your-service-token>"
```

If the profile uses **Environment Variable**, `alchemy login` only verifies that the variable is available. Run `alchemy login --configure` to switch the profile to a stored token.

### 2. Create the stack [#2-create-the-stack]

```ts title="alchemy.run.ts"
import * as Alchemy from "alchemy";
import * as Prisma from "alchemy/Prisma";
import * as Effect from "effect/Effect";

export default Alchemy.Stack(
  "MyApp",
  {
    providers: Prisma.providers(),
    state: Alchemy.localState(),
  },
  Effect.gen(function* () {
    const project = yield* Prisma.Project("project", {
      createDatabase: false,
    });

    const postgres = yield* Prisma.Postgres("database", {
      project,
      region: "us-east-1",
    });

    const connection = yield* Prisma.Connection("app-connection", {
      database: postgres,
    });

    const app = yield* Prisma.Compute("app", {
      project,
      build: "auto",
      env: {
        DATABASE_URL: connection.databaseUrl,
      },
    });

    return { url: app.url };
  }),
);
```

`build: "auto"` detects and builds Bun, Next.js, Nuxt, Astro, TanStack Start, and NestJS applications from the current directory. It expects deployable server output: Next.js needs standalone output, Astro needs the Node adapter in standalone mode, and TanStack Start needs its Nitro deployment adapter (`bunx @tanstack/cli@latest add nitro`). Plain Bun servers must listen on `process.env.PORT` and bind to `0.0.0.0`.

Alchemy provisions the database but does not infer or run production schema migrations. For Prisma ORM 7, pass `connection.directConnectionString` to the migration process as `DIRECT_URL` and read it from `prisma.config.ts`:

```ts title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  datasource: {
    url: env("DIRECT_URL"),
  },
});
```

Keep `connection.databaseUrl` as the application's pooled `DATABASE_URL`. Run migrations separately or model them as a dependency before Compute, as shown in the linked TanStack Start example.

### 3. Deploy and verify [#3-deploy-and-verify]

  

#### bun

```bash title="Terminal"
bunx alchemy deploy
curl "<url-from-stack-output>"
```

#### pnpm

```bash title="Terminal"
pnpm dlx alchemy deploy
curl "<url-from-stack-output>"
```

#### yarn

```bash title="Terminal"
yarn dlx alchemy deploy
curl "<url-from-stack-output>"
```

#### npm

```bash title="Terminal"
npx alchemy deploy
curl "<url-from-stack-output>"
```

Alchemy shows the plan before creating the project, database, connection, and Compute deployment. Copy the printed `url` into the `curl` command.

After changing your application or infrastructure, run the same commands again:

  

#### bun

```bash title="Terminal"
bunx alchemy deploy
curl "<url-from-stack-output>"
```

#### pnpm

```bash title="Terminal"
pnpm dlx alchemy deploy
curl "<url-from-stack-output>"
```

#### yarn

```bash title="Terminal"
yarn dlx alchemy deploy
curl "<url-from-stack-output>"
```

#### npm

```bash title="Terminal"
npx alchemy deploy
curl "<url-from-stack-output>"
```

## Default or explicit database [#default-or-explicit-database]

The complete stack above declares its database explicitly. The important wiring is:

```ts title="Explicit database"
const postgres = yield* Prisma.Postgres("database", { project });
const connection = yield* Prisma.Connection("connection", {
  database: postgres,
});

const app = yield* Prisma.Compute("app", {
  project,
  build: "auto",
  env: {
    DATABASE_URL: connection.databaseUrl,
  },
});
```

Alternatively, let the project create its default database:

```ts title="Default database"
const project = yield* Prisma.Project("project", {
  region: "us-east-1",
});

const app = yield* Prisma.Compute("app", {
  project,
  build: "auto",
});
```

> [!WARNING]
> Prisma injects the default database's system-managed `DATABASE_URL` and `DATABASE_URL_POOLED` variables. Do not add either key to `env` when using the default database.

## Local development [#local-development]

Configure the local app process alongside the database:

```ts title="alchemy.run.ts"
const postgres = yield* Prisma.Postgres("database", {
  project,
  dev: {
    persistenceMode: "stateful",
  },
});

const connection = yield* Prisma.Connection("connection", {
  database: postgres,
});

const app = yield* Prisma.Compute("app", {
  project,
  build: "auto",
  env: {
    DATABASE_URL: connection.databaseUrl,
  },
  dev: {
    command: "bun run dev",
    port: 3000,
  },
});
```

  

#### bun

```bash title="Terminal"
bunx alchemy dev
```

#### pnpm

```bash title="Terminal"
pnpm dlx alchemy dev
```

#### yarn

```bash title="Terminal"
yarn dlx alchemy dev
```

#### npm

```bash title="Terminal"
npx alchemy dev
```

Alchemy starts a local Prisma Postgres server, passes its connection string to the application, and runs the configured development command. Use `dev.migrate` on `Prisma.Postgres` when the local database needs a setup command before the application starts.

## Production options [#production-options]

Use an application directory, health check, and old-deployment cleanup when needed:

```ts title="alchemy.run.ts"
const app = yield* Prisma.Compute("app", {
  project,
  path: "./apps/web",
  build: "auto",
  env: {
    DATABASE_URL: connection.databaseUrl,
  },
  healthCheck: {
    path: "/health",
  },
  destroyOldDeployment: true,
});

const domain = yield* Prisma.CustomDomain("domain", {
  app,
  hostname: "app.example.com",
});

return {
  url: app.url,
  dnsRecords: domain.dnsRecords,
};
```

Your application must return a successful response from the configured health-check path before promotion. Add the returned `dnsRecords` at your DNS provider to activate the custom domain. Custom domains can only attach to applications on the project's default branch.

## CI and cleanup [#ci-and-cleanup]

  

#### bun

```bash title="CI"
bunx alchemy deploy --stage "pr-${PR_NUMBER}" --yes
bunx alchemy destroy --stage "pr-${PR_NUMBER}" --yes
```

#### pnpm

```bash title="CI"
pnpm dlx alchemy deploy --stage "pr-${PR_NUMBER}" --yes
pnpm dlx alchemy destroy --stage "pr-${PR_NUMBER}" --yes
```

#### yarn

```bash title="CI"
yarn dlx alchemy deploy --stage "pr-${PR_NUMBER}" --yes
yarn dlx alchemy destroy --stage "pr-${PR_NUMBER}" --yes
```

#### npm

```bash title="CI"
npx alchemy deploy --stage "pr-${PR_NUMBER}" --yes
npx alchemy destroy --stage "pr-${PR_NUMBER}" --yes
```

Use a unique preview stage for each pull request and destroy that same stage when it closes. Cleanup must never target `prod`.

Use a shared [Alchemy state store](https://alchemy.run/state-store/) for team and CI deployments. State can contain database credentials, so never commit `.alchemy/`.

Replace `Alchemy.localState()` before deploying from CI. Local state is only suitable when one machine owns the stack.

Destroying the stack deletes the Prisma project and everything inside it, including databases and applications.

## API reference [#api-reference]

* [`Prisma.Project`](https://alchemy.run/providers/prisma/project/)
* [`Prisma.Branch`](https://alchemy.run/providers/prisma/branch/)
* [`Prisma.Database` and `Prisma.Postgres`](https://alchemy.run/providers/prisma/database/)
* [`Prisma.Connection`](https://alchemy.run/providers/prisma/connection/)
* [`Prisma.Compute`](https://alchemy.run/providers/prisma/compute/)
* [`Prisma.App`](https://alchemy.run/providers/prisma/app/)
* [`Prisma.Deployment`](https://alchemy.run/providers/prisma/deployment/)
* [`Prisma.CustomDomain`](https://alchemy.run/providers/prisma/customdomain/)
* [`Prisma.EnvironmentVariable`](https://alchemy.run/providers/prisma/environmentvariable/)
* [`Prisma.SourceRepository`](https://alchemy.run/providers/prisma/sourcerepository/)

## Related pages

- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.
- [`Domains`](https://www.prisma.io/docs/compute/domains): Point a custom domain at a production app and the platform verifies DNS and provisions TLS for you.

# Branching (/docs/compute/branching)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Branches are isolated environments that map to your Git branches, so preview work never touches production.

Location: Compute > Branching

A branch is an isolated environment for one line of work. Every branch in a project owns its own services, deployments, and any databases created on it, so preview deploys never share Compute resources with production. One caveat: a database your app reaches through a `DATABASE_URL` environment variable is only as isolated as that variable's value. Give previews their own preview-scoped `DATABASE_URL`. See [Environment variables](https://www.prisma.io/docs/compute/environment-variables) for details.

A platform branch usually matches a Git branch name, but in Prisma it is a real resource that owns its own services and databases:

<ConceptAnimation name="compute-model" />

## Production and preview [#production-and-preview]

Every branch has a role:

* The **first branch** in a project is your production branch, usually `main`. It's protected and durable: with [deploy on push](https://www.prisma.io/docs/compute/deploy-on-push) set up, pushes to your default Git branch deploy to it, and automated cleanup never touches it.
* **Every other branch** is a preview by default: disposable resources for testing changes before they merge.

To learn more, see the [Deployments docs](https://www.prisma.io/docs/compute/deployments).

## How the CLI picks a branch [#how-the-cli-picks-a-branch]

Commands that take a branch resolve it in this order:

1. `--branch <name>`, if you pass it.
2. Your active Git branch.
3. `main`.

Inside a Git repo, running `service list` from `feature/search` targets the `feature/search` branch automatically. To target a branch explicitly:

  

#### bun

```bash
bunx prisma service list --branch feature/search
```

#### pnpm

```bash
pnpm prisma service list --branch feature/search
```

#### yarn

```bash
yarn prisma service list --branch feature/search
```

#### npm

```bash
npx prisma service list --branch feature/search
```

Inspect platform branches:

  

#### bun

```bash
bunx prisma branch list
```

#### pnpm

```bash
pnpm prisma branch list
```

#### yarn

```bash
yarn prisma branch list
```

#### npm

```bash
npx prisma branch list
```

Listing branches doesn't expand the services and databases inside them. Use the `service` and `postgres` commands to inspect those.

## Creating branches [#creating-branches]

You rarely create branches manually. They are created automatically:

* **From GitHub**: when a repo is connected, creating a Git branch creates the matching platform branch, and your repository's [deploy workflow](https://www.prisma.io/docs/compute/deploy-on-push) deploys each push to it as a preview. To set this up, see the [GitHub integration docs](https://www.prisma.io/docs/compute/github).
* **From the CLI**: commands that target a branch that doesn't exist yet, such as `service create --branch feature/search` or a [Composer stage deploy](https://www.prisma.io/docs/composer/deploying), create it.

Connecting GitHub doesn't create branches retroactively. It aligns your default branch with the repo's default branch and wires up automation for future events.

## Cleaning up [#cleaning-up]

When GitHub is connected, deleting a Git branch tears down the matching platform branch, as long as it isn't your production or default branch. Those are always left alone.

## Next steps [#next-steps]

* [Environment variables](https://www.prisma.io/docs/compute/environment-variables): preview values and per-branch overrides.
* [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push): a preview environment for every branch you push.
* [GitHub integration](https://www.prisma.io/docs/compute/github): keep platform branches in sync with your repo.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.
- [`Domains`](https://www.prisma.io/docs/compute/domains): Point a custom domain at a production app and the platform verifies DNS and provisions TLS for you.

# Deploy Button (/docs/compute/deploy-button)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.

Location: Compute > Deploy Button

The Deploy Button starts a guided deployment from a compatible public GitHub repository. Prisma copies the source into a new repository under the chosen GitHub account or organization and adds a managed GitHub Actions workflow. That workflow runs Composer, which creates the Prisma project and provisions the resources declared by the repository.

<img src="/docs/img/deploy-button.svg" alt="Deploy with Prisma" width="172" height="36" />

Add the button to a README, blog post, or website so other users can deploy their own copy.

## Create your button [#create-your-button]

Enter your repository URL and copy the generated snippet:

<DeployButtonGenerator />

## Repository requirements [#repository-requirements]

Before publishing the button, make sure the source repository:

* is a public GitHub repository;
* has a Composer config and module at its root;
* default-exports a Composer module whose name is a string literal;
* has a root `package.json` with a `build` script, or uses Nx build targets;
* has one supported root lockfile: `bun.lock`, `package-lock.json`, `pnpm-lock.yaml`, or `yarn.lock`; and
* declares every required service and resource in its Composer module.

The repository can contain up to 100 files and 25 MB in total, with no file larger than 5 MB. Symlinks, Git submodules, and custom GitHub Actions workflows are not supported.

See [Getting started with Composer](https://www.prisma.io/docs/composer/getting-started) to prepare a repository.

## URL options [#url-options]

A Deploy Button links to:

```text title="Deploy Button URL"
https://console.prisma.io/new/clone?repository-url=<your repository URL>
```

| Parameter        | Required | Description                                                                                                  |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| `repository-url` | Yes      | Public GitHub repository in the form `https://github.com/owner/repo`. URL-encode it when composing the link. |
| `project-name`   | No       | Prefills the destination repository name. The user can change it.                                            |
| `utm_source`     | No       | Records where the deployment link was published, such as `github-readme`.                                    |

Deploy Button URLs do not accept environment variables. The first deployment must not depend on secrets that Composer cannot provide. Add any other variables to the project after deployment, then redeploy.

## How it works [#how-it-works]

1. The user chooses a workspace, a GitHub account or organization, a repository name, and its visibility.
2. Prisma copies the source into a new repository under that account or organization and adds the deployment workflow.
3. The workflow runs Composer, which creates the Prisma project, provisions its resources, and deploys the app. Future pushes run the workflow again.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.
- [`Domains`](https://www.prisma.io/docs/compute/domains): Point a custom domain at a production app and the platform verifies DNS and provisions TLS for you.

# Deploy on push (/docs/compute/deploy-on-push)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.

Location: Compute > Deploy on push

You have a [Composer](https://www.prisma.io/docs/composer) app that you deploy by running `deploy module.ts` in a terminal. In this guide you connect its GitHub repository and add a deploy workflow, so pushing replaces that manual step: a push to the default branch updates production, every other branch gets an isolated preview environment, and deleting a branch cleans its preview up.

## How it works [#how-it-works]

Push-to-deploy has two parts, and you set up both:

1. **The repository connection.** [`git connect`](https://www.prisma.io/docs/cli/git) installs the Prisma GitHub App and registers the repository with your project. This lets workflow runs authenticate: a job exchanges its GitHub OIDC token for a Prisma workspace token that expires after 30 minutes, so the workflow needs no repository secrets. The connection also subscribes the project to branch events, which is what tears a preview down when its Git branch is deleted.
2. **The deploy workflow.** [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action) runs in your repository's GitHub Actions. On each push it installs dependencies, runs your build, and runs the [`deploy` command](https://www.prisma.io/docs/cli/deploy) against production or a stage named after the branch.

Connecting a repository does not deploy it; deploys come from the workflow. Without the connection, the workflow has no credential: the action prints a notice, sets its `outcome` output to `skipped-no-credential`, and exits successfully, so the run stays green.

You can connect in the [Console](https://pris.ly/pdp) or from the CLI. The Console opens a pull request that adds the workflow file at the same time. The CLI registers the connection only, and you add the workflow file yourself. This guide uses the CLI.

## Prerequisites [#prerequisites]

* A Composer app that builds and deploys from your machine. The [full-stack tutorial](https://www.prisma.io/docs/full-stack-tutorial) ends with one.
* Admin access to the GitHub repository, so you can install the Prisma GitHub App on it.

## 1. Push the project to GitHub [#1-push-the-project-to-github]

If the app is not on GitHub yet, create a repository from the project directory and push it. With the [GitHub CLI](https://cli.github.com/):

```bash
gh repo create my-app --private --source . --push
```

## 2. Link the directory to the project [#2-link-the-directory-to-the-project]

The `git` commands operate on the project this directory is linked to. If you have deployed from this directory before, it is already linked and you can skip this step. Otherwise, link it to the project your deploys created:

  

#### bun

```bash
bunx prisma project link my-app
```

#### pnpm

```bash
pnpm prisma project link my-app
```

#### yarn

```bash
yarn prisma project link my-app
```

#### npm

```bash
npx prisma project link my-app
```

Run the command in the project root, next to `module.ts`. Linking records the current directory, and it accepts a parent directory without a warning. If later commands fail with `PROJECT.SETUP_REQUIRED`, re-run `project link` from the project root. See the [`project` command reference](https://www.prisma.io/docs/cli/project) for how the link is stored and resolved.

## 3. Connect the repository [#3-connect-the-repository]

Connect the project to the repository from step 1:

  

#### bun

```bash
bunx prisma git connect https://github.com/you/my-app
```

#### pnpm

```bash
pnpm prisma git connect https://github.com/you/my-app
```

#### yarn

```bash
yarn prisma git connect https://github.com/you/my-app
```

#### npm

```bash
npx prisma git connect https://github.com/you/my-app
```

The command opens your browser to install the Prisma GitHub App if it is not installed yet, then registers the connection. It needs an interactive terminal. With `--no-interactive` it fails with `CLI.INTERACTION_REQUIRED`; if you cannot run it interactively, connect through the [Console](https://pris.ly/pdp) instead.

## 4. Add the deploy workflow [#4-add-the-deploy-workflow]

Commit a workflow that runs the deploy action on every push:

```yaml title=".github/workflows/prisma-deploy.yml"
name: prisma-deploy

on:
  push:

concurrency:
  group: prisma-deploy-${{ github.ref }}
  cancel-in-progress: false

permissions:
  contents: read
  id-token: write

jobs:
  deploy:
    if: github.ref_type == 'branch'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - uses: oven-sh/setup-bun@v2
      - uses: prisma/cloud-deploy-action@v1
        with:
          build-command: npm run build
```

A few settings to be aware of:

* `id-token: write` lets the job request the OIDC token that the action exchanges for a workspace token. Without this permission the exchange cannot happen and the run skips.
* `build-command` runs verbatim. The action does not detect your framework or build for you. If the app runs its source directly, set `build-command: none`.
* The action requires Bun on the runner PATH, which `oven-sh/setup-bun@v2` provides.

When the repository has a `prisma` devDependency, the action deploys with that installed version, so keep it current. The action's [README](https://github.com/prisma/cloud-deploy-action) documents the remaining inputs, including `module` for an entry file that is not `module.ts` and `working-directory` for monorepos.

## 5. Push to deploy production [#5-push-to-deploy-production]

Commit the workflow and push to your default branch. In the repository's **Actions** tab, the `prisma-deploy` run installs, builds, and deploys, and ends with the same deploy report you know from your terminal:

```text no-copy
my-app
├─ db    postgres-database db_def456
└─ api   compute-service cps_abc123
         https://xyz.ewr.prisma.build
```

Every later push to the default branch updates production the same way, as if you had run `deploy module.ts` yourself.

If the deploy step fails with `CLI.UNKNOWN_COMMAND`, the action release predates the unified CLI: releases up to v1.5.0 call the removed `prisma composer` commands. Use a release that runs the top-level `deploy` command; the action's [releases page](https://github.com/prisma/cloud-deploy-action/releases) lists what changed in each. If the run is green but its log shows `skipped-no-credential`, the repository is not connected; repeat step 3. Runs triggered from forks skip the same way, because GitHub does not issue OIDC tokens to them, so contributors' pushes keep a green CI without reaching your workspace.

## 6. Preview a branch [#6-preview-a-branch]

Push a branch to try the preview flow:

```bash
git switch -c feature/search
git push -u origin feature/search
```

The action deploys the branch as a [stage](https://www.prisma.io/docs/composer/deploying#production-and-stages) named after it, which is a [preview branch](https://www.prisma.io/docs/compute/branching) of the same project. The preview has its own services, its own databases assigned to that branch, its own buckets, and its own URL. The only thing it shares with production is the code. Confirm it from your terminal:

  

#### bun

```bash
bunx prisma service list --branch feature/search
```

#### pnpm

```bash
pnpm prisma service list --branch feature/search
```

#### yarn

```bash
yarn prisma service list --branch feature/search
```

#### npm

```bash
npx prisma service list --branch feature/search
```

Further pushes to the branch update the same preview. Its configuration comes from the branch's [environment variables](https://www.prisma.io/docs/compute/environment-variables), so a preview reads preview-scoped values rather than production ones.

## 7. Delete the branch to clean up [#7-delete-the-branch-to-clean-up]

When the branch has served its purpose, delete it:

```bash
git push origin --delete feature/search
```

The platform tears down the matching preview: its services, databases, and buckets are removed. This automation comes from the connection you set up in step 3, so it runs whether or not a workflow fires for the deletion. Automated cleanup skips your production and default branches.

## Next steps [#next-steps]

* [GitHub integration](https://www.prisma.io/docs/compute/github): what the repository connection is and does.
* [Branching](https://www.prisma.io/docs/compute/branching): how preview branches relate to Git branches.
* [Deploying](https://www.prisma.io/docs/composer/deploying): stages, deploy state, and per-stage secrets, which apply to CI deploys too.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.
- [`Domains`](https://www.prisma.io/docs/compute/domains): Point a custom domain at a production app and the platform verifies DNS and provisions TLS for you.

# Deployments (/docs/compute/deployments)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

Location: Compute > Deployments

A deploy produces a **version** of a service: one built artifact that can serve traffic. Versions live inside a [branch](https://www.prisma.io/docs/compute/branching), and the live version is the one currently serving requests.

## Where versions come from [#where-versions-come-from]

Versions are created three ways:

* **A git push.** After you [set up deploy on push](https://www.prisma.io/docs/compute/deploy-on-push), your repository's GitHub Actions workflow builds and deploys each pushed branch: the default Git branch deploys to production, and every other branch gets an isolated preview.
* **The [Console](https://pris.ly/pdp).** Trigger a build and deploy from the browser.
* **[`deploy`](https://www.prisma.io/docs/cli/deploy).** For a [Prisma Composer](https://www.prisma.io/docs/composer) app, `deploy` assembles the services you have already built and provisions them from your terminal or CI.

The `service` commands below manage the versions those flows create. They are targeted explicitly: the service is the first positional argument, and version-scoped commands take a globally unique version id, so there is no interactive picker and no dependence on your current git branch.

## Inspect services and versions [#inspect-services-and-versions]

  

#### bun

```bash
bunx prisma service show web
bunx prisma service open web
bunx prisma service version list web
bunx prisma service version show ver_123
```

#### pnpm

```bash
pnpm prisma service show web
pnpm prisma service open web
pnpm prisma service version list web
pnpm prisma service version show ver_123
```

#### yarn

```bash
yarn prisma service show web
yarn prisma service open web
yarn prisma service version list web
yarn prisma service version show ver_123
```

#### npm

```bash
npx prisma service show web
npx prisma service open web
npx prisma service version list web
npx prisma service version show ver_123
```

`service show` describes the service and its live version, `service open` opens its URL, `version list` lists the version history, and `version show` shows one version in detail.

## Logs [#logs]

Read a version's logs with `service logs`. It defaults to the live version; `--version-id <id>` selects another:

  

#### bun

```bash
bunx prisma service logs web --follow
bunx prisma service logs web --version-id ver_123 --tail 200
```

#### pnpm

```bash
pnpm prisma service logs web --follow
pnpm prisma service logs web --version-id ver_123 --tail 200
```

#### yarn

```bash
yarn prisma service logs web --follow
yarn prisma service logs web --version-id ver_123 --tail 200
```

#### npm

```bash
npx prisma service logs web --follow
npx prisma service logs web --version-id ver_123 --tail 200
```

Build output for a deploy is available in the [Console](https://pris.ly/pdp) alongside the version it produced.

## Promote and roll back [#promote-and-roll-back]

Promote a preview version to production:

  

#### bun

```bash
bunx prisma service version promote ver_123
```

#### pnpm

```bash
pnpm prisma service version promote ver_123
```

#### yarn

```bash
yarn prisma service version promote ver_123
```

#### npm

```bash
npx prisma service version promote ver_123
```

Promotion rebuilds the version with **production** environment variables and makes the result live behind the service's endpoint. The rebuild is what lets a version built for a preview branch pick up production environment variables on its way to production.

Roll back production to a previous version. Rollback reuses an existing build, so there is no rebuild step between you and a known-good state:

  

#### bun

```bash
bunx prisma service version rollback web
bunx prisma service version rollback web --to ver_123
```

#### pnpm

```bash
pnpm prisma service version rollback web
pnpm prisma service version rollback web --to ver_123
```

#### yarn

```bash
yarn prisma service version rollback web
yarn prisma service version rollback web --to ver_123
```

#### npm

```bash
npx prisma service version rollback web
npx prisma service version rollback web --to ver_123
```

Without `--to`, rollback targets the version before the live one.

## Start, stop, delete [#start-stop-delete]

  

#### bun

```bash
bunx prisma service version stop ver_123
bunx prisma service version start ver_123
bunx prisma service version delete ver_123
```

#### pnpm

```bash
pnpm prisma service version stop ver_123
pnpm prisma service version start ver_123
pnpm prisma service version delete ver_123
```

#### yarn

```bash
yarn prisma service version stop ver_123
yarn prisma service version start ver_123
yarn prisma service version delete ver_123
```

#### npm

```bash
npx prisma service version stop ver_123
npx prisma service version start ver_123
npx prisma service version delete ver_123
```

Stopping a version takes it out of service without deleting its artifact; starting it brings it back. Deleting a version permanently removes it and the artifact it holds, after confirmation.

## Delete a service [#delete-a-service]

  

#### bun

```bash
bunx prisma service delete web
```

#### pnpm

```bash
pnpm prisma service delete web
```

#### yarn

```bash
yarn prisma service delete web
```

#### npm

```bash
npx prisma service delete web
```

This permanently deletes the service from the branch you target with `--branch`. Pass `--yes` to skip the confirmation prompt.

## Next steps [#next-steps]

* [Environment variables](https://www.prisma.io/docs/compute/environment-variables): persist config across deploys.
* [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push): the push-to-deploy flow in detail.
* [Domains](https://www.prisma.io/docs/compute/domains): point a custom domain at production.
* [Prisma Composer](https://www.prisma.io/docs/composer): declare the app the `deploy` command deploys.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Domains`](https://www.prisma.io/docs/compute/domains): Point a custom domain at a production app and the platform verifies DNS and provisions TLS for you.

# Domains (/docs/compute/domains)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Point a custom domain at a production app and the platform verifies DNS and provisions TLS for you.

Location: Compute > Domains

Configure custom domains that point to your [production app](https://www.prisma.io/docs/compute/branching). You can't configure custom domains for preview apps.

## Before you start [#before-you-start]

You'll need:

* A [linked project](https://www.prisma.io/docs/compute/getting-started).
* A production app with a [promoted, running deployment](https://www.prisma.io/docs/compute/deployments).
* Access to edit DNS records within your DNS provider.

Domain commands target the [production branch](https://www.prisma.io/docs/compute/branching). Pointing them at any other branch fails with a `BRANCH_NOT_DEPLOYABLE` error. Every domain subcommand also accepts `--project` and `--branch` flags.

## Add a custom domain [#add-a-custom-domain]

### 1. Add a domain [#1-add-a-domain]

  

#### bun

```bash
bunx prisma service domain add shop.acme.com --service web
```

#### pnpm

```bash
pnpm prisma service domain add shop.acme.com --service web
```

#### yarn

```bash
yarn prisma service domain add shop.acme.com --service web
```

#### npm

```bash
npx prisma service domain add shop.acme.com --service web
```

Registration verifies DNS up front. If the **CNAME** record isn't visible yet, the command fails with a `DOMAIN_DNS_NOT_CONFIGURED` error and prints the record name and value for you to create. Re-running `add` for a hostname that's already attached is safe: it shows the existing domain instead of failing.

### 2. Create CNAME Record [#2-create-cname-record]

Add the printed DNS record, which points at `switchboard.{region}.prisma.build`.

Example:

| Type  | Name            | Value                          | TTL |
| ----- | --------------- | ------------------------------ | --- |
| CNAME | `shop.acme.com` | `switchboard.cdg.prisma.build` | 300 |

The CLI prints the record name as the full hostname. If your DNS provider expects a relative name, enter just the label (`shop`).

> [!NOTE]
> What is switchboard?
> 
> Switchboard is the routing layer that sits in front of your Compute app. Switchboard verifies the domain, provisions and terminates TLS, then forwards traffic to your app.

### 3. Re-run `add`, then wait for provisioning [#3-re-run-add-then-wait-for-provisioning]

Once the CNAME record has propagated, re-run `service domain add`. This time registration succeeds and TLS provisioning starts. Track it with:

  

#### bun

```bash
bunx prisma service domain wait shop.acme.com --service web
```

#### pnpm

```bash
pnpm prisma service domain wait shop.acme.com --service web
```

#### yarn

```bash
yarn prisma service domain wait shop.acme.com --service web
```

#### npm

```bash
npx prisma service domain wait shop.acme.com --service web
```

`wait` polls until the domain is active, up to 15 minutes. For a single status check, use `--timeout 0`:

  

#### bun

```bash
bunx prisma service domain wait shop.acme.com --service web --timeout 0 --json
```

#### pnpm

```bash
pnpm prisma service domain wait shop.acme.com --service web --timeout 0 --json
```

#### yarn

```bash
yarn prisma service domain wait shop.acme.com --service web --timeout 0 --json
```

#### npm

```bash
npx prisma service domain wait shop.acme.com --service web --timeout 0 --json
```

A single check exits non-zero with `DOMAIN_VERIFICATION_TIMEOUT` while the domain is still provisioning, so automation should read the status event rather than the exit code. In `--json` mode, `wait` streams newline-delimited status events, so an agent can track provisioning as it progresses.

## Remove a domain [#remove-a-domain]

  

#### bun

```bash
bunx prisma service domain remove shop.acme.com --service web
```

#### pnpm

```bash
pnpm prisma service domain remove shop.acme.com --service web
```

#### yarn

```bash
yarn prisma service domain remove shop.acme.com --service web
```

#### npm

```bash
npx prisma service domain remove shop.acme.com --service web
```

Removing detaches the domain from the app. Pass `--yes` to skip the confirmation prompt. Prisma can't touch your DNS, so the CNAME record stays behind. Delete it at your provider once you no longer need it.

## States [#states]

A domain moves through these states:

| Status             | Meaning                                                         |
| ------------------ | --------------------------------------------------------------- |
| `pending_dns`      | The domain is registered; TLS provisioning hasn't started yet   |
| `provisioning_tls` | The TLS certificate is being issued                             |
| `active`           | The domain is fully provisioned and routing traffic to your app |
| `failed`           | Registration or provisioning failed; see the failure reason     |

## Limits [#limits]

* Custom domains are only available on production apps.
* DNS uses CNAME records only. Apex domains need a DNS provider that supports CNAME-like records (ALIAS, ANAME, or CNAME flattening) at the apex.
* Wildcard hostnames such as `*.acme.com` are rejected.
* Up to 3 custom domains per app. Adding more returns `DOMAIN_QUOTA_EXCEEDED`.
* There's no workspace-wide domain list in the CLI.

## Troubleshooting [#troubleshooting]

  

#### bun

```bash
bunx prisma service domain show shop.acme.com --service web
bunx prisma service domain retry shop.acme.com --service web
```

#### pnpm

```bash
pnpm prisma service domain show shop.acme.com --service web
pnpm prisma service domain retry shop.acme.com --service web
```

#### yarn

```bash
yarn prisma service domain show shop.acme.com --service web
yarn prisma service domain retry shop.acme.com --service web
```

#### npm

```bash
npx prisma service domain show shop.acme.com --service web
npx prisma service domain retry shop.acme.com --service web
```

`show` prints the exact state, certificate details, and any DNS hints. `retry` restarts stuck provisioning. If a domain isn't in a retryable state, it returns `DOMAIN_RETRY_NOT_ELIGIBLE`.

## Next steps [#next-steps]

* [Deployments](https://www.prisma.io/docs/compute/deployments): promote a deployment to production first.
* [Known limitations](https://www.prisma.io/docs/compute/limitations): what Compute can and can't do.
* [`service domain` reference](https://www.prisma.io/docs/cli/service#service-domain): every domain subcommand and flag.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# Environment variables (/docs/compute/environment-variables)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Project configuration that gets injected into your deployments, scoped to production, preview, or a single branch.

Location: Compute > Environment variables

Environment variables are project configuration that gets injected into your deployments. You scope each one to production, to preview, or to a single preview branch. This is also how you connect your app to a database: set its connection string as a variable like `DATABASE_URL`.

## How it works [#how-it-works]

There are three layers:

1. **Production variables**: used by production deploys.
2. **Preview variables**: used by every preview deploy.
3. **Branch overrides**: replace a preview value for one specific branch.

<ConceptAnimation name="env-layers" />

A preview deploy gets the preview variables, with any branch overrides layered on top. Overrides help when one branch needs a different API key, database URL, or feature flag than the rest.

Values are resolved at deploy time and baked into the deployment. Changing a variable doesn't touch deployments that already exist and doesn't trigger a redeploy. The new value applies the next time you deploy.

## Set a variable [#set-a-variable]

Pass `KEY=value` and a role or branch:

  

#### bun

```bash
bunx prisma project env add DATABASE_URL=postgresql://example --role production
bunx prisma project env add DATABASE_URL=postgresql://preview --role preview
bunx prisma project env add FEATURE_FLAG=enabled --branch feature/search
```

#### pnpm

```bash
pnpm prisma project env add DATABASE_URL=postgresql://example --role production
pnpm prisma project env add DATABASE_URL=postgresql://preview --role preview
pnpm prisma project env add FEATURE_FLAG=enabled --branch feature/search
```

#### yarn

```bash
yarn prisma project env add DATABASE_URL=postgresql://example --role production
yarn prisma project env add DATABASE_URL=postgresql://preview --role preview
yarn prisma project env add FEATURE_FLAG=enabled --branch feature/search
```

#### npm

```bash
npx prisma project env add DATABASE_URL=postgresql://example --role production
npx prisma project env add DATABASE_URL=postgresql://preview --role preview
npx prisma project env add FEATURE_FLAG=enabled --branch feature/search
```

To keep a secret out of your shell history, pass just the key and let the CLI read it from your environment:

```bash
DATABASE_URL=postgresql://example npx prisma project env add DATABASE_URL --role production
```

To import many variables at once, pass a dotenv file with `--file` instead of a `KEY=value` argument (one or the other, not both). It works for `add` and `update`:

  

#### bun

```bash
bunx prisma project env add --file .env.production --role production
```

#### pnpm

```bash
pnpm prisma project env add --file .env.production --role production
```

#### yarn

```bash
yarn prisma project env add --file .env.production --role production
```

#### npm

```bash
npx prisma project env add --file .env.production --role production
```

## Connect a database [#connect-a-database]

To give your app a database, set its connection string per scope, then redeploy. Use a different database per scope if you want preview deployments isolated from production data.

> [!NOTE]
> Don't assume production data is copied into preview branches, and don't assume migrations run automatically on deploy. Run migrations yourself against the right database.

## List, update, remove [#list-update-remove]

  

#### bun

```bash
bunx prisma project env list --role production
bunx prisma project env list --branch feature/search
bunx prisma project env update DATABASE_URL=postgresql://new --role production
bunx prisma project env delete DATABASE_URL --role preview
```

#### pnpm

```bash
pnpm prisma project env list --role production
pnpm prisma project env list --branch feature/search
pnpm prisma project env update DATABASE_URL=postgresql://new --role production
pnpm prisma project env delete DATABASE_URL --role preview
```

#### yarn

```bash
yarn prisma project env list --role production
yarn prisma project env list --branch feature/search
yarn prisma project env update DATABASE_URL=postgresql://new --role production
yarn prisma project env delete DATABASE_URL --role preview
```

#### npm

```bash
npx prisma project env list --role production
npx prisma project env list --branch feature/search
npx prisma project env update DATABASE_URL=postgresql://new --role production
npx prisma project env delete DATABASE_URL --role preview
```

`list --role` shows names and metadata, never values. `list --branch` shows the variables a deploy of that branch would receive. `rm` works as an alias for `remove`.

`add` never overwrites: it fails if the key already exists in that scope, so use `update` to change a value. Every `project env` subcommand also accepts `--project <id-or-name>` to target a project other than the linked one.

## Values are write-only [#values-are-write-only]

Once you save a variable, its value is encrypted at rest and never returned: not by the CLI, the API, or the Console. In practice:

* `project env list` shows keys and metadata, not values.
* There's no command to pull values into a local `.env`.
* To rotate a secret, `project env update` it and redeploy.
* To confirm an app sees a value, redeploy and check its behavior or logs.

Keep your own copy of every value in a secret manager. Treat Prisma as the place values are *injected*, not a store you read back from.

## Rules [#rules]

* Keys must match `[A-Z_][A-Z0-9_]*`, up to 256 characters.
* Values must be non-empty, up to 8 KB.
* Production variables can't be branch-scoped: use `--role production` for production, and `--branch <name>` only for preview overrides.

## In CI and agents [#in-ci-and-agents]

Add `--json` so the output is machine-readable, and `--no-interactive` so the CLI fails with an error code instead of waiting on a prompt:

  

#### bun

```bash
bunx prisma project env list --role preview --json --no-interactive
```

#### pnpm

```bash
pnpm prisma project env list --role preview --json --no-interactive
```

#### yarn

```bash
yarn prisma project env list --role preview --json --no-interactive
```

#### npm

```bash
npx prisma project env list --role preview --json --no-interactive
```

Don't build anything that depends on reading a value back. Pass the source value in from your own secret store, and let Prisma inject it at deploy time.

## Next steps [#next-steps]

* [Deployments](https://www.prisma.io/docs/compute/deployments): redeploy to apply new values.
* [Branching](https://www.prisma.io/docs/compute/branching): how preview branches work.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# FAQ (/docs/compute/faq)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Quick answers to common questions about Prisma Compute.

Location: Compute > FAQ

## Which package do I install? [#which-package-do-i-install]

Compute is part of the unified Prisma CLI, published as `prisma@latest`. The quickest way to run it without installing anything is:

  

#### bun

```bash
bunx prisma service show
```

#### pnpm

```bash
pnpm prisma service show
```

#### yarn

```bash
yarn prisma service show
```

#### npm

```bash
npx prisma service show
```

## How do I deploy? [#how-do-i-deploy]

Run your build, then deploy a [Prisma Composer](https://www.prisma.io/docs/composer) app with `npx prisma deploy module.ts` from your terminal or CI; `deploy` does not build for you. To deploy on every push, connect the GitHub repository and add the deploy workflow; see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push). You can also trigger a deploy from the [Console](https://pris.ly/pdp).

## What's the difference between a project and an app? [#whats-the-difference-between-a-project-and-an-app]

A project groups the resources for one product or codebase. An app is a single HTTP service inside a project's branch. The full hierarchy:

<ConceptAnimation name="compute-model" />

## What's a branch? [#whats-a-branch]

A branch is an isolated environment for one line of work. It usually matches a Git branch name, but in Prisma it is a real resource that owns its own apps and databases. To learn more, see the [Branching docs](https://www.prisma.io/docs/compute/branching).

## Does `git connect` deploy my app? [#does-git-connect-deploy-my-app]

No, it links a project to a GitHub repository, lets that repository's GitHub Actions runs authenticate, and keeps platform branches in sync when Git branches are created or deleted. It does not deploy anything, on connect or on push. Deploys come from a workflow you add; see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push). To set the connection up, see the [GitHub integration docs](https://www.prisma.io/docs/compute/github).

## What does a GitHub push do? [#what-does-a-github-push-do]

The platform does not handle pushes; your repository's workflow deploys them. Once you [set up deploy on push](https://www.prisma.io/docs/compute/deploy-on-push), each push runs [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action), which builds and deploys to production or to an isolated preview named after the branch. Without that workflow, a push deploys nothing.

## Why can't I read my environment variable values back? [#why-cant-i-read-my-environment-variable-values-back]

Variable values are encrypted and never returned by any surface. `project env list` shows only the keys and their metadata, so keep your own copy of each value in a secret manager. To learn more, see [Values are write-only](https://www.prisma.io/docs/compute/environment-variables#values-are-write-only).

## How do I rotate a secret? [#how-do-i-rotate-a-secret]

Update the value, then redeploy production. To redeploy, run `deploy` again, push to your default branch if you have set up [deploy on push](https://www.prisma.io/docs/compute/deploy-on-push), or promote a version, which rebuilds with production environment variables:

  

#### bun

```bash
bunx prisma project env update DATABASE_URL=postgresql://new --role production
```

#### pnpm

```bash
pnpm prisma project env update DATABASE_URL=postgresql://new --role production
```

#### yarn

```bash
yarn prisma project env update DATABASE_URL=postgresql://new --role production
```

#### npm

```bash
npx prisma project env update DATABASE_URL=postgresql://new --role production
```

## Does changing a variable redeploy my app? [#does-changing-a-variable-redeploy-my-app]

No. Variables resolve at deploy time, so you need to redeploy for the app to pick up a new value.

## How do I run the CLI from CI? [#how-do-i-run-the-cli-from-ci]

Use a service token and explicit targets:

```bash
PRISMA_SERVICE_TOKEN=... npx prisma service show \
  --project my-app \
  --service web \
  --json \
  --no-interactive
```

Passing every target explicitly keeps the run self-contained. `--json` makes the result parseable, and `--no-interactive` turns any prompt into a structured error.

## Why `SERVICE.PROJECT_SETUP_REQUIRED`? [#why-serviceproject_setup_required]

The current directory isn't linked to a project, and the CLI won't guess one from package or directory names. Create or link a project first with `project create` or `project link`, or name one directly on the command with `--project`.

## How do I add a custom domain? [#how-do-i-add-a-custom-domain]

Once the service has a running production version:

  

#### bun

```bash
bunx prisma service domain add shop.acme.com --service web
bunx prisma service domain wait shop.acme.com --service web
```

#### pnpm

```bash
pnpm prisma service domain add shop.acme.com --service web
pnpm prisma service domain wait shop.acme.com --service web
```

#### yarn

```bash
yarn prisma service domain add shop.acme.com --service web
yarn prisma service domain wait shop.acme.com --service web
```

#### npm

```bash
npx prisma service domain add shop.acme.com --service web
npx prisma service domain wait shop.acme.com --service web
```

Add the CNAME record the command returns at your DNS provider. To learn more, see the [Domains docs](https://www.prisma.io/docs/compute/domains).

## Can preview branches have custom domains? [#can-preview-branches-have-custom-domains]

No. Custom domains are production-only, so they cannot be attached to preview branches.

## Does Prisma clone my production database for previews? [#does-prisma-clone-my-production-database-for-previews]

You should not assume it does. These docs cover app deployment and runtime configuration only, so pass database URLs through [environment variables](https://www.prisma.io/docs/compute/environment-variables) and manage data and migrations yourself.

## Do I need Prisma Postgres to use Compute? [#do-i-need-prisma-postgres-to-use-compute]

No. Your app connects to a database through a connection string you set as an environment variable, such as `DATABASE_URL`. Running [Prisma Postgres](https://www.prisma.io/docs/postgres) with Compute keeps your app next to your database.

## Can I use the Console instead? [#can-i-use-the-console-instead]

Yes. Use it to inspect projects, branches, services, deployments, integrations, environment variable names, and domain status.

## Is Prisma Compute free? [#is-prisma-compute-free]

You can run apps for free: each month, the Free plan includes 1M requests, 360 GB-hours of provisioned memory, 4 active vCPU-hours, and 10 GB of outbound bandwidth, with no usage billing. Paid plans include from 5M to 100M requests a month, then bill `$1 per million`; provisioned memory, active CPU, and outbound bandwidth are billed per use. See [Pricing](https://pris.ly/pricing-compute) for the rates, included usage by plan, worked examples, and what is not billed separately. For how those rates compare to Vercel's for the same workload, see [Prisma Compute vs Vercel pricing](https://www.prisma.io/blog/prisma-compute-vs-vercel-pricing?utm_source=docs).

## Why does my service return `504 Gateway Time-out` from openresty? [#why-does-my-service-return-504-gateway-time-out-from-openresty]

Your service took more than 60 seconds to start responding, so Compute's ingress answered the client and cancelled the request. Your service is not crashing. The cancellation happens outside it, so no timeout appears in your logs, though the Console does report the 504. Start responding within 60 seconds and move the rest of the work into the background or a queue. See [Request timeout](https://www.prisma.io/docs/compute/request-timeout).

## What are the current limits? [#what-are-the-current-limits]

See [Known limitations](https://www.prisma.io/docs/compute/limitations) for what Compute can and can't do.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# Getting started (/docs/compute/getting-started)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Deploy your first Prisma Compute app with the unified Prisma CLI, then connect GitHub to deploy on every push.

Location: Compute > Getting started

Get an app live on [Prisma Compute](https://www.prisma.io/docs/compute) with the unified Prisma CLI: sign in, deploy a [Prisma Composer](https://www.prisma.io/docs/composer) app, then connect GitHub so every push deploys. This guide takes you from your code to a live URL, then covers deploying on push, environment variables, CI, and agents. For every command and flag, see the [CLI reference](https://www.prisma.io/docs/cli).

> [!NOTE]
> This guide uses the Prisma CLI, run as `npx prisma <command>`. Deployments come from the [`deploy` command](https://www.prisma.io/docs/cli/deploy) for a [Prisma Composer](https://www.prisma.io/docs/composer) app, from a git push once you [set up deploy on push](https://www.prisma.io/docs/compute/deploy-on-push), or from the [Console](https://pris.ly/pdp). The CLI creates the project, connects GitHub, and inspects the results.

## Prerequisites [#prerequisites]

* A JavaScript runtime. The commands below run with `npx` or `pnpm` on Node.js 22.18 or newer, or with `bunx` (Bun).
* A [Prisma Data Platform account](https://pris.ly/pdp).
* A [Prisma Composer](https://www.prisma.io/docs/composer) app. [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy) shows how to declare a new app or one you already have. To deploy on push, the app also needs a GitHub repository you can connect.

## Sign in [#sign-in]

Authenticate first. Every other command needs a session:

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

This opens a browser to sign you in, then stores a session that every later command inherits. Because the browser step is interactive, CI and other headless environments use a [service token](#automation-and-ci) instead. To check who you are signed in as, run `auth whoami`.

> [!NOTE]
> Next.js apps should set `output: "standalone"` in their Next.js config.
> 
> ```ts title="next.config.ts"
> export default { output: "standalone" };
> ```

## Deploy [#deploy]

`deploy` does not build for you, so build the app first, then deploy its root module:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

The first deploy creates a project named after the app your module exports, unless you override the name with `--name`. It provisions the app's services on Compute and any databases on Prisma Postgres, and prints each service's URL. A new project needs a region, so set one in your deploy config or as `PRISMA_REGION` before the first deploy; see [`deploy`](https://www.prisma.io/docs/cli/deploy). [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy) walks through the whole flow.

Each deploy produces a service **version**. List, inspect, and open your services:

  

#### bun

```bash
bunx prisma service list
bunx prisma service show <service>
bunx prisma service open <service>
```

#### pnpm

```bash
pnpm prisma service list
pnpm prisma service show <service>
pnpm prisma service open <service>
```

#### yarn

```bash
yarn prisma service list
yarn prisma service show <service>
yarn prisma service open <service>
```

#### npm

```bash
npx prisma service list
npx prisma service show <service>
npx prisma service open <service>
```

`service show` prints the service and its live version. Read the version's logs with:

  

#### bun

```bash
bunx prisma service logs <service> --follow
```

#### pnpm

```bash
pnpm prisma service logs <service> --follow
```

#### yarn

```bash
yarn prisma service logs <service> --follow
```

#### npm

```bash
npx prisma service logs <service> --follow
```

To learn how versions are promoted, rolled back, started, and stopped, see [Deployments](https://www.prisma.io/docs/compute/deployments).

## Link a project [#link-a-project]

A project groups your services, branches, and databases. The `service` and `git` commands act on the project this directory is linked to. If you deployed from this directory, it is already linked. To work from another checkout, or with a project your team already deployed, link to it by name:

  

#### bun

```bash
bunx prisma project link my-app
```

#### pnpm

```bash
pnpm prisma project link my-app
```

#### yarn

```bash
yarn prisma project link my-app
```

#### npm

```bash
npx prisma project link my-app
```

Linking writes the selected project to `.prisma/local.json`. This file is gitignored and only stores your local link, so it should not be treated as committed configuration. To verify the link, run:

  

#### bun

```bash
bunx prisma project show
bunx prisma project list
```

#### pnpm

```bash
pnpm prisma project show
pnpm prisma project list
```

#### yarn

```bash
yarn prisma project show
yarn prisma project list
```

#### npm

```bash
npx prisma project show
npx prisma project list
```

`project show` tells you what this directory is linked to. `project list` shows the projects you can see.

## Deploy on push [#deploy-on-push]

To deploy on every push, connect the project to your GitHub repository and add a deploy workflow. Connect first:

  

#### bun

```bash
bunx prisma git connect
```

#### pnpm

```bash
pnpm prisma git connect
```

#### yarn

```bash
yarn prisma git connect
```

#### npm

```bash
npx prisma git connect
```

This starts the GitHub App install flow if needed and links the repository. The connection lets the repository's GitHub Actions runs sign in to your workspace, but it does not deploy anything. Pushes are deployed by a workflow that runs [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action): on each push it installs dependencies, runs your build, and runs the same `deploy` command. Add the workflow file as shown in [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push#4-add-the-deploy-workflow). If you connect in the [Console](https://pris.ly/pdp) instead of the CLI, it opens a pull request that adds the workflow for you.

Once the workflow is committed, every push deploys: the default Git branch deploys to production, and every other branch gets its own isolated preview named after it. Follow each run in the repository's **Actions** tab.

## Environment variables [#environment-variables]

Set environment variables per scope, production or preview, before the deploy that should use them. To connect a database, create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database in the project (`npx prisma postgres create my-db` prints its connection string once) and store the URL as an environment variable:

  

#### bun

```bash
bunx prisma project env add DATABASE_URL=postgres://... --role production
bunx prisma project env add DATABASE_URL=postgres://... --role preview
```

#### pnpm

```bash
pnpm prisma project env add DATABASE_URL=postgres://... --role production
pnpm prisma project env add DATABASE_URL=postgres://... --role preview
```

#### yarn

```bash
yarn prisma project env add DATABASE_URL=postgres://... --role production
yarn prisma project env add DATABASE_URL=postgres://... --role preview
```

#### npm

```bash
npx prisma project env add DATABASE_URL=postgres://... --role production
npx prisma project env add DATABASE_URL=postgres://... --role preview
```

Values are write-only and resolve at deploy time. See [Environment variables](https://www.prisma.io/docs/compute/environment-variables) for details.

## Automation and CI [#automation-and-ci]

The same commands run unattended in CI or under a coding agent.

If you have signed in with `auth login`, anything running in that environment inherits your session, including an agent working in your directory. Check the session:

  

#### bun

```bash
bunx prisma auth whoami
```

#### pnpm

```bash
pnpm prisma auth whoami
```

#### yarn

```bash
yarn prisma auth whoami
```

#### npm

```bash
npx prisma auth whoami
```

For CI, or any environment where the browser sign-in is not an option, authenticate with a **service token** instead. Set `PRISMA_SERVICE_TOKEN` and the CLI uses it before any stored session. Pass targets explicitly so nothing depends on a prompt. Add `--json` for structured output, and `--no-interactive` so the CLI fails instead of asking:

```bash
PRISMA_SERVICE_TOKEN=... npx prisma service show web \
  --project my-app \
  --json \
  --no-interactive
```

### Agent skills [#agent-skills]

If a coding agent does your deploying, install the Prisma Compute agent skill into your repo:

  

#### bun

```bash
bunx skills add prisma/skills --skill prisma-compute
```

#### pnpm

```bash
pnpm dlx skills add prisma/skills --skill prisma-compute
```

#### yarn

```bash
yarn dlx skills add prisma/skills --skill prisma-compute
```

#### npm

```bash
npx skills add prisma/skills --skill prisma-compute
```

The `prisma-compute` skill teaches your agent the Compute workflow (auth, config, deploys, logs, and domains), so it follows the right steps. Supported agents pick it up automatically. See [Agent Skills](https://www.prisma.io/docs/ai/tools/skills) for the full catalog. For a Composer app, also run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once. It syncs the Composer skill that ships inside `@prisma/composer` and keeps it matching the installed version; that package-shipped set is what the CLI's own [`skills` commands](https://www.prisma.io/docs/cli/skills) manage.

### Structured output [#structured-output]

In `--json` mode, every command emits an envelope with an `ok` flag. On failure, `error.code` is a dotted `NAMESPACE.SUBCODE` (for example `SERVICE.PROJECT_SETUP_REQUIRED`), `error.summary` and `error.why` explain the problem, and `nextActions` lists concrete follow-up commands. Scripts and agents should branch on the code rather than the message: codes are a stable contract, while wording can change between releases.

## Console [#console]

To browse and manage the same resources without the CLI, open the [Console](https://pris.ly/pdp). It shows projects, branches, services, deployments, integrations, and domains.

## Next steps [#next-steps]

* [Deployments](https://www.prisma.io/docs/compute/deployments): inspect, promote, roll back, start, stop.
* [Environment variables](https://www.prisma.io/docs/compute/environment-variables): production, preview, and per-branch overrides.
* [Branching](https://www.prisma.io/docs/compute/branching): how branches isolate work and map to Git.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# GitHub (/docs/compute/github)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Connect a GitHub repository to a project to authenticate your Actions deploys and keep platform branches in sync with your Git branches.

Location: Compute > GitHub

Connecting a GitHub repository wires a project to your repo. Deploys run in your own GitHub Actions, through [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action); the connection provides two things around them:

* **Credentials.** Workflow runs in the connected repository exchange their GitHub OIDC token for a short-lived Prisma workspace token, so the deploy workflow needs no secrets.
* **Branch lifecycle.** Branch events keep the matching platform branches in sync, including tearing a preview down when its Git branch is deleted.

For the full setup, from connection to a live preview per branch, follow [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

## How it works [#how-it-works]

The connection has two levels:

<ConceptAnimation name="github-connection" />

The workspace owns the GitHub App installation; each project points at a single repository. Once connected, Prisma verifies the repository identity behind each credential exchange and listens for the repo's branch events.

## Connect a repo [#connect-a-repo]

You can connect through the [Console](https://pris.ly/pdp) or from the CLI. The Console also opens a pull request that adds the deploy workflow to the repository. The CLI sets up the connection only, and you [add the workflow yourself](https://www.prisma.io/docs/compute/deploy-on-push#4-add-the-deploy-workflow).

From a linked project directory, connect your Git origin:

  

#### bun

```bash
bunx prisma git connect
```

#### pnpm

```bash
pnpm prisma git connect
```

#### yarn

```bash
yarn prisma git connect
```

#### npm

```bash
npx prisma git connect
```

To name the repository explicitly:

  

#### bun

```bash
bunx prisma git connect https://github.com/acme/shop
```

#### pnpm

```bash
pnpm prisma git connect https://github.com/acme/shop
```

#### yarn

```bash
yarn prisma git connect https://github.com/acme/shop
```

#### npm

```bash
npx prisma git connect https://github.com/acme/shop
```

If the GitHub App isn't installed yet, the CLI opens the browser to finish the install. The command needs an interactive terminal: it waits for the install to complete, and `--no-interactive` fails with `CLI.INTERACTION_REQUIRED`. For headless setups, connect through the Console instead.

Disconnect when you're done:

  

#### bun

```bash
bunx prisma git disconnect
```

#### pnpm

```bash
pnpm prisma git disconnect
```

#### yarn

```bash
yarn prisma git disconnect
```

#### npm

```bash
npx prisma git disconnect
```

Disconnecting stops the credential exchange and the branch automation. It doesn't delete the project or tear down existing branches.

## What the connection does [#what-the-connection-does]

Once a project is connected:

* **Actions runs can authenticate.** A workflow job with `id-token: write` gets a workspace token through the OIDC exchange. The token is valid for 30 minutes and is only issued for the connected repository; unconnected repositories and forks are refused, and the deploy action then skips with a green run.
* **Branch created** → creates the matching platform branch.
* **Branch deleted** → tears down the matching platform branch and its resources. Your production and default branches are exempt from this cleanup.

Pushes are not handled by the platform. Your repository's own workflow deploys them, so a connected repo without a deploy workflow deploys nothing. Connecting also doesn't create branches retroactively: it aligns your default branch with the repo's default branch and wires up automation for future events.

## What's not supported [#whats-not-supported]

GitHub is the only supported provider; others return `REPO_PROVIDER_UNSUPPORTED`. Pull-request comments and preview comments aren't currently supported.

## Next steps [#next-steps]

* [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push): the full walkthrough, from connection to per-branch previews.
* [Branching](https://www.prisma.io/docs/compute/branching): how platform branches map to Git.
* [Environment variables](https://www.prisma.io/docs/compute/environment-variables): per-branch config for previews.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# Image Transformations (/docs/compute/image-transformations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Resize, encode, cache, and serve images from a Prisma Compute app using Bun's native image pipeline and ordinary HTTP routes.

Location: Compute > Image Transformations

[Prisma Compute](https://www.prisma.io/docs/compute) apps run on Bun, and Bun ships [`Bun.Image`](https://bun.com/docs/runtime/image): a native pipeline for decoding, resizing, rotating, flipping, adjusting, and re-encoding images. So you build image transformations as part of your app, not as a separate image service.

A transformation route is an ordinary [Compute deployment](https://www.prisma.io/docs/compute/deployments). It receives a request, uses CPU and memory, and returns bytes. It is billed and operated like every other route in your app.

## What Bun handles natively [#what-bun-handles-natively]

`Bun.Image` supports the common image optimization path:

| Need                                | Bun API                                                              |
| ----------------------------------- | -------------------------------------------------------------------- |
| Read image dimensions and format    | `metadata()`                                                         |
| Resize by width or width and height | `resize(width)` or `resize(width, height)`                           |
| Preserve aspect ratio inside a box  | `resize(width, height, { fit: "inside" })`                           |
| Prevent upscaling                   | `resize(width, height, { withoutEnlargement: true })`                |
| Choose resize filter                | `filter: "lanczos3"`, `"mitchell"`, `"box"`, `"nearest"`, and others |
| Rotate                              | `rotate(90)`, `rotate(180)`, `rotate(270)`                           |
| Flip                                | `flip()` for vertical, `flop()` for horizontal                       |
| Adjust brightness and saturation    | `modulate({ brightness, saturation })`                               |
| Encode JPEG                         | `jpeg({ quality, progressive })`                                     |
| Encode PNG                          | `png({ compressionLevel })` or `png({ palette, colors, dither })`    |
| Encode WebP                         | `webp({ quality })` or `webp({ lossless: true })`                    |
| Generate a placeholder              | `placeholder()`                                                      |
| Return HTTP response body           | `blob()`, `bytes()`, or `buffer()`                                   |
| Write a transformed file            | `write(path)`, `write(Bun.file(...))`, or `write(Bun.s3(...))`       |

Stick to JPEG, PNG, and WebP for portable Compute routes. Bun's HEIC and AVIF support depends on operating-system image backends, so treat those formats as unavailable unless you add and test your own encoder path.

## Minimal service [#minimal-service]

Build the route in a Hono or plain Bun HTTP app. The example below uses Hono to match the other [Compute examples](https://www.prisma.io/docs/compute/getting-started); the `Bun.Image` code is identical in any framework.

```bash title="Install Hono"
bun add hono
```

```ts title="src/index.ts"
import { Hono } from "hono";

const app = new Hono();

const IMAGE_ORIGIN = "https://assets.example.com/";
const MAX_DIMENSION = 2400;
const MAX_PIXELS = 4096 * 4096;

function parseDimension(value: string | undefined) {
  if (!value) return undefined;
  const parsed = Number.parseInt(value, 10);
  if (!Number.isFinite(parsed) || parsed <= 0) return undefined;
  return Math.min(parsed, MAX_DIMENSION);
}

function parseQuality(value: string | undefined) {
  if (!value) return 80;
  const parsed = Number.parseInt(value, 10);
  if (!Number.isFinite(parsed)) return 80;
  return Math.min(Math.max(parsed, 1), 100);
}

function negotiateFormat(request: Request, requested: string | undefined) {
  if (requested === "jpeg" || requested === "png" || requested === "webp") {
    return requested;
  }

  const accept = request.headers.get("accept") ?? "";
  return accept.includes("image/webp") ? "webp" : "jpeg";
}

async function applyResize(image: Bun.Image, width?: number, height?: number, fit: "fill" | "inside" = "inside") {
  const options = {
    fit,
    withoutEnlargement: true,
    filter: "lanczos3" as const,
  };

  if (width && height) return image.resize(width, height, options);
  if (width) return image.resize(width, undefined, options);

  if (height) {
    const metadata = await image.metadata();
    const computedWidth = Math.max(1, Math.round((metadata.width * height) / metadata.height));
    return image.resize(computedWidth, height, options);
  }

  return image;
}

function assertImagePath(path: string) {
  if (!/^[a-zA-Z0-9/_ .-]+\.(jpe?g|png|webp)$/i.test(path)) {
    throw new Error("Invalid image path");
  }
}

app.get("/images/*", async (c) => {
  const path = c.req.path.replace(/^\/images\//, "");

  try {
    assertImagePath(path);
  } catch {
    return c.text("Invalid image path", 400);
  }

  const sourceUrl = new URL(path, IMAGE_ORIGIN);
  const source = await fetch(sourceUrl);

  if (!source.ok) {
    return c.text("Source image not found", 404);
  }

  const input = await source.arrayBuffer();
  const width = parseDimension(c.req.query("w"));
  const height = parseDimension(c.req.query("h"));
  const quality = parseQuality(c.req.query("q"));
  const fit = c.req.query("fit") === "fill" ? "fill" : "inside";
  const format = negotiateFormat(c.req.raw, c.req.query("format"));

  let image = new Bun.Image(input, {
    maxPixels: MAX_PIXELS,
    autoOrient: true,
  });

  image = await applyResize(image, width, height, fit);

  if (format === "webp") {
    image = image.webp({ quality });
  } else if (format === "png") {
    image = image.png({ compressionLevel: 6 });
  } else {
    image = image.jpeg({ quality, progressive: true });
  }

  const body = await image.blob();

  return new Response(body, {
    headers: {
      "Cache-Control": "public, max-age=31536000, immutable",
      "Content-Type": body.type,
      "Vary": "Accept",
    },
  });
});

export default app;
```

Deploy it by pushing once you have [set up deploy on push](https://www.prisma.io/docs/compute/deploy-on-push), or follow [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy) to set the project up first.

Request variants:

```text title="Requests"
/images/products/chair.jpg?w=640&q=75
/images/products/chair.jpg?w=1280&format=webp
/images/products/chair.jpg?w=512&h=512&fit=inside
```

This example sends `Cache-Control: immutable`, which is only safe when the source path is versioned (a content hash or version segment). If `chair.jpg` can change in place, drop `immutable` and use a shorter `max-age` with an `ETag`. See [Caching](#caching) for the full rules.

## Source images [#source-images]

`Bun.Image` accepts a path, bytes, or a `Blob`. On Compute, prefer bytes or trusted storage handles over raw user-controlled paths.

### Remote source [#remote-source]

```ts title="Remote source"
const response = await fetch(sourceUrl);
if (!response.ok) throw new Error("Image not found");

const image = new Bun.Image(await response.arrayBuffer(), {
  maxPixels: 4096 * 4096,
  autoOrient: true,
});
```

Validate remote sources before fetching them:

* Allow only trusted hostnames or storage prefixes.
* Reject private network addresses if users can submit URLs.
* Cap redirects or disable them when you do not need them.
* Set a maximum decoded pixel count with `maxPixels`.
* Cap requested dimensions and quality.

### Local file [#local-file]

```ts title="Local file"
const image = Bun.file("public/avatars/alice.png").image();
```

Do not pass a user-controlled string directly to `new Bun.Image(path)`. If the source is user-selected, resolve it through your own database or object store first, then read the trusted object.

### S3-compatible object [#s3-compatible-object]

An [Object Store bucket](https://www.prisma.io/docs/compute/object-storage) in the same project works here directly: set its credentials as the `S3_*` environment variables and `Bun.s3` reads them.

```ts title="S3 source"
const image = Bun.s3("uploads/photo.jpg").image();
```

You can also write generated variants back to S3:

```ts title="Write variant"
await Bun.s3("uploads/photo.jpg")
  .image()
  .resize(640, undefined, { withoutEnlargement: true })
  .webp({ quality: 80 })
  .write(Bun.s3("variants/photo-640.webp"));
```

## Transform options [#transform-options]

### Resize [#resize]

```ts title="Resize"
image.resize(800);
image.resize(800, 600);
image.resize(800, 600, { fit: "inside" });
image.resize(800, 600, { withoutEnlargement: true });
image.resize(800, 600, { filter: "mitchell" });
```

Use `fit: "inside"` for the common thumbnail behavior: preserve aspect ratio and fit within a box. Without `fit: "inside"`, width and height produce an exact output size, which can stretch the image.

Use `withoutEnlargement: true` when handling user uploads or product assets so small source images are not upscaled.

### Rotate and flip [#rotate-and-flip]

```ts title="Rotate and flip"
image.rotate(90);
image.flip();
image.flop();
```

`rotate()` accepts multiples of 90 degrees.

### Brightness, saturation, and grayscale [#brightness-saturation-and-grayscale]

```ts title="Adjust color"
image.modulate({
  brightness: 1.1,
  saturation: 0,
});
```

`saturation: 0` creates a grayscale output.

### Output formats [#output-formats]

```ts title="Output formats"
image.jpeg({ quality: 82, progressive: true });
image.png({ compressionLevel: 6 });
image.png({ palette: true, colors: 64, dither: true });
image.webp({ quality: 80 });
image.webp({ lossless: true });
```

If you do not choose an output format, Bun reuses the source format.

### Placeholders [#placeholders]

```ts title="Placeholder"
const placeholder = await Bun.file("hero.jpg").image().placeholder();
```

Inline the result as a low-quality placeholder in HTML or React components while the full image loads.

## Content negotiation [#content-negotiation]

To implement `format=auto`, inspect the `Accept` header.

```ts title="Format negotiation"
function autoFormat(request: Request) {
  const accept = request.headers.get("accept") ?? "";
  if (accept.includes("image/webp")) return "webp";
  return "jpeg";
}
```

Return `Vary: Accept` when the same URL can produce different formats:

```ts title="Response headers"
return new Response(body, {
  headers: {
    "Content-Type": body.type,
    "Vary": "Accept",
  },
});
```

## Caching [#caching]

Every unique URL should map to one deterministic output. Keep query parameters normalized and bounded.

Recommended cache rules:

* Include all transformation parameters in the URL or path.
* Sort query parameters when generating URLs from code.
* Use immutable cache headers for versioned source paths.
* Use shorter cache headers or ETags when the source can change in place.
* Return `Vary: Accept` when format negotiation depends on request headers.
* Add a source version, hash, or updated timestamp to the URL when invalidating.

Example:

```ts title="Cache headers"
headers.set("Cache-Control", "public, max-age=31536000, immutable");
headers.set("Vary", "Accept");
```

## Vercel Image Optimization equivalents [#vercel-image-optimization-equivalents]

Vercel Image Optimization supports framework image components, width and quality parameters, automatic format selection, source allowlists, caching, and fixed source limits. On Prisma Compute, implement those pieces in the app route.

| Vercel behavior                       | Prisma Compute approach                                                                        |
| ------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `url` source parameter                | Resolve a trusted object key or allowlisted source URL. Do not fetch arbitrary user URLs.      |
| `w` width parameter                   | Parse and cap `w`, then call `resize(w, ...)`.                                                 |
| `q` quality parameter                 | Parse and cap `q`, then pass it to `jpeg()` or `webp()`.                                       |
| Automatic WebP or AVIF                | Inspect `Accept`. Use WebP natively. Add and test a separate AVIF encoder if you require AVIF. |
| Local and remote source patterns      | Keep allowlists in code or config. Reject anything else before fetching.                       |
| Cache optimized variants              | Make the URL the cache key and return appropriate `Cache-Control` and `Vary` headers.          |
| Framework image component integration | Point your framework loader or image component at your Compute image route.                    |
| Source size limits                    | Use `maxPixels`, cap response body size, and reject dimensions above your product limit.       |

## Cloudflare Images equivalents [#cloudflare-images-equivalents]

Cloudflare Images exposes many URL and Worker options. The table below maps each option to the Compute implementation path.

| Cloudflare option                          | Prisma Compute approach                                                                                                                                        |
| ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `anim`                                     | Bun's native output path is best for static variants. Preserve animated originals separately, or use an animation-aware library when you need animated output. |
| `background`                               | Use CSS for display backgrounds, or add an image library that supports canvas extension/padding.                                                               |
| `blur`                                     | Add an image library with blur support. Do not rely on URL blur for access control.                                                                            |
| `border`                                   | Prefer CSS borders for display. Use an image library if the border must be encoded into the asset.                                                             |
| `brightness`                               | Use `modulate({ brightness })`.                                                                                                                                |
| `compression`                              | Choose faster formats/settings in your route, usually JPEG or WebP with a lower quality, and cache the result.                                                 |
| `contrast`                                 | Add an image library with contrast adjustment.                                                                                                                 |
| `dpr`                                      | Multiply requested width and height by the DPR value before resizing, and cap the result.                                                                      |
| `fit=scale-down`                           | Use `fit: "inside"` with `withoutEnlargement: true`.                                                                                                           |
| `fit=contain`                              | Use `fit: "inside"`; omit `withoutEnlargement` if you allow upscaling.                                                                                         |
| `fit=cover`, `fit=crop`, `fit=aspect-crop` | Add a library with crop/extract support, or pre-generate cropped variants. Current `Bun.Image` does not expose crop coordinates.                               |
| `fit=pad`                                  | Use CSS object-fit where possible, or add a library that can extend the canvas with a background color.                                                        |
| `fit=squeeze`                              | Use `resize(width, height)` without `fit: "inside"` when distortion is acceptable.                                                                             |
| `fit=scale-up`                             | Use `fit: "inside"` and allow upscaling; cap dimensions.                                                                                                       |
| `flip`                                     | Use `flip()` for vertical or `flop()` for horizontal.                                                                                                          |
| `format` / `f`                             | Choose `.jpeg()`, `.png()`, or `.webp()`. Implement `auto` with the `Accept` header.                                                                           |
| `gamma`                                    | Add an image library with gamma adjustment.                                                                                                                    |
| `gravity` / `g`                            | For fixed focal points, store focal metadata and use a crop-capable library. For `auto` or `face`, use a vision model or external service to choose the crop.  |
| `height` / `h`                             | Parse and cap `h`, then pass it to `resize()`.                                                                                                                 |
| `metadata`                                 | Bun can apply EXIF orientation with `autoOrient`. Use an additional library if you need explicit EXIF preservation or removal policy.                          |
| `onerror=redirect`                         | Catch transform errors and redirect to the original source when that is safe for your app.                                                                     |
| `quality` / `q`                            | Pass a capped quality to `jpeg()` or `webp()`. For PNG, use `compressionLevel` or palette output.                                                              |
| `rotate`                                   | Use `rotate(90)`, `rotate(180)`, or `rotate(270)`.                                                                                                             |
| `saturation`                               | Use `modulate({ saturation })`; `0` creates grayscale.                                                                                                         |
| `segment`                                  | Use a background-removal model or API, then composite the result with an image library.                                                                        |
| `sharpen`                                  | Add an image library with sharpen support.                                                                                                                     |
| `slow-connection-quality` / `scq`          | Read client hints such as `Save-Data`, `RTT`, `ECT`, or `Downlink`, then lower quality in route logic.                                                         |
| `trim`                                     | Add a library that supports edge trimming or explicit crop/extract.                                                                                            |
| `upscale`                                  | Use native resize for interpolation. Use a super-resolution model or API for AI upscaling.                                                                     |
| `width` / `w`                              | Parse and cap `w`, then pass it to `resize()`.                                                                                                                 |
| `width=auto`                               | Choose a breakpoint from client hints, user agent, or your own layout metadata.                                                                                |
| `zoom` / `face-zoom`                       | Use face detection plus a crop-capable library.                                                                                                                |

## Adding advanced image libraries [#adding-advanced-image-libraries]

If you need operations that `Bun.Image` does not expose, add a library and keep the same route shape:

1. Validate source, dimensions, format, and quality.
2. Fetch or read the trusted source.
3. Run native Bun transformations for the common path when possible.
4. Route advanced presets through the library.
5. Return the same cache headers and error behavior.

Keep advanced transformations behind named presets instead of exposing every option directly. For example:

```text title="Preset URLs"
/images/products/chair.jpg?p=thumb
/images/products/chair.jpg?p=hero
/images/products/chair.jpg?p=square
```

Presets make cache keys stable and prevent users from creating unbounded transformation combinations.

## Security checklist [#security-checklist]

* Do not pass user-controlled filesystem paths to `new Bun.Image(path)`.
* Allowlist remote origins before fetching.
* Reject private IP ranges for user-submitted URLs.
* Cap width, height, quality, DPR, and decoded pixels.
* Prefer named presets for public image URLs.
* Return clear `400` responses for invalid parameters.
* Return `404` for missing source images.
* Set `Vary: Accept` when negotiating formats.
* Use `maxPixels` to reject decompression bombs before pixel allocation.
* Do not use reversible transformations such as blur as an access-control mechanism.

## What to read next [#what-to-read-next]

* [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy): take a route like this one to a live URL.
* [Deployments](https://www.prisma.io/docs/compute/deployments): build, deploy, logs, promote, and roll back.
* [Environment variables](https://www.prisma.io/docs/compute/environment-variables): point a preview at a staging bucket and production at a production one.
* [Branching](https://www.prisma.io/docs/compute/branching): give every image route its own isolated preview.
* [Pricing](https://www.prisma.io/docs/compute/pricing): how request, CPU, memory, and bandwidth metering works.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# Prisma Compute (/docs/compute)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Deploy TypeScript services alongside Prisma Postgres, with hosting, database branches, and previews managed together.

Location: Prisma Compute

Prisma Compute is a hosting platform for TypeScript services. It runs your application next to [Prisma Postgres](https://www.prisma.io/docs/postgres) and gives every Git branch an isolated environment: its own service, environment variables, and optionally its own database.

Compute works with any supported TypeScript framework. It pairs with [Prisma ORM](https://www.prisma.io/docs/orm) for data access, but that is not required.

> [!NOTE]
> These docs use the Prisma CLI, run as `npx prisma@latest`. Deployments come from the [`deploy` command](https://www.prisma.io/docs/cli/deploy) for a [Prisma Composer](https://www.prisma.io/docs/composer) app, from a git push once you [set up deploy on push](https://www.prisma.io/docs/compute/deploy-on-push), or from the [Console](https://pris.ly/pdp). See [Deployments](https://www.prisma.io/docs/compute/deployments) for details.

## Get started [#get-started]

- [Deploy your first service](https://www.prisma.io/docs/compute/getting-started): Sign in, deploy a Composer app, and set up deploys on push.

- [Deploy quickstart](https://www.prisma.io/docs/prisma-compute/deploy): The short path: declare a new app or bring one you have, then deploy it with Composer.

Declare your app with [Prisma Composer](https://www.prisma.io/docs/composer), whether it has one service or several: you describe each service and the databases it depends on in TypeScript, and one deploy provisions them together.

## The model [#the-model]

Compute organizes everything into a few resources:

* A **project** groups one product or codebase.
* A **branch** maps to a Git branch in the linked repository. Each branch is an isolated environment with its own services, environment variables, and deployments, and can have its own database.
* A **service** is an HTTP application, such as a frontend or backend. Each deploy of a service creates a **version**. One version is live at a time.

The default Git branch (usually `main`) is the **production** branch. Every other branch is a **preview** branch with its own Compute resources: services, deployments, and environment variables. Data isolation is yours to configure. A preview deploy reads the preview-scoped variables. If preview work must not touch production data, point the preview `DATABASE_URL` at a non-production database. See [Environment variables](https://www.prisma.io/docs/compute/environment-variables) for details. After you [set up deploy on push](https://www.prisma.io/docs/compute/deploy-on-push), pushing to a branch deploys that branch from your repository's GitHub Actions.

The animation below shows how a project, its branches, and their infrastructure fit together, and how each branch's variables resolve by scope:

<ConceptAnimation name="compute-model" />

For the full picture, see [Branching](https://www.prisma.io/docs/compute/branching).

## CLI and Console [#cli-and-console]

Use the **CLI** for anything you want to repeat: local development, CI, and agent workflows. Every command supports a `--json` flag that switches its output to machine-readable JSON, so scripts and agents can parse results instead of scraping terminal text.

Use the &#x2A;*[Console](https://pris.ly/pdp)** to view and manage projects, branches, services, and deployments in a browser instead of running commands.

## What to read next [#what-to-read-next]

Once you have deployed something, read [Deployments](https://www.prisma.io/docs/compute/deployments) for logs, promoting, and rolling back, and [Environment variables](https://www.prisma.io/docs/compute/environment-variables) for configuration per scope. [Object storage](https://www.prisma.io/docs/compute/object-storage) covers S3-compatible Object Store buckets, next to your databases in the same project. The [CLI reference](https://www.prisma.io/docs/cli) documents every command and flag. For what Compute can and can't do, read the [known limitations](https://www.prisma.io/docs/compute/limitations).

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# Keeping instances awake (/docs/compute/keeping-instances-awake)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Keep a Prisma Compute instance awake so it does not scale to zero while bounded background work completes.

Location: Compute > Keeping instances awake

By default, Prisma Compute [scales idle instances to zero](https://www.prisma.io/docs/compute/pricing) to save cost: idle instances sleep with a memory snapshot, then resume with memory intact in milliseconds. Some bounded background work needs the instance to keep running after a request ends or while no request is in flight.

`@prisma/compute` provides two primitives for these cases:

* `waitUntil`: keeps the current instance awake until a background promise settles.
* `KeepAwakeGuard`: keeps the current instance awake until you release the guard.

> [!WARNING]
> These primitives are for best-effort background work. They only prevent the current instance from scaling to zero; they do not make work durable, retry failures, guarantee that work continues through restarts or deployments, or change connection-lifetime limits. Persist progress and design work so it can safely restart.
> 
> WebSocket servers are not currently supported.

## When to keep instances awake [#when-to-keep-instances-awake]

Reach for `waitUntil` or `KeepAwakeGuard` for bounded, best-effort work between requests, for example:

* A bounded job that outlives the request that started it.
* Background processing you kick off after returning a response.

This also covers work that would exceed the [60-second request timeout](https://www.prisma.io/docs/compute/request-timeout): return the response first, then let the work continue under `waitUntil`.

If your work always finishes inside a single request, you do not need either primitive. Let the instance sleep as usual.

## Use `waitUntil` for background promises [#use-waituntil-for-background-promises]

Use `waitUntil` when you have a promise for background work that should keep the instance awake. This is the most direct API for work you start during a request but do not await before returning a response:

```ts title="src/index.ts"
import { waitUntil } from "@prisma/compute";

export default {
  fetch(req: Request) {
    waitUntil(processInBackground(req), {
      // Optional. Prevents a hanging promise from keeping the instance awake indefinitely.
      signal: AbortSignal.timeout(30_000),
    });

    return new Response("Accepted");
  },
};
```

`waitUntil` follows the same pattern as [Cloudflare Workers](https://developers.cloudflare.com/workers/runtime-apis/context/#waituntil) and the [Service Worker API](https://developer.mozilla.org/en-US/docs/Web/API/ExtendableEvent/waitUntil): the instance stays awake until the promise settles. Prisma Compute adds an optional caller-owned `signal` value so you can stop the keep-awake effect if a promise hangs or never settles. The signal does not cancel the promise or the work it started.

## Use `KeepAwakeGuard` for block-scoped or manual lifetimes [#use-keepawakeguard-for-block-scoped-or-manual-lifetimes]

Use `KeepAwakeGuard` when the keep-awake lifetime does not map cleanly to one promise, or when a block scope should control when the instance can resume normal scaling.

`KeepAwakeGuard` implements the JavaScript [`Disposable` interface](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Resource_management), so you can use the `using` keyword to release it automatically at the end of the scope:

```ts title="src/index.ts"
import { KeepAwakeGuard } from "@prisma/compute";

async function processBatch() {
  using guard = new KeepAwakeGuard();

  await fetchAllRecords();
  await transformData();
  await writeResults();
}
```

While the guard is active, the instance does not sleep. When the scope exits, `using` disposes the guard and normal scaling resumes.

If `using` is not available in your runtime or build setup, or if you need more granular control, release the guard in a `finally` block. This prevents a thrown error from leaving the guard active longer than intended:

```ts title="src/index.ts"
import { KeepAwakeGuard } from "@prisma/compute";

async function processBatch() {
  const guard = new KeepAwakeGuard();
  try {
    await fetchAllRecords();
    await transformData();
    await writeResults();
  } finally {
    guard.release();
  }
}
```

Calling `guard.release()` signals that the work is done and the instance can resume normal scaling behavior. Always release manually created guards, preferably from `finally`, unless `using` owns the lifetime for you.

## The `signal` option [#the-signal-option]

`KeepAwakeGuard` accepts a caller-owned `signal` option. Use it as a safety fallback to release the guard if your code does not reach `release()`. The signal releases the keep-awake guard; it does not cancel the work protected by the guard.

```ts title="src/index.ts"
import { KeepAwakeGuard } from "@prisma/compute";

const guard = new KeepAwakeGuard({
  // Optional. Prevents a leaked guard from keeping the instance awake indefinitely.
  signal: AbortSignal.timeout(30_000),
});
```

> [!WARNING]
> The `signal` option is a fallback, not the primary way to control your work. Prefer `using` or `try`/`finally` for normal guard lifetimes. Use `signal` to cap the maximum keep-awake lifetime and avoid dangling guards.

For example, combine `AbortSignal.timeout()` with `try`/`finally` when a job should keep the instance awake, but never for longer than a fixed duration:

```ts title="src/index.ts"
import { KeepAwakeGuard } from "@prisma/compute";

async function processBatch() {
  const guard = new KeepAwakeGuard({
    // Optional. Prevents a leaked guard from keeping the instance awake indefinitely.
    signal: AbortSignal.timeout(30_000),
  });

  try {
    await fetchAllRecords();
    await transformData();
    await writeResults();
  } finally {
    guard.release();
  }
}
```

The `signal` follows the standard `AbortSignal` pattern, so you can pass any signal you control.

## API reference [#api-reference]

### `waitUntil` [#waituntil]

```ts title="@prisma/compute"
waitUntil(promise: PromiseLike<unknown>, options?: { signal?: AbortSignal }): void;
```

Keeps the instance awake until `promise` settles. Pass `options.signal` as a caller-owned fallback to stop keeping the instance awake if the promise hangs or never settles. The signal does not cancel the promise.

### `KeepAwakeGuard` [#keepawakeguard]

```ts title="@prisma/compute"
new KeepAwakeGuard(options?: { signal?: AbortSignal });
```

Creates a guard that keeps the instance awake until the guard is disposed, released, or its optional caller-owned `signal` aborts. The signal releases the guard; it does not cancel the work protected by the guard.

| Member       | Type             | Description                                                                  |
| ------------ | ---------------- | ---------------------------------------------------------------------------- |
| `release()`  | `() => void`     | Releases the guard, allowing the instance to resume normal scaling behavior. |
| `Disposable` | `Symbol.dispose` | Enables automatic release with `using`.                                      |

## Next steps [#next-steps]

* [Get started with Prisma Compute](https://www.prisma.io/docs/compute/getting-started): deploy your first app.
* [Pricing](https://www.prisma.io/docs/compute/pricing): how scale-to-zero billing works.
* [Deployments](https://www.prisma.io/docs/compute/deployments): build, deploy, logs, promote, and roll back.
* [Environment variables](https://www.prisma.io/docs/compute/environment-variables): scoped configuration and secrets.
* [Known limitations](https://www.prisma.io/docs/compute/limitations): what Compute can and can't do.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# Known limitations (/docs/compute/limitations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

What Prisma Compute can and can't do.

Location: Compute > Known limitations

This page lists what Prisma Compute can and can't do.

## CLI [#cli]

* The quickest way to run the CLI is `npx prisma <command>` (or `bunx`/`pnpm dlx`), with Node.js 22.18 or newer.
* The platform command groups are `auth`, `project` (including `project env`), `postgres`, `bucket`, `branch`, `git`, `service` (including `service version` and `service domain`), and `agent`, plus the root-level [`dev`](https://www.prisma.io/docs/cli/dev) and [`deploy`](https://www.prisma.io/docs/cli/deploy) verbs for Composer apps. The same binary also carries the [Prisma ORM data commands](https://www.prisma.io/docs/cli) (`contract`, `db`, `migration`). There is no `compute` namespace: Compute is managed through the resource groups above.
* Commands are targeted by parameters, not ambient state: the subject resource is the first positional argument, and there is no interactive picker. A missing target fails with a structured error (exit 2) before any network call.
* There is no committed compute config file. A Composer app describes itself, including each service's build, in its module. `.prisma/local.json` is gitignored and only stores your local link to the workspace and project. In CI, set `PRISMA_PROJECT_ID` / `PRISMA_SERVICE_ID` to override the linked project and service.

## Projects and branches [#projects-and-branches]

* Project setup is explicit: `--yes` won't create or choose a project for you.
* The first branch in a project is production; the rest are preview by default.
* `branch list` inspects branches; it doesn't create remote state.
* Deleting a branch on GitHub can tear down the matching platform branch, but production and default branches are always left alone.

## Frameworks and runtimes [#frameworks-and-runtimes]

* A [Prisma Composer](https://www.prisma.io/docs/composer) app declares its build explicitly per service (the `node` and `nextjs` build adapters). Neither `deploy` nor the [deploy action](https://www.prisma.io/docs/compute/deploy-on-push) detects your framework or builds for you: you run the build before `deploy`, and the action runs your `build-command` verbatim.
* The [framework guides](https://www.prisma.io/docs/guides) cover Next.js, Nuxt, Astro, Hono, NestJS, TanStack Start, Elysia, and Bun, each deployed as a Composer app.

## Environment variables [#environment-variables]

* Values are write-only: once saved, they are never returned by any surface, and there is no command to pull them into a local `.env`.
* `project env list` returns keys and metadata only.
* Values resolve at deploy time; changing one does not mutate existing versions or trigger a redeploy.
* Production variables can't be branch-scoped.
* Keys must match `[A-Z_][A-Z0-9_]*`; values are non-empty, up to 8 KB.

## GitHub [#github]

* GitHub is the only supported provider, and a project connects to one repository.
* Pushes deploy only through a workflow in your repository, such as one that runs [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action); see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push). Any other CI can deploy with a service token and `deploy`.
* The connection reacts only to branch created and deleted events. There are no PR comments or PR status automation.

## Domains [#domains]

* Custom domains are production-only and CNAME-based: they attach to the default (production) branch, and the service needs a promoted version first.
* Up to 3 custom domains per service.
* There is no workspace-wide domain list in the CLI.

## Logs [#logs]

* `service logs <service>` reads a version's logs (`--version-id <id>` selects one); build output for a deploy is available in the Console.
* It returns `FEATURE_UNAVAILABLE` when the platform can't serve logs for the resolved version.
* Logs stream in time-bounded segments, so direct API clients should expect to reconnect.

## Runtime [#runtime]

* This release focuses on HTTP services. Background work between requests is supported through the `@prisma/compute` keep-awake primitives; see [Keeping instances awake](https://www.prisma.io/docs/compute/keeping-instances-awake). Cron scheduling, a persistent filesystem, and edge runtimes are not part of it.
* Your service has 60 seconds to start responding to a request. If it sends nothing in that time, the client gets `504 Gateway Time-out` and Compute cancels the request, which surfaces in your handler as the request's abort signal rather than an error. The deadline covers the wait for the first bytes, so a response that has started streaming is not cut off. Move longer work out of the request; see [Request timeout](https://www.prisma.io/docs/compute/request-timeout).
* WebSocket servers are not currently supported. `waitUntil` and `KeepAwakeGuard` only prevent an instance from scaling to zero; they do not change [connection-lifetime limits](https://www.prisma.io/docs/compute/request-timeout) or guarantee continuity through restarts or deployments.
* No multi-region deployments. Each service lives in one region, chosen at creation (`service create --region`): `us-east-1`, `us-west-1`, `eu-west-3`, `eu-central-1`, `ap-northeast-1`, or `ap-southeast-1`. When you do not choose one, the service takes its project's region, and a project created without a region is in `us-east-1`.

## Databases and migrations [#databases-and-migrations]

* These docs cover deployment and runtime config only: not schema migrations or data cloning. Databases are managed with the [`postgres` commands](https://www.prisma.io/docs/cli/postgres).
* Don't assume production data is copied into preview branches.
* Don't assume production migrations run automatically on deploy.
* Pass database URLs and other runtime config through [environment variables](https://www.prisma.io/docs/compute/environment-variables).

## Next steps [#next-steps]

* [FAQ](https://www.prisma.io/docs/compute/faq): quick answers to common questions.
* [Get started with the Prisma CLI](https://www.prisma.io/docs/compute/getting-started): your first deploy.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# Object storage (/docs/compute/object-storage)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Store and serve files from a Prisma Compute app with an Object Store bucket, S3-compatible storage that lives in the same Prisma project as your database.

Location: Compute > Object storage

Object Store buckets are S3-compatible file storage for your Prisma project: a place for user avatars, PDF exports, uploaded CSVs, generated images. A bucket lives inside the project, next to its [Prisma Postgres](https://www.prisma.io/docs/postgres) databases, and is managed from the same [Console](https://pris.ly/pdp) and [REST API](https://www.prisma.io/docs/rest-api), so you don't need a separate storage provider or a second set of credentials.

This page walks the whole path: create a bucket, mint an access key, and deploy a Compute route that writes a file and serves it back over a presigned URL.

Buckets speak the S3 API, so any S3 client or SDK works. Compute apps run on Bun, and Bun ships a [built-in S3 client](https://bun.com/docs/api/s3), so the examples below need no extra dependency.

## How buckets fit a project [#how-buckets-fit-a-project]

* **A bucket belongs to a project.** It can be associated with a branch at creation, via `branchId` or `branchGitName`. Omit both and the bucket attaches to the project's default branch. Paired with [Compute branching](https://www.prisma.io/docs/compute/branching), a preview environment can carry its own files next to its own database.
* **Access keys are minted per bucket** with a `read` or `read_write` role, enforced by the storage layer: a write with a `read` key is rejected with `AccessDenied`. The `secretAccessKey` is returned exactly once at mint time and is not retrievable afterward.
* **Deleting a bucket removes its contents and keys in the same call**, even when it is not empty. There is no empty-the-bucket-first step, so treat deletion as destructive and confirm it deliberately.

You can manage buckets from the [Console](https://pris.ly/pdp), with the CLI's [`bucket` commands](https://www.prisma.io/docs/cli/bucket), or over the [REST API](https://www.prisma.io/docs/rest-api) with a [service token](https://www.prisma.io/docs/rest-api/authentication). This page uses the API, since that is what you would automate against. The Console and CLI cover the same operations, so the steps map one to one.

The whole API surface is seven endpoints:

| Operation          | Endpoint                                                                                                               |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| Create a bucket    | [`POST /v1/buckets`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets)                                                         |
| List buckets       | [`GET /v1/buckets`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets)                                                           |
| Get a bucket       | [`GET /v1/buckets/{bucketId}`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id)                                   |
| Delete a bucket    | [`DELETE /v1/buckets/{bucketId}`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id)                             |
| Mint an access key | [`POST /v1/buckets/{bucketId}/keys`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets-by-bucket-id-keys)                       |
| List keys          | [`GET /v1/buckets/{bucketId}/keys`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id-keys)                         |
| Revoke a key       | [`DELETE /v1/buckets/{bucketId}/keys/{keyId}`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id-keys-by-key-id) |

> [!NOTE]
> Object Store pricing and plan limits are not published yet. Keep that in mind before provisioning storage unattended, for example from an agent workflow.

## Prerequisites [#prerequisites]

* A Prisma project. The [deploy quickstart](https://www.prisma.io/docs/prisma-compute/deploy) creates one if you don't have one yet.
* A [service token](https://www.prisma.io/docs/rest-api/authentication) for the API examples, created in the Console under your workspace's **Settings**, then **Service Tokens**. If you prefer clicking, you can create the bucket and key in the [Console](https://pris.ly/pdp) instead and skip to step 3.
* Your project id, visible in the project's Console URL or one [`GET /v1/projects`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects) call away.

## 1. Create a bucket [#1-create-a-bucket]

Create a bucket in your project. The response includes the bucket id you need for every later call.

```bash title="Create a bucket"
curl -X POST https://api.prisma.io/v1/buckets \
  -H "Authorization: Bearer $PRISMA_SERVICE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"projectId": "<your project id>", "name": "uploads"}'
```

The response comes back with `"status": "ready"` and a `branchId` pointing at your project's default branch. There is nothing to wait for; you can write to the bucket right away. To tie it to a specific branch instead, pass `branchId` or `branchGitName` in the request body.

## 2. Mint an access key [#2-mint-an-access-key]

Mint a key for the bucket. The response contains everything an S3 client needs: `accessKeyId`, `secretAccessKey`, `endpoint`, and `bucketName`.

```bash title="Mint a read-write key"
curl -X POST https://api.prisma.io/v1/buckets/<bucketId>/keys \
  -H "Authorization: Bearer $PRISMA_SERVICE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "app-key", "role": "read_write"}'
```

Save the `secretAccessKey` now; this is the only time the API returns it. If you lose it, revoke the key and mint a new one.

Give each key the narrowest role that works: a deployment that only serves files should hold a `read` key, and `read_write` stays with the code paths that upload.

## 3. Add the credentials to your Compute app [#3-add-the-credentials-to-your-compute-app]

Store the four values as [environment variables](https://www.prisma.io/docs/compute/environment-variables) so your deployed app can reach the bucket. Bun's S3 client reads these exact names by default, so the code below needs no explicit configuration:

```bash title="Set the bucket variables"
npx prisma project env add S3_ENDPOINT=<endpoint> --role production
npx prisma project env add S3_BUCKET=<bucketName> --role production
npx prisma project env add S3_ACCESS_KEY_ID=<accessKeyId> --role production
npx prisma project env add S3_SECRET_ACCESS_KEY=<secretAccessKey> --role production
```

Environment variables are scoped by role and branch, so production and previews can point at different buckets: repeat the commands with `--role preview` (or `--branch <name>`) and the credentials of a second, branch-associated bucket. Values resolve at deploy time, so set them before the deploy that should use them.

## 4. Read, write, and serve files from a route [#4-read-write-and-serve-files-from-a-route]

A storage route is an ordinary [Compute deployment](https://www.prisma.io/docs/compute/deployments). The example below uses Hono to match the other [Compute examples](https://www.prisma.io/docs/compute/getting-started); the S3 code is identical in any framework. `Bun.s3` picks up the `S3_*` variables from step 3.

```ts title="src/index.ts"
import { Hono } from "hono";

const app = new Hono();

// Upload: write the request body to the bucket.
app.put("/files/:name", async (c) => {
  const name = c.req.param("name");

  if (!/^[a-zA-Z0-9_.-]+$/.test(name)) {
    return c.text("Invalid file name", 400);
  }

  await Bun.s3.file(`uploads/${name}`).write(await c.req.arrayBuffer());
  return c.json({ stored: `uploads/${name}` }, 201);
});

// Serve: redirect to a presigned URL instead of proxying the bytes.
// The URL is time-boxed and needs no credentials on the client.
app.get("/files/:name", (c) => {
  const name = c.req.param("name");

  if (!/^[a-zA-Z0-9_.-]+$/.test(name)) {
    return c.text("Invalid file name", 400);
  }

  const url = Bun.s3.file(`uploads/${name}`).presign({ expiresIn: 3600 });
  return c.redirect(url, 302);
});

export default app;
```

Deploy it as part of your [Composer](https://www.prisma.io/docs/composer) app, as the [deploy quickstart](https://www.prisma.io/docs/prisma-compute/deploy) sets it up: build, then run `deploy`. If you have [set up deploy on push](https://www.prisma.io/docs/compute/deploy-on-push), committing and pushing deploys it instead. Then check the result:

```bash title="Deploy"
npm run build
npx prisma deploy module.ts
npx prisma service show
```

## 5. Verify [#5-verify]

Upload a file to the deployed app, then fetch it back through the presigned redirect:

```bash title="Upload and read back"
curl -X PUT --data "hello from a bucket" https://<your-app-url>/files/hello.txt
curl -L https://<your-app-url>/files/hello.txt
```

You should see the upload respond with `{"stored":"uploads/hello.txt"}` and the second request print `hello from a bucket`. If the upload fails with `AccessDenied`, the app is holding a `read` key; mint a `read_write` key for the uploading deployment and update the environment variables.

## Deleting a bucket [#deleting-a-bucket]

Deleting a bucket removes its objects and its access keys in one call:

```bash title="Delete a bucket"
curl -X DELETE https://api.prisma.io/v1/buckets/<bucketId> \
  -H "Authorization: Bearer $PRISMA_SERVICE_TOKEN"
```

This succeeds even when the bucket still contains objects. That makes tearing down an environment a single call, but it also means there is no undo, so double-check the bucket id before running it. If an agent manages your buckets, have it confirm deletions with you first.

## What to read next [#what-to-read-next]

* [Environment variables](https://www.prisma.io/docs/compute/environment-variables): scope bucket credentials per branch.
* [Branching](https://www.prisma.io/docs/compute/branching): give a preview environment its own bucket next to its own database.
* [Image Transformations](https://www.prisma.io/docs/compute/image-transformations): resize and serve images from a bucket with `Bun.s3` sources.
* [REST API: buckets](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets): the full endpoint reference.
* [Your AI agent needs file storage](https://www.prisma.io/blog/object-store-buckets): the launch post, with the full agent-driven lifecycle as one script.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# Pricing (/docs/compute/pricing)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How Prisma Compute pricing works, with the usage rates, included usage by plan, and worked examples.

Location: Compute > Pricing

Compute pricing is usage-based. Every plan includes a monthly request allowance, and the meters below cover the work your app does. An idle app scales to zero and costs nothing.

## Usage rates [#usage-rates]

Each meter measures a different resource: how often your app runs (requests), how much memory it holds and CPU it uses while running (provisioned memory and active CPU), and how much data it sends back (outbound bandwidth).

| Meter              | Price                | What it means                                                                         |
| ------------------ | -------------------- | ------------------------------------------------------------------------------------- |
| Requests           | `$1 per million`     | Every inbound request your app handles, after your plan's included requests.          |
| Provisioned memory | `$0.006 / GB-hour`   | Memory allocated while your app is running or intentionally kept awake.               |
| Active CPU         | `$0.064 / vCPU-hour` | CPU time your app actually consumes.                                                  |
| Outbound bandwidth | `$0.025 / GB`        | Data your app sends out to the internet. Incoming requests do not count as bandwidth. |

## Included usage by plan [#included-usage-by-plan]

The Free plan includes monthly limits for all four meters and has no usage billing. Paid plans include a monthly request allowance, then bill additional requests and the other three meters at the rates above.

| Plan     | Monthly price | Requests included | Provisioned memory included | Active CPU included | Outbound bandwidth included | Requests beyond that |
| -------- | ------------- | ----------------- | --------------------------- | ------------------- | --------------------------- | -------------------- |
| Free     | `$0`          | 1M                | 360 GB-hours                | 4 vCPU-hours        | 10 GB                       | No usage billing     |
| Starter  | `$10`         | 5M                | Billed per use              | Billed per use      | Billed per use              | `$1 per million`     |
| Pro      | `$49`         | 20M               | Billed per use              | Billed per use      | Billed per use              | `$1 per million`     |
| Business | `$129`        | 100M              | Billed per use              | Billed per use      | Billed per use              | `$1 per million`     |

See the [pricing page](https://www.prisma.io/pricing) for what each plan includes across Prisma Compute and Prisma Postgres.

## Example costs by workload [#example-costs-by-workload]

The three examples below show how the same rates add up for different kinds of apps, from a short-lived preview to a bandwidth-heavy service.

These examples are estimates, not benchmarks. The inputs are round numbers so you can follow the math, and every meter is priced from zero. In practice your plan's included requests cover the request line first.

### Preview workflow [#preview-workflow]

A pull request might deploy a preview several times as an agent fixes and tests a change.

Assume the preview gets `10,000` requests, stays running for `3,000s` at `1 GB`, uses `600 vCPU-seconds` of active CPU, and sends `0.25 GB` of data out.

| Meter              | Estimate                                                 |
| ------------------ | -------------------------------------------------------- |
| Requests           | `10,000 * $1.00 / 1M = $0.0100`                          |
| Provisioned memory | `3,000s at 1 GB = 0.833 GB-hours * $0.006 = $0.0050`     |
| Active CPU         | `600 vCPU-seconds = 0.167 vCPU-hours * $0.064 = $0.0107` |
| Outbound bandwidth | `0.25 GB * $0.025 = $0.0063`                             |
| Total              | `$0.0320`, about `$0.03`                                 |

Only the usage is billed; the deploys and the [preview branch](https://www.prisma.io/docs/compute/branching) itself are not.

### Agent workflow [#agent-workflow]

Agent work often spends more time waiting on other services than running on the CPU.

Assume an app runs `10,000` agent tasks in a month. Each task takes `30s` wall-clock time, mostly waiting on a model API or another service. Together, the tasks stay running for `300,000s` at `1 GB`, use `30,000 vCPU-seconds` of active CPU, and send `5 GB` of data out.

| Meter              | Estimate                                                   |
| ------------------ | ---------------------------------------------------------- |
| Requests           | `10,000 * $1.00 / 1M = $0.0100`                            |
| Provisioned memory | `300,000s at 1 GB = 83.33 GB-hours * $0.006 = $0.5000`     |
| Active CPU         | `30,000 vCPU-seconds = 8.33 vCPU-hours * $0.064 = $0.5333` |
| Outbound bandwidth | `5 GB * $0.025 = $0.1250`                                  |
| Total              | `$1.1683`, about `$1.17`                                   |

While a task waits it uses almost no CPU, so active CPU stays low. But the app keeps running the whole time, so it holds its memory and you pay for that. This is why Compute bills provisioned memory separately from active CPU.

### High-transfer workflow [#high-transfer-workflow]

If your app streams responses, returns large results, or serves file downloads, bandwidth can make up most of the bill instead of compute. It is worth estimating this before you ship.

Assume an app serves `50,000` requests in a month, stays running for `15,000s` at `1 GB`, uses `1,500 vCPU-seconds` of active CPU, and sends `200 GB` of data out.

| Meter              | Estimate                                                   |
| ------------------ | ---------------------------------------------------------- |
| Requests           | `50,000 * $1.00 / 1M = $0.0500`                            |
| Provisioned memory | `15,000s at 1 GB = 4.167 GB-hours * $0.006 = $0.0250`      |
| Active CPU         | `1,500 vCPU-seconds = 0.417 vCPU-hours * $0.064 = $0.0267` |
| Outbound bandwidth | `200 GB * $0.025 = $5.0000`                                |
| Total              | `$5.1017`, about `$5.10`                                   |

Here compute is almost free and bandwidth is nearly the whole bill. If your app moves a lot of data, estimate bandwidth first.

## Formula to estimate your bill [#formula-to-estimate-your-bill]

To estimate any month yourself, subtract your plan's included requests, then add up the four meters at their rates:

```text
bill =
  max(0, requests - included_requests) * 1.00 / 1_000_000
  + provisioned_memory_gb_hours * 0.006
  + active_vcpu_hours * 0.064
  + outbound_bandwidth_gb * 0.025
```

## What is not billed separately [#what-is-not-billed-separately]

You pay for the work your app does, not for resources sitting idle. These are not billed on their own:

* Deployments
* Preview branch creation
* Inactive apps
* Apps that have scaled to zero
* A Prisma-specific compute unit

A preview branch only costs money when it does work, such as serving traffic or running a background task. Creating one is free.

## Usage data for humans and agents [#usage-data-for-humans-and-agents]

Database usage is available from the [CLI](https://www.prisma.io/docs/cli/postgres) (`postgres usage`) and API, including as JSON, and an agent can read it to estimate a cost, explain a change, or suggest a fix. Equivalent usage reporting for Compute is still being built.

## Bandwidth [#bandwidth]

Outbound bandwidth is the data your app sends from Compute to the public internet; inbound requests don't count. Small JSON or API responses use little of it, while streaming, file downloads, and media use much more. If your app moves a lot of data, estimate bandwidth before you ship.

## Share your pricing feedback [#share-your-pricing-feedback]

If a rate, meter, or included amount doesn't match how your app actually runs, tell us in the `prisma-compute` channel on our [Discord](https://pris.ly/discord).

## What to read next [#what-to-read-next]

* [Prisma Compute vs Vercel pricing](https://www.prisma.io/blog/prisma-compute-vs-vercel-pricing?utm_source=docs): the same monthly workload priced line by line on both platforms.
* [Get started](https://www.prisma.io/docs/compute/getting-started): deploy your first app to a live URL.
* [Known limitations](https://www.prisma.io/docs/compute/limitations): what Compute can and can't do.
* [FAQ](https://www.prisma.io/docs/compute/faq): quick answers to common questions.
* [Branching](https://www.prisma.io/docs/compute/branching): how preview branches isolate work and when they cost money.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# Request timeout (/docs/compute/request-timeout)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Compute cancels a request when your service takes more than 60 seconds to start responding. How to recognize the 504 and how to structure work that runs longer.

Location: Compute > Request timeout

Your service has **60 seconds** to start responding. Compute's ingress starts that clock when it forwards the request to your service. If nothing has come back by then, the client receives `504 Gateway Time-out` and Compute cancels the request.

The deadline covers the wait for your first bytes, not the time your response takes to finish. A response that has started is not cut off when it passes 60 seconds, which is how [streaming responses](#streaming-responses) work.

## What your service sees [#what-your-service-sees]

Compute cancels the request from outside your service, so no timeout error is raised in your code and none is written to your logs. Your handler keeps running, but the response it eventually produces has nowhere to go.

Three consequences follow:

* **The request's abort signal is how you notice.** Cancelling the request aborts the signal on it. Check `req.signal` if you want your handler to stop work it no longer needs to finish.
* **Your own timeout handling cannot rescue the response.** A guard longer than the limit, such as `AbortSignal.timeout(90_000)`, still fires, but the client got the 504 half a minute earlier. Keep in-request timeouts under 60 seconds, for example 50, so your handler fails first and returns an error the caller can read.
* **The instance can sleep with your handler mid-execution.** Once the request is cancelled, Compute stops counting it as in flight, even though your handler is still working. If the work has to finish, hold the instance with [`waitUntil`](https://www.prisma.io/docs/compute/keeping-instances-awake).

## How to recognize it [#how-to-recognize-it]

* The client gets `504 Gateway Time-out` with a short HTML body that mentions `openresty`, about 60 seconds after the request was sent.
* The Console reports a 504 for that request, in your service's metrics.
* Your own logs show whatever your handler logged, with no timeout error, because the cancellation happens outside your service.
* The same route succeeds whenever it starts responding in under 60 seconds.

A 504 like this is not a crash or a sign of an unhealthy platform. Your service took more than 60 seconds to send anything back.

## Work that takes longer than 60 seconds [#work-that-takes-longer-than-60-seconds]

Do not tie long-running work to the lifetime of a single inbound request. Respond first, then do the work.

### Respond, then continue in the background [#respond-then-continue-in-the-background]

Validate the request, start the work, and return immediately. For a webhook, that means a `200` or `202` before any processing. Wrap the work in `waitUntil` from `@prisma/compute` so the instance stays awake until it finishes. Without it, the instance can scale to zero as soon as the response is sent.

```ts title="src/index.ts"
import { waitUntil } from "@prisma/compute";

export default {
  async fetch(req: Request) {
    const job = await parseWebhook(req);

    waitUntil(processJob(job), {
      // Optional. Prevents a hanging promise from keeping the instance awake indefinitely.
      signal: AbortSignal.timeout(10 * 60_000),
    });

    return new Response(null, { status: 202 });
  },
};
```

`waitUntil` is best-effort. It keeps the current instance awake, but it does not make the work durable, retry failures, or continue through a restart or a new deployment. Use it for work you can afford to lose occasionally, or combine it with the next pattern.

### Persist, then process in steps [#persist-then-process-in-steps]

For work that must not be lost, have the inbound request store the job, as a database row or a queue message, and process it from a separate trigger. Compute does not run scheduled jobs for you, so the trigger is a request from an external scheduler or a worker you run elsewhere. See [Known limitations](https://www.prisma.io/docs/compute/limitations).

Size each step to finish inside one request, and record progress as you go. A later run resumes from the last step you recorded. The step that was interrupted runs again from its start, so make every step safe to repeat rather than assuming it ran once.

## Streaming responses [#streaming-responses]

Because the 60 seconds covers only the wait for your first bytes, a response that has started is not cut off when it runs past them. Server-sent events and other streaming responses work on that basis: send the first bytes promptly, then keep streaming.

Send something early even when the real payload is not ready, and keep data flowing rather than letting a started stream sit idle for long stretches. For anything long-lived, have the client reconnect rather than holding one connection open indefinitely. WebSocket connections are not supported; see [Known limitations](https://www.prisma.io/docs/compute/limitations).

## Next steps [#next-steps]

* [Keeping instances awake](https://www.prisma.io/docs/compute/keeping-instances-awake): `waitUntil` and `KeepAwakeGuard` for background work.
* [Known limitations](https://www.prisma.io/docs/compute/limitations): what Compute can and can't do.

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/compute/alchemy): Provision Prisma Postgres and deploy applications to Prisma Compute in one TypeScript stack.
- [`Branching`](https://www.prisma.io/docs/compute/branching): Branches are isolated environments that map to your Git branches, so preview work never touches production.
- [`Deploy Button`](https://www.prisma.io/docs/compute/deploy-button): Add a Deploy with Prisma button that copies a public Composer repository and starts a Composer-managed deployment.
- [`Deploy on push`](https://www.prisma.io/docs/compute/deploy-on-push): Graduate a Composer app from manual deploys to a Git workflow, with production deploys on push and an isolated preview environment per branch.
- [`Deployments`](https://www.prisma.io/docs/compute/deployments): How deploys create service versions on Prisma Compute, and how to inspect, promote, roll back, start, and stop them.

# Concepts (/docs/console/concepts)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Understand the core concepts of the Prisma Console: user accounts, workspaces, projects, and resources

Location: Console > Concepts

The Console workflows are based on five main concepts:

* [**User account**](#user-account): In order to use Prisma products, you need to have a Console user account. A *user* will typically create one user account to manage all their workspaces, projects and resources. The *user* can also be invited to join other workspaces to collaborate on the projects in that workspace.
* [**Workspaces**](#workspace): A user account can belong to multiple workspaces. A workspace typically represents a *team* of individuals working together on one or more projects. **Billing is on a workspace level**, i.e. the invoice for a workspace at the end of the month captures all costs associated with the projects in that workspace.
* [**Projects**](#project): A project belongs to a workspace. It typically represents the *application* or *service* a team is working on.
* [**Branches**](#branch): For projects that use [Prisma Compute](https://www.prisma.io/docs/compute), resources are grouped into branches. A branch is an isolated infrastructure boundary for one line of work, usually mapping to a Git branch.
* [**Resources**](#resources): Resources represent the actual services or databases within a project. For example, in Prisma Postgres, each project can contain multiple databases. For Prisma Compute, each branch contains apps and their deployments. For Accelerate, resources might correspond to different environments (like `Development`, `Staging`, or `Production`). **Connection strings are provisioned at the resource level**, and products are configured per resource as well (e.g., the database connection string used for Accelerate).

Here is a visual illustration of how these concepts relate to each other:

![How the concepts of the Console (user account, workspaces, projects, and resources) relate to each other](https://www.prisma.io/img/platform/pdp-concepts.png)

## User account [#user-account]

A user account is the prerequisite for any interactions with Prisma products. You can use it to manage your workspaces (and their projects). A user account can be invited to collaborate on workspaces created by other users as well.

If you need to delete your user account, go to [Deleting your PDP account](https://www.prisma.io/docs/console/more/support#deleting-your-pdp-account).

## Workspace [#workspace]

You can create several workspaces. A workspace is an isolated space to host projects. A workspace can have multiple user accounts associated with it so that multiple users can collaborate on the projects in the workspace.

In each workspace, you can:

* view and manage all projects (and their resources) in that workspace.
* manage billing, i.e. select a [subscription plan](https://www.prisma.io/pricing?utm_source=docs\&utm_medium=platform-docs), configure payment methods, or view the invoice history.
* view the usage of your enabled Prisma products across all projects in that workspace.
* invite other users to collaborate in the workspace.
* access [Query Insights](https://www.prisma.io/docs/query-insights) to measure query performance and receive AI-powered recommendations (available with Prisma Postgres).

## Project [#project]

In each workspace, you can create several projects. A project typically represents an application (a product or service). You typically have one [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) per project.

In each project, you can:

* view and manage all resources (like databases) in that project.

The number of projects you can create in a workspace depends on the [subscription plan](https://www.prisma.io/pricing?utm_source=docs\&utm_medium=platform-docs) configured in that workspace.

## Branch [#branch]

For projects that use [Prisma Compute](https://www.prisma.io/docs/compute), a branch groups the resources for one line of work:

```text
workspace → project → branch → { apps, databases }
```

A branch usually maps to a Git branch, but it's a real resource that owns the apps and databases for that work:

* The **first branch** in a project is the production branch, usually `main`. It's protected and durable.
* **Every other branch** is a preview branch by default: disposable infrastructure for testing changes before they merge.
* [Environment variables](https://www.prisma.io/docs/compute/environment-variables) are scoped to production, to preview, or to a single preview branch.

Learn more in [Branching](https://www.prisma.io/docs/compute/branching).

## Resources [#resources]

Resources represent the actual services or databases within a project. The type of resources available depends on the Prisma products you're using:

* **For Prisma Postgres**: Each project can contain multiple databases. These databases are the primary resources you'll manage.
* **For Prisma Compute**: Each branch contains apps. An app is an HTTP service, and each built version of an app is a deployment. See [Prisma Compute](https://www.prisma.io/docs/compute).
* **For Accelerate**: Resources typically correspond to different deployment stages (like `Development`, `Staging`, or `Production`).

In each project, you can:

* Create and manage multiple resources (databases or environments)
* Generate connection strings specific to each resource
* Configure product-specific settings:
  * **For Prisma Postgres databases**:
    * View database metrics and performance
    * Configure connection settings
    * Manage database users and permissions
  * **For Accelerate resources**:
    * Set your database connection string
    * Configure the region for connection pooling
    * Adjust connection pool size and performance settings
    * Set query duration and response size limits
    * Enable static IP for secure connections

The number of resources you can create in a project depends on your [subscription plan](https://www.prisma.io/pricing?utm_source=docs\&utm_medium=platform-docs).

## Related pages

- [`Getting Started`](https://www.prisma.io/docs/console/getting-started): Quick start guide for setting up and using the Prisma Console

# Getting Started (/docs/console/getting-started)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Quick start guide for setting up and using the Prisma Console

Location: Console > Getting Started

This guide walks you through setting up your Console account and creating your first project.

## Prerequisites [#prerequisites]

* A GitHub account (for authentication)
* A Prisma project (optional, but recommended)

## Step 1: Create your account [#step-1-create-your-account]

1. Go to [console.prisma.io/login](https://console.prisma.io/login?utm_source=docs\&utm_medium=content\&utm_content=console)
2. Click **Sign in with GitHub**
3. Authorize Prisma Console to access your GitHub account

You now have a Console account with a default workspace.

## Step 2: Set up a workspace [#step-2-set-up-a-workspace]

When you create an account, a default workspace is automatically created for you. You can create additional workspaces for different teams or organizations.

### Create a workspace (optional) [#create-a-workspace-optional]

To create an additional workspace:

1. Click the workspace dropdown in the top navigation
2. Click **Create Workspace**
3. Enter a name for your workspace
4. Click **Create**

## Step 3: Create a project [#step-3-create-a-project]

Projects organize your databases and environments within a workspace.

### Using the Console web interface [#using-the-console-web-interface]

1. Navigate to your workspace
2. Click **Create Project**
3. Enter a project name
4. Click **Create**

## Step 4: Create a resource [#step-4-create-a-resource]

Resources are the actual databases or environments within your project.

### For Prisma Postgres [#for-prisma-postgres]

1. Navigate to your project
2. Click **Create Database**
3. Enter a database name
4. Select a region
5. Click **Create**

### For Accelerate [#for-accelerate]

> [!WARNING]
> Accelerate retirement
> 
> Prisma Accelerate will be retired on December 1, 2026, so new Accelerate environments are not recommended. Create a Prisma Postgres database instead, as described above. If you already run Accelerate, choose the path that matches your setup:
> 
> * [Migrate a PostgreSQL database to Prisma Postgres](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql)
> * [Keep your existing database and remove Accelerate](https://www.prisma.io/docs/accelerate/keep-your-database)
> * [Connect to Prisma Postgres without Accelerate](https://www.prisma.io/docs/postgres/database/switch-from-accelerate)

1. Navigate to your project
2. Click **Create Environment**
3. Enter an environment name (e.g., "production")
4. Click **Create**

## Step 5: Generate a connection string [#step-5-generate-a-connection-string]

Connection strings authenticate your application's requests to Prisma products.

### Using the Console web interface [#using-the-console-web-interface-1]

1. Navigate to your resource (database or environment)
2. Click **Connection Strings** tab
3. Click **Create Connection String**
4. Enter a name for the connection string
5. Copy the connection string and store it securely
6. Click **Done**

## Step 6: Use the connection string in your application [#step-6-use-the-connection-string-in-your-application]

Add the connection string to your `.env` file. For Prisma Postgres, use the pooled connection string for application queries and the direct connection string for migrations, introspection and Prisma Studio:

```bash
# Application traffic over pooled TCP
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"

# Prisma CLI commands and administrative tooling
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

In a Node.js runtime, pass the pooled connection string to Prisma Client through the [`@prisma/adapter-pg`](https://www.prisma.io/docs/postgres/database/connecting-to-your-database) driver adapter. In an edge or TCP-constrained runtime, use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver) with the direct connection string instead.

> [!WARNING]
> Accelerate retirement
> 
> Prisma Accelerate will be retired on December 1, 2026. This covers both the Accelerate environments from Step 4, which use `prisma://accelerate.prisma-data.net/?api_key=YOUR_API_KEY` connection strings, and hosted Accelerate connections for Prisma Postgres, which use `prisma+postgres://accelerate.prisma-data.net/?api_key=YOUR_API_KEY`. Choose the path that matches your setup:
> 
> * [Connect to Prisma Postgres without Accelerate](https://www.prisma.io/docs/postgres/database/switch-from-accelerate)
> * [Keep your existing database and remove Accelerate](https://www.prisma.io/docs/accelerate/keep-your-database)

## Next steps [#next-steps]

* Learn more about [Console concepts](https://www.prisma.io/docs/console/concepts)
* Explore [database metrics](https://www.prisma.io/docs/console/features/metrics)
* Check out the [CLI reference](https://www.prisma.io/docs/cli/v7/console)

## Related pages

- [`Concepts`](https://www.prisma.io/docs/console/concepts): Understand the core concepts of the Prisma Console: user accounts, workspaces, projects, and resources

# Console (/docs/console)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use the Console to manage and integrate Prisma products into your application.

Location: Console

## Overview [#overview]

The [Console](https://console.prisma.io/login?utm_source=docs\&utm_medium=content\&utm_content=console) enables you to manage and configure your projects that use Prisma products, and helps you integrate them into your application:

* [Query Insights](https://www.prisma.io/docs/query-insights): Inspect slow queries, connect Prisma calls to SQL, and apply focused fixes.
* [Prisma Postgres](https://www.prisma.io/docs/postgres): A managed PostgreSQL database that is optimized for Prisma ORM.
* [Prisma Compute](https://www.prisma.io/docs/compute): Runs your app next to your Prisma Postgres database. Inspect projects, branches, apps, and deployments in the Console; deploy with the [Prisma CLI](https://www.prisma.io/docs/compute/getting-started).

## Getting started [#getting-started]

To start using Prisma products, you'll need to:

1. Create a Console account
2. Set up a workspace for your team
3. Create a project for your application
4. Generate connection strings for your resources

Learn more in the [Getting Started](https://www.prisma.io/docs/console/getting-started) guide.

## Core concepts [#core-concepts]

The Console is organized around four main concepts:

* **[User account](https://www.prisma.io/docs/console/concepts#user-account)**: Your personal account to manage workspaces and projects
* **[Workspaces](https://www.prisma.io/docs/console/concepts#workspace)**: Team-level container where billing is managed
* **[Projects](https://www.prisma.io/docs/console/concepts#project)**: Application-level container within a workspace
* **[Resources](https://www.prisma.io/docs/console/concepts#resources)**: Actual services or databases within a project (databases for Prisma Postgres)

Read more about [Console concepts](https://www.prisma.io/docs/console/concepts).

## Console CLI [#console-cli]

In addition to the web interface, the Prisma CLI provides another way to interact with your Console account and manage Prisma products. This can be useful for programmatic access, such as integrating into CI workflows.

Learn more about the [Console CLI commands](https://www.prisma.io/docs/cli/v7/console).

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.
- [`Overview`](https://www.prisma.io/docs/cli): Prisma CLI reference

# auth (/docs/cli/auth)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.

Location: CLI > auth

Use `auth` commands to manage authentication for the platform commands. Signing in opens a browser flow and stores a session. Every platform command in that environment reuses that session.

## Usage [#usage]

  

#### bun

```bash
bunx prisma auth login
bunx prisma auth whoami
```

#### pnpm

```bash
pnpm prisma auth login
pnpm prisma auth whoami
```

#### yarn

```bash
yarn prisma auth login
yarn prisma auth whoami
```

#### npm

```bash
npx prisma auth login
npx prisma auth whoami
```

## Commands [#commands]

| Command                              | Description                                           |
| ------------------------------------ | ----------------------------------------------------- |
| `auth login`                         | Log in to your Prisma platform account (browser flow) |
| `auth logout`                        | Clear stored authentication credentials               |
| `auth whoami`                        | Show the authenticated user and accessible workspace  |
| `auth workspace list`                | List your workspace sessions                          |
| `auth workspace use [id-or-name]`    | Make one of your workspace sessions current           |
| `auth workspace logout <id-or-name>` | End one workspace session                             |

`auth login` signs you in through the browser. Afterward, anything running in that environment inherits the session, including coding agents. For CI, set [`PRISMA_SERVICE_TOKEN`](https://www.prisma.io/docs/cli/environment-variables) instead.

## Related pages

- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.
- [`contract infer`](https://www.prisma.io/docs/cli/contract-infer): Infer a starter contract from an existing database.

# branch (/docs/cli/branch)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

List platform branches for a project.

Location: CLI > branch

Use `branch` commands to inspect the platform branches of a project. The commands do not create anything on the platform. See [Branching](https://www.prisma.io/docs/compute/branching) for how platform branches work.

## Usage [#usage]

  

#### bun

```bash
bunx prisma branch list
```

#### pnpm

```bash
pnpm prisma branch list
```

#### yarn

```bash
yarn prisma branch list
```

#### npm

```bash
npx prisma branch list
```

## Commands [#commands]

| Command       | Description                                   |
| ------------- | --------------------------------------------- |
| `branch list` | List platform branches for the linked project |

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.
- [`contract infer`](https://www.prisma.io/docs/cli/contract-infer): Infer a starter contract from an existing database.

# bucket (/docs/cli/bucket)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create and manage object-store buckets.

Location: CLI > bucket

Use `bucket` commands to manage object-store buckets in a project.

## Usage [#usage]

  

#### bun

```bash
bunx prisma bucket list
bunx prisma bucket create --name my-bucket
```

#### pnpm

```bash
pnpm prisma bucket list
pnpm prisma bucket create --name my-bucket
```

#### yarn

```bash
yarn prisma bucket list
yarn prisma bucket create --name my-bucket
```

#### npm

```bash
npx prisma bucket list
npx prisma bucket create --name my-bucket
```

## Commands [#commands]

| Command                                  | Description                                                                                      |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `bucket list`                            | List object-store buckets                                                                        |
| `bucket create`                          | Create an object-store bucket (`--name <name>` sets the display name, auto-generated if omitted) |
| `bucket delete <bucket-id>`              | Delete a bucket and all its access keys                                                          |
| `bucket key list <bucket-id>`            | List access keys for a bucket                                                                    |
| `bucket key create <bucket-id>`          | Create a bucket access key and print its one-time credentials                                    |
| `bucket key delete <bucket-id> <key-id>` | Revoke and delete a bucket access key                                                            |

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.
- [`contract infer`](https://www.prisma.io/docs/cli/contract-infer): Infer a starter contract from an existing database.

# Configuration (/docs/cli/configuration)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Configure Prisma ORM CLI commands with prisma.config.ts and global flags.

Location: CLI > Configuration

Prisma ORM CLI commands read `prisma.config.ts`, starting in the directory you run them from. The file has one section per part of the CLI. The `orm` section holds your schema, database, and migration settings, which the `contract`, `db`, and `migration` commands read. The `skills` section holds the settings for the [agent skills commands](https://www.prisma.io/docs/cli/skills), which copy Prisma's instructions for AI coding agents into your project.

## Config file [#config-file]

The outer `definePrismaConfig` comes from `prisma/config` and marks the file as a Prisma ORM 8 CLI config. A Prisma ORM 7 `prisma.config.ts` without that marker is rejected rather than misread. The import resolves from your project's `node_modules`, so `prisma` must be a local dependency. The `orm` section uses the config helper for your database. For PostgreSQL:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./prisma/contract.prisma",
    db: {
      connection: process.env["DATABASE_URL"]!,
    },
  }),
});
```

For MongoDB projects, import the section helper from `@prisma/orm-mongo/config` instead. Both packages export this helper as `defineConfig`, and the examples on this page rename it to `ormConfig` when they import it.

This paragraph is only for a config written for a Prisma ORM 8 release candidate before `8.0.0-rc.12`. Such a config may import `defineConfig` from `@prisma/cli-engine`. That import no longer exists, so the config fails to load. Replace it with `definePrismaConfig` from `prisma/config`, and rename the call to match: it is the same function under its new name. Leave the `defineConfig` import from `@prisma/orm-postgres/config` or `@prisma/orm-mongo/config` as it is. That one is the helper for the `orm` section, and its name has not changed.

[`orm init`](https://www.prisma.io/docs/cli/orm-init) writes this file for you. Without `--config`, the CLI looks for `prisma.config.ts` in the directory you run the command from and in the directories above it, as [How the CLI finds the config](#how-the-cli-finds-the-config) explains. Pass `--config` to use a config file in another place, such as a subdirectory:

  

#### bun

```bash
bunx prisma contract emit --config ./config/prisma.config.ts
```

#### pnpm

```bash
pnpm prisma contract emit --config ./config/prisma.config.ts
```

#### yarn

```bash
yarn prisma contract emit --config ./config/prisma.config.ts
```

#### npm

```bash
npx prisma contract emit --config ./config/prisma.config.ts
```

## How the CLI finds the config [#how-the-cli-finds-the-config]

The CLI starts with `prisma.config.ts` in the current directory, or with the file you pass to `--config`. It then also reads the `prisma.config.ts` in each parent directory that has one, up to the root of the repository, which is the first directory that has a `.git` entry. If neither the starting directory nor any directory above it has a `.git` entry, the CLI reads only the file it started with.

The CLI combines the files it finds one section at a time. Inside a section such as `orm`, it takes each top-level key, such as `contract`, `db`, or `migrations`, from the nearest file that sets it, and it takes the whole value of that key from that one file. So if a config higher up sets `db.connection` and your project's config sets only `contract`, the CLI uses your `contract` and the other file's `db`.

Extensions are the exception: if your project config has its own `orm` section, it never inherits `extensions` from a config higher up, even when it lists none. List the extensions your contract uses, as [Extension packs](#extension-packs) shows, in each project's own config.

> [!WARNING]
> More than one project in a repository
> 
> If a `prisma.config.ts` higher up sets `db` or `migrations`, a project config that leaves them out uses that file's database and migrations folder. `db update`, `db migrate` and `db verify` then connect to the other project's database, and `migration plan` writes into the other project's migrations folder, without a warning. Set `db` and `migrations`, such as `migrations: { dir: "./migrations" }`, in every project's own config, or add `parent: false` to it.

To stop a project's config from inheriting anything, add `parent: false` to it. The search then ends at that file:

```typescript title="prisma.config.ts"
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  parent: false,
  orm: ormConfig({
    contract: "./prisma/contract.prisma",
  }),
});
```

`parent` can also be a path to another config file, which the CLI reads next in place of the one in the parent directory. The path is relative to the directory of the config file that sets it, and it may point outside the repository. After reading that file, the CLI goes on to search the directories above that file in the usual way, unless that file sets `parent` too:

```typescript title="prisma.config.ts"
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  parent: "../shared/prisma.config.ts",
  orm: ormConfig({
    contract: "./prisma/contract.prisma",
  }),
});
```

A relative path in a config file, such as `contract`, `output`, or `migrations.dir`, resolves from the directory of the config file that sets it, not from the directory you run the command in. So `--config ./config/prisma.config.ts` with `contract: "./prisma/contract.prisma"` reads `./config/prisma/contract.prisma`.

## Split the schema across several files [#split-the-schema-across-several-files]

`contract` accepts a glob, a path pattern where `*` matches any file name and `**` matches any number of folders, so one schema can span several `.prisma` files:

```typescript title="prisma.config.ts"
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./prisma/**/*.prisma",
  }),
});
```

`contract emit` builds one contract from every matched file whose first line is `// use prisma-8`. The same rule applies when `contract` names a single file: that file must start with the line too. `contract emit` skips a matched file without that line and does not warn, so the line is what makes a file part of the schema. The Prisma editor extension uses the same rule, so the editor and `contract emit` agree on which files make up the schema.

If the glob matches files but none of them starts with the line, `contract emit` fails with `CONTRACT.SOURCE_LOAD_FAILED`, and the error's details name the problem `PSL_NO_OPTED_IN_SCHEMA_FILES`. If the glob matches no file at all, for example because of a typo in the pattern, they name it `PSL_NO_SCHEMA_FILES_MATCHED` instead. [What `contract emit` creates](https://www.prisma.io/docs/cli/contract-emit#what-it-creates) says where these details appear in the output.

A new file joins the schema the next time you run `contract emit`, with no change to the config. The emitted files go in the folder before the first wildcard, here `./prisma/contract.json` and `./prisma/contract.d.ts`.

## Use a Prisma ORM 7 schema [#use-a-prisma-orm-7-schema]

On PostgreSQL, Prisma ORM 8 can read a Prisma ORM 7 `schema.prisma` directly as its contract source, so the two versions can run side by side on the database that Prisma ORM 7 migrates. Wrap the path in `prisma7Schema`:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig, prisma7Schema } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: prisma7Schema("prisma/schema.prisma"),
    db: {
      connection: process.env["DATABASE_URL"]!,
    },
  }),
});
```

`prisma7Schema` takes one schema file, or a directory of `.prisma` files as Prisma ORM 7 reads it. It reads every `.prisma` file it is given, so these files do not need the `// use prisma-8` first line. `contract emit` writes `contract.json` and `contract.d.ts` into the directory that holds the schema, here `prisma/`, unless you set `output`. Prisma ORM 7 keeps owning the database and its migrations, and you run its commands as `prisma7`, the Prisma ORM 7 CLI that [`orm init --from-prisma7-schema`](https://www.prisma.io/docs/cli/orm-init#on-a-prisma-orm-7-project) installs next to Prisma ORM 8.

Once the config is in place, run `npx prisma contract emit` and then [`npx prisma db sign`](https://www.prisma.io/docs/cli/db-sign). `db sign` checks that the database matches the contract and then records that in the database, without changing your tables. Run both commands again after each Prisma ORM 7 migration, whether you ran `npx prisma7 migrate dev` or `npx prisma7 migrate deploy`, so that the record names the new contract.

`contract emit` fails on any part of the schema that Prisma ORM 8 cannot represent exactly, such as a `view` block, `Unsupported(...)`, or `relationMode = "prisma"`. The error names the file and the line and suggests an edit to the Prisma ORM 7 schema. When that edit would also change the database on the next Prisma ORM 7 migration, the error says so. For example, removing an `Unsupported(...)` field drops its column, so for that field the error suggests adding `@@ignore` to the model instead, which leaves the next Prisma ORM 7 migration empty but removes the model from the Prisma ORM 7 client. Prisma ORM 8 has no views, so for a `view` block the error suggests removing the view or replacing it with a model over the table the view reads. `orm init --from-prisma7-schema` writes this config for you.

## Use a Prisma ORM 6 MongoDB schema [#use-a-prisma-orm-6-mongodb-schema]

On MongoDB, Prisma ORM 8 can read a Prisma ORM 6 `schema.prisma` directly as its contract source. Wrap the path in `prisma6Schema`:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig, prisma6Schema } from "@prisma/orm-mongo/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: prisma6Schema("prisma/schema.prisma"),
    db: {
      connection: process.env["DATABASE_URL"]!,
    },
  }),
});
```

The schema file does not need the `// use prisma-8` first line. Run `npx prisma contract emit` and then [`npx prisma db sign`](https://www.prisma.io/docs/cli/db-sign), which checks that the database Prisma ORM 6 built matches the contract.

`contract emit` fails on any part of the schema that Prisma ORM 8 cannot represent exactly, with an error code that starts with `PSL.PRISMA6_MONGO_`. The [error reference](https://www.prisma.io/docs/orm/reference/error-reference) lists each code and what to change.

## Write your own contract source [#write-your-own-contract-source]

A config that builds `contract.source` itself, as an object with a `load` function, must give the object a `format`: `"psl"` when its inputs are PSL text, and `"typescript"` when it builds the contract in TypeScript. Without it, every command that reads the config fails with `CONFIG.VALIDATION_FAILED`. A path, a glob, `prisma7Schema` and `prisma6Schema` set the format for you.

## Emit-only config [#emit-only-config]

`contract emit` does not connect to a database, so the `orm` section can omit `db.connection`:

```typescript title="prisma.config.ts"
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./prisma/contract.prisma",
  }),
});
```

Add `db.connection` before running commands such as `db verify`, `db sign`, `db init`, `db update`, `db schema`, `contract infer`, or `db migrate`.

## Extension packs [#extension-packs]

Add extension control descriptors to the `orm` section when your contract uses extension-provided types:

```typescript title="prisma.config.ts"
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";
import pgvector from "@prisma/orm-extension-pgvector/control";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./prisma/contract.prisma",
    extensions: [pgvector],
    db: {
      connection: process.env["DATABASE_URL"]!,
    },
  }),
});
```

Re-run `contract emit` after changing extension packs, then update the matching runtime client.

## Agent skills [#agent-skills]

The `skills` section controls the [agent skills commands](https://www.prisma.io/docs/cli/skills) and the staleness check:

```typescript title="prisma.config.ts"
import { definePrismaConfig } from "prisma/config";

export default definePrismaConfig({
  skills: {
    agents: ["claude", "cursor"],
    check: true,
  },
});
```

| Field    | What it does                                                                                                                                                                                                                                            |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agents` | The agent harnesses `skills sync` writes and `skills list` reports: `claude`, `cursor`, `agents`, `devin`. An empty array records that no agent skills are wanted, and the next `skills sync` removes the copies already on disk. Default: all of them. |
| `check`  | Set `false` to stop commands reporting out-of-date skills, for everyone working in the project. Default: `true`.                                                                                                                                        |

[`init`](https://www.prisma.io/docs/cli/init) scaffolds this section for you.

## Database URLs [#database-urls]

Database commands accept `--db <url>`. If you omit it, Prisma ORM uses the database connection from `prisma.config.ts`.

  

#### bun

```bash
bunx prisma db verify --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db verify --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma db verify --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma db verify --db "$DATABASE_URL"
```

## Environment variables [#environment-variables]

The variables the CLI reads, such as `PRISMA_DISABLE_TELEMETRY`, `PRISMA_SKILLS_CHECK`, and the `PRISMA_SERVICE_TOKEN` pair for CI, are listed on [Environment variables](https://www.prisma.io/docs/cli/environment-variables). `DATABASE_URL` is not one of them: your config file reads it, as in the example above.

## Output modes [#output-modes]

Use the default text output when running commands locally. Use `--json` in CI or automation:

  

#### bun

```bash
bunx prisma db verify --db "$DATABASE_URL" --json
```

#### pnpm

```bash
pnpm prisma db verify --db "$DATABASE_URL" --json
```

#### yarn

```bash
yarn prisma db verify --db "$DATABASE_URL" --json
```

#### npm

```bash
npx prisma db verify --db "$DATABASE_URL" --json
```

For an AI agent that reads the output as text rather than parsing JSON, use `--format markdown`; see [Global flags](https://www.prisma.io/docs/cli/global-flags#output-formats).

Use `--no-interactive` for scripts that must never pause for user input. Use `--confirm <token>` to grant a consent prompt non-interactively. For example, [`db update`](https://www.prisma.io/docs/cli/db-update) asks for the database name before a destructive change.

## JSON output [#json-output]

In `--json` mode, commands emit newline-delimited JSON events. Progress events have `kind: "step-finished"`. The final event has `kind: "result"` and carries the `envelope` object your script branches on:

* `envelope.ok`: `true` or `false`.
* `envelope.result`: the command's data, when `ok` is `true`.
* `envelope.error.code`: a dotted `NAMESPACE.SUBCODE`, for example `PROJECT.NOT_FOUND` or `SERVICE.PROJECT_SETUP_REQUIRED`.
* `envelope.error.summary` and `envelope.error.why`: what failed and why it was rejected.
* `envelope.nextActions`: machine-readable follow-up commands, so agents can drive the CLI.

Branch on `envelope.error.code`, not the message text: codes are a stable contract, while message wording can change between releases.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.
- [`contract infer`](https://www.prisma.io/docs/cli/contract-infer): Infer a starter contract from an existing database.

# contract emit (/docs/cli/contract-emit)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Emit Prisma ORM contract artifacts.

Location: CLI > contract emit

`contract emit` reads your contract source (TypeScript or Prisma schema) and writes the generated artifacts used by the runtime, verification, and migration tooling.

The command is offline. It does not need a database connection.

A Prisma schema source can be one `.prisma` file or a glob that matches several files; see [Split the schema across several files](https://www.prisma.io/docs/cli/configuration#split-the-schema-across-several-files). `contract emit` reads only the `.prisma` files whose first line is `// use prisma-8`, and skips any other file without a warning. When no file starts with that line, it fails with `CONTRACT.SOURCE_LOAD_FAILED` and reports the problem with the code `PSL_NO_OPTED_IN_SCHEMA_FILES`.

## Usage [#usage]

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

## Options [#options]

| Option                | What it does                                                          |
| --------------------- | --------------------------------------------------------------------- |
| `--output-path <dir>` | Writes `contract.json` and `contract.d.ts` into a specific directory. |
| `--config <path>`     | Read this config file instead of `./prisma.config.ts`.                |
| `--json`              | Prints a machine-readable result.                                     |

## What it creates [#what-it-creates]

The command emits:

* `contract.json`, the canonical machine-readable contract
* `contract.d.ts`, the generated TypeScript contract declarations

Do not edit these files by hand. Re-run `contract emit` after changing the contract source or extension pack list. The first emit after you upgrade from a release before `8.0.0-rc.12` reorders the entries in `contract.d.ts` to follow the order in `contract.json`, which needs no change to your code. The first emit after you upgrade to `8.0.0-rc.13` renames two keys in `contract.json`: each generated default under `execution.mutations.defaults` names its target as `entry` and `field` instead of `table` and `column`. The client refuses a contract that has the old keys, so run `contract emit` after you upgrade. `contract emit` does not rewrite the contract snapshots under `migrations/snapshots/`. In each snapshot that has an `execution` section, rename `table` to `entry` and `column` to `field` in every `ref` under `execution.mutations.defaults`, in both `contract.json` and `contract.d.ts`. Leave the snapshot's `executionHash` as it is.

When the contract source cannot be read, the command fails with `CONTRACT.SOURCE_LOAD_FAILED` and prints each finding, meaning each problem it found in the source, with the file and line where it knows them. In `--json` output, the findings are the entries of the `envelope.diagnostics` array in the final `result` event, next to `envelope.error`. Each entry has a `code`, a `summary`, and, where known, `where.path` and `where.line`. If an entry's `code` is `CONTRACT.SOURCE_DIAGNOSTIC`, the code of the specific problem, such as `PSL_NO_OPTED_IN_SCHEMA_FILES`, is in its `meta.code`.

## Run it automatically [#run-it-automatically]

In development, a Vite plugin runs `contract emit` for you: once when the dev server starts, and again whenever the contract source or `prisma.config.ts` changes. It needs Vite 7 or 8, and comes with your database package, so there is nothing to install:

```typescript title="vite.config.ts"
import { defineConfig } from "vite";
import { prismaVitePlugin } from "@prisma/orm-postgres/vite-plugin-contract-emit";

export default defineConfig({
  plugins: [prismaVitePlugin()],
});
```

On MongoDB, import it from `@prisma/orm-mongo/vite-plugin-contract-emit`. The plugin reads `prisma.config.ts` from the Vite root; pass another path as the first argument, `prismaVitePlugin("config/prisma.config.ts")`. A second argument takes `debounceMs` (how long to wait after a change before emitting, 150 by default) and `logLevel` (`"silent"`, `"info"`, or `"debug"`). The dev server prints one line per emit:

```text
[prisma-vite-plugin-contract-emit] Emitted contract (storageHash: ab5014a0...)
```

An emit that fails shows in Vite's error overlay. The plugin does nothing in a production build, so builds and CI still run the command themselves. With any other bundler, or for a build, add the command as a `prebuild` script, which npm, pnpm, and yarn run before `build`:

```json title="package.json (excerpt)"
{
  "scripts": {
    "prebuild": "prisma contract emit",
    "build": "next build"
  }
}
```

## Examples [#examples]

  

#### bun

```bash
bunx prisma contract emit
bunx prisma contract emit --output-path ./generated
bunx prisma contract emit --json
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma contract emit --output-path ./generated
pnpm prisma contract emit --json
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma contract emit --output-path ./generated
yarn prisma contract emit --json
```

#### npm

```bash
npx prisma contract emit
npx prisma contract emit --output-path ./generated
npx prisma contract emit --json
```

## Next steps [#next-steps]

After emitting, choose the database workflow:

* use [`db init`](https://www.prisma.io/docs/cli/db-init) for first-time bootstrap
* use [`db update`](https://www.prisma.io/docs/cli/db-update) for direct reconciliation
* use [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) for checked-in migrations
* use [`db verify`](https://www.prisma.io/docs/cli/db-verify) to check drift

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract infer`](https://www.prisma.io/docs/cli/contract-infer): Infer a starter contract from an existing database.

# contract infer (/docs/cli/contract-infer)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Infer a starter contract from an existing database.

Location: CLI > contract infer

`contract infer` inspects a live database and writes a starter PSL contract. An existing file at the output path is overwritten, with a warning.

Use it when you are adding Prisma ORM to an existing database and want an initial contract to review and edit.

## Usage [#usage]

  

#### bun

```bash
bunx prisma contract infer [--db "$DATABASE_URL"]
```

#### pnpm

```bash
pnpm prisma contract infer [--db "$DATABASE_URL"]
```

#### yarn

```bash
yarn prisma contract infer [--db "$DATABASE_URL"]
```

#### npm

```bash
npx prisma contract infer [--db "$DATABASE_URL"]
```

## Options [#options]

| Option            | What it does                                                                                                                                 |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `--db <url>`      | Connects to the database. Optional: without it the command uses `db.connection` from `prisma.config.ts`, and fails only when neither is set. |
| `--output <path>` | Writes the inferred PSL contract to a specific path.                                                                                         |
| `--config <path>` | Read this config file instead of `./prisma.config.ts`.                                                                                       |
| `--json`          | Prints a machine-readable result.                                                                                                            |

## Examples [#examples]

  

#### bun

```bash
bunx prisma contract infer --db "$DATABASE_URL"
bunx prisma contract infer --db "$DATABASE_URL" --output ./prisma/contract.prisma
bunx prisma contract infer --db "$DATABASE_URL" --json
```

#### pnpm

```bash
pnpm prisma contract infer --db "$DATABASE_URL"
pnpm prisma contract infer --db "$DATABASE_URL" --output ./prisma/contract.prisma
pnpm prisma contract infer --db "$DATABASE_URL" --json
```

#### yarn

```bash
yarn prisma contract infer --db "$DATABASE_URL"
yarn prisma contract infer --db "$DATABASE_URL" --output ./prisma/contract.prisma
yarn prisma contract infer --db "$DATABASE_URL" --json
```

#### npm

```bash
npx prisma contract infer --db "$DATABASE_URL"
npx prisma contract infer --db "$DATABASE_URL" --output ./prisma/contract.prisma
npx prisma contract infer --db "$DATABASE_URL" --json
```

## What to review [#what-to-review]

Inference gives you a starting point, not a finished design. Review:

* model and field names
* relation names
* mapped database names
* defaults, indexes, and constraints
* extension-backed column types

The file starts with `// use prisma-8`, because `contract emit` reads only `.prisma` files that start with that line. Each model is named after its table, and gets `@@map` only when the table name differs from the model name: a table `User` becomes `model User`, and a table `user_profile` becomes `model UserProfile` with `@@map("user_profile")`.

Every column default is written in a form `contract emit` accepts, so you can emit the file without editing it. [Default values](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#default-values) shows those forms. A list column that allows `NULL` is written `Type[]?`, and a list column that is `NOT NULL` is written `Type[]`.

If you keep an inferred contract in version control, running `contract infer` again after an upgrade can write the same database differently, so review the diff before you commit it.

The command stops at `contract.prisma`. Follow it with the emit and sign steps:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma db sign --db "$DATABASE_URL"
bunx prisma db verify --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma db sign --db "$DATABASE_URL"
pnpm prisma db verify --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma db sign --db "$DATABASE_URL"
yarn prisma db verify --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma contract emit
npx prisma db sign --db "$DATABASE_URL"
npx prisma db verify --db "$DATABASE_URL"
```

`db sign` is the handoff point where you record that the existing database matches the reviewed contract.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# contract print (/docs/cli/contract-print)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Write the configured contract as a Prisma ORM 8 PSL contract.

Location: CLI > contract print

`contract print` loads the contract that `contract` names in `prisma.config.ts` and writes it as a Prisma ORM 8 PSL contract. The source can be a Prisma ORM 7 schema, a TypeScript contract, or a PSL contract.

Use it to move from a Prisma ORM 7 `schema.prisma`, read through [`prisma7Schema`](https://www.prisma.io/docs/cli/configuration#use-a-prisma-orm-7-schema), to a contract file written for Prisma ORM 8.

The command is offline. It does not need a database connection.

## Usage [#usage]

  

#### bun

```bash
bunx prisma contract print [--output <path>]
```

#### pnpm

```bash
pnpm prisma contract print [--output <path>]
```

#### yarn

```bash
yarn prisma contract print [--output <path>]
```

#### npm

```bash
npx prisma contract print [--output <path>]
```

## Options [#options]

| Option            | What it does                                                                            |
| ----------------- | --------------------------------------------------------------------------------------- |
| `--output <path>` | Writes the PSL to this file. Without it, the command prints the PSL and writes no file. |
| `--format human`  | Prints the PSL to standard output, so you can redirect it to a file.                    |
| `--config <path>` | Read this config file instead of `./prisma.config.ts`.                                  |
| `--json`          | Prints a machine-readable result, with the PSL in `psl.text`.                           |

## Examples [#examples]

  

#### bun

```bash
bunx prisma contract print
bunx prisma contract print --output ./src/prisma/contract.prisma
bunx prisma contract print --json
```

#### pnpm

```bash
pnpm prisma contract print
pnpm prisma contract print --output ./src/prisma/contract.prisma
pnpm prisma contract print --json
```

#### yarn

```bash
yarn prisma contract print
yarn prisma contract print --output ./src/prisma/contract.prisma
yarn prisma contract print --json
```

#### npm

```bash
npx prisma contract print
npx prisma contract print --output ./src/prisma/contract.prisma
npx prisma contract print --json
```

## What it writes [#what-it-writes]

The file starts with `// use prisma-8`. When you point `contract` at the file and run `contract emit`, you get the same contract as before, with the same hashes, so the database needs no migration and no new `db sign`.

When a part of the contract has no PSL form, the command names that part, fails, and writes nothing. It also refuses an `--output` path that is one of the files it reads, `prisma.config.ts`, or a file `contract emit` writes.

## Next steps [#next-steps]

* Set `contract` in `prisma.config.ts` to the file you wrote, as [Configuration](https://www.prisma.io/docs/cli/configuration) shows.
* Run [`contract emit`](https://www.prisma.io/docs/cli/contract-emit) to write `contract.json` and `contract.d.ts` from it.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# db init (/docs/cli/db-init)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Initialize a database from the current Prisma ORM contract.

Location: CLI > db init

`db init` bootstraps a database to match the current emitted contract and signs it.

It creates everything the contract declares and the database does not have yet, using additive operations only. Structures already in place and compatible are left alone. A conflict that would need a destructive change stops the run.

## Usage [#usage]

  

#### bun

```bash
bunx prisma db init --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db init --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma db init --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma db init --db "$DATABASE_URL"
```

## Options [#options]

| Option                 | What it does                                                                                                                                                                            |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--db <url>`           | Connects to the database.                                                                                                                                                               |
| `--dry-run`            | Shows planned operations without applying them.                                                                                                                                         |
| `--advance-ref <name>` | Advances the named [ref](https://www.prisma.io/docs/cli/migration-ref) to the post-command contract hash. Without it, `db init` advances `db` when `--db` is omitted, and advances nothing when `--db` is passed. |
| `--config <path>`      | Read this config file instead of `./prisma.config.ts`.                                                                                                                                  |
| `--json`               | Prints a machine-readable result.                                                                                                                                                       |

## Behavior [#behavior]

`db init` is intended for bootstrap work. It creates missing structures needed by the contract and writes the contract marker after the database matches.

### How the db ref moves [#how-the-db-ref-moves]

Run without `--db`, `db init` takes the connection from `db.connection` in `prisma.config.ts` and advances the [ref](https://www.prisma.io/docs/cli/migration-ref) named `db` to the contract it just applied. Pass `--db` and that advancement is suppressed, even when the URL is the same one the config holds. Pass `--advance-ref db` alongside `--db` to get it back.

The `db` ref is what [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) uses as its starting point when you do not pass `--from`. Passing `--db` only suppresses the advancement; it never removes a `db` ref that already exists. So a loop that always passes `--db` without `--advance-ref db` leaves the ref wherever it was last set, and the next `migration plan` starts from that stale contract. If the ref was never created, `migration plan` plans from an empty database while `migrations/app/` is empty, and refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN` once migrations exist on disk.

Run a dry run first when you are not working with a disposable local database:

  

#### bun

```bash
bunx prisma db init --db "$DATABASE_URL" --dry-run
```

#### pnpm

```bash
pnpm prisma db init --db "$DATABASE_URL" --dry-run
```

#### yarn

```bash
yarn prisma db init --db "$DATABASE_URL" --dry-run
```

#### npm

```bash
npx prisma db init --db "$DATABASE_URL" --dry-run
```

## Examples [#examples]

  

#### bun

```bash
bunx prisma contract emit
bunx prisma db init --db "$DATABASE_URL" --advance-ref db
bunx prisma db verify --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma db init --db "$DATABASE_URL" --advance-ref db
pnpm prisma db verify --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma db init --db "$DATABASE_URL" --advance-ref db
yarn prisma db verify --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma contract emit
npx prisma db init --db "$DATABASE_URL" --advance-ref db
npx prisma db verify --db "$DATABASE_URL"
```

  

#### bun

```bash
bunx prisma db init --db "$DATABASE_URL" --dry-run --json
```

#### pnpm

```bash
pnpm prisma db init --db "$DATABASE_URL" --dry-run --json
```

#### yarn

```bash
yarn prisma db init --db "$DATABASE_URL" --dry-run --json
```

#### npm

```bash
npx prisma db init --db "$DATABASE_URL" --dry-run --json
```

## When to use db update instead [#when-to-use-db-update-instead]

Use [`db update`](https://www.prisma.io/docs/cli/db-update) when the database already exists and you want Prisma ORM to reconcile it with a changed contract. Use [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) when you want a reviewable migration package in version control.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# db migrate (/docs/cli/db-migrate)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Apply pending Prisma ORM migrations.

Location: CLI > db migrate

`db migrate` applies pending on-disk migrations to advance the database. It walks every contract space (app and extensions) and applies migrations in canonical order: extensions alphabetically, then the app. It applies only the migrations that exist on disk and never generates new operations.

Use it from a controlled deployment step after reviewing migration packages.

## Usage [#usage]

  

#### bun

```bash
bunx prisma db migrate --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db migrate --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma db migrate --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma db migrate --db "$DATABASE_URL"
```

## Options [#options]

| Option                 | What it does                                                                                                                                                           |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--db <url>`           | Connects to the database.                                                                                                                                              |
| `--to <contract>`      | Applies migrations up to a target contract (hash, prefix, ref name, migration directory name, `<dir>^`, or `./path`).                                                  |
| `--advance-ref <name>` | Advances the named [ref](https://www.prisma.io/docs/cli/migration-ref) to the post-apply marker after success.                                                                                   |
| `--show`               | Previews the migration route without applying (read-only).                                                                                                             |
| `--from <contract>`    | Sets the from-state for the `--show` preview: `@contract` (the emitted contract), `@db` (the database's current marker), a hash, a ref name, or a migration directory. |
| `--config <path>`      | Read this config file instead of `./prisma.config.ts`.                                                                                                                 |
| `--json`               | Prints a machine-readable result.                                                                                                                                      |

## Recommended flow [#recommended-flow]

  

#### bun

```bash
bunx prisma migration status --db "$DATABASE_URL"
bunx prisma db migrate --db "$DATABASE_URL"
bunx prisma migration status --db "$DATABASE_URL"
bunx prisma db verify --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma migration status --db "$DATABASE_URL"
pnpm prisma db migrate --db "$DATABASE_URL"
pnpm prisma migration status --db "$DATABASE_URL"
pnpm prisma db verify --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma migration status --db "$DATABASE_URL"
yarn prisma db migrate --db "$DATABASE_URL"
yarn prisma migration status --db "$DATABASE_URL"
yarn prisma db verify --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma migration status --db "$DATABASE_URL"
npx prisma db migrate --db "$DATABASE_URL"
npx prisma migration status --db "$DATABASE_URL"
npx prisma db verify --db "$DATABASE_URL"
```

Run `migration status` before and after applying migrations to see what changed.

## Previewing the route [#previewing-the-route]

`--show` prints the route `db migrate` would take without touching the database:

  

#### bun

```bash
bunx prisma db migrate --show
bunx prisma db migrate --show --from @contract --to production
```

#### pnpm

```bash
pnpm prisma db migrate --show
pnpm prisma db migrate --show --from @contract --to production
```

#### yarn

```bash
yarn prisma db migrate --show
yarn prisma db migrate --show --from @contract --to production
```

#### npm

```bash
npx prisma db migrate --show
npx prisma db migrate --show --from @contract --to production
```

## Applying to a target [#applying-to-a-target]

If your project uses named [refs](https://www.prisma.io/docs/cli/migration-ref), apply up to a target ref:

  

#### bun

```bash
bunx prisma db migrate --db "$DATABASE_URL" --to production
```

#### pnpm

```bash
pnpm prisma db migrate --db "$DATABASE_URL" --to production
```

#### yarn

```bash
yarn prisma db migrate --db "$DATABASE_URL" --to production
```

#### npm

```bash
npx prisma db migrate --db "$DATABASE_URL" --to production
```

Manage refs with [`migration ref`](https://www.prisma.io/docs/cli/migration-ref).

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# db schema (/docs/cli/db-schema)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Inspect a live database schema.

Location: CLI > db schema

`db schema` reads the live database schema and prints it as a tree, or as the result document with `--json`. The command is always read-only: it never writes a file and never changes the database.

Use it when you need to inspect what Prisma ORM sees in the database before inferring, signing, updating, or debugging drift.

## Usage [#usage]

  

#### bun

```bash
bunx prisma db schema --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db schema --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma db schema --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma db schema --db "$DATABASE_URL"
```

## Options [#options]

| Option            | What it does                                           |
| ----------------- | ------------------------------------------------------ |
| `--db <url>`      | Connects to the database.                              |
| `--config <path>` | Read this config file instead of `./prisma.config.ts`. |
| `--json`          | Prints machine-readable schema output.                 |

## Examples [#examples]

  

#### bun

```bash
bunx prisma db schema --db "$DATABASE_URL"
bunx prisma db schema --db "$DATABASE_URL" --json > schema.json
```

#### pnpm

```bash
pnpm prisma db schema --db "$DATABASE_URL"
pnpm prisma db schema --db "$DATABASE_URL" --json > schema.json
```

#### yarn

```bash
yarn prisma db schema --db "$DATABASE_URL"
yarn prisma db schema --db "$DATABASE_URL" --json > schema.json
```

#### npm

```bash
npx prisma db schema --db "$DATABASE_URL"
npx prisma db schema --db "$DATABASE_URL" --json > schema.json
```

## Related commands [#related-commands]

Use [`contract infer`](https://www.prisma.io/docs/cli/contract-infer) when you want to turn a live schema into a starter PSL contract. Use [`db verify`](https://www.prisma.io/docs/cli/db-verify) when you want to compare the live schema with the emitted contract.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# db sign (/docs/cli/db-sign)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Sign a database with the current Prisma ORM contract.

Location: CLI > db sign

`db sign` verifies that the live database satisfies the emitted contract and, if so, writes or updates the database signature. The signature records that this database instance matches a specific contract version.

It is idempotent and safe to run in CI or a deployment pipeline. Use it after importing or inferring an existing schema, or after a deployment flow that already applied the required database changes.

After a successful signature, `db sign` also stores the signed contract as a snapshot and points the [ref](https://www.prisma.io/docs/cli/migration-ref) named `db` at it, so the next [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) starts from the state you just signed instead of from an empty database. Unlike `db init` and `db update`, passing `--db` does not turn this off, because you normally sign the real database. Pass `--no-advance-ref` when you do not want the command to write a ref or a snapshot, for example in a deployment pipeline.

## Usage [#usage]

  

#### bun

```bash
bunx prisma db sign --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db sign --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma db sign --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma db sign --db "$DATABASE_URL"
```

## Options [#options]

| Argument or option      | What it does                                                                                                                        |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `[contract]`            | Signs against a specific contract reference (hash, prefix, ref name, or migration directory name) instead of the emitted contract.  |
| `--db <url>`            | Connects to the database.                                                                                                           |
| `--contract <contract>` | The contract reference as a flag. Also accepts the `<dir>^` and `./path` forms that the positional argument does not.               |
| `--advance-ref <name>`  | Advances this ref instead of `db` after a successful signature.                                                                     |
| `--no-advance-ref`      | Signs without writing any ref or snapshot. Cannot be combined with `--advance-ref`.                                                 |
| `--config <path>`       | Read this config file instead of `./prisma.config.ts`.                                                                              |
| `--json`                | Prints a machine-readable result. It includes `advancedRef` with the ref name and contract hash, or `null` when no ref was written. |

## Exit codes [#exit-codes]

| Code | Meaning                                                                                                   |
| ---- | --------------------------------------------------------------------------------------------------------- |
| `0`  | The database was signed.                                                                                  |
| `2`  | The command could not run: unresolvable contract reference, no emitted contract, or unreachable database. |
| `4`  | Schema verification failed and no signature was written.                                                  |

## Example [#example]

  

#### bun

```bash
bunx prisma contract emit
bunx prisma db sign --db "$DATABASE_URL"
bunx prisma db verify --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma db sign --db "$DATABASE_URL"
pnpm prisma db verify --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma db sign --db "$DATABASE_URL"
yarn prisma db verify --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma contract emit
npx prisma db sign --db "$DATABASE_URL"
npx prisma db verify --db "$DATABASE_URL"
```

## Adopting an existing database [#adopting-an-existing-database]

After [`contract infer`](https://www.prisma.io/docs/cli/contract-infer) and `contract emit`, one `db sign` is enough to hand the database over to Prisma ORM:

  

#### bun

```bash
bunx prisma db sign --db "$DATABASE_URL"
bunx prisma migration plan --name add-users-bio
```

#### pnpm

```bash
pnpm prisma db sign --db "$DATABASE_URL"
pnpm prisma migration plan --name add-users-bio
```

#### yarn

```bash
yarn prisma db sign --db "$DATABASE_URL"
yarn prisma migration plan --name add-users-bio
```

#### npm

```bash
npx prisma db sign --db "$DATABASE_URL"
npx prisma migration plan --name add-users-bio
```

The plan starts from the signed contract, so it contains only the change you made after signing. Because `migrations/app/` is still empty, that first plan also writes a baseline package that records the schema you adopted; see [the automatic baseline](https://www.prisma.io/docs/cli/migration-plan#the-automatic-baseline).

## When to use it [#when-to-use-it]

Use `db sign` only after you believe the live database already matches the emitted contract. It is common after:

* `contract infer` for a brownfield database
* a manually reviewed migration flow
* a database restore that you need to mark as matching the current contract

Do not use `db sign` to hide drift. If verification fails, fix the contract or database first.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# db update (/docs/cli/db-update)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Update a database to match the current Prisma ORM contract.

Location: CLI > db update

`db update` compares the live database with the emitted contract and applies the changes that close the gap, whether or not the database was bootstrapped with `db init`.

Use it for direct reconciliation when you do not need a checked-in migration package.

## Usage [#usage]

  

#### bun

```bash
bunx prisma db update --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db update --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma db update --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma db update --db "$DATABASE_URL"
```

## Options [#options]

| Option                 | What it does                                                                                                                                                                              |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--db <url>`           | Connects to the database.                                                                                                                                                                 |
| `--dry-run`            | Shows planned operations without applying them.                                                                                                                                           |
| `--to <contract>`      | Updates to a specific contract (hash, prefix, ref name, migration directory name, or `./path`).                                                                                           |
| `--advance-ref <name>` | Advances the named [ref](https://www.prisma.io/docs/cli/migration-ref) to the post-command contract hash. Without it, `db update` advances `db` when `--db` is omitted, and advances nothing when `--db` is passed. |
| `--config <path>`      | Read this config file instead of `./prisma.config.ts`.                                                                                                                                    |
| `--json`               | Prints a machine-readable result.                                                                                                                                                         |

## How the db ref moves [#how-the-db-ref-moves]

Run without `--db`, `db update` takes the connection from `db.connection` in `prisma.config.ts` and advances the [ref](https://www.prisma.io/docs/cli/migration-ref) named `db` to the contract it just applied. Pass `--db` and that advancement is suppressed, even when the URL is the same one the config holds. Pass `--advance-ref db` alongside `--db` to get it back.

The `db` ref is what [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) uses as its starting point when you do not pass `--from`. Passing `--db` only suppresses the advancement; it never removes a `db` ref that already exists. So a loop that always passes `--db` without `--advance-ref db` leaves the ref wherever it was last set, and the next `migration plan` starts from that stale contract. If the ref was never created, `migration plan` plans from an empty database while `migrations/app/` is empty, and refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN` once migrations exist on disk.

## Destructive changes need consent [#destructive-changes-need-consent]

An operation that would destroy data is applied only with your consent: the command asks you to type the database name. In a CI job or a run with `--no-interactive`, where the command cannot ask, pass the consent as `--confirm <database>` instead:

  

#### bun

```bash
bunx prisma db update --db "$DATABASE_URL" --no-interactive --confirm appdb
```

#### pnpm

```bash
pnpm prisma db update --db "$DATABASE_URL" --no-interactive --confirm appdb
```

#### yarn

```bash
yarn prisma db update --db "$DATABASE_URL" --no-interactive --confirm appdb
```

#### npm

```bash
npx prisma db update --db "$DATABASE_URL" --no-interactive --confirm appdb
```

## Recommended flow [#recommended-flow]

  

#### bun

```bash
bunx prisma contract emit
bunx prisma db update --db "$DATABASE_URL" --dry-run
bunx prisma db update --db "$DATABASE_URL" --advance-ref db
bunx prisma db verify --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma db update --db "$DATABASE_URL" --dry-run
pnpm prisma db update --db "$DATABASE_URL" --advance-ref db
pnpm prisma db verify --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma db update --db "$DATABASE_URL" --dry-run
yarn prisma db update --db "$DATABASE_URL" --advance-ref db
yarn prisma db verify --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma contract emit
npx prisma db update --db "$DATABASE_URL" --dry-run
npx prisma db update --db "$DATABASE_URL" --advance-ref db
npx prisma db verify --db "$DATABASE_URL"
```

Use `--dry-run` before applying changes in shared environments.

## When to use migrations instead [#when-to-use-migrations-instead]

For reviewable database changes in version control, use [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) and [`db migrate`](https://www.prisma.io/docs/cli/db-migrate).

Use `db update` for local development, preview environments, and workflows where direct reconciliation is acceptable.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# db verify (/docs/cli/db-verify)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Verify a database against the current Prisma ORM contract.

Location: CLI > db verify

`db verify` checks whether the database marker and live schema match your emitted contract. It verifies the marker first, then checks the schema.

Use it in CI and deployment checks before application code that depends on a contract reaches users.

## Usage [#usage]

  

#### bun

```bash
bunx prisma db verify --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db verify --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma db verify --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma db verify --db "$DATABASE_URL"
```

## Options [#options]

| Option            | What it does                                                                |
| ----------------- | --------------------------------------------------------------------------- |
| `--db <url>`      | Connects to the database.                                                   |
| `--marker-only`   | Checks only the database marker.                                            |
| `--schema-only`   | Checks only whether the live schema satisfies the contract.                 |
| `--strict`        | Fails if the database includes schema elements not present in the contract. |
| `--config <path>` | Read this config file instead of `./prisma.config.ts`.                      |
| `--json`          | Prints machine-readable output.                                             |

## Exit codes [#exit-codes]

| Code | Meaning                                                                                        |
| ---- | ---------------------------------------------------------------------------------------------- |
| `0`  | The database matches the contract.                                                             |
| `2`  | The check could not run: conflicting mode flags, no emitted contract, or unreachable database. |
| `4`  | Drift or a marker finding.                                                                     |

## Examples [#examples]

  

#### bun

```bash
bunx prisma db verify --db "$DATABASE_URL"
bunx prisma db verify --db "$DATABASE_URL" --strict
bunx prisma db verify --db "$DATABASE_URL" --schema-only
bunx prisma db verify --db "$DATABASE_URL" --marker-only
```

#### pnpm

```bash
pnpm prisma db verify --db "$DATABASE_URL"
pnpm prisma db verify --db "$DATABASE_URL" --strict
pnpm prisma db verify --db "$DATABASE_URL" --schema-only
pnpm prisma db verify --db "$DATABASE_URL" --marker-only
```

#### yarn

```bash
yarn prisma db verify --db "$DATABASE_URL"
yarn prisma db verify --db "$DATABASE_URL" --strict
yarn prisma db verify --db "$DATABASE_URL" --schema-only
yarn prisma db verify --db "$DATABASE_URL" --marker-only
```

#### npm

```bash
npx prisma db verify --db "$DATABASE_URL"
npx prisma db verify --db "$DATABASE_URL" --strict
npx prisma db verify --db "$DATABASE_URL" --schema-only
npx prisma db verify --db "$DATABASE_URL" --marker-only
```

Use JSON output in automation:

  

#### bun

```bash
bunx prisma db verify --db "$DATABASE_URL" --json
```

#### pnpm

```bash
pnpm prisma db verify --db "$DATABASE_URL" --json
```

#### yarn

```bash
yarn prisma db verify --db "$DATABASE_URL" --json
```

#### npm

```bash
npx prisma db verify --db "$DATABASE_URL" --json
```

## What failures mean [#what-failures-mean]

| Failure            | Meaning                                                                                      |
| ------------------ | -------------------------------------------------------------------------------------------- |
| Marker mismatch    | The database was not signed for the emitted contract, or the contract changed after signing. |
| Schema mismatch    | The live database does not satisfy the emitted contract.                                     |
| Strict mismatch    | The database has extra schema elements not present in the contract.                          |
| Extension mismatch | The contract requires an extension that is not wired in the config.                          |

Fix the database or contract, emit again if needed, then verify again.

## How PostgreSQL defaults are compared [#how-postgresql-defaults-are-compared]

When a column default is a literal value, `db verify` reads it as a value before it compares it with your contract, so the casts PostgreSQL adds when it prints the default do not cause a difference. This covers numbers such as `'-1'::integer` and `(5)::smallint`, text and enum values, including an enum value cast to a type in another PostgreSQL schema, `timestamp` values, `true`, `false`, `NULL`, JSON, and lists written as `'{...}'` or `ARRAY[...]`. `db verify` also recognizes `now()`, `clock_timestamp()`, `gen_random_uuid()`, and a sequence default, which it treats as `autoincrement()`.

Any other default is a SQL expression, which you write in your contract as a `sql` default, such as ``@default(sql`(now() + '00:03:00'::interval)`)``. [Default values](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#default-values) shows how to write one. `db verify` cannot work out whether two SQL expressions give the same value, so it compares their text, ignoring letter case and spaces. PostgreSQL often rewrites an expression when it stores it, for example by adding casts, so write a `sql` default in your contract the way PostgreSQL stores it. To see that form, run `npx prisma contract infer --output ./inferred.prisma` and copy the column's `@default` from that file.

Check constraints and the `WHERE` clause of a partial index are compared more strictly than `sql` defaults: their text must match exactly, including letter case and spaces.

If `db verify` reports a difference in a `timestamptz` value inside a check constraint or a partial index's `WHERE` clause, check whether your contract was inferred before `8.0.0-rc.12` from a server that was not set to UTC. `db verify` reads the database with the time zone set to UTC and dates in ISO format, whatever the server or your database role sets, so a value that your contract has in another time zone no longer matches as text. To fix it, copy the new text from a fresh `npx prisma contract infer --output ./inferred.prisma` into your contract, emit the contract, and run `db sign`.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# deploy (/docs/cli/deploy)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Deploy a Composer application to Prisma Compute, to production or an isolated stage.

Location: CLI > deploy

`deploy` deploys a [Prisma Composer](https://www.prisma.io/docs/composer) application to [Prisma Compute](https://www.prisma.io/docs/compute). It takes an `<entry>` argument: the module whose default export is the application root, typically `module.ts`. The command streams the deploy pipeline's own output to the terminal.

`deploy` and [`dev`](https://www.prisma.io/docs/cli/dev) are root-level commands of the unified Prisma CLI. There is no `composer` command group.

By default, the command uses the credentials from your existing `auth login` session. In CI or other headless environments, set `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` instead. See [Deploying](https://www.prisma.io/docs/composer/deploying#credentials) for details.

The first deploy of an app creates its project in your workspace, and a new project needs a region. Set it once, either as `prismaCloud({ region: 'us-east-1' })` in your deploy config or as the `PRISMA_REGION` environment variable; without one, the deploy stops with `project "<name>" does not exist yet and no deploy region is configured`. A project that already exists keeps its region and needs neither. The region ids are listed under [Limitations](https://www.prisma.io/docs/compute/limitations).

The `deploy` command does not build your application. Run your build command before deploying.

## Usage [#usage]

  

#### bun

```bash
bunx prisma deploy module.ts
bunx prisma deploy module.ts --stage feat-auth
```

#### pnpm

```bash
pnpm prisma deploy module.ts
pnpm prisma deploy module.ts --stage feat-auth
```

#### yarn

```bash
yarn prisma deploy module.ts
yarn prisma deploy module.ts --stage feat-auth
```

#### npm

```bash
npx prisma deploy module.ts
npx prisma deploy module.ts --stage feat-auth
```

## Flags [#flags]

| Flag              | Description                                                                                                                                                                                                                                                                                                                                                                                                          |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--name <name>`   | Override the application name for this deploy. It defaults to the name of the exported application, and that name selects the project in your workspace: a project this module deployed before is reused, and a same-name project whose hosted state cannot be verified stops the deploy with `HostedStateBootstrapError`, so pass `--name` when the default would land in a project you did not mean to deploy into |
| `--stage <stage>` | Deploy scope to target; omit for production                                                                                                                                                                                                                                                                                                                                                                          |
| `--report <path>` | Write the deploy's outcome as JSON to this path: resources, preview URLs, and the failure cause. Also settable as `PRISMA_COMPOSER_REPORT_FILE`                                                                                                                                                                                                                                                                      |
| `--build-id <id>` | Join the deploy record your CI already created rather than letting the target create one                                                                                                                                                                                                                                                                                                                             |

## Global flags [#global-flags]

The Prisma CLI's global flags also apply: `--format`, `--json`, `--log-level`, `--verbose`, `--quiet`, `--yes`, `--confirm`, `--interactive`, `--color`, and `--config`.

## Environment variables [#environment-variables]

| Variable                      | Description                                                                                                                                                                                                                                 |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PRISMA_SERVICE_TOKEN`        | A workspace service token from the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=cli), for CI and other headless environments. When unset, the command uses your stored `auth login` session |
| `PRISMA_WORKSPACE_ID`         | The workspace ID from the workspace's settings; pair it with the service token                                                                                                                                                              |
| `PRISMA_REGION`               | The region for a project this deploy creates; `prismaCloud({ region })` in the deploy config wins when both are set. Ignored once the project exists                                                                                        |
| `PRISMA_COMPOSER_REPORT_FILE` | Path to write the deploy's JSON outcome report; the `--report` flag wins when both are set                                                                                                                                                  |

## Tearing down and log tailing [#tearing-down-and-log-tailing]

The unified CLI has no `destroy` or `log` command. Both operations are available in-process through the control API below: `destroy` takes an explicit target (`{ kind: 'production' }` or `{ kind: 'stage', stage }`), and `log` tails a locally running application.

## The control API [#the-control-api]

Everything the CLI does is also callable in-process, from `@prisma/composer/control`: typed `deploy`, `destroy`, `dev`, and `log` operations that return structured results instead of printing and exiting:

```ts
import { deploy } from '@prisma/composer/control';

const result = await deploy({ entry: 'module.ts', stage: 'pr-42' });
if (!result.ok) console.error(result.failure.message);
```

Operations return `{ ok: true, value }` or `{ ok: false, failure }`. Failures come back as structured errors with a dotted `failure.code` and the same fix-naming `message` the CLI renders. The deploy engine's live output still streams to your process's stdio; the operations do not capture it.

The operations authenticate with `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` only. They do not read the session stored by `auth login`, so a script that runs fine next to the CLI's `deploy` fails under the control API with `environment variable PRISMA_WORKSPACE_ID is required` until both variables are exported.

## Next steps [#next-steps]

* [`dev`](https://www.prisma.io/docs/cli/dev): run the same application locally, with no credentials.
* [Getting started](https://www.prisma.io/docs/composer/getting-started): the commands in a working flow.
* [Deploying](https://www.prisma.io/docs/composer/deploying): stages, CI, and what a deploy prints.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# dev (/docs/cli/dev)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Bring a Composer application up entirely on this machine, with no cloud credentials.

Location: CLI > dev

`dev` brings a [Prisma Composer](https://www.prisma.io/docs/composer) application up entirely on this machine. It takes an `<entry>` argument: the module whose default export is the application root, typically `module.ts`. The command runs credential-free against local emulators standing in for Prisma Compute and Prisma Postgres, watches the built output, and restarts a service when its build changes. See [Local development](https://www.prisma.io/docs/composer/local-development).

`dev` and [`deploy`](https://www.prisma.io/docs/cli/deploy) are root-level commands of the unified Prisma CLI. There is no `composer` command group. Like `deploy`, `dev` runs your *built* output, so build first.

## Usage [#usage]

  

#### bun

```bash
bunx prisma dev module.ts
bunx prisma dev module.ts --fresh
```

#### pnpm

```bash
pnpm prisma dev module.ts
pnpm prisma dev module.ts --fresh
```

#### yarn

```bash
yarn prisma dev module.ts
yarn prisma dev module.ts --fresh
```

#### npm

```bash
npx prisma dev module.ts
npx prisma dev module.ts --fresh
```

## Flags [#flags]

| Flag            | Description                                                                                                                                                                                                                          |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--name <name>` | Override the application name for the local dev instance                                                                                                                                                                             |
| `--fresh`       | Destroy the dev stack and wipe the dev state directory before starting. In this release the flag fails for apps with a database; see [Local development](https://www.prisma.io/docs/composer/local-development#whats-local-vs-whats-real) for the manual reset |

`dev` needs no credentials or environment variables; local runs never talk to the platform.

To tail the running application's merged logs, use the `log` operation of the [control API](https://www.prisma.io/docs/cli/deploy#the-control-api); the unified CLI has no `log` command.

## Next steps [#next-steps]

* [Local development](https://www.prisma.io/docs/composer/local-development): warm restarts, `--fresh`, and what persists.
* [`deploy`](https://www.prisma.io/docs/cli/deploy): the same application, on Prisma Compute.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# Environment variables (/docs/cli/environment-variables)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The environment variables the Prisma CLI reads, what each one does, and the release that added it.

Location: CLI > Environment variables

The `prisma` command reads these environment variables. Set them in your shell profile or in your CI configuration. For one command, put the variable in front of it, as in this [`contract emit`](https://www.prisma.io/docs/cli/contract-emit) run:

```bash title="Terminal"
PRISMA_DISABLE_TELEMETRY=1 npx prisma contract emit
```

In PowerShell, set it for the session:

```powershell title="PowerShell"
$env:PRISMA_DISABLE_TELEMETRY = "1"
npx prisma contract emit
```

The CLI does not read `.env` files or `DATABASE_URL` itself. Your `prisma.config.ts` does that, and the one [`orm init`](https://www.prisma.io/docs/cli/orm-init) writes already loads `.env`; see [Configuration](https://www.prisma.io/docs/cli/configuration#config-file).

> [!NOTE]
> If you used the
> 
> `prisma-next`
> 
>  preview command
> 
> The `prisma` command ignores every `PRISMA_NEXT_*` variable, including `PRISMA_NEXT_DISABLE_TELEMETRY`. Drop the `NEXT_` part in shell profiles and CI: `PRISMA_NEXT_DISABLE_TELEMETRY` becomes `PRISMA_DISABLE_TELEMETRY`.
> 
> Your `prisma-next` telemetry opt-out does not carry over either, so the one-time telemetry notice prints again. Run `prisma telemetry disable` to opt out. The `prisma` command stores that choice in `~/.config/prisma/config.json` (Windows: `%APPDATA%\prisma\config.json`).

"Since" is the first `prisma` release that reads the variable.

| Variable                   | What it does                                                                                                                                                                                                                                                                                                                         | Since      |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- |
| `PRISMA_DISABLE_TELEMETRY` | Set to `1` to turn off anonymous [CLI telemetry](https://www.prisma.io/docs/cli/telemetry). Empty, `0`, and `false` leave it on.                                                                                                                                                                                                                               | 8.0.0-rc.1 |
| `DO_NOT_TRACK`             | Set to `1` to turn off telemetry. Other values do nothing.                                                                                                                                                                                                                                                                           | 8.0.0-rc.1 |
| `PRISMA_DEBUG`             | Set to `1` to print the CLI's debug output to stderr.                                                                                                                                                                                                                                                                                | 8.0.0-rc.1 |
| `PRISMA_SKILLS_CHECK`      | Set to `0` to silence the notice that your project's [agent skills](https://www.prisma.io/docs/cli/skills) are out of date.                                                                                                                                                                                                                                    | 8.0.0-rc.9 |
| `PRISMA_SERVICE_TOKEN`     | A service token for a Prisma Platform workspace, created in the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=cli). Only the [Platform commands](https://www.prisma.io/docs/cli#platform-commands) such as `auth`, `project`, and `deploy` use it, in place of a browser login, even if you are also logged in. | 8.0.0-rc.1 |
| `PRISMA_WORKSPACE_ID`      | The ID of the workspace the service token belongs to, from the workspace's settings in the Prisma Console. Set it alongside the token.                                                                                                                                                                                               | 8.0.0-rc.1 |
| `NO_COLOR`                 | Set to any value to turn off colored output. The [`--color` and `--no-color` flags](https://www.prisma.io/docs/cli/global-flags) override it.                                                                                                                                                                                                                  | 8.0.0-rc.1 |
| `CI`                       | Set to any value except `false` to mark the run as CI: no telemetry, no skills notice, and no interactive prompts. `CI=false` forces the non-CI behavior even when a CI system set it.                                                                                                                                               | 8.0.0-rc.1 |

Agent skills are files in your project, in `.claude/skills` and similar folders, that teach AI coding agents about Prisma. Silencing the notice does not update them; `prisma skills sync` does.

You rarely need to set `CI` yourself: the CLI also detects the variables that CI providers such as GitHub Actions and GitLab CI set.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# Error reference (/docs/cli/error-reference)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Every structured error code the unified Prisma CLI can emit, by namespace, with the condition that raises it.

Location: CLI > Error reference

Every user-facing error the unified Prisma CLI emits is a structured envelope identified by a dotted `NAMESPACE.SUBCODE` code (see [Error Conventions](https://github.com/prisma/prisma-cli/blob/main/docs/product/error-conventions.md) and [ADR 0003](https://github.com/prisma/prisma-cli/blob/main/docs/architecture/adrs/0003-structured-output-and-errors.md)). This page lists every published code. Each code anchors as `#<CODE>` — the fragment an emitted error's `docsUrl` resolves to. This page is generated from the canonical registry in the `prisma/prisma-cli` repository, whose CI requires every code in production source to be documented before it ships.

Recognize an error programmatically by running with `--json` and matching on `error.code` in the emitted envelope — never on message text. Envelopes carry `message`, and optionally `why`, `fix`, `where`, `meta`, `cause`, `nextActions`, and `docsUrl`.

Most codes on this page are expected failures. Some are warn-severity diagnostics that ride a successful run: the command completes and exits `0`, and the diagnostic carries the code (the entry says so where it applies). The process exit-code contract is in [Error Conventions](https://github.com/prisma/prisma-cli/blob/main/docs/product/error-conventions.md).

Every code on this page is assigned where the error is raised, and this page lists every code the CLI can emit. No boundary invents a code from a server response or rewrites one on the way out, so an error's code never depends on which command you reached the failure through. When a REST API request fails, the CLI raises the domain's registered `*.API_ERROR` code and carries the API's own code and HTTP status in `meta.apiCode` and `meta.status`, where they are data you can read rather than a code you have to guess at.

Namespaces:

| Namespace  | Covers                                                                                             |
| ---------- | -------------------------------------------------------------------------------------------------- |
| `AUTH`     | Workspace authentication and sessions (`prisma auth`, credential resolution)                       |
| `BRANCH`   | Branch listing (`prisma branch`)                                                                   |
| `BUCKET`   | Bucket and bucket-key management (`prisma bucket`)                                                 |
| `CLI`      | Engine-level invocation: arguments, config loading, prompts, consent, credentials, child processes |
| `FEEDBACK` | Sending product feedback (`prisma feedback`)                                                       |
| `GIT`      | Git repository connections (`prisma git`)                                                          |
| `INIT`     | Project initialization diagnostics (`prisma init`)                                                 |
| `POSTGRES` | Database management (`prisma postgres`)                                                            |
| `PROJECT`  | Project and environment management (`prisma project`)                                              |
| `SERVICE`  | Deployed service management (`prisma service`)                                                     |
| `SKILLS`   | Agent-skill delivery (`prisma skills`)                                                             |

## AUTH [#auth]

### AUTH.CREDENTIAL_WORKSPACE_MISMATCH [#AUTH.CREDENTIAL_WORKSPACE_MISMATCH]

A credential's `workspace_id` claim disagrees with the workspace it is being stored under — raised by every CredentialManager (the CLI's file-backed manager and the engine's in-memory one) both when `createSession` receives a token claiming a different workspace and when a rotated token written back during refresh would re-scope an existing session. The fix is to run `prisma auth login` again and pick the intended workspace. Meta: none.

### AUTH.LOGIN_WORKSPACE_UNKNOWN [#AUTH.LOGIN_WORKSPACE_UNKNOWN]

`prisma auth login` completed the browser sign-in but the minted credential carries no `workspace_id` claim, so no workspace session can be keyed by it. The fix is to sign in again and pick a workspace in the browser. Meta: none.

### AUTH.LOGIN_DENIED [#AUTH.LOGIN_DENIED]

The OAuth callback reported `access_denied`. Authorization was not granted; this is an expected refusal, not a CLI crash. No session is created or cleared. Run `prisma auth login` again only to grant access intentionally. The callback description is not echoed. Meta: none.

### AUTH.NO_SESSION_FOR_WORKSPACE [#AUTH.NO_SESSION_FOR_WORKSPACE]

A workspace reference matched none of the stored workspace sessions — raised by the command-side ref resolver behind `prisma auth workspace use` and `prisma auth workspace logout` (exact id match first, then case-insensitive name match), and by the credential managers when a session operation names a workspace with no stored record. Sessions are created only by `prisma auth login`, so the suggested fix is to sign in and pick that workspace in the browser; the workspace reference appears in the message, not in meta. Meta: none.

### AUTH.NO_WORKSPACE_SESSIONS [#AUTH.NO_WORKSPACE_SESSIONS]

`prisma auth workspace use` was run with zero stored workspace sessions, so there is nothing to select among — the command only selects, it never creates a session or opens a browser. The fix is to run `prisma auth login` first. Meta: none.

### AUTH.SERVICE_TOKEN_EMPTY [#AUTH.SERVICE_TOKEN_EMPTY]

The `PRISMA_SERVICE_TOKEN` environment variable is set but blank; a blank token authenticates nothing while still overriding stored workspace sessions, so the CLI surfaces it instead of silently ignoring it. It is raised identically wherever the environment credential is read — `activeCredential()`, the command needs check, and the engine's request path, including at the start of `prisma auth login` before a browser opens. The suggested actions are to unset the variable or set it to a valid service token. Meta: none.

### AUTH.SERVICE_TOKEN_REJECTED [#AUTH.SERVICE_TOKEN_REJECTED]

The management API rejected (401) the service token supplied through `PRISMA_SERVICE_TOKEN`; such a token carries no refresh token and can never be renewed, and nothing stored is cleared. Built only through the shared `credentialRejectedError` dispatcher in the engine's API request path — the one place wording differs by credential origin (a stored session with the same failure gets `CLI.CREDENTIALS_REQUIRED` instead). `prisma auth whoami` fails with this code too rather than reporting the rejected token as signed in. The suggested action is to replace the variable with a valid service token or unset it to fall back to stored sessions. Meta: none.

### AUTH.SESSIONS_UNSUPPORTED [#AUTH.SESSIONS_UNSUPPORTED]

A session mutation (`createSession`, `selectSession`, `endSession`, `endAllSessions`) was attempted on a host that uses the environment-only credential manager, whose sole credential source is `PRISMA_SERVICE_TOKEN` (plus `PRISMA_WORKSPACE_ID`) — such hosts, like composer's rebuilt CLI, hold no stored sessions, so there is nothing to create, select, or end. The suggested action is to set or change the environment variable instead. Meta: none.

### AUTH.USAGE_ERROR [#AUTH.USAGE_ERROR]

A command that needs an active workspace found an authenticated credential that names no workspace — raised by the resource commands' `resolveActiveWorkspace` and the service commands' `requireWorkspace`, which read the engine's pinned credential; an environment token whose claims carry no workspace id is the usual cause. The suggested fix is to run `prisma auth login` and choose a workspace. Meta: none.

### AUTH.WORKSPACE_AMBIGUOUS [#AUTH.WORKSPACE_AMBIGUOUS]

A user-typed workspace name matched more than one workspace, from two raise sites with different meta: the session-ref resolver behind `prisma auth workspace use`/`logout` when several stored sessions share the name (meta carries `workspaceIds` and `sessions`, each session holding `workspaceId` and a nullable `user`), and `prisma project transfer` when a `--to-workspace` reference matches several authenticated workspaces (meta carries `workspaceRef` and `matches`, each match holding `id`, `name`, `credentialWorkspaceId`). Both point the user at `prisma auth workspace list` to retry with an exact workspace id. Meta: `workspaceIds`, `sessions` (workspace commands) or `workspaceRef`, `matches` (project transfer).

### AUTH.WORKSPACE_NOT_AUTHENTICATED [#AUTH.WORKSPACE_NOT_AUTHENTICATED]

`prisma project transfer` could not resolve the transfer recipient: the `--to-workspace` reference matched no stored OAuth session, or the matched recipient session proved invalid. The suggested fix is to run `prisma auth login` and authorize that workspace, after checking `prisma auth workspace list`. Meta: `workspaceRef`.

## BRANCH [#branch]

### BRANCH.API_ERROR [#BRANCH.API_ERROR]

A REST API call made by `prisma branch list` failed. The `why` carries the API's message or, failing that, the HTTP status, and the fix suggests rerunning with `--log-level verbose` for the response details. Meta: `status`, `apiCode` (the API's own error code, when the response supplied one).

## BUCKET [#bucket]

### BUCKET.API_ERROR [#BUCKET.API_ERROR]

A bucket REST API request (listing, creating, or deleting buckets or bucket keys) failed — raised by the provider (`lib/bucket/provider.ts`). The `why` carries the API's message or HTTP status, and the fix is the API's hint when it sent one. An HTTP 401 or 403 raises this code too, with a `why` saying the API rejected the request as unauthorized and a `prisma auth login` next action. Meta: `status`, `apiCode` (the API's own error code, when the response supplied one).

### BUCKET.KEY_SECRET_MISSING [#BUCKET.KEY_SECRET_MISSING]

`prisma bucket key create` created the key, but the REST API response omitted part of the one-time credential payload (secret access key, access key id, endpoint, or bucket name), so the CLI cannot show credentials it will never see again. The fix is to create another key and store the returned credentials immediately. Meta: none.

### BUCKET.USAGE_ERROR [#BUCKET.USAGE_ERROR]

A bucket subcommand was called without its required id argument: `bucket delete` and `bucket key create`/`bucket key list` need a bucket id, and `bucket key delete` needs both a bucket id and a key id. The nextActions point at `bucket list` (or `bucket key list`) to find the ids. Meta: none.

## CLI [#cli]

### CLI.ABORTED [#CLI.ABORTED]

The run's abort signal fired before the command completed — a thrown abort error is recognized in settlement and reported as this code rather than as a bug. When the abort came from a delivered SIGINT/SIGTERM the run exits 130/143; an abort with no recorded signal (an engine-internal abort) exits 3. Meta: none.

### CLI.AUTH_SERVICE_ERROR [#CLI.AUTH_SERVICE_ERROR]

The authentication service failed transiently while refreshing a stored OAuth session; the stored credentials are left untouched, and the guidance is to retry rather than sign in again, because the credentials themselves were not rejected. `prisma auth whoami` does not fail with this code: it answers from the credential's own claims and reports `verified: false`. Meta: none.

### CLI.BROWSER_WAIT_TIMEOUT [#CLI.BROWSER_WAIT_TIMEOUT]

A `ctx.prompt.browserWait` flow (the command opened a URL and polled for the user to finish there) reached its timeout before the poll succeeded. `prisma git connect` catches this code from its GitHub-app install wait and rethrows a command-specific error, so consumers usually see it from other browserWait flows. Meta: `url`, `timeoutMs`.

### CLI.CHILD_PROCESS_FAILED [#CLI.CHILD_PROCESS_FAILED]

Emitted only as a json-mode error envelope when a command that handed the terminal to a child process (`exitWithChildStatus`) saw that child exit non-zero or die on a signal; the run's exit code is the child's own status verbatim, not the CLI's usual 2. Meta: `exitCode`, `signal`.

### CLI.COMMAND_MOVED [#CLI.COMMAND_MOVED]

The user typed a retired command path, or a retired flag on a surviving command, that the redirect table claims; instead of failing as unknown, the run names the replacement invocation as a run-command next action, with the retirement reason in `why` when one is recorded. Exits 2. Meta: none.

### CLI.CONFIG_MISSING_MARKER [#CLI.CONFIG_MISSING_MARKER]

The evaluated `prisma.config.ts` default export carries no `$prismaConfig` version marker — most likely a Prisma ORM 7 config, which uses the same filename — so the loader stops rather than misread it; the fix is to wrap the exported object in `definePrismaConfig`. Raised by the config loader for any command with a `needs.config` section. The file's absolute path is in `where.path`. Meta: none.

### CLI.CONFIG_NOT_FOUND [#CLI.CONFIG_NOT_FOUND]

The file `--config` named does not exist. Only an explicitly named file is an error — an absent `prisma.config.ts` found by discovery is fine, because section validators own absence and supply defaults. The path is in `where.path`. Meta: none.

### CLI.CONFIG_PARENT_CYCLE [#CLI.CONFIG_PARENT_CYCLE]

A config file's explicit `parent` names a file that is already on the config chain, which would loop forever. Raised by the config loader while following the chain; the declaring file's absolute path is in `where.path` and the summary names both files. The fix is to point `parent` elsewhere or set it to `false`. Meta: none.

### CLI.CONFIG_PARENT_INVALID [#CLI.CONFIG_PARENT_INVALID]

A config file declares `parent` with a value that is neither `false` nor a path string. Raised by the config loader while following the chain; the declaring file's absolute path is in `where.path`. Meta: none.

### CLI.CONFIG_PARENT_NOT_FOUND [#CLI.CONFIG_PARENT_NOT_FOUND]

A config file's explicit `parent` names a file that does not exist. Naming a parent is deliberate, so its absence is an error — unlike discovery, where finding no file is fine. Raised by the config loader while following the chain; the declaring file's absolute path is in `where.path` and the summary names the missing target. Meta: none.

### CLI.CONFIG_FIELD_INVALID [#CLI.CONFIG_FIELD_INVALID]

One field of a config section declared by schema failed that schema: the wrong type, a missing required field, or a value outside the declared set. The summary names the section and the field with arktype's description of the problem; `where.path` is the config file that declared the field's top-level key (so the file to fix on a chain), and `meta.section` and `meta.field` carry the names. Travels as an accompanying diagnostic under `CLI.CONFIG_SECTION_INVALID`. Raised by the engine's schema validation before the handler runs. Meta: `section`, `field`.

### CLI.CONFIG_SECTION_INVALID [#CLI.CONFIG_SECTION_INVALID]

The config section a command declared in `needs.config` failed its validator; the individual problems travel as accompanying diagnostics on the envelope, and the summary names the section and the config file actually read (respecting `--config`). Raised by the engine's needs check before the handler runs. Meta: none.

### CLI.CONFIG_UNKNOWN_SECTION [#CLI.CONFIG_UNKNOWN_SECTION]

The config file has a top-level key that is not a section any mounted command or command family declares; the set of section names is closed, so an unrecognized key is a typo or leftover the CLI refuses to silently ignore. The `why` lists the recognized section names, and the file path is in `where.path`. Raised by the engine's needs check, deliberately outside the host-replaceable loader. Meta: none.

### CLI.CONFIG_UNREADABLE [#CLI.CONFIG_UNREADABLE]

Evaluating `prisma.config.ts` threw. Two variants share the code: when the error chain shows the `prisma/config` entry point could not be resolved (the prisma package missing from the project, or too old), the guidance is to install the prisma package matching the CLI's version; otherwise the summary carries the first line of the evaluation error and the fix is to repair the file. The path is in `where.path`. Meta: none.

### CLI.CONFIG_VERSION_UNSUPPORTED [#CLI.CONFIG_VERSION_UNSUPPORTED]

The config file's `$prismaConfig` marker declares a version other than the one this CLI supports; the fix is to regenerate the config with a matching `definePrismaConfig` or update the CLI. The path is in `where.path`. Meta: none.

### CLI.CONSENT_REQUIRED [#CLI.CONSENT_REQUIRED]

A consent prompt was reached under `--yes` or in a non-interactive session. Consent has no default answer and `--yes` does not grant it, so there is nothing for the run to assume. When the consent declares a token, the message and next action say to pass `--confirm <token>`, and the token travels in meta; without a token, the only path is running the command interactively. Meta: `consentToken` (only when the consent declares a token).

### CLI.CREDENTIALS_LOCKED [#CLI.CREDENTIALS_LOCKED]

The advisory lock on the stored-credentials file was held by another prisma process for longer than the wait timeout, so this run's credential mutation gave up; the fix is to wait for the other command and retry. Raised by the auth state file's lock helper in `packages/cli`. Meta: none.

### CLI.CREDENTIALS_REQUIRED [#CLI.CREDENTIALS_REQUIRED]

The command needs a signed-in credential and none is usable. One constructor covers five reasons: not signed in at all, an expired session, a session expiring too soon for a command that hands credentials to a child process (which cannot refresh them), a workspace session that ended mid-run, and workspace sessions held with none selected as current. Raised identically by the engine's needs check, `ctx.activeCredential`, and the request path; next actions point at signing in or `prisma auth workspace use`. When `prisma auth whoami` meets this code during its identity lookup it reports `authenticated: false` with exit `0` instead of failing. Meta: none.

### CLI.CREDENTIALS_UNREADABLE [#CLI.CREDENTIALS_UNREADABLE]

The stored-credentials file exists but could not be read (any read failure other than the file being absent, which yields empty state instead); the guidance is to check the file's permissions. The underlying error is attached as `cause`. Meta: none.

### CLI.INTERACTION_REQUIRED [#CLI.INTERACTION_REQUIRED]

The session is not interactive (no TTY stdin, CI, or `--no-interactive`) and the command cannot proceed without a person. Two raise sites: the engine's needs check for a command declaring `needs.interaction`, and `ctx.prompt.browserWait`, which refuses to start a browser wait it could never finish — in that case the URL travels in the error so the user can finish there manually. Meta: `url` (browserWait raise only; none from the needs check).

### CLI.INTERNAL_ERROR [#CLI.INTERNAL_ERROR]

A bug, not a user error: a non-structured throw from a handler, an engine invariant violation (undocumented exit code, malformed result), or a stricli internal failure that never settled. The summary is the first line of the underlying error message. Exits 1, the taxonomy's bug code, rather than the usual 2. Meta: none.

### CLI.INVALID_ARGUMENTS [#CLI.INVALID_ARGUMENTS]

The invocation's arguments did not parse or contradict each other. Raise sites: stricli's argument-parse failure mapped at the adapter boundary (its usage text becomes summary and `why`), `--config=` given an empty value, `prisma init --skills` given `none` combined with agent names or an unknown agent name, and `prisma skills sync` given both `--disable` and `--enable`. Exits 2 as a usage error. Meta: none.

### CLI.MISSING_DEPENDENCY [#CLI.MISSING_DEPENDENCY]

A command declared an optional peer dependency in `needs.dependencies` that does not resolve from the project; the engine probes with `require.resolve` and phrases the install command for the package manager it detected. Meta: `specifier`, `installCommand`.

### CLI.PACKAGE_MANAGER_FAILED [#CLI.PACKAGE_MANAGER_FAILED]

A `ctx.packages` operation (an install, or running a package through the manager) exited non-zero — or nothing ran at all because the host wires no package-manager runner, recorded in `meta.reason`. The redacted command line is offered as a run-command next action so the user can run it themselves. Meta: `form`, `manager`, `command`, `exitCode`, `stderrTail`, `reason` (only when the runner is unavailable).

### CLI.PROMPT_CANCELLED [#CLI.PROMPT_CANCELLED]

The user cancelled a prompt: EOF on stdin at a line-rendered prompt, a clack cancel (Ctrl-C at the prompt UI), an abort during a browserWait poll, or — via the service commands' `userCancelledError` — consent declined interactively. Settles with exit 3, the cancellation code, instead of 2. Meta: none.

### CLI.PROMPT_INVALID [#CLI.PROMPT_INVALID]

An answer could not be interpreted: not a yes/no for a confirm, not one of a select's options with no default to fall back to, or a consent token typed wrong where re-prompting is impossible (scripted answers or piped stdin — the interactive clack renderer re-prompts instead). Meta: `consentToken` (token-mismatch raise only).

### CLI.PROMPT_REQUIRED [#CLI.PROMPT_REQUIRED]

A prompt with no declared default was reached where it cannot be shown — under `--yes` or in a non-interactive session — so the run halts; the fix is to run from an interactive terminal or pass a flag that answers the prompt. Meta: none.

### CLI.SPAWN_FAILED [#CLI.SPAWN_FAILED]

`ctx.spawn` could not start the requested program, or the child's lifecycle promise rejected; the first line of the underlying failure is in `why`, and the guidance is to check the program is installed and on PATH. Meta: `command`.

### CLI.TELEMETRY_PREFERENCE_UNAVAILABLE [#CLI.TELEMETRY_PREFERENCE_UNAVAILABLE]

The `prisma telemetry status|enable|disable` commands could not resolve the user-level config directory because none of XDG_CONFIG_HOME, HOME, APPDATA, or USERPROFILE is set; unreachable in production, where HOME or USERPROFILE is always set. Meta: none.

### CLI.UNKNOWN_COMMAND [#CLI.UNKNOWN_COMMAND]

The typed path routed to no command (stricli's route failure, mapped at the adapter boundary) and no redirect claims it; next actions carry up to three "did you mean" suggestions ranked by edit distance over command paths and their prefixes, plus a pointer to `--help`. Exits 2. Meta: none.

## FEEDBACK [#feedback]

### FEEDBACK.EMAIL_INVALID [#FEEDBACK.EMAIL_INVALID]

`prisma feedback --email` was given a value that fails the CLI's local check (a basic address pattern, at most 320 characters), which mirrors the feedback service's own limit so the refusal happens before any network round trip. The suggested actions are to pass a valid address or drop the flag to send anonymously. Meta: none.

### FEEDBACK.MESSAGE_REQUIRED [#FEEDBACK.MESSAGE_REQUIRED]

`prisma feedback` was run with a message that is empty after trimming. The fix is to pass a non-empty message. Meta: none.

### FEEDBACK.MESSAGE_TOO_LONG [#FEEDBACK.MESSAGE_TOO_LONG]

The `prisma feedback` message exceeds 4000 characters, the feedback service's limit, checked locally before the network round trip; the actual length and the limit are stated in `why`. The fix is to shorten the message. Meta: none.

### FEEDBACK.SEND_FAILED [#FEEDBACK.SEND_FAILED]

`prisma feedback` could not deliver the submission: the feedback endpoint was unreachable (or timed out), the service answered a non-OK HTTP status (the status and any service-supplied error message go into `why`), or the response body could not be read; a body that arrived but was not JSON is treated as success, and a user cancellation is rethrown rather than wrapped. The suggested action is to check the network and rerun. Meta: none.

## GIT [#git]

### GIT.REPO_ALREADY_CONNECTED [#GIT.REPO_ALREADY_CONNECTED]

`prisma git connect` found the resolved project already connected to a different GitHub repository than the one requested (reconnecting the same repository is idempotent and succeeds). The fix is to run `prisma git disconnect` first. Meta: `repository`.

### GIT.REPO_CONNECTION_FAILED [#GIT.REPO_CONNECTION_FAILED]

A management API call in the `prisma git connect`/`disconnect` flow failed — creating the install intent, listing installations or repositories, reading or writing the source-repository connection, or a pagination cursor that stopped advancing; the API's message and hint, when present, become `why` and the suggested fix, and a 401/403 is routed to the auth error path instead. Meta: `status`, `apiCode` (when the API supplied one).

### GIT.REPO_INSTALLATION_REQUIRED [#GIT.REPO_INSTALLATION_REQUIRED]

`prisma git connect` waited for a GitHub App installation but the wait ended (timeout or final poll) with the workspace still holding no inspectable installation that could link the repository. The fix is to finish installing the GitHub App at the install URL, then rerun `prisma git connect`; the URL is also offered as an open-url next action. Meta: `repository`, `installUrl`.

### GIT.REPO_NOT_ACCESSIBLE [#GIT.REPO_NOT_ACCESSIBLE]

`prisma git connect` waited for repository access but the wait ended with the workspace's existing GitHub App installations still not exposing the requested repository — the same install wait as `GIT.REPO_INSTALLATION_REQUIRED`, distinguished by at least one inspectable installation existing. The fix is to grant the App access to this repository at the install URL, then rerun `prisma git connect`. Meta: `repository`, `installUrl`.

### GIT.REPO_NOT_CONNECTED [#GIT.REPO_NOT_CONNECTED]

`prisma git disconnect` found no active GitHub repository connection on the resolved project, so there is nothing to disconnect. The fix is to run `prisma git connect` first. Meta: none.

### GIT.REPO_PROVIDER_UNSUPPORTED [#GIT.REPO_PROVIDER_UNSUPPORTED]

The URL given to `prisma git connect` (or read from the local `origin` remote) did not parse as a GitHub repository URL; repository connection supports GitHub only. The fix is to pass a GitHub repository URL. Meta: none.

### GIT.USAGE_ERROR [#GIT.USAGE_ERROR]

`prisma git connect` was run with no repository URL argument and the local repository has no `origin` remote to fall back on. The fix is to pass a GitHub repository URL or add a GitHub `origin` remote and rerun. Meta: none.

## INIT [#init]

### INIT.CONFIG_KEPT [#INIT.CONFIG_KEPT]

A warn diagnostic from `prisma init`: a `prisma.config.ts` already exists that does not configure `skills.agents`, and init never edits an existing config, so it was left untouched. The nextAction carries the exact `skills: { agents: [...] }` snippet to add to the `definePrismaConfig` call; a config that already sets `skills.agents` produces no diagnostic at all. Meta: none.

### INIT.CONFIG_UNWRITABLE [#INIT.CONFIG_UNWRITABLE]

A warn diagnostic from `prisma init`: writing the scaffolded `prisma.config.ts` failed, so the config step was skipped. The nextAction asks the user to create the file themselves with the intended `skills: { agents: [...] }` section. Meta: none.

### INIT.DEV_DEPENDENCIES_NOT_AN_OBJECT [#INIT.DEV_DEPENDENCIES_NOT_AN_OBJECT]

A warn diagnostic from `prisma init`: the `devDependencies` field in package.json is not an object, so init did not add the `prisma` dev dependency (the postinstall-hook edit still proceeds when its own field is fine). The nextAction is to fix the field, add `"prisma": "<version>"` by hand, and run the package manager's install. Meta: none.

### INIT.NO_PACKAGE_JSON [#INIT.NO_PACKAGE_JSON]

A warn diagnostic from `prisma init`: there is no package.json in the current directory, so neither the skills-sync postinstall hook nor the `prisma` dev dependency was added. The nextActions are to rerun init from the directory that holds package.json, or to add the dependency by hand. Meta: none.

### INIT.PACKAGE_JSON_UNREADABLE [#INIT.PACKAGE_JSON_UNREADABLE]

A warn diagnostic from `prisma init`: package.json exists but could not be parsed as JSON, so the postinstall hook and the `prisma` dev dependency were not added. The nextActions give the exact postinstall script and dependency entry to add by hand. Meta: none.

### INIT.PACKAGE_JSON_UNWRITABLE [#INIT.PACKAGE_JSON_UNWRITABLE]

A warn diagnostic from `prisma init`: the manifest edit was prepared but writing package.json back failed, so the file was left unchanged. The nextActions cover only what the failed write would have added — the postinstall script, the dev dependency, or both. Meta: none.

### INIT.POSTINSTALL_KEPT [#INIT.POSTINSTALL_KEPT]

A warn diagnostic from `prisma init`: package.json already has a postinstall script that is not the CLI's own, and init never overwrites a user's script, so it was left alone. The nextAction is to append `prisma skills sync || exit 0` to the existing script yourself so skills resync on every install. Meta: none.

### INIT.SCRIPTS_NOT_AN_OBJECT [#INIT.SCRIPTS_NOT_AN_OBJECT]

A warn diagnostic from `prisma init`: the `scripts` field in package.json is not an object, so init left the manifest untouched instead of adding the postinstall hook (which also skips adding the dev dependency, since the manifest is not edited at all). The nextAction gives the postinstall script to add by hand. Meta: none.

### INIT.SKILLS_SYNC_FAILED [#INIT.SKILLS_SYNC_FAILED]

A warn diagnostic from `prisma init`: the final step, syncing the agent skills from installed Prisma packages, threw; the cause's message is appended to the summary. The nextAction is to retry with `prisma skills sync` on its own. Meta: none.

## POSTGRES [#postgres]

### POSTGRES.AMBIGUOUS [#POSTGRES.AMBIGUOUS]

A database name passed to a `prisma postgres` subcommand matched more than one database in the resolved project — raised by the shared database resolver (`controllers/database.ts`). The fix is to pass the database id, or `--branch <git-name>` to narrow the match; the candidates are carried in meta as `matches`, each with `id`, `name`, and `branchName`. Meta: `matches`.

### POSTGRES.API_ERROR [#POSTGRES.API_ERROR]

A database REST API request failed without a more specific code — the generic fallback for every `prisma postgres` operation, raised by the provider (`lib/database/provider.ts`), and also when a database response omits its project id. The `why` carries the API's message or HTTP status, and the fix is the API's hint when it sent one. An HTTP 401 or 403 raises this code too, with a `why` saying the API rejected the request as unauthorized and a `prisma auth login` next action. Meta: `status`, `apiCode` (the API's own error code, when the response supplied one).

### POSTGRES.BACKUP_NOT_FOUND [#POSTGRES.BACKUP_NOT_FOUND]

`prisma postgres backup restore` got a 404 from the restore endpoint; the source and target databases are resolved before the call, so the 404 identifies the backup id. The fix is to pass a backup id from `prisma postgres backup list <database>`. Meta: none.

### POSTGRES.BACKUPS_UNSUPPORTED [#POSTGRES.BACKUPS_UNSUPPORTED]

Listing backups returned a 422 because the platform does not manage backups for this database — for example a remote/BYO database (raised by `prisma postgres backup list`). The fix is to use your own backup tooling for externally managed databases. Meta: none.

### POSTGRES.CONNECTION_MISSING [#POSTGRES.CONNECTION_MISSING]

`prisma postgres create` created the database, but the API response did not include the first one-time connection payload. The fix is to create a connection explicitly with `prisma postgres connection create <database>`. Meta: none.

### POSTGRES.CONNECTION_STRING_MISSING [#POSTGRES.CONNECTION_STRING_MISSING]

A connection create or rotate succeeded, but the API response did not include the one-time connection string the CLI would show exactly once (raised by `prisma postgres create`, `postgres connection create`, and `postgres connection rotate`). The fix is to rerun the operation, or create a replacement connection and store the returned URL immediately. Meta: none.

### POSTGRES.NOT_FOUND [#POSTGRES.NOT_FOUND]

The database a `prisma postgres` subcommand targets could not be resolved: either no database matched the given id or name in the project (and optional `--branch`) scope, or a database that was just listed returned 404 on read because it was removed while the command ran (raised by the shared resolver in `controllers/database.ts`). The fix is to pass an id or name from `prisma postgres list`. Meta: none.

### POSTGRES.PLAN_LIMIT_REACHED [#POSTGRES.PLAN_LIMIT_REACHED]

A database operation was blocked because the workspace has used up the operations included in its plan — the API's structured plan-limit discriminator, detected on any `prisma postgres` REST API call; this is a workspace plan restriction, not a Prisma outage. The one nextAction is to upgrade the workspace plan, with the upgrade URL and current plan name when the workspace subscription could be read. Meta: `workspaceId`, `blockedFeature`, `planName`, `usageBlocked`, `upgradeUrl` (each `null` when unavailable).

### POSTGRES.RESTORE_CONFLICT [#POSTGRES.RESTORE_CONFLICT]

`prisma postgres backup restore` got a 409 because the target database is provisioning or already recovering. The fix is to wait for the database to become ready — check with `prisma postgres show <database>` — then retry. Meta: none.

### POSTGRES.USAGE_ERROR [#POSTGRES.USAGE_ERROR]

A `prisma postgres` subcommand was called with missing or invalid arguments: `create` without a name, `connection delete`/`connection rotate` without a connection id, `backup restore` without `--backup`, or `usage` with `--from` later than `--to`. The nextActions show the corrected command form. Meta: none.

## PROJECT [#project]

### PROJECT.AMBIGUOUS [#PROJECT.AMBIGUOUS]

Project resolution matched more than one project: an explicit project reference (matched by id first, then by name) hit several projects, or the implicit directory context did — raised by any command that resolves a project, including `branch list`. The fix is to pass `--project <id-or-name>`, and the next actions include `prisma project link <id>` with the first match's id verbatim so the user can copy an exact disambiguating reference. Meta: `matches`.

### PROJECT.API_ERROR [#PROJECT.API_ERROR]

A REST API project operation (list, rename, delete, or transfer) failed. Listing projects deliberately throws this rather than returning an empty list, so a rejected request is distinguishable from a workspace that genuinely has no projects. The `why` carries the API's message or HTTP status, and the API's own error code, when it sent one, is in `meta.apiCode`. Meta: `status`, `apiCode` (each present only when the response supplied it).

### PROJECT.CREATE_FAILED [#PROJECT.CREATE_FAILED]

The platform rejected creating a project — raised by `prisma project create` and by the create-a-new-project path of `prisma project link`. An HTTP 401/403 gets a permissions-focused fix; any other failure surfaces the underlying error message as the `why`. Meta: none.

### PROJECT.DELETE_BLOCKED [#PROJECT.DELETE_BLOCKED]

The REST API answered `prisma project delete` with HTTP 400, which typically means the project still has active deployments; the fix is to delete the project's services first (`prisma service delete --service <name>`) and retry. The API's own message replaces the default `why` when present. Meta: none.

### PROJECT.ENV_API_ERROR [#PROJECT.ENV_API_ERROR]

A REST API call made by the `prisma project env` commands (reading, writing, or deleting variables, or resolving and creating branches for a scope) failed. The summary names the call that failed, for example "Failed to add STRIPE_KEY". An HTTP 401 or 403 raises this code too, with a `why` saying the API rejected the request as unauthorized and a `prisma auth login` next action. Meta: `status`, `apiCode` (the API's own error code, when the response supplied one).

### PROJECT.ENV_BRANCH_CREATE_REQUIRES_DEFAULT_BRANCH [#PROJECT.ENV_BRANCH_CREATE_REQUIRES_DEFAULT_BRANCH]

`prisma project env add --branch <git-name>` will create a missing preview branch, but the project has no default branch yet, and creating the first branch would make it the default while branch env overrides are preview-only. The fix is to create or deploy the default branch first, for example via `prisma git connect`. Meta: none.

### PROJECT.ENV_BRANCH_NOT_FOUND [#PROJECT.ENV_BRANCH_NOT_FOUND]

A `prisma project env` update, list, or delete named a branch scope (`--branch <git-name>`) that does not exist — only `env add` creates missing branches. The fix is to create the branch by deploying it, or to use `project env add --branch` to create its first override. Meta: none.

### PROJECT.ENV_BRANCH_SCOPE_IS_PRODUCTION [#PROJECT.ENV_BRANCH_SCOPE_IS_PRODUCTION]

A `prisma project env` command's `--branch` flag resolved to the project's production branch; production variables are project-level only, and branch overrides apply to preview branches. The fix is to use `--role production` instead. Meta: none.

### PROJECT.ENV_FILE_APPLY_FAILED [#PROJECT.ENV_FILE_APPLY_FAILED]

`prisma project env add --file` or `update --file` failed while writing one of the file's keys, after zero or more earlier keys were already written. The `why` names the keys written before the failure and the underlying cause, and the next actions include a retry command scoped to a file of the remaining keys. Meta: `file`, `failedKey`, `writtenKeys`.

### PROJECT.ENV_PREVIEW_DEFAULT_MISSING [#PROJECT.ENV_PREVIEW_DEFAULT_MISSING]

Not an error: a warn diagnostic emitted on a successful `prisma project env add` to a branch scope (single key or `--file`) for each key that has no preview-level default, meaning the variable will exist only on that branch. Meta: none.

### PROJECT.ENV_VARIABLE_ALREADY_EXISTS [#PROJECT.ENV_VARIABLE_ALREADY_EXISTS]

`prisma project env add` targeted a key (or, in `--file` mode, one or more keys) that already exists in the targeted scope. The single-key fix is to use `prisma project env update`; the file-mode fix is to split the input file and update existing keys separately from adding new ones. Meta: `keys` (file mode only; the single-key form carries no meta).

### PROJECT.ENV_VARIABLE_NOT_FOUND [#PROJECT.ENV_VARIABLE_NOT_FOUND]

`prisma project env update` or `env delete` targeted a key (or, in update's `--file` mode, one or more keys) that does not exist in the targeted scope. The fix for update is to create the variable with `env add` (or split a mixed file); for delete it is to list the scope's variables first. Meta: `keys` (file-mode update only; the single-key forms carry no meta).

### PROJECT.LOCAL_STATE_STALE [#PROJECT.LOCAL_STATE_STALE]

The local project binding in `.prisma/local.json` is unusable: the pinned project is no longer in the selected workspace's project list, or the pin file is invalid JSON or has an invalid shape — raised by any command that resolves the project implicitly through the pin. The fix is to delete the pin file and choose a project explicitly. Meta: `pinPath`.

### PROJECT.LOCAL_STATE_WRITE_FAILED [#PROJECT.LOCAL_STATE_WRITE_FAILED]

`prisma project link` or `project create` could not save the local binding: writing `.prisma/local.json` failed, or updating `.gitignore` to keep the binding out of git failed — the fix is to check directory permissions and retry. The same code is also emitted as a warn diagnostic (not an error) by `project delete` and `project transfer` when the operation itself succeeded but the now-stale local pin could not be removed or rewritten. Meta: `pinPath` or `gitignorePath`, plus `operation` (the error form; the diagnostic form carries none).

### PROJECT.LOCAL_WORKSPACE_MISMATCH [#PROJECT.LOCAL_WORKSPACE_MISMATCH]

`.prisma/local.json` links the directory to a project in one workspace, but the CLI session's active workspace is a different one — raised by any command that resolves the project through the pin. The fix is to switch to the pinned workspace (`prisma auth workspace use <id>`) or relink the directory to a project in the current workspace. Meta: `pinPath`, `pinnedWorkspaceId`, `pinnedProjectId`, `activeWorkspaceId`, `activeWorkspaceName`.

### PROJECT.NOT_FOUND [#PROJECT.NOT_FOUND]

An explicit project reference matched no project in the active workspace, either because it does not exist or because the credential cannot see it — raised during project resolution for any command that accepts one, including `branch list` and the `project link`/`transfer`/`delete` target lookup. The fix is to pass an id or name from `prisma project list`. Service commands raise the same code one step later, when the services API answers "Resource Not Found" for a project that did resolve — the directory binding points at a project that no longer exists or is no longer accessible — and their next actions point at `project show` to inspect the binding and `project link` to fix it. Meta: none.

### PROJECT.RENAME_FAILED [#PROJECT.RENAME_FAILED]

The REST API answered `prisma project rename` with HTTP 400 or 422, meaning the platform rejected the new name; the API's message and hint replace the default `why` and fix when present, and the fallback fix is to retry with a different name. Meta: none.

### PROJECT.SETUP_REQUIRED [#PROJECT.SETUP_REQUIRED]

A command needed a project but the directory is not linked and no `--project` flag was given; the CLI deliberately refuses to pick a project from package or directory names, treating them as suggestions only. The meta carries the inferred name suggestion and any matching candidate projects, and the next actions walk through choosing between linking an existing project (`prisma project link`) and creating a new one. Meta: `suggestedProjectName`, `suggestedProjectNameSource`, `candidates`, `recoveryCommands`.

### PROJECT.TRANSFER_RECIPIENT_REQUIRED [#PROJECT.TRANSFER_RECIPIENT_REQUIRED]

`prisma project transfer` was invoked without naming a receiving workspace: neither `--to-workspace <id-or-name>` (for a locally authenticated workspace) nor `--recipient-token <token>` (for a cross-account transfer) was passed. Meta: none.

### PROJECT.TRANSFER_RECIPIENT_UNAVAILABLE [#PROJECT.TRANSFER_RECIPIENT_UNAVAILABLE]

`prisma project transfer --to-workspace` needs to resolve locally stored OAuth workspace sessions, but `PRISMA_SERVICE_TOKEN` is set and service-token mode does not read them. The fix is to pass `--recipient-token <token>` for the receiving workspace, or to unset the service token. Meta: none.

### PROJECT.TRANSFER_REJECTED [#PROJECT.TRANSFER_REJECTED]

The REST API answered `prisma project transfer` with HTTP 400 — for example because the recipient token is invalid or expired; the API's message replaces the default `why` when present, and the fix is to check the recipient session or token and retry. Meta: none.

### PROJECT.USAGE_ERROR [#PROJECT.USAGE_ERROR]

A `project` or `branch` group command was invoked with unusable arguments — for example a `project env` write without an explicit `--role` or `--branch` scope, `project transfer` with both recipient flags at once, `project create` with an empty name, or an interactive `project link` whose selection was cancelled. Usage errors exit 2. Meta: none.

## SERVICE [#service]

### SERVICE.BRANCH_INVALID [#SERVICE.BRANCH_INVALID]

A `--branch` flag was passed with an empty or whitespace-only value to a service command; the check runs before any resolution because a blank value must never fall through to the default-branch behavior of omitting the flag. The fix is to pass a non-empty branch name, or omit `--branch` to target the default branch. Meta: none.

### SERVICE.BRANCH_NOT_DEPLOYABLE [#SERVICE.BRANCH_NOT_DEPLOYABLE]

A `service domain` command was pointed at a non-production branch, which the domain-target resolver refuses because custom domains on preview branches are not supported in Public Beta. The fix is to use `--branch production`, or attach the domain after promoting to the production branch. Meta: none.

### SERVICE.DELETE_FAILED [#SERVICE.DELETE_FAILED]

`service delete` called the platform's app-teardown API and it rejected; the underlying error's message becomes `why` and the original error is carried in `cause`. Next actions point at `service show` and `service version list` for the service. Meta: none.

### SERVICE.DEPLOY_FAILED [#SERVICE.DEPLOY_FAILED]

The general "REST API call failed" wrapper for the `service` command family — despite the name there is no deploy command here: it wraps failures to create a service, list services or versions, show/promote/roll back/delete/start/stop a version, resolve a service URL, and unrecognized custom-domain API failures. The underlying error's message becomes `why` and the original error is carried in `cause`; each raise site attaches its own next actions. On the domain fallback path only, a `DomainApiError` adds debug meta. Meta: `status`, `apiCode`, `hint` (domain fallback path only; otherwise none).

### SERVICE.DOMAIN_ALREADY_REGISTERED [#SERVICE.DOMAIN_ALREADY_REGISTERED]

`service domain add` got HTTP 409 from the domain API because the hostname is already registered, to this or another service. The fix is to delete the domain on the service that owns it, or contact Prisma support if that service is not accessible. Meta: `status`, `apiCode`, `hint`.

### SERVICE.DOMAIN_DNS_NOT_CONFIGURED [#SERVICE.DOMAIN_DNS_NOT_CONFIGURED]

`service domain add` got HTTP 400 or 422 whose message the CLI recognizes as a DNS problem (no CNAME, DNS verification failed, and similar). When the API's text names a `*.prisma.build` target, the CLI composes the exact CNAME record to add and carries it in `meta.dnsRecord` and in the advice action; without a target it advises rerunning with `--log-level verbose` to see the API response. Meta: `status`, `apiCode`, `hint`, `dnsRecord` (when the DNS target could be extracted).

### SERVICE.DOMAIN_HOSTNAME_INVALID [#SERVICE.DOMAIN_HOSTNAME_INVALID]

The hostname given to a `service domain` command is not a usable custom domain — raised either by local validation before any API call (protocol, path, port, wildcard, single label, or bad DNS labels) or when `service domain add` gets a plain HTTP 400 rejection from the domain API. The fix is to pass a bare hostname such as `shop.acme.com`. Meta: `status`, `apiCode`, `hint` (API-rejection path only; none for local validation).

### SERVICE.DOMAIN_NOT_FOUND [#SERVICE.DOMAIN_NOT_FOUND]

A `service domain` command targeted a hostname that is not attached to the resolved service — raised when the service's domain listing has no matching hostname, or when a show/delete/retry/wait call gets HTTP 404. The fix is to check the hostname and service, or add the domain first. Meta: none.

### SERVICE.DOMAIN_QUOTA_EXCEEDED [#SERVICE.DOMAIN_QUOTA_EXCEEDED]

`service domain add` was refused because the custom-domain quota is reached — HTTP 429, or a 409 whose text mentions a quota, maximum, or limit. The fix is to delete an existing custom domain before adding another. Meta: `status`, `apiCode`, `hint`.

### SERVICE.DOMAIN_RETRY_NOT_ELIGIBLE [#SERVICE.DOMAIN_RETRY_NOT_ELIGIBLE]

`service domain retry` got HTTP 409: the domain is not in a state that can be retried, typically because a verification or TLS step is still in progress. The fix is to wait for the current step to finish and retry only if the domain then fails. Meta: `status`, `apiCode`, `hint`.

### SERVICE.DOMAIN_VERIFICATION_FAILED [#SERVICE.DOMAIN_VERIFICATION_FAILED]

`service domain wait` observed the domain reach the terminal `failed` status; `why` carries the platform's failure category and reason when reported, and a failure-specific fix line is attached when the CLI can derive one from the domain record. Next actions point at `service domain show` and `service domain retry`. Meta: none.

### SERVICE.DOMAIN_VERIFICATION_TIMEOUT [#SERVICE.DOMAIN_VERIFICATION_TIMEOUT]

`service domain wait` ran out of time (default 15m, or `--timeout 0` for a single check) before the domain became active; `why` reports the status the domain was last seen in. The fix is to inspect the domain with `service domain show` or rerun the wait with a longer `--timeout`. Meta: none.

### SERVICE.FEATURE_UNAVAILABLE [#SERVICE.FEATURE_UNAVAILABLE]

`service open` found a live version but the provider does not expose a stable live service URL for this service yet, so there is nothing to open. The next action is to inspect the service state with `service show`. Meta: none.

### SERVICE.LIVE_VERSION_UNKNOWN [#SERVICE.LIVE_VERSION_UNKNOWN]

`service version rollback` without `--to` needs to know which version is live, because the default rollback target is defined relative to it, and the service record names no live version — the CLI refuses rather than guess what production is serving. The fix is to pass `--to <version>` explicitly. Meta: none.

### SERVICE.LOGS_FAILED [#SERVICE.LOGS_FAILED]

`service logs` could not read the log — either the logs endpoint answered with a non-OK HTTP status (other than 404, which becomes SERVICE.VERSION_NOT_FOUND), or a page's closing terminal record reported `kind: "error"`, meaning the platform itself says the log read failed. The meta differs by path: the HTTP path carries `status`; the terminal-record path carries the platform's error `code`, `retryable`, and the resume `cursor` when present (in `--follow` mode one retryable terminal error is retried once before this settles the run). Meta: `status` (HTTP path) or `code`, `retryable`, `cursor` (stream path).

### SERVICE.LOGS_INCOMPLETE [#SERVICE.LOGS_INCOMPLETE]

A `service logs` response body ended without the terminal record that closes a page, so the read was truncated and the lines already printed may be only part of the page; the run must not settle as if it had read the whole page. Distinct from SERVICE.LOGS_NO_CURSOR, which is a properly closed page with nothing to resume from. The fix is to rerun the command. Meta: none.

### SERVICE.LOGS_NO_CURSOR [#SERVICE.LOGS_NO_CURSOR]

`service logs --follow` needs a resume cursor from each page to fetch the next one, and the page ended without one — continuing would re-request the default tail and silently print the same lines every interval, so the run stops and says why. It settles as an error rather than a clean end because `--follow` has no successful ending. The fix is to rerun without `--follow`, or retry if the version is still starting. Meta: none.

### SERVICE.LOGS_RANGE_CONFLICT [#SERVICE.LOGS_RANGE_CONFLICT]

`service logs` was invoked with both `--tail` and `--from-start`, which ask for opposite ends of the log; the run is refused before any work. The fix is to pass `--tail <n>` for the last n lines or `--from-start` for the whole log, not both. Meta: none.

### SERVICE.NAME_REQUIRED [#SERVICE.NAME_REQUIRED]

`service create` received an empty or whitespace-only name positional; the check runs before any resolution. The fix is to pass a name, as in `service create my-service`. Meta: none.

### SERVICE.NO_PREVIOUS_VERSION [#SERVICE.NO_PREVIOUS_VERSION]

`service version rollback` without `--to` found no earlier version to switch back to — the service has no versions at all, or every version is the live one. The fix is to deploy a second version first, or pass `--to <version-id>` for a specific version. Meta: none.

### SERVICE.NO_VERSIONS [#SERVICE.NO_VERSIONS]

The resolved service has no usable version for the command — raised by `service open` when the service has no versions, by `service logs` when it has no live version, and by `service domain add` when the API answers 422 because the production service has no promoted version that can receive a custom domain. The fix on the domain path is to promote a version on the production branch first, then add the domain again. Meta: `status`, `apiCode`, `hint` (domain-add path only; otherwise none).

### SERVICE.SELECTION_INVALID [#SERVICE.SELECTION_INVALID]

The named service could not be found among the resolved project branch's services — the match tries the stable platform id first, then the name. The fix is to pass the id or name of an existing service; the suggested command is `service list`, deliberately not `service version list`, which itself has to resolve a service and would fail the same way. Meta: none.

### SERVICE.TARGET_REQUIRED [#SERVICE.TARGET_REQUIRED]

A service command that acts on an existing service was run without naming one; service commands act only on an explicitly named target — nothing is inferred, remembered, or prompted for. The fix is to pass the service id or name as the first argument, with `service list` to find one. Meta: none.

### SERVICE.TIMEOUT_INVALID [#SERVICE.TIMEOUT_INVALID]

The `--timeout` value passed to `service domain wait` is not a duration the parser accepts (`0`, or an integer with `ms`/`s`/`m`/`h`, such as `30s` or `15m`). Meta: none.

### SERVICE.VERSION_ALREADY_LIVE [#SERVICE.VERSION_ALREADY_LIVE]

Not an error: a warn-severity diagnostic attached by `service version promote` and `service version rollback` when the selected version is already live for the service — the command skips the promote call, still reports the result, and exits 0. Meta: none.

### SERVICE.VERSION_ALREADY_RUNNING [#SERVICE.VERSION_ALREADY_RUNNING]

Not an error: a warn-severity diagnostic attached by `service version start` when the selected version already reports `running` status — the start call is skipped, the result carries `alreadyInState: true`, and the run exits 0. Meta: none.

### SERVICE.VERSION_ALREADY_STOPPED [#SERVICE.VERSION_ALREADY_STOPPED]

Not an error: a warn-severity diagnostic attached by `service version stop` when the selected version already reports `stopped` status — the stop call is skipped, the result carries `alreadyInState: true`, and the run exits 0. Meta: none.

### SERVICE.VERSION_DETACHED [#SERVICE.VERSION_DETACHED]

A version was resolved by its globally-unique id but the REST API returned it without an owning service, so there is nothing to report or act on it as. The next action shows the version with `service version show`. Meta: none.

### SERVICE.VERSION_NOT_FOUND [#SERVICE.VERSION_NOT_FOUND]

The requested service version does not exist or is not available — raised when resolving a version by its globally-unique id finds nothing (including a 404 from the logs endpoint), and, in the "for service" variant used by rollback and logs `--version-id`, when the id exists but does not belong to the resolved service. The fix is to pick an id from `service version list`. Meta: none.

### SERVICE.WORKSPACE_REQUIRED [#SERVICE.WORKSPACE_REQUIRED]

A service command ran without a credential that names a workspace — either no authenticated session, or an environment token whose claims carry no workspace, which cannot scope these commands and is treated the same as having no credential. The fix is `auth login`. Meta: none.

## SKILLS [#skills]

### SKILLS.CONFIG_INVALID [#SKILLS.CONFIG_INVALID]

An error diagnostic from validating the `skills` section of `prisma.config.ts`, surfaced by the commands that consume it (`init`, `skills sync`, `skills list`): the section is not an object, `skills.check` is not a boolean, `skills.agents` is not an array of strings, or an agent name is one this CLI does not know. Each variant's nextAction says what to write instead; code that reads the config outside a command handler (the staleness check, the post-login tip) treats an invalid config as absent and falls back to the default agent set rather than silencing the check. Meta: none.

### SKILLS.UNMANAGED_DIRECTORY [#SKILLS.UNMANAGED_DIRECTORY]

A warn diagnostic from the skills sync (`skills sync`, and the sync step of `init`): a target agent skill directory already holds a skill this CLI does not manage, so sync left it untouched instead of installing the packaged skill there. The nextAction is to move or remove the unmanaged directory and rerun `skills sync`. Meta: none.

### SKILLS.VERSION_CONFLICT [#SKILLS.VERSION_CONFLICT]

A warn diagnostic from the skills sync (`skills sync`, and the sync step of `init`): workspace members install different versions of the same skill-bearing Prisma package, so the skills for the highest version were installed and the members pinning a lower version get a skill describing a version they did not install. The nextAction is to pin one version of the package across the workspace. Meta: none.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# feedback (/docs/cli/feedback)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Send feedback to the Prisma CLI team.

Location: CLI > feedback

`feedback` sends feedback to the Prisma CLI team, straight from the terminal.

## Usage [#usage]

  

#### bun

```bash
bunx prisma feedback "The service logs command saved my afternoon"
```

#### pnpm

```bash
pnpm prisma feedback "The service logs command saved my afternoon"
```

#### yarn

```bash
yarn prisma feedback "The service logs command saved my afternoon"
```

#### npm

```bash
npx prisma feedback "The service logs command saved my afternoon"
```

The message can be up to 4000 characters. Feedback is anonymous unless you add `--email <address>` so the team can reply.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# git (/docs/cli/git)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Connect a GitHub repository for push-to-deploy.

Location: CLI > git

Use `git` commands to manage the GitHub repository connection. Connecting enables the OIDC credential exchange for GitHub Actions deploys and the branch lifecycle automation. See [GitHub integration](https://www.prisma.io/docs/compute/github) and [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

## Usage [#usage]

  

#### bun

```bash
bunx prisma git connect
```

#### pnpm

```bash
pnpm prisma git connect
```

#### yarn

```bash
yarn prisma git connect
```

#### npm

```bash
npx prisma git connect
```

Run it from a [linked](https://www.prisma.io/docs/cli/project) project directory. The command needs an interactive terminal: it opens the browser to install the GitHub App when needed and waits for the install. With `--no-interactive` it fails with `CLI.INTERACTION_REQUIRED`. Connecting from the CLI does not add a deploy workflow to the repository. [Add it yourself](https://www.prisma.io/docs/compute/deploy-on-push#4-add-the-deploy-workflow), or connect through the [Console](https://pris.ly/pdp), which opens a pull request with the workflow.

## Commands [#commands]

| Command                 | Description                                                                                     |
| ----------------------- | ----------------------------------------------------------------------------------------------- |
| `git connect [git-url]` | Connect the linked project to a GitHub repository. Starts the GitHub App install flow if needed |
| `git disconnect`        | Stop the credential exchange and branch automation. Keeps the project and existing branches     |

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# Global flags (/docs/cli/global-flags)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Flags accepted by every command in the unified Prisma CLI.

Location: CLI > Global flags

All commands in the unified Prisma CLI accept these flags.

| Flag                                 | What it does                                                                                                                                      |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--json`                             | Print machine-readable output (shorthand for `--format json`). Use this in CI and scripts.                                                        |
| `--format <mode>`                    | Output format: `human`, `json`, or `markdown`.                                                                                                    |
| `--log-level <level>`                | Commentary verbosity: `error`, `warn`, `info`, or `verbose`.                                                                                      |
| `-q`, `--quiet`                      | Suppress nonessential output (shorthand for `--log-level error`).                                                                                 |
| `-v`, `--verbose`                    | Print more detail (shorthand for `--log-level verbose`).                                                                                          |
| `--color` / `--no-color`             | Force colored output on or off.                                                                                                                   |
| `--interactive` / `--no-interactive` | Force prompts on or off.                                                                                                                          |
| `-y`, `--yes`                        | Accept prompt defaults without asking.                                                                                                            |
| `--confirm <token>`                  | Grant a consent prompt in advance by giving its token, so the command does not ask (repeatable). Works in scripts and in an interactive terminal. |
| `--config <path>`                    | Read this config file instead of `./prisma.config.ts`.                                                                                            |
| `-h`, `--help`                       | Print the manual for a command: what it does, its options, a workflow where one applies, and examples.                                            |
| `--version`                          | Print the CLI version and exit.                                                                                                                   |

## Output formats [#output-formats]

Without `--format`, a terminal gets `human` output and a pipe gets `json`. `markdown` is never chosen for you; pass `--format markdown` to get it.

`markdown` is for AI agents that read command output as text rather than parsing JSON. It prints the same content as `human`, as plain Markdown: a summary line, `label: value` lines, pipe tables, bullet lists, and fenced code, followed by a `### Next` section with the suggested next commands and a `### Diagnostics` section with any findings. There is no padding, alignment, or color, and no JSON envelope. Everything the command produces, including errors, help, `--version`, and progress, goes to stdout, so an agent reads one stream.

Use `npx prisma <command> --help` when you need the exact command help from the installed version.

The output modes and the JSON envelope these flags select are documented on [Configuration](https://www.prisma.io/docs/cli/configuration#output-modes).

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# Overview (/docs/cli)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma CLI reference

Location: Overview

Prisma ORM ships with a unified Prisma CLI. One binary contains the ORM commands and the platform commands for [Prisma Composer](https://www.prisma.io/docs/composer), [Prisma Compute](https://www.prisma.io/docs/compute), Prisma Postgres, and object-store buckets.

> [!NOTE]
> Prisma ORM 7 users
> 
> Prisma ORM 8 is the current release, as a release candidate. Prisma ORM 7 remains fully supported; its docs live at [/orm/v7](https://www.prisma.io/docs/orm/v7) and its setup paths at [/v7/getting-started](https://www.prisma.io/docs/v7/getting-started).
> 
> For what release candidate means, when the final release is expected, and how to stay on version 7, see [Release status](https://www.prisma.io/docs/orm/release-status). For the Prisma ORM 8 name of every Prisma ORM 7 API, see [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7).

The Prisma ORM CLI ships in the `prisma` package. Run it without installing:

  

#### bun

```bash
bunx prisma --help
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma --help
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma --help
yarn prisma contract emit
```

#### npm

```bash
npx prisma --help
npx prisma contract emit
```

With `prisma` installed in your project, these commands become plain `prisma contract emit` and so on.

For a full app scaffold, use a [Prisma ORM quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql). That path creates the project files and package scripts for you. This CLI reference is for the lower-level commands those scripts call.

## Platform commands [#platform-commands]

The platform commands manage the services, databases, and buckets your app runs on. With [`deploy`](https://www.prisma.io/docs/cli/deploy) and [`dev`](https://www.prisma.io/docs/cli/dev) you deploy a [Prisma Composer](https://www.prisma.io/docs/composer) app to [Prisma Compute](https://www.prisma.io/docs/compute) and run it locally; with [`service`](https://www.prisma.io/docs/cli/service) and [`git`](https://www.prisma.io/docs/cli/git) you manage services, their versions, logs, and domains, and the repository connection. With [`postgres`](https://www.prisma.io/docs/cli/postgres) you spin up and manage [Prisma Postgres](https://www.prisma.io/docs/postgres) databases. With [`bucket`](https://www.prisma.io/docs/cli/bucket) you create blob-storage buckets and their access keys. [`auth`](https://www.prisma.io/docs/cli/auth), [`project`](https://www.prisma.io/docs/cli/project), and [`branch`](https://www.prisma.io/docs/cli/branch) handle the account, project, and branch plumbing around them. Each command group has its own page in this section. Deployments are created by `deploy`, by a git push once you [set up deploy on push](https://www.prisma.io/docs/compute/deploy-on-push), or from the [Console](https://pris.ly/pdp), and each deploy produces a service **version**.

## Common workflows [#common-workflows]

There are two main entry points. Platform users deploy apps, create databases, and provision buckets with the [platform commands](#platform-commands). ORM users manage their schema, contracts, and migrations with the ORM and migration commands.

### Deploy an app [#deploy-an-app]

Sign in, then build and deploy a [Prisma Composer](https://www.prisma.io/docs/composer) app. `deploy` creates the project on its first run, and a new project needs a region, set in the deploy config or as `PRISMA_REGION`; see [`deploy`](https://www.prisma.io/docs/cli/deploy).

  

#### bun

```bash
bunx prisma auth login
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm prisma auth login
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn prisma auth login
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npx prisma auth login
npm run build
npx prisma deploy module.ts
```

To deploy on every push, also connect the repository with [`git connect`](https://www.prisma.io/docs/cli/git) and add the deploy workflow; see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

Follow a deploy with [`service logs`](https://www.prisma.io/docs/cli/service) and manage the result with the [`service` commands](https://www.prisma.io/docs/cli/service).

### Create a database [#create-a-database]

  

#### bun

```bash
bunx prisma postgres create mydb
bunx prisma postgres connection create mydb
```

#### pnpm

```bash
pnpm prisma postgres create mydb
pnpm prisma postgres connection create mydb
```

#### yarn

```bash
yarn prisma postgres create mydb
yarn prisma postgres connection create mydb
```

#### npm

```bash
npx prisma postgres create mydb
npx prisma postgres connection create mydb
```

`postgres create` prints a one-time connection URL; `postgres connection create` mints another when you need one. See [`postgres`](https://www.prisma.io/docs/cli/postgres).

### Create a bucket [#create-a-bucket]

  

#### bun

```bash
bunx prisma bucket create --name my-bucket
bunx prisma bucket key create <bucket-id>
```

#### pnpm

```bash
pnpm prisma bucket create --name my-bucket
pnpm prisma bucket key create <bucket-id>
```

#### yarn

```bash
yarn prisma bucket create --name my-bucket
yarn prisma bucket key create <bucket-id>
```

#### npm

```bash
npx prisma bucket create --name my-bucket
npx prisma bucket key create <bucket-id>
```

`bucket key create` prints the key's one-time credentials. See [`bucket`](https://www.prisma.io/docs/cli/bucket).

### Start in an existing project [#start-in-an-existing-project]

  

#### bun

```bash
bunx prisma@latest orm init --target postgres --authoring psl
bunx prisma contract emit
bunx prisma db init --db "$DATABASE_URL" --advance-ref db
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --target postgres --authoring psl
pnpm prisma contract emit
pnpm prisma db init --db "$DATABASE_URL" --advance-ref db
```

#### yarn

```bash
yarn dlx prisma@latest orm init --target postgres --authoring psl
yarn prisma contract emit
yarn prisma db init --db "$DATABASE_URL" --advance-ref db
```

#### npm

```bash
npx prisma@latest orm init --target postgres --authoring psl
npx prisma contract emit
npx prisma db init --db "$DATABASE_URL" --advance-ref db
```

`db init` and `db update` advance the [ref](https://www.prisma.io/docs/cli/migration-ref) named `db` on their own when you leave `--db` off and let the connection come from `prisma.config.ts`. Passing `--db` suppresses that, so add `--advance-ref db` to keep the ref current. Without it, `--db` leaves any existing `db` ref where it was, and a later [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) starts from that stale contract; if the ref was never created, `migration plan` refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN` as soon as migrations exist on disk.

### Adopt an existing database [#adopt-an-existing-database]

  

#### bun

```bash
bunx prisma contract infer --db "$DATABASE_URL" --output ./prisma/contract.prisma
bunx prisma contract emit
bunx prisma db sign --db "$DATABASE_URL"
bunx prisma db verify --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma contract infer --db "$DATABASE_URL" --output ./prisma/contract.prisma
pnpm prisma contract emit
pnpm prisma db sign --db "$DATABASE_URL"
pnpm prisma db verify --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma contract infer --db "$DATABASE_URL" --output ./prisma/contract.prisma
yarn prisma contract emit
yarn prisma db sign --db "$DATABASE_URL"
yarn prisma db verify --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma contract infer --db "$DATABASE_URL" --output ./prisma/contract.prisma
npx prisma contract emit
npx prisma db sign --db "$DATABASE_URL"
npx prisma db verify --db "$DATABASE_URL"
```

`db sign` also sets the `db` ref to the signed contract, so the next `migration plan` starts from the database you adopted. Pass `--no-advance-ref` to sign without moving a ref.

### Use checked-in migrations [#use-checked-in-migrations]

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_users
bunx prisma migration status --db "$DATABASE_URL"
bunx prisma db migrate --db "$DATABASE_URL" --advance-ref db
bunx prisma db verify --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_users
pnpm prisma migration status --db "$DATABASE_URL"
pnpm prisma db migrate --db "$DATABASE_URL" --advance-ref db
pnpm prisma db verify --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_users
yarn prisma migration status --db "$DATABASE_URL"
yarn prisma db migrate --db "$DATABASE_URL" --advance-ref db
yarn prisma db verify --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_users
npx prisma migration status --db "$DATABASE_URL"
npx prisma db migrate --db "$DATABASE_URL" --advance-ref db
npx prisma db verify --db "$DATABASE_URL"
```

Plain `db migrate` never moves a ref; `--advance-ref db` is what keeps the next `migration plan` incremental. Leave it off in deploy and CI applies, where a repository ref should not move.

## Agent skills [#agent-skills]

Prisma packages ship [agent skills](https://www.prisma.io/docs/ai/tools/skills): instructions that teach AI coding agents the installed version's commands and APIs. [`init`](https://www.prisma.io/docs/cli/init) prepares a repository once, and [`skills sync`](https://www.prisma.io/docs/cli/skills) keeps the installed copies matching your package versions.

  

#### bun

```bash
bunx --bun prisma@latest init
bunx prisma skills sync
```

#### pnpm

```bash
pnpm dlx prisma@latest init
pnpm prisma skills sync
```

#### yarn

```bash
yarn dlx prisma@latest init
yarn prisma skills sync
```

#### npm

```bash
npx prisma@latest init
npx prisma skills sync
```

## Other commands [#other-commands]

A few commands ship without dedicated pages yet. `contract format` formats your PSL contract source in place, including a Prisma ORM 7 schema read through `prisma7Schema`, and `lsp` starts the Prisma ORM language server (spawned by editors, not run interactively; see [Editor support](https://www.prisma.io/docs/orm/contract-authoring/editor-support)). The `migration` group also has read-only inspection commands: `migration list` (on-disk migrations per contract space; `--space`, `--ascii`, `--legend`), `migration log` (executed history from the database ledger; `--db`, `--utc`, `--ascii`), `migration graph` (graph topology; `--space`, `--dot` for Graphviz output, `--ascii`, `--legend`), and `migration check [target]` (artifact and graph integrity; `--space`). Run any of them with `--help` for the details.

## Global flags [#global-flags]

Every command accepts the same set of output, prompt, and config flags. They are documented on [Global flags](https://www.prisma.io/docs/cli/global-flags).

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# init (/docs/cli/init)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prepare a repository for Prisma development.

Location: CLI > init

`init` prepares the current directory for Prisma development. It runs locally and calls no platform API. It does not scaffold the ORM: use [`orm init`](https://www.prisma.io/docs/cli/orm-init) to add the Prisma ORM config, contract, and runtime files to a project.

`init` does three things:

1. Adds a `postinstall` script to `package.json` (`prisma skills sync || exit 0`), so the [Prisma agent skills](https://www.prisma.io/docs/cli/skills) resync on every install and upgrade.
2. Scaffolds a `prisma.config.ts` recording which agents to install skills for, in the [`skills` config section](https://www.prisma.io/docs/cli/configuration#agent-skills).
3. Runs [`skills sync`](https://www.prisma.io/docs/cli/skills) once.

It never prompts, always exits 0, and is safe to rerun: each step reports what is already done. A `prisma.config.ts` or `postinstall` script that already exists is never edited. If `package.json` already has a different `postinstall` script, `init` reports it and tells you what to append instead of chaining or replacing it.

## Usage [#usage]

  

#### bun

```bash
bunx --bun prisma@latest init
```

#### pnpm

```bash
pnpm dlx prisma@latest init
```

#### yarn

```bash
yarn dlx prisma@latest init
```

#### npm

```bash
npx prisma@latest init
```

## Options [#options]

| Option                             | What it does                                                                                                                                                       |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--skills <agents>`                | Agents to install skills for, comma-separated: `claude`, `cursor`, `agents`, `devin`. Pass `none` to record that no agent skills are wanted. Default: all of them. |
| `--postinstall`/`--no-postinstall` | Add the skills-sync `postinstall` hook. `--no-postinstall` skips that step.                                                                                        |

## Examples [#examples]

  

#### bun

```bash
bunx --bun prisma@latest init
bunx --bun prisma@latest init --skills=claude,cursor
bunx --bun prisma@latest init --skills=none
bunx --bun prisma@latest init --no-postinstall
```

#### pnpm

```bash
pnpm dlx prisma@latest init
pnpm dlx prisma@latest init --skills=claude,cursor
pnpm dlx prisma@latest init --skills=none
pnpm dlx prisma@latest init --no-postinstall
```

#### yarn

```bash
yarn dlx prisma@latest init
yarn dlx prisma@latest init --skills=claude,cursor
yarn dlx prisma@latest init --skills=none
yarn dlx prisma@latest init --no-postinstall
```

#### npm

```bash
npx prisma@latest init
npx prisma@latest init --skills=claude,cursor
npx prisma@latest init --skills=none
npx prisma@latest init --no-postinstall
```

## The scaffolded config [#the-scaffolded-config]

`init` writes a minimal `prisma.config.ts` when none exists:

```typescript title="prisma.config.ts"
import { definePrismaConfig } from "prisma/config";

export default definePrismaConfig({
  skills: {
    agents: ["claude", "cursor", "agents", "devin"],
  },
});
```

The `prisma/config` import resolves from your project's `node_modules`, so add `prisma` as a dev dependency before running other commands against this file. See [Configuration](https://www.prisma.io/docs/cli/configuration).

Only `init` writes the `postinstall` hook. No other command edits `package.json`; [`skills sync`](https://www.prisma.io/docs/cli/skills) itself never touches it.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# migration new (/docs/cli/migration-new)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Scaffold a Prisma ORM migration package for manual authoring.

Location: CLI > migration new

`migration new` creates a migration package with a `migration.ts` file for manual authoring.

Use it when the generated plan is not enough and you want to write the migration operations yourself. The command is offline. It does not consult the database.

## Usage [#usage]

  

#### bun

```bash
bunx prisma migration new --name split-name
```

#### pnpm

```bash
pnpm prisma migration new --name split-name
```

#### yarn

```bash
yarn prisma migration new --name split-name
```

#### npm

```bash
npx prisma migration new --name split-name
```

## Options [#options]

| Option            | What it does                                                                                                                                                                                     |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--name <slug>`   | Sets the migration directory name suffix.                                                                                                                                                        |
| `--from <hash>`   | Starts from the contract state an existing migration ends at: the `to` hash in that migration's `migration.json`, or a unique prefix of it. Without it, see [Where it starts](#where-it-starts). |
| `--config <path>` | Read this config file instead of `./prisma.config.ts`.                                                                                                                                           |
| `--json`          | Prints a machine-readable result.                                                                                                                                                                |

`migration new --from` takes only a hash or a unique prefix of one. Unlike [`migration plan --from`](https://www.prisma.io/docs/cli/migration-plan#options), it does not accept a migration directory name or a ref name. It refuses `--from` when `migrations/app/` has no migrations, and refuses a prefix that matches more than one migration. Run `npx prisma migration list` to see the hashes of your migrations.

## Where it starts [#where-it-starts]

Without `--from`, `migration new` picks its starting point the way [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) does. The result depends on whether the [`db` ref](https://www.prisma.io/docs/cli/migration-ref#the-db-ref) exists and whether `migrations/app/` has migrations. The `db` ref is the file `migrations/app/refs/db.json`, which records the contract state you expect your local database to match. `migrations/app/` is the folder for your application's own migrations, and each extension package that ships migrations has its own folder beside it.

* When the `db` ref exists and `migrations/app/` has migrations, it starts from the `db` ref.
* When there are no migrations and no `db` ref, it starts from an empty database.
* When migrations exist but there is no `db` ref, it refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN`. Pass `--from` with the `to` hash of the migration to build on, or point the `db` ref at the state your database is on. To find that state, run `npx prisma migration status --db "$DATABASE_URL" --json`: the `currentContract` of the `app` entry in `result.spaces` is the hash of the contract state your database matches. Then run `npx prisma migration ref set db <contract>`, where `<contract>` is that hash or the directory name of the migration that ends at it.
* When the `db` ref exists but there are no migrations, it refuses with `MIGRATION.HASH_NOT_IN_GRAPH`, because there is no migration yet that ends at the state the `db` ref names. Run `migration plan` first. It writes a [baseline migration](https://www.prisma.io/docs/orm/migrations/the-migration-graph#baselines), a migration from an empty database to that state, and then `migration new` can start from it. `migration plan` reads that state from the copy saved under `migrations/snapshots/` by the command that set the `db` ref, and if the copy is missing, it fails and asks you to restore `migrations/snapshots/` from version control.

Before `8.0.0-rc.12`, `migration new` started from the newest migration. Scripts that relied on that should pass `--from` with the newest migration's `to` hash.

## Examples [#examples]

  

#### bun

```bash
bunx prisma migration new --name split-name
bunx prisma migration new --name custom-fk --from abc123
```

#### pnpm

```bash
pnpm prisma migration new --name split-name
pnpm prisma migration new --name custom-fk --from abc123
```

#### yarn

```bash
yarn prisma migration new --name split-name
yarn prisma migration new --name custom-fk --from abc123
```

#### npm

```bash
npx prisma migration new --name split-name
npx prisma migration new --name custom-fk --from abc123
```

## After scaffolding [#after-scaffolding]

Write the migration body in `migration.ts`, then run the file with Node so it emits `ops.json` and attests the package:

```bash
node migration.ts
```

Inspect the result:

  

#### bun

```bash
bunx prisma migration show <migration-dir>
```

#### pnpm

```bash
pnpm prisma migration show <migration-dir>
```

#### yarn

```bash
yarn prisma migration show <migration-dir>
```

#### npm

```bash
npx prisma migration show <migration-dir>
```

Apply the migration only after review:

  

#### bun

```bash
bunx prisma db migrate --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db migrate --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma db migrate --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma db migrate --db "$DATABASE_URL"
```

Manual migrations should still end at a contract state that matches the emitted contract.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# migration plan (/docs/cli/migration-plan)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Plan an on-disk migration from Prisma ORM contract changes.

Location: CLI > migration plan

`migration plan` compares the emitted contract against a starting contract and produces a new migration package with the required operations.

The starting contract is whatever `--from` names, or the [ref](https://www.prisma.io/docs/cli/migration-ref) named `db` when `--from` is absent.

With neither, what happens depends on the migrations already on disk:

* **`migrations/app/` is empty.** The plan starts from an empty database and contains the full `CREATE` operations for the whole contract. This is the first migration in a new project. The command says so under its summary (`No db ref set — planning from an empty database`), and `--json` output carries `fromDefaulted: true`, so a plan that recreates a database you already have is easy to spot. If a database already exists, run `db init`, `db update`, or `db sign` first.
* **Migrations already exist.** The command refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN` rather than write a full-create package that no real database could apply. The error names the three exits: `migration ref set db <contract>` to point the ref at the state your database is on, `--from <ref>` to name the origin for this one plan, or `--from @empty` to plan from an empty database deliberately.

Keep the `db` ref current and you never see the refusal. [`db init`](https://www.prisma.io/docs/cli/db-init) and [`db update`](https://www.prisma.io/docs/cli/db-update) advance it for you when you run them without `--db`; with `--db` you have to add `--advance-ref db`. [`db sign`](https://www.prisma.io/docs/cli/db-sign) advances it whenever it signs, `--db` or not. [`db migrate`](https://www.prisma.io/docs/cli/db-migrate) advances nothing unless you pass `--advance-ref db`.

### The automatic baseline [#the-automatic-baseline]

Say `migrations/app/` has no migrations yet, the `db` ref is set, and `migrations/snapshots/` holds a copy of the contract the ref points at. Then `migration plan` writes a baseline: a migration from an empty database to the ref's contract. If your emitted contract has changed since then, the same run also writes a second migration with those changes. Expect one or two new directories in `git status`.

`db migrate` never applies the baseline to a database that already records which contract it matches, such as one you ran `db sign` on. It applies only the migrations after the contract that database records.

The baseline only creates things, because it is planned from an empty database, so it never removes data. The second migration can remove data. `migration plan` writes it without asking, and the command's output marks each destructive operation in it and warns that it may cause data loss. Review that migration before you apply it.

If a migration already starts from the contract the `db` ref points at, `migration plan` writes a second migration that starts from the same contract, so the [migration history](https://www.prisma.io/docs/orm/migrations/the-migration-graph) splits into two branches. This happens, for example, after `db migrate` without `--advance-ref db`, which applies migrations but leaves the `db` ref where it was. `migration plan` still writes the migration and prints a warning. A database that has already run the existing migration then has no migration leading to your new contract, so `db migrate` on that database fails with `MIGRATION.PATH_UNREACHABLE`. To build on the newest migration instead, delete the directory this run wrote and plan again with `--from` set to the newest migration's directory name.

The command is offline. It does not need a database connection.

## Usage [#usage]

  

#### bun

```bash
bunx prisma migration plan --name add_users_table
```

#### pnpm

```bash
pnpm prisma migration plan --name add_users_table
```

#### yarn

```bash
yarn prisma migration plan --name add_users_table
```

#### npm

```bash
npx prisma migration plan --name add_users_table
```

## Options [#options]

| Option              | What it does                                                                                                                                                                                                                          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--name <slug>`     | Sets the migration directory name suffix.                                                                                                                                                                                             |
| `--from <contract>` | Uses a specific starting contract reference (hash, prefix, ref name, migration directory name, `<dir>^`, `./path`, or `@empty`) instead of the `db` ref. `migration plan` is offline, so `@db` and `@contract` are not accepted here. |
| `--to <contract>`   | Sets the destination contract reference. Defaults to the emitted contract. Same grammar as `--from`, except that `@empty` is refused as a destination.                                                                                |
| `--config <path>`   | Read this config file instead of `./prisma.config.ts`.                                                                                                                                                                                |
| `--json`            | Prints a machine-readable result.                                                                                                                                                                                                     |

## Recommended flow [#recommended-flow]

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_users_table
bunx prisma migration show <migration-dir>
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_users_table
pnpm prisma migration show <migration-dir>
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_users_table
yarn prisma migration show <migration-dir>
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_users_table
npx prisma migration show <migration-dir>
```

Review the generated migration package before applying it with [`db migrate`](https://www.prisma.io/docs/cli/db-migrate).

## Planning a rollback [#planning-a-rollback]

Because `--to` accepts `<dir>^` (the source contract of a migration), you can plan a migration that walks back a change:

  

#### bun

```bash
bunx prisma migration plan --to <migration-dir>^ --name rollback
```

#### pnpm

```bash
pnpm prisma migration plan --to <migration-dir>^ --name rollback
```

#### yarn

```bash
yarn prisma migration plan --to <migration-dir>^ --name rollback
```

#### npm

```bash
npx prisma migration plan --to <migration-dir>^ --name rollback
```

## When to use migration plan [#when-to-use-migration-plan]

Use `migration plan` when your team wants database changes reviewed in version control. For local prototypes where review is not needed, [`db update`](https://www.prisma.io/docs/cli/db-update) is usually faster.

If the generated migration is not the migration you want, use [`migration new`](https://www.prisma.io/docs/cli/migration-new) and author the migration manually.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# migration ref (/docs/cli/migration-ref)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Manage named Prisma ORM refs that point at contracts.

Location: CLI > migration ref

Use `migration ref` commands to manage named refs stored with your migration history. A ref maps a logical environment name, such as `staging` or `production`, to a contract hash. Other commands can then target that environment by name: [`db migrate --to production`](https://www.prisma.io/docs/cli/db-migrate), [`db update --to production`](https://www.prisma.io/docs/cli/db-update), or [`db sign production`](https://www.prisma.io/docs/cli/db-sign).

Refs live on disk as `migrations/app/refs/<name>.json`, so they are versioned with your migrations. The commands are offline. The contract a ref points at must already be part of the on-disk migration graph, which is why `migration ref set` does not accept `@db`: that token stands for the live database's marker, and the offline commands never read one.

## The db ref [#the-db-ref]

The `db` ref has a special meaning: it records the contract state you expect your local database to match. When you run [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) without `--from`, Prisma ORM assumes you mean from the `db` ref, so as long as the ref is kept up to date, each plan contains only your latest change.

The `db` ref is updated automatically in the following situations:

* [`db init`](https://www.prisma.io/docs/cli/db-init) and [`db update`](https://www.prisma.io/docs/cli/db-update) update it when you run them without `--db`, so that the connection comes from `prisma.config.ts`. With `--db`, they leave it alone unless you also pass `--advance-ref db`.
* [`db sign`](https://www.prisma.io/docs/cli/db-sign) updates it after a successful signature, with or without `--db`. `--no-advance-ref` turns that off.
* [`db migrate --advance-ref db`](https://www.prisma.io/docs/cli/db-migrate) updates it after an apply. Plain `db migrate` never touches it, on purpose: a deploy or CI run should not change a file in your repository.

You can also set it by hand with `migration ref set db <contract>`.

## Usage [#usage]

  

#### bun

```bash
bunx prisma migration ref set production 4cb4256
bunx prisma migration ref list
bunx prisma migration ref delete production
```

#### pnpm

```bash
pnpm prisma migration ref set production 4cb4256
pnpm prisma migration ref list
pnpm prisma migration ref delete production
```

#### yarn

```bash
yarn prisma migration ref set production 4cb4256
yarn prisma migration ref list
yarn prisma migration ref delete production
```

#### npm

```bash
npx prisma migration ref set production 4cb4256
npx prisma migration ref list
npx prisma migration ref delete production
```

## Subcommands [#subcommands]

| Subcommand              | What it does                                                                                                                                                  |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `set <name> <contract>` | Points a ref at a contract. The contract is a hash or prefix, another ref name, a migration directory name, or `<dir>^` for that migration's source contract. |
| `list`                  | Lists every ref with the contract hash it points at and the invariants recorded against it.                                                                   |
| `delete <name>`         | Deletes a ref. The contract it pointed at is untouched.                                                                                                       |

## Example workflow [#example-workflow]

  

#### bun

```bash
bunx prisma migration ref set production 20260101T1000_add_user
bunx prisma migration status --db "$DATABASE_URL" --to production
bunx prisma db migrate --db "$DATABASE_URL" --to production
```

#### pnpm

```bash
pnpm prisma migration ref set production 20260101T1000_add_user
pnpm prisma migration status --db "$DATABASE_URL" --to production
pnpm prisma db migrate --db "$DATABASE_URL" --to production
```

#### yarn

```bash
yarn prisma migration ref set production 20260101T1000_add_user
yarn prisma migration status --db "$DATABASE_URL" --to production
yarn prisma db migrate --db "$DATABASE_URL" --to production
```

#### npm

```bash
npx prisma migration ref set production 20260101T1000_add_user
npx prisma migration status --db "$DATABASE_URL" --to production
npx prisma db migrate --db "$DATABASE_URL" --to production
```

Use refs when you want to name the contract state an environment should match, instead of always applying up to the latest migration on disk. If you pass `--advance-ref <name>` to a command that changes the database, that command also points the ref at the state it applied, once it succeeds.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# migration show (/docs/cli/migration-show)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Inspect a Prisma ORM migration package.

Location: CLI > migration show

`migration show` displays the operations, statement preview, and metadata for one migration package.

Use this command during review before applying a migration package. The command is offline. It does not consult the database.

## Usage [#usage]

  

#### bun

```bash
bunx prisma migration show <target>
```

#### pnpm

```bash
pnpm prisma migration show <target>
```

#### yarn

```bash
yarn prisma migration show <target>
```

#### npm

```bash
npx prisma migration show <target>
```

## Options [#options]

| Argument or option | What it does                                                                         |
| ------------------ | ------------------------------------------------------------------------------------ |
| `<target>`         | The migration to inspect: a directory name, a hash or hash prefix, a ref, or a path. |
| `--config <path>`  | Read this config file instead of `./prisma.config.ts`.                               |
| `--json`           | Prints a machine-readable result.                                                    |

## Examples [#examples]

  

#### bun

```bash
bunx prisma migration show 20260101_100000_add_user
bunx prisma migration show a1b2c3
bunx prisma migration show migrations/app/20260101_100000_add_user
bunx prisma migration show 20260101_100000_add_user --json
```

#### pnpm

```bash
pnpm prisma migration show 20260101_100000_add_user
pnpm prisma migration show a1b2c3
pnpm prisma migration show migrations/app/20260101_100000_add_user
pnpm prisma migration show 20260101_100000_add_user --json
```

#### yarn

```bash
yarn prisma migration show 20260101_100000_add_user
yarn prisma migration show a1b2c3
yarn prisma migration show migrations/app/20260101_100000_add_user
yarn prisma migration show 20260101_100000_add_user --json
```

#### npm

```bash
npx prisma migration show 20260101_100000_add_user
npx prisma migration show a1b2c3
npx prisma migration show migrations/app/20260101_100000_add_user
npx prisma migration show 20260101_100000_add_user --json
```

## What to check [#what-to-check]

Before applying, review:

* the source and destination contract hashes
* the planned operations
* generated SQL statements or operation payloads
* the migration's metadata

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# migration status (/docs/cli/migration-status)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Show the Prisma ORM migration path and pending status.

Location: CLI > migration status

The database stores a marker, a row that says which version of your contract it currently matches. `migration status` compares that marker with a target version and lists the migrations in between. The target is the contract you last ran `contract emit` on, unless `--to` names another.

Use it before and after [`db migrate`](https://www.prisma.io/docs/cli/db-migrate), and when debugging why an environment is not at the expected contract state.

## Usage [#usage]

  

#### bun

```bash
bunx prisma migration status --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma migration status --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma migration status --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma migration status --db "$DATABASE_URL"
```

## Options [#options]

| Option              | What it does                                                                                                           |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `--db <url>`        | Connects to the database.                                                                                              |
| `--space <id>`      | Narrows output to a single contract space.                                                                             |
| `--to <contract>`   | Sets the target contract reference (hash, prefix, ref name, migration directory name, `<dir>^`, or `./path`).          |
| `--from <contract>` | Sets the origin contract reference. With `--from`, the command computes the path offline and does not need a database. |
| `--legend`          | Prints a key for the tree glyphs and lane colors.                                                                      |
| `--ascii`           | Uses ASCII glyphs (pipe-friendly).                                                                                     |
| `--config <path>`   | Read this config file instead of `./prisma.config.ts`.                                                                 |
| `--json`            | Prints a machine-readable result.                                                                                      |

## Examples [#examples]

  

#### bun

```bash
bunx prisma migration status --db "$DATABASE_URL"
bunx prisma migration status --to production
bunx prisma migration status --from abc123 --to production
bunx prisma migration status --ascii
```

#### pnpm

```bash
pnpm prisma migration status --db "$DATABASE_URL"
pnpm prisma migration status --to production
pnpm prisma migration status --from abc123 --to production
pnpm prisma migration status --ascii
```

#### yarn

```bash
yarn prisma migration status --db "$DATABASE_URL"
yarn prisma migration status --to production
yarn prisma migration status --from abc123 --to production
yarn prisma migration status --ascii
```

#### npm

```bash
npx prisma migration status --db "$DATABASE_URL"
npx prisma migration status --to production
npx prisma migration status --from abc123 --to production
npx prisma migration status --ascii
```

## Reading the result [#reading-the-result]

With `--db`, status reads the marker from the database and compares it with the target. With `--from`, it starts from the state you name instead and needs no database.

With `--json`, the command prints one `"kind": "result"` line. Inside its `envelope`:

* `result.summary` is the sentence the human output ends with, such as `Up to date` or a count of pending migrations.
* `result.spaces[].migrations[]` lists each migration on disk with a `status`: `pending` (on the way to the target, not yet applied), `applied` (on the way to the target, already applied), or `null` (not on the way to the target).
* `diagnostics[]`, beside `result` rather than inside it, lists each problem found. Each entry has a `code`, for example `MIGRATION.MARKER_NOT_IN_HISTORY`, a `summary`, and a `severity`, which this command always sets to `warn`.

The exit code is 0 even when `diagnostics` is not empty. A non-zero exit code means the command itself failed, for example with `MIGRATION.REF_NOT_FOUND` when `--to` names a ref that does not exist.

The `migration` group has three more read-only views: `migration graph` draws the chain of migrations, `migration log` lists what has run, and `migration list` lists the migrations on disk. Run each with `--help` for details.

Use [`db verify`](https://www.prisma.io/docs/cli/db-verify) after applying migrations to check the final database shape against the emitted contract.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# orm init (/docs/cli/orm-init)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Initialize Prisma ORM files in a project.

Location: CLI > orm init

`orm init` scaffolds the Prisma ORM config, contract source, and runtime files inside an existing project, installs dependencies, and emits the contract. It gets you from zero to typed queries in one step.

Use a [Prisma ORM quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql) when you want a complete new application template. Use `orm init` when you already have a project and want to add the lower-level Prisma ORM files.

## Usage [#usage]

Run it interactively for a guided setup:

  

#### bun

```bash
bunx prisma@latest orm init
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init
```

#### yarn

```bash
yarn dlx prisma@latest orm init
```

#### npm

```bash
npx prisma@latest orm init
```

Or supply `--target` and `--authoring` for a fully scriptable run (CI, AI coding agents, automation):

  

#### bun

```bash
bunx prisma@latest orm init --yes --target postgres --authoring psl
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### yarn

```bash
yarn dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### npm

```bash
npx prisma@latest orm init --yes --target postgres --authoring psl
```

## Options [#options]

| Option                         | What it does                                                                                                                                                                         |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--target <db>`                | Sets the database target. Use `postgres` or `mongodb`.                                                                                                                               |
| `--authoring <style>`          | Sets the contract authoring style. Use `psl` or `typescript`.                                                                                                                        |
| `--schema-path <path>`         | Sets where the starter contract is written.                                                                                                                                          |
| `--from-prisma7-schema <path>` | Uses the Prisma ORM 7 schema at `<path>` as the contract source instead of writing a starter contract. PostgreSQL only. See [On a Prisma ORM 7 project](#on-a-prisma-orm-7-project). |
| `--write-env`                  | Writes `.env` from `.env.example` (gitignored).                                                                                                                                      |
| `--probe-db`                   | Connects to `DATABASE_URL` once and checks the server version.                                                                                                                       |
| `--strict-probe`               | Treats a failed database probe as fatal.                                                                                                                                             |
| `--skip-install`               | Skips dependency installation and contract emission.                                                                                                                                 |
| `--keep-previous-facade`       | Keeps the previous target package in `package.json` when switching targets.                                                                                                          |

## What it creates [#what-it-creates]

The exact files depend on the target and authoring style, but a Postgres PSL setup normally includes:

* `prisma.config.ts`
* a starter contract file such as `src/prisma/contract.prisma`, whose first line is `// use prisma-8`. Keep that line, because `contract emit` reads only `.prisma` files that start with it.
* emitted contract artifacts after installation runs
* a runtime client file (`src/prisma/db.ts`) that imports `contract.json`
* `.env.example`, `tsconfig.json`, and updated `package.json`
* `prisma-8.md`, a short quick reference for writing your first typed query

The install step adds the target package and `dotenv` to `dependencies`. It adds `prisma@latest`, `@types/node`, and the matching `@prisma/cli-engine` to `devDependencies`.

`orm init` also changes the `module` settings in `tsconfig.json` and can add `"type": "module"` to `package.json`. If your app is CommonJS, read [In a CommonJS project](#in-a-commonjs-project) before you run the app again.

The generated `prisma.config.ts` imports `definePrismaConfig` from `@prisma/cli-engine`, while projects created by `create-prisma` (and the examples in [Configuration](https://www.prisma.io/docs/cli/configuration)) import it from `prisma/config`. Both work; keep the import your project already has when you copy a config example.

## In a CommonJS project [#in-a-commonjs-project]

A CommonJS project is one where your code loads other files with `require`, or where `tsc` compiles your `import` lines to `require` calls. `orm init` changes `package.json` and `tsconfig.json` in ways that stop a CommonJS app from starting. This list says what it changes, and the sections after it say what to change back before you run the app again:

* In `package.json`, `orm init` adds `"type": "module"` when the file has no `"type"` field, and Node.js then loads every `.js` file in the project as an ES module. When the file already declares `"type": "commonjs"`, `orm init` keeps it and prints a warning.
* In `tsconfig.json`, `orm init` sets `"module": "preserve"` and `"moduleResolution": "bundler"` in place of the values you had, and adds `"resolveJsonModule": true`.

What you do next depends on how you run the app.

### You run the app through `tsx` [#you-run-the-app-through-tsx]

If `orm init` added `"type": "module"` to `package.json`, remove that line. Change nothing else. If you also compile with `tsc` for production, follow the next section instead.

### You compile with `tsc` and run the output with `node` [#you-compile-with-tsc-and-run-the-output-with-node]

With the files as `orm init` leaves them, the compiled app does not start: `node` stops with `ERR_MODULE_NOT_FOUND`, or with `SyntaxError: Cannot use import statement outside a module` if your `package.json` declares `"type": "commonjs"`. To keep the app CommonJS, make the following changes. They also work if you run the app through `tsx` while you develop.

1. If `orm init` added `"type": "module"` to `package.json`, remove that line.

2. In `tsconfig.json`, set `module` and `moduleResolution` to `nodenext`, and set `skipLibCheck` to `true`:

   ```json title="tsconfig.json (excerpt)"
   {
     "compilerOptions": {
       "module": "nodenext",
       "moduleResolution": "nodenext",
       "resolveJsonModule": true,
       "skipLibCheck": true
     }
   }
   ```

3. In `src/prisma/db.ts`, remove `with { type: 'json' }` from the line that imports `contract.json`:

   ```typescript title="src/prisma/db.ts (excerpt)"
   import contractJson from './contract.json';
   ```

With `nodenext`, `tsc` still writes CommonJS output, because your `package.json` does not say `"type": "module"`. Your relative imports stay as they are, without file extensions, and `tsc` copies `contract.json` into the output directory beside `db.js`. `prisma contract emit` does not rewrite `db.ts`, so you make that edit once.

Do not restore `"module": "commonjs"` with `"moduleResolution": "node"`, because `tsc` cannot find the Prisma ORM packages with those values.

### You want the app to run as ES modules [#you-want-the-app-to-run-as-es-modules]

Keep `"type": "module"` in `package.json`, or set it if `orm init` kept `"type": "commonjs"`, and leave the scaffolded files as they are. Every file in the project then runs as an ES module, so each file that uses `require`, `module.exports`, or `__dirname` needs rewriting.

## On a Prisma ORM 7 project [#on-a-prisma-orm-7-project]

`orm init` can set up Prisma ORM 8 beside Prisma ORM 7 on PostgreSQL, with Prisma ORM 8 reading your existing `schema.prisma` as its contract source. Pass the schema path:

  

#### bun

```bash title="Terminal"
bunx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
```

#### pnpm

```bash title="Terminal"
pnpm dlx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
```

#### yarn

```bash title="Terminal"
yarn dlx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
```

#### npm

```bash title="Terminal"
npx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
```

A plain `orm init` offers the same setup when it finds a Prisma ORM 7 config, or a `prisma/schema.prisma` with a `datasource` block. The database target comes from the schema's `datasource` provider, and a `--target` that disagrees with it fails with `CLI.INIT_PRISMA7_TARGET_MISMATCH`.

First, `orm init` installs `@prisma/orm-postgres` and `dotenv`, adding them to `package.json` if they are not there yet, and uses the installed package to check that Prisma ORM 8 can read the schema. Apart from that install, it changes nothing until the check passes. A schema it cannot read, for example one with a `view` block, stops the command with `CLI.INIT_PRISMA7_SCHEMA_REFUSED`, which lists each problem with its line and the Prisma ORM 7 edit that removes it, and gives the command that removes the packages it just added.

When the check passes, `orm init` asks you to confirm by typing the name of the directory you run it in. In a script, where nobody can type, pass that name with `--confirm`, and add `--no-interactive` so that any other question takes its default answer. For a project in a directory named `my-app`:

  

#### bun

```bash title="Terminal"
bunx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma --no-interactive --confirm my-app
```

#### pnpm

```bash title="Terminal"
pnpm dlx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma --no-interactive --confirm my-app
```

#### yarn

```bash title="Terminal"
yarn dlx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma --no-interactive --confirm my-app
```

#### npm

```bash title="Terminal"
npx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma --no-interactive --confirm my-app
```

After you confirm, `orm init`:

* renames the Prisma ORM 7 config to `prisma7.config.ts` and points its import at `@prisma/prisma7/config`
* changes every `package.json` script that runs `prisma` to run `prisma7`
* installs the latest Prisma ORM 7 release as `@prisma/prisma7`, next to `prisma@latest`
* writes `prisma.config.ts` with `contract: prisma7Schema("<schema path>")`, plus `src/prisma/db.ts` and `prisma-8.md`

It does not write a starter contract, and it changes nothing in `prisma/` or in the database. Prisma ORM 7 keeps owning the schema and its migrations. From now on, `prisma` runs Prisma ORM 8 and `prisma7` runs Prisma ORM 7, so a Prisma ORM 7 command such as `migrate dev` becomes `npx prisma7 migrate dev`. Your application keeps using the Prisma ORM 7 client until you move its routes, one at a time, to the Prisma ORM 8 client in `src/prisma/db.ts`. If the project still uses a Prisma ORM version before 7, so that your `package.json` lists `@prisma/client` below version 7, `orm init` upgrades `@prisma/client` to version 7, because the Prisma ORM 7 CLI it installs needs a client of the same major version. Run `npx prisma7 generate` afterwards to generate the upgraded client.

To finish, set `DATABASE_URL` and run `npx prisma db sign` once. [`db sign`](https://www.prisma.io/docs/cli/db-sign) checks that the database matches the contract and then writes the marker, a row that records which contract the database matches. The row goes in the table `prisma_contract.marker`, which the first `db sign` creates in a PostgreSQL schema of its own named `prisma_contract`, so your own tables do not change. After each Prisma ORM 7 migration, whether you ran `npx prisma7 migrate dev` or `npx prisma7 migrate deploy`, run `npx prisma contract emit` and then `npx prisma db sign` again. [Configuration](https://www.prisma.io/docs/cli/configuration#use-a-prisma-orm-7-schema) explains `prisma7Schema`, and [the upgrade guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql) covers the rest of the move.

## Examples [#examples]

  

#### bun

```bash
bunx prisma@latest orm init --yes --target postgres --authoring psl
bunx prisma@latest orm init --yes --target mongodb --authoring typescript --json
bunx prisma@latest orm init --skip-install
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl
pnpm dlx prisma@latest orm init --yes --target mongodb --authoring typescript --json
pnpm dlx prisma@latest orm init --skip-install
```

#### yarn

```bash
yarn dlx prisma@latest orm init --yes --target postgres --authoring psl
yarn dlx prisma@latest orm init --yes --target mongodb --authoring typescript --json
yarn dlx prisma@latest orm init --skip-install
```

#### npm

```bash
npx prisma@latest orm init --yes --target postgres --authoring psl
npx prisma@latest orm init --yes --target mongodb --authoring typescript --json
npx prisma@latest orm init --skip-install
```

## After initialization [#after-initialization]

Review the generated files, set `DATABASE_URL`, and emit the contract when you change the schema:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

Then initialize a new database, or verify one that Prisma ORM already set up. On a database that already has your tables, run [`db sign`](https://www.prisma.io/docs/cli/db-sign) instead of `db init`:

  

#### bun

```bash
bunx prisma db init --db "$DATABASE_URL"
bunx prisma db verify --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db init --db "$DATABASE_URL"
pnpm prisma db verify --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma db init --db "$DATABASE_URL"
yarn prisma db verify --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma db init --db "$DATABASE_URL"
npx prisma db verify --db "$DATABASE_URL"
```

The scaffolded `db.ts` starts with `import 'dotenv/config'`, so any script that imports `db` reads `DATABASE_URL` from the `.env` file in the directory you run it from.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# postgres (/docs/cli/postgres)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create and manage Prisma Postgres databases.

Location: CLI > postgres

Use `postgres` commands to manage [Prisma Postgres](https://www.prisma.io/docs/postgres) databases in a project. Most commands let you target a specific project with `--project <id-or-name>` and a branch with `--branch <git-name>`.

## Usage [#usage]

  

#### bun

```bash
bunx prisma postgres list
bunx prisma postgres create mydb
```

#### pnpm

```bash
pnpm prisma postgres list
pnpm prisma postgres create mydb
```

#### yarn

```bash
yarn prisma postgres list
yarn prisma postgres create mydb
```

#### npm

```bash
npx prisma postgres list
npx prisma postgres create mydb
```

## Commands [#commands]

| Command                                      | Description                                                                                         |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `postgres list`                              | List databases                                                                                      |
| `postgres show <database>`                   | Show database metadata without secret values                                                        |
| `postgres create <name>`                     | Create a database and print its one-time connection URL. `--region` sets the Prisma Postgres region |
| `postgres usage <database>`                  | Show usage metrics for a database                                                                   |
| `postgres delete <database>`                 | Permanently delete a database, after exact id confirmation                                          |
| `postgres backup list <database>`            | List platform-created backups for a database                                                        |
| `postgres backup restore <database>`         | Restore from a backup, after exact id confirmation                                                  |
| `postgres connection list <database>`        | List a database's connections                                                                       |
| `postgres connection create <database>`      | Create a database connection and print its one-time connection URL                                  |
| `postgres connection rotate <connection-id>` | Rotate connection credentials and print the new one-time connection URL                             |
| `postgres connection delete <connection-id>` | Permanently delete a database connection, after exact id confirmation                               |

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# project (/docs/cli/project)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create, link, and inspect projects; manage project environment variables.

Location: CLI > project

Use `project` commands to create, link, and inspect projects, and to manage project environment variables.

## Usage [#usage]

  

#### bun

```bash
bunx prisma project list
bunx prisma project show
```

#### pnpm

```bash
pnpm prisma project list
pnpm prisma project show
```

#### yarn

```bash
yarn prisma project list
yarn prisma project show
```

#### npm

```bash
npx prisma project list
npx prisma project show
```

## Commands [#commands]

| Command                         | Description                                                                                                                         |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `project list`                  | List all projects in your workspace                                                                                                 |
| `project show [id-or-name]`     | Show a project (defaults to the one this directory is linked to)                                                                    |
| `project create <name>`         | Create a project and link the directory to it (`--region <region>` sets the Prisma Compute region)                                  |
| `project link [id-or-name]`     | Link the directory to an existing project                                                                                           |
| `project rename <name>`         | Rename the linked project                                                                                                           |
| `project delete <id-or-name>`   | Permanently delete a project, after exact id confirmation                                                                           |
| `project transfer <id-or-name>` | Transfer a project to another workspace (`--to-workspace <id-or-name>` or `--recipient-token <token>`), after exact id confirmation |

When you link a project, Prisma writes the selected workspace and project to `.prisma/local.json`. This file is gitignored and only stores your local link, so it should not be treated as committed configuration. It is the only directory context commands read; everything else is targeted explicitly with arguments and flags. Commands find the link by walking up from the current directory to the nearest directory containing `.prisma/`, so a repository linked at its root works from any subdirectory. The nearest link wins: a subdirectory linked to a different project takes precedence over the root's.

## project env [#project-env]

Use `project env` commands to manage environment variables for the linked project. Every write requires an explicit scope: pass exactly one of `--role <production|preview>` or `--branch <git-name>`. A write without a scope fails with `PROJECT.USAGE_ERROR`, so a write targets production only when you ask for it. See [Environment variables](https://www.prisma.io/docs/compute/environment-variables).

| Command                               | Description                                                                                                          |
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `project env add [KEY=value\|KEY]`    | Create a variable. Pass just `KEY` to read the value from your environment, or omit the assignment and pass `--file` |
| `project env update [KEY=value\|KEY]` | Replace an existing variable's value. A bare `KEY` also reads from your environment                                  |
| `project env list`                    | List variable names and metadata for a scope, never values                                                           |
| `project env delete <key>`            | Delete a variable from a scope                                                                                       |

`add` and `update` also accept `--file <path>` to read `KEY=VALUE` assignments from a dotenv file, and every `project env` command takes `--project <id-or-name>`.

Values are write-only: they are encrypted at rest and cannot be read back. A deployment picks up the values at deploy time. Redeploy to apply changes.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# service (/docs/cli/service)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Manage Compute services, their versions, logs, and custom domains.

Location: CLI > service

Use `service` commands to manage the services in a project. A deploy produces a **version** of a service; one version is live at a time. Deploys start from [`deploy`](https://www.prisma.io/docs/cli/deploy) for a Composer app, from a git push once you [set up deploy on push](https://www.prisma.io/docs/compute/deploy-on-push), or from the [Console](https://pris.ly/pdp). The commands below inspect and manage services and the versions that already exist.

Commands are targeted by parameters, not by ambient state. A command that acts on a service takes the service as its first positional argument (`service show <service>`), with `PRISMA_SERVICE_ID` as the environment fallback; the argument wins when both are set. Scope with `--branch <name>` and `--project <id-or-name>`. There is no interactive picker: a missing target fails with a structured `SERVICE.TARGET_REQUIRED` error (exit 2) before any network call, even in an interactive terminal. Commands targeted by a globally unique version id (`service version promote|start|stop|delete <version-id>`) need no other context.

## Usage [#usage]

  

#### bun

```bash
bunx prisma service list
bunx prisma service show my-service
```

#### pnpm

```bash
pnpm prisma service list
pnpm prisma service show my-service
```

#### yarn

```bash
yarn prisma service list
yarn prisma service show my-service
```

#### npm

```bash
npx prisma service list
npx prisma service show my-service
```

## Commands [#commands]

| Command                    | Description                                                                                                                                                                                                                       |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `service list`             | List the services in a project (`--branch` scopes it)                                                                                                                                                                             |
| `service create <name>`    | Create a service (`--region`, `--branch`)                                                                                                                                                                                         |
| `service show <service>`   | Show the service and its live version                                                                                                                                                                                             |
| `service open <service>`   | Open the service's live URL                                                                                                                                                                                                       |
| `service logs <service>`   | Read logs for a version of the service. Defaults to the live version (`--version-id <id>` selects another). `--tail <n>` sets the line count (default 100), `--from-start` reads from the beginning, and `--follow` keeps polling |
| `service delete <service>` | Permanently delete the service from the branch you target, after confirmation                                                                                                                                                     |

## service version [#service-version]

Use `service version` commands to manage the versions of a service. Versions are created by deploys; these commands operate on the versions that already exist.

| Command                                | Description                                                                                                   |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `service version list <service>`       | List versions of the service                                                                                  |
| `service version show <version-id>`    | Show a version in detail                                                                                      |
| `service version promote <version-id>` | Promote a version to production by rebuilding with production env vars                                        |
| `service version rollback <service>`   | Roll back production to a previous version (`--to <version-id>`; defaults to the one before the live version) |
| `service version start <version-id>`   | Start a stopped version                                                                                       |
| `service version stop <version-id>`    | Stop a running version                                                                                        |
| `service version delete <version-id>`  | Permanently delete a version and the artifact it holds                                                        |

Promotion rebuilds the version with production environment variables, so configuration changes take effect on promote. Rollback switches production back to an existing version. See [Deployments](https://www.prisma.io/docs/compute/deployments).

## service domain [#service-domain]

Use `service domain` commands to manage custom domains for a service. All commands take a `<hostname>` argument plus the usual service and project selectors and a `--branch <name>` scope. Domains target the production branch by default. See [Domains](https://www.prisma.io/docs/compute/domains) for details.

| Command                            | Description                                                                          |
| ---------------------------------- | ------------------------------------------------------------------------------------ |
| `service domain add <hostname>`    | Register a custom domain on the service's production branch                          |
| `service domain show <hostname>`   | Show custom domain status and certificate details                                    |
| `service domain wait <hostname>`   | Wait until a custom domain is active or failed (`--timeout <duration>`, default 15m) |
| `service domain retry <hostname>`  | Retry custom domain DNS verification and TLS provisioning                            |
| `service domain delete <hostname>` | Permanently delete a custom domain from the service                                  |

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# skills (/docs/cli/skills)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Keep the Prisma agent skills in a project current.

Location: CLI > skills

Use `skills` commands to keep a project's [Prisma agent skills](https://www.prisma.io/docs/ai/tools/skills) current. An agent skill is a directory with a `SKILL.md`: instructions that teach an AI coding agent (Claude Code, Cursor, Devin) how to use a library. Skills ship inside the Prisma npm packages your project installs, so they always describe the version in use. `skills sync` copies them into the directories the agent harnesses read.

## Usage [#usage]

  

#### bun

```bash
bunx prisma skills sync
```

#### pnpm

```bash
pnpm prisma skills sync
```

#### yarn

```bash
yarn prisma skills sync
```

#### npm

```bash
npx prisma skills sync
```

Run [`init`](https://www.prisma.io/docs/cli/init) once to add a `postinstall` hook that reruns the sync on every install and upgrade.

## Commands [#commands]

| Command       | Description                                                           |
| ------------- | --------------------------------------------------------------------- |
| `skills sync` | Copy the agent skills from installed Prisma packages into the project |
| `skills list` | Show which Prisma agent skills are installed in the project           |

`skills sync` takes:

| Option      | What it does                                                                                       |
| ----------- | -------------------------------------------------------------------------------------------------- |
| `--disable` | Stop other commands reporting out-of-date skills in this project (stored in `.prisma/skills.json`) |
| `--enable`  | Undo `--disable` for this project                                                                  |

## Where skills come from [#where-skills-come-from]

Sync resolves a fixed allowlist of Prisma packages by name, from the project root and each workspace member:

* `@prisma/orm-postgres`
* `@prisma/orm-sqlite`
* `@prisma/orm-mongo`
* `@prisma/composer`
* `prisma` itself, which ships the `prisma-platform-core-concepts` skill

It never scans `node_modules` for skills. A skill is instructions an agent will follow, so installing one from an arbitrary transitive dependency would hand that dependency's author influence over your agent. Only packages you deliberately installed are sources. If two workspace members pin different versions of one package, the highest version wins and sync warns.

## Where skills go [#where-skills-go]

Sync writes one copy per configured agent harness:

| Agent    | Directory        |
| -------- | ---------------- |
| `claude` | `.claude/skills` |
| `cursor` | `.cursor/skills` |
| `agents` | `.agents/skills` |
| `devin`  | `.devin/skills`  |

Without configuration, sync writes every directory, so a harness you adopt later finds the skills already there. Narrow the set with `skills: { agents: [...] }` in `prisma.config.ts`; see [Configuration](https://www.prisma.io/docs/cli/configuration#agent-skills). The copies are ordinary files that git tracks: commit them so agents have the skills on a fresh clone.

Each copy carries the source package's version in its `SKILL.md` frontmatter. Sync compares that stamp against the installed package and re-copies on mismatch, and removes copies whose source package is no longer installed or whose agent is no longer named in `skills.agents`; `agents: []` removes them all. A directory sync does not own, such as a hand-written skill whose name collides, is left intact and reported as refused. Sync does nothing, and exits 0, when everything is already current.

## The staleness check [#the-staleness-check]

After a package upgrade that nobody follows with a sync, every `prisma` command appends one line to stderr (or, under `--format markdown`, a short section to stdout, shown below):

```text
Prisma agent skills are out of date (installed @prisma/orm-postgres 8.1.0, synced 8.0.0). Run: prisma skills sync
```

The notice never changes the exit code. It is not conditioned on a TTY: agents run without one, and they are who it is for.

Under `--format markdown` the notice moves to stdout, after the command's output, so an agent still reads one stream:

```text
### Notice
Prisma agent skills are out of date (installed @prisma/orm-postgres 8.1.0, synced 8.0.0).
- Sync agent skills: `prisma skills sync`
```

Every other format keeps it on stderr and writes nothing to stdout. It is suppressed by any of:

1. `prisma skills sync --disable` (persistent, per project).
2. `skills: { check: false }` in `prisma.config.ts`.
3. The [`PRISMA_SKILLS_CHECK=0`](https://www.prisma.io/docs/cli/environment-variables) environment variable.
4. A `CI` or `GITHUB_ACTIONS` environment variable.
5. The `--quiet`, `--json`, `--format json`, or `--version` flags on the current invocation.
6. Running a `skills` or `init` command itself.

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# telemetry (/docs/cli/telemetry)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Show, enable, or disable anonymous CLI telemetry.

Location: CLI > telemetry

Use `telemetry` commands to inspect and change anonymous CLI telemetry. Telemetry is on by default.

## Usage [#usage]

  

#### bun

```bash
bunx prisma telemetry status
```

#### pnpm

```bash
pnpm prisma telemetry status
```

#### yarn

```bash
yarn prisma telemetry status
```

#### npm

```bash
npx prisma telemetry status
```

## Commands [#commands]

| Command             | Description                                             |
| ------------------- | ------------------------------------------------------- |
| `telemetry status`  | Show whether anonymous CLI telemetry is enabled and why |
| `telemetry enable`  | Enable anonymous CLI telemetry                          |
| `telemetry disable` | Disable anonymous CLI telemetry                         |

## Where the preference is stored [#where-the-preference-is-stored]

`telemetry enable` and `telemetry disable` write `config.json` in the CLI's config directory: `$XDG_CONFIG_HOME/prisma/` if that variable is set, otherwise `~/.config/prisma/` on macOS and Linux and `%APPDATA%\prisma\` on Windows. The same file holds the random installation id that the first enabled telemetry run creates, right after it prints the notice. `telemetry status` prints the path it is using. The ORM commands mounted in the unified CLI share this preference; there is no second store to change.

## Environment variables [#environment-variables]

`PRISMA_DISABLE_TELEMETRY=1` and `DO_NOT_TRACK=1` turn telemetry off for the current CLI invocation. If you set them in a shell profile or CI configuration, they apply to every `prisma` run in that environment. The full list, and what to rename if you set `PRISMA_NEXT_*` variables for the early `prisma-next` command, is on [Environment variables](https://www.prisma.io/docs/cli/environment-variables).

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# Overview (/docs/guides)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Practical, step-by-step guides for building with Prisma ORM, each one run end to end before it ships.

Location: Overview

Practical, step-by-step guides for building with Prisma ORM. Every command in a published guide was run end to end against a live database before it landed here. The [Prisma ORM 7 guides](https://www.prisma.io/docs/guides/v7) remain available for Prisma ORM 7 projects.

Use the version dropdown in the sidebar to switch between these guides and the Prisma ORM 7 guides.

## Frameworks [#frameworks]

Each framework guide scaffolds a working app with `create-prisma`, initializes the database, and ends with your data rendering:

- [Next.js](https://www.prisma.io/docs/guides/frameworks/nextjs)

- [Astro](https://www.prisma.io/docs/guides/frameworks/astro)

- [Nuxt](https://www.prisma.io/docs/guides/frameworks/nuxt)

- [SvelteKit](https://www.prisma.io/docs/guides/frameworks/sveltekit)

- [TanStack Start](https://www.prisma.io/docs/guides/frameworks/tanstack-start)

- [NestJS](https://www.prisma.io/docs/guides/frameworks/nestjs)

- [Hono](https://www.prisma.io/docs/guides/frameworks/hono)

- [Elysia](https://www.prisma.io/docs/guides/frameworks/elysia)

## Runtimes [#runtimes]

- [Bun](https://www.prisma.io/docs/guides/runtimes/bun)

- [Deno](https://www.prisma.io/docs/guides/runtimes/deno)

## Deployment [#deployment]

- [Docker](https://www.prisma.io/docs/guides/deployment/docker)

- [Cloudflare Workers](https://www.prisma.io/docs/guides/deployment/cloudflare-workers)

- [Turborepo](https://www.prisma.io/docs/guides/deployment/turborepo)

- [pnpm workspaces](https://www.prisma.io/docs/guides/deployment/pnpm-workspaces)

- [Bun workspaces](https://www.prisma.io/docs/guides/deployment/bun-workspaces)

## Database [#database]

- [Multiple databases](https://www.prisma.io/docs/guides/database/multiple-databases)

- [Expand-and-contract migrations](https://www.prisma.io/docs/guides/database/data-migration)

- [Schema changes as a team](https://www.prisma.io/docs/guides/database/schema-changes)

## Switch to Prisma ORM [#switch-to-prisma-orm]

- [From Drizzle](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-drizzle)

- [From Sequelize or TypeORM](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-sql-orms)

- [From Mongoose](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-mongoose)

## Integrations [#integrations]

- [GitHub Actions](https://www.prisma.io/docs/guides/integrations/github-actions)

- [AI SDK](https://www.prisma.io/docs/guides/integrations/ai-sdk)

## Upgrading [#upgrading]

- [Prisma ORM 7 to 8 on PostgreSQL](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql)

- [Prisma ORM 7 to 8 on MongoDB](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb)

## Still on Prisma ORM 7 [#still-on-prisma-orm-7]

The authentication guides and the remaining integration and Prisma Postgres guides in the sidebar are written for Prisma ORM 7 and carry a note at the top saying so. Some wait on third-party adapters that still require Prisma Client; the rest land here as they are ported. Cloudflare D1 and the Accelerate integrations live under the [Prisma ORM 7 guides](https://www.prisma.io/docs/guides/v7) only.

## Next steps [#next-steps]

* [Start with the quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql) if you don't have a Prisma ORM project yet.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): reading, writing, relations, transactions, and advanced queries.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts, typed queries, and migrations.

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# Writing guides (/docs/guides/making-guides)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to write, validate, and file a Prisma ORM guide for the Prisma documentation.

Location: Guides > Writing guides

## Introduction [#introduction]

This page is for people writing guides in this section. It covers the required structure, the formatting conventions, the validation rule every guide must pass, and how a guide's Prisma ORM 7 twin is versioned.

The short version: a guide is a walkthrough you ran end to end before publishing, written for Prisma ORM, with every command shown alongside the real output it produced.

## Prerequisites [#prerequisites]

* A clear understanding of the topic you are writing about
* Access to the Prisma documentation repository
* Familiarity with Markdown and MDX
* Node.js 24 or later and a PostgreSQL database to validate against (a local server or `npx create-db@latest`)

## The validation rule [#the-validation-rule]

Every command, file, and code block in a published guide was run by its author against a live database before it landed. Outputs shown in the guide are pasted from that run, trimmed for noise. If a step could not be run (a platform account you do not have, a paid service), the guide says so in the step and does not show output for it.

Two reference guides show the finished shape. Read them before writing:

* [Hono](https://www.prisma.io/docs/guides/frameworks/hono): a new project scaffolded with `create-prisma`, deployed to Prisma Compute.
* [PostgreSQL, existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql): the `orm init` and `contract infer` path for an app that already exists.

## Guide structure [#guide-structure]

### Required frontmatter [#required-frontmatter]

```mdx
---
title: '[Descriptive title]'
description: '[One sentence: what the reader builds or accomplishes]'
url: /guides/[category]/[slug]
metaTitle: How to use Prisma ORM with [Topic]
metaDescription: '[One sentence for search results]'
---
```

* `title`: a short, descriptive title in sentence case (for example "Docker", "Multiple databases", "GitHub Actions")
* `description`: one sentence describing what the reader accomplishes
* `url`: the page path under `content/docs` without the extension; the build derives the URL from the file path, and this field must match it
* `metaTitle` and `metaDescription`: the title and description for search engines
* `image`: a header image for social sharing, only if one exists at `/img/guides/`

### Required sections [#required-sections]

1. **Introduction** (`## Introduction`): what the guide builds, in two or three sentences, followed by the `Using Prisma ORM 7?` note (see [Versioning](#versioning-the-prisma-7-twin)).
2. **Prerequisites** (`## Prerequisites`): Node.js 24 or later, a database connection string or `npx create-db@latest`, and any accounts the guide needs. Keep it to what is truly necessary.
3. **Use with your agent** (`## Use with your agent`): an `<AgentPrompt>` block with a numbered prompt a coding agent can follow to complete the guide. Reference the guide's own `.md` URL (`https://www.prisma.io/docs/guides/[category]/[slug].md`) so the agent can read it.
4. **Numbered steps** (`## 1. Scaffold the project`, `## 2. Initialize the database`, and so on): each step is one bounded action with its command, its real output in a `no-copy` block, and one or two sentences on what happened.
5. **Common gotchas** (`## Common gotchas`): the failures you hit while validating, with the verbatim error text and the fix.
6. **Prompt your coding agent** (`## Prompt your coding agent`): a pointer to `npx prisma@latest init` for the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills) and two or three follow-up prompts that map to the guide.
7. **Next steps** (`## Next steps`): links to the fundamentals and the related Prisma ORM pages.

## Writing style and voice [#writing-style-and-voice]

* Write direct instructional prose: say what to do, show the command, show the output.
* Use active voice and present tense, and address the reader as "you".
* Keep sentences short. One idea per sentence.
* Do not use em dashes anywhere, including code comments. Use a period, a comma, or a colon.
* Explain a removed Prisma ORM 7 step in one sentence only where a reader coming from Prisma ORM 7 would look for it (for example, "There is no `prisma generate` step; the runtime reads the emitted contract.").
* Do not describe Prisma ORM 8 as a preview or as not production ready, and do not mention release candidate numbers. Prisma ORM 8 is the current release; Prisma ORM 7 remains supported.

### Code examples [#code-examples]

* Every code block is complete and was run as shown.
* Use `title=` on file blocks: ` ```ts title="src/prisma/db.ts" `.
* Use ` ```npm ` for package manager commands (the UI converts them to pnpm, yarn, and bun).
* Use ` ```bash ` for other shell commands and for `.env` files, so `# [!code ++]` and `# [!code --]` annotations render.
* Use ` ```text no-copy ` and ` ```json no-copy ` for captured output.
* Use ` ```prisma ` for contract files, ` ```typescript ` or ` ```ts ` for TypeScript, ` ```json ` for JSON.
* Use `// [!code ++]`, `// [!code --]`, and `// [!code highlight]` to show changes inside a file.

### Formatting conventions [#formatting-conventions]

* Backticks for file names (`contract.prisma`), directories (`src/prisma/`), commands, and code elements (`db.orm.public.User`).
* Admonitions for asides:
  ```markdown
  :::note
  Important details to remember
  :::

  :::warning
  A gotcha that breaks the flow if missed
  :::

  :::tip
  A shortcut or best practice
  :::
  ```
* Never skip heading levels.
* Link Prisma ORM 8 pages with relative paths: `/orm/...`, `/cli/...`, `/prisma-orm/...`. Never link `/orm/v7/...` from a Prisma ORM 8 guide except in the `Using Prisma ORM 7?` note.

## Prisma ORM patterns [#prisma-orm-patterns]

### Versions in commands [#versions-in-commands]

Commands that run before the project has Prisma installed use the `@latest` tag, never a pinned version:

  

#### bun

```bash
bunx create-prisma@latest my-app --template hono --provider postgres --no-deploy
bunx prisma@latest orm init --target postgres
bunx --bun prisma@latest init
bunx create-db@latest
```

#### pnpm

```bash
pnpm dlx create-prisma@latest my-app --template hono --provider postgres --no-deploy
pnpm dlx prisma@latest orm init --target postgres
pnpm dlx prisma@latest init
pnpm dlx create-db@latest
```

#### yarn

```bash
yarn dlx create-prisma@latest my-app --template hono --provider postgres --no-deploy
yarn dlx prisma@latest orm init --target postgres
yarn dlx prisma@latest init
yarn dlx create-db@latest
```

#### npm

```bash
npx create-prisma@latest my-app --template hono --provider postgres --no-deploy
npx prisma@latest orm init --target postgres
npx prisma@latest init
npx create-db@latest
```

Every other command is `npx prisma <command>`, which runs the version the project has installed. In CI that is the version from the lockfile, and a reader never sees a guide behave differently from their own checkout. The docs' command tabs render `npx prisma` as `pnpm prisma` and `yarn prisma` for the same reason.

Package installs happen inside `create-prisma` and `orm init`; show their output rather than hand-written `npm install` lines with version numbers.

### New project [#new-project]

Scaffold with `create-prisma` and one of its templates (`minimal`, `hono`, `elysia`, `nest`, `next`, `svelte`, `astro`, `nuxt`, `tanstack-start`):

  

#### bun

```bash
bunx create-prisma@latest my-app --template next --provider postgres --no-deploy
```

#### pnpm

```bash
pnpm dlx create-prisma@latest my-app --template next --provider postgres --no-deploy
```

#### yarn

```bash
yarn dlx create-prisma@latest my-app --template next --provider postgres --no-deploy
```

#### npm

```bash
npx create-prisma@latest my-app --template next --provider postgres --no-deploy
```

The template ships the contract in `src/prisma/contract.prisma`, the runtime in `src/prisma/db.ts`, and package scripts for `contract:emit`, `db:init`, `db:update`, `migration:plan`, and `migrate`.

### Existing project [#existing-project]

Add Prisma ORM to an app that already exists:

  

#### bun

```bash
bunx prisma@latest orm init --target postgres
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --target postgres
```

#### yarn

```bash
yarn dlx prisma@latest orm init --target postgres
```

#### npm

```bash
npx prisma@latest orm init --target postgres
```

For a database that already has tables, follow with `npx prisma contract infer --output ./src/prisma/contract.prisma`, review the contract, then `contract emit` and `db sign`. Two things to check in the review: `orm init` keeps `"type": "commonjs"` if your `package.json` declares it and adds `"type": "module"` if there is no `"type"` field (a new project should use `"type": "module"`; an existing CommonJS app follows [In a CommonJS project](https://www.prisma.io/docs/cli/orm-init#in-a-commonjs-project)), and `contract infer` writes `Timestamptz` for timestamp columns while the runtime on Node.js needs `TimestamptzString`.

### Runtime instantiation [#runtime-instantiation]

Show the scaffolded `src/prisma/db.ts` rather than writing a client by hand:

```ts title="src/prisma/db.ts"
import "dotenv/config";
import postgres from "@prisma/orm-postgres/runtime";
import type { Contract } from "./contract.d";
import contractJson from "./contract.json" with { type: "json" };

export const db = postgres<Contract>({
  contractJson,
  url: process.env.DATABASE_URL!,
});
```

Queries name the PostgreSQL schema (`db.orm.public.User.select("id", "email").all()`). Close the client once on process shutdown with `await db.close()`, never per request; in a per-request environment such as Cloudflare Workers, create the client inside the handler instead (see [Cloudflare Workers](https://www.prisma.io/docs/guides/deployment/cloudflare-workers)).

### Database lifecycle [#database-lifecycle]

| Task                                       | Command                                   |
| ------------------------------------------ | ----------------------------------------- |
| First apply and sign                       | `npx prisma db init`                      |
| Check the database matches the contract    | `npx prisma db verify`                    |
| Apply a contract change during development | `npx prisma db update`                    |
| Plan a checked-in migration                | `npx prisma migration plan --name <name>` |
| Apply checked-in migrations                | `npx prisma db migrate`                   |

### Environment variables [#environment-variables]

Show `.env` files with ` ```bash title=".env" `:

```bash title=".env"
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
```

The CLI loads `.env` through `prisma.config.ts`. Scaffolded `db.ts` files import `dotenv/config`; `create-prisma` templates read the environment variable only, so tell the reader to export it in the shell.

## Versioning the Prisma ORM 7 twin [#versioning-the-prisma-7-twin]

The unversioned tree under `guides/` is Prisma ORM 8. Prisma ORM 7 guides live under `guides/v7/` with the same subpath, and the sidebar version dropdown switches between them.

When you port a Prisma ORM 7 guide:

1. Copy the Prisma ORM 7 file to `guides/v7/<same subpath>` and change only its `url:` to the `/guides/v7/...` path. Keep its Prisma ORM 7 pins.
2. Add the file to the matching `guides/v7/<category>/meta.json` and to the list on [/guides/v7](https://www.prisma.io/docs/guides/v7).
3. Write the Prisma ORM 8 guide over the original path.
4. Add this note right after the introduction of the Prisma ORM 8 guide:

```markdown
:::note[Using Prisma ORM 7?]

Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/[category]/[slug]](/guides/v7/[category]/[slug]).

:::
```

If a topic cannot be ported because Prisma ORM 8 does not support it yet (for example Cloudflare D1, or a third-party adapter that requires Prisma Client), move the page under `guides/v7/`, change its `url:` frontmatter to the `/guides/v7/...` path (or re-run `npx tsx scripts/add-url-frontmatter.ts` in `apps/docs`; a stale `url:` fails silently and no linter catches it), add its filename to the matching `guides/v7/<category>/meta.json` and its link to `guides/v7/index.mdx` (a redirect alone leaves it out of the Prisma ORM 7 navigation), and add a redirect from the old URL in the live region of `redirects()` in `apps/docs/next.config.mjs`, near the `/llms/next.txt` entry (`apps/docs/vercel.json` holds the legacy redirects and the entries `pnpm generate:rest-api-docs` writes, not new page moves). Then run `pnpm run audit:redirects:strict` in `apps/docs`: it checks that every `vercel.json` destination still resolves, so it catches the legacy redirects whose destination just moved; it does not read `next.config.mjs`. Do not leave a Prisma ORM 7 page at a Prisma ORM 8 URL without a version marker.

## Guide categories [#guide-categories]

| Category            | Directory                      | Description                             | Examples                                                                                                                                                                        |
| ------------------- | ------------------------------ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Framework**       | `guides/frameworks/`           | Integrate Prisma ORM with frameworks    | [Next.js](https://www.prisma.io/docs/guides/frameworks/nextjs), [Hono](https://www.prisma.io/docs/guides/frameworks/hono), [React Router](https://www.prisma.io/docs/guides/frameworks/react-router-7)                                                        |
| **Runtime**         | `guides/runtimes/`             | Run Prisma ORM on a runtime             | [Bun](https://www.prisma.io/docs/guides/runtimes/bun), [Deno](https://www.prisma.io/docs/guides/runtimes/deno)                                                                                                                      |
| **Deployment**      | `guides/deployment/`           | Deploy apps and set up monorepos        | [Docker](https://www.prisma.io/docs/guides/deployment/docker), [Cloudflare Workers](https://www.prisma.io/docs/guides/deployment/cloudflare-workers), [Turborepo](https://www.prisma.io/docs/guides/deployment/turborepo)                                     |
| **Integration**     | `guides/integrations/`         | Use Prisma ORM with platforms and tools | [GitHub Actions](https://www.prisma.io/docs/guides/integrations/github-actions), [AI SDK](https://www.prisma.io/docs/guides/integrations/ai-sdk)                                                                                    |
| **Database**        | `guides/database/`             | Database patterns and migrations        | [Multiple databases](https://www.prisma.io/docs/guides/database/multiple-databases), [Expand-and-contract migrations](https://www.prisma.io/docs/guides/database/data-migration), [Schema changes](https://www.prisma.io/docs/guides/database/schema-changes) |
| **Authentication**  | `guides/authentication/`       | Authentication patterns                 | [Clerk with Next.js](https://www.prisma.io/docs/guides/authentication/clerk/nextjs)                                                                                                                       |
| **Prisma Postgres** | `guides/postgres/`             | Prisma Postgres features                | [Vercel](https://www.prisma.io/docs/guides/postgres/vercel), [Netlify](https://www.prisma.io/docs/guides/postgres/netlify), [Viewing data](https://www.prisma.io/docs/guides/postgres/viewing-data)                                                           |
| **Migration**       | `guides/switch-to-prisma-orm/` | Switch from other ORMs                  | [From Drizzle](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-drizzle), [From Mongoose](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-mongoose)                                                          |
| **Upgrade**         | `guides/upgrade-prisma-orm/`   | Move between Prisma versions            | [Prisma ORM 7 to 8 on PostgreSQL](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql)                                                                                                        |

## Guide template [#guide-template]

Copy this template for a new guide that adds Prisma ORM to an existing framework project. For a `create-prisma` template project, replace step 1 with the scaffold command and drop the `orm init` step.

````markdown
---
title: '[Your guide title]'
description: '[One sentence: what the reader builds]'
url: /guides/[category]/[slug]
metaTitle: How to use Prisma ORM with [Topic]
metaDescription: '[One sentence for search results]'
---

## Introduction

[What this guide builds and what the reader ends up with. Two or three sentences.]

:::note[Using Prisma ORM 7?]

Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/[category]/[slug]](/guides/v7/[category]/[slug]).

:::

## Prerequisites

- [Node.js](https://nodejs.org) 24 or later
- A PostgreSQL connection string, or nothing at all: `npx create-db@latest` creates a [Prisma Postgres](/postgres) database for you

## Use with your agent

<AgentPrompt>

```text
[Numbered instructions an agent can follow to complete this guide, referencing https://www.prisma.io/docs/guides/[category]/[slug].md]
```

</AgentPrompt>

## 1. Set up the project

```npm
[Framework scaffold command]
```

## 2. Add Prisma ORM

```npm
npx prisma@latest orm init --target postgres
```

```text no-copy
[Trimmed real output]
```

Set the connection string:

```bash title=".env"
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
```

## 3. Define the contract

```prisma title="src/prisma/contract.prisma"
[Your models]
```

```npm
npx prisma contract emit
```

## 4. Initialize the database

```npm
npx prisma db init
```

```text no-copy
"summary": "Applied N operation(s) across 1 space(s), database signed"
```

## 5. [Integration-specific steps]

[Framework or platform steps, each with its command and real output]

## Common gotchas

[Failures you hit while validating, with the verbatim error and the fix]

## Prompt your coding agent

Run [`npx prisma@latest init`](/cli/init) once to install the [Prisma ORM skills](/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. Prompts that map to this guide:

- "[Prompt 1]"
- "[Prompt 2]"

## Next steps

- [Learn the fundamentals](/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
- [Read the Prisma ORM overview](/orm) for the concepts behind contracts and typed queries.
````

## Adding guides to navigation [#adding-guides-to-navigation]

Guides are organized by category in subdirectories. To add a guide to the navigation, update the category's `meta.json`:

```json title="apps/docs/content/docs/guides/frameworks/meta.json"
{
  "title": "Frameworks",
  "defaultOpen": true,
  "pages": [
    "nextjs",
    "astro",
    "nuxt",
    "your-new-guide" // [!code ++]
  ]
}
```

The page name is the `.mdx` filename without the extension. The top-level `guides/meta.json` lists the categories, and `guides/v7/meta.json` plus `guides/v7/<category>/meta.json` do the same for the Prisma ORM 7 tree.

## Next steps [#next-steps]

* Read the [Hono](https://www.prisma.io/docs/guides/frameworks/hono) guide and match its shape.
* Validate your guide end to end, then open a pull request with the sandbox commands you ran in the description.

## Related pages

- [`Guides`](https://www.prisma.io/docs/guides/v7): A collection of guides for various tasks and workflows

# Local app (/docs/local-development/app-development)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Run your app locally on the runtime Prisma Compute deploys, wire it to a local database, and bring up the whole app with Composer.

Location: Local Development > Local app

Building locally with Prisma is ordinary app development: you run your framework's dev server, query a database, and iterate. What the platform adds is parity: the pieces you develop against locally behave like the ones you deploy to.

## Compute runs Bun [#compute-runs-bun]

[Prisma Compute](https://www.prisma.io/docs/compute) runs deployed apps on [Bun](https://bun.com). There is no proprietary runtime layer to emulate locally: run your app with Bun on your machine and you are exercising the same runtime your deployment uses. Bun's built-in APIs, like [its S3 client](https://www.prisma.io/docs/local-development/storage), work identically in both places.

Day to day, iteration stays your framework's usual loop. A scaffolded [Prisma ORM](https://www.prisma.io/docs/prisma-orm) app starts with:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

For a Bun-native server, run the entry file directly:

```bash
bun run src/index.ts
```

The [Bun runtime guide](https://www.prisma.io/docs/guides/runtimes/bun) walks through a full local build on Bun.

## Wire in a local database [#wire-in-a-local-database]

Point your app at a local Prisma Postgres instance instead of a hosted one. Start it from your project directory:

  

#### bun

```bash
bunx prisma dev
```

#### pnpm

```bash
pnpm prisma dev
```

#### yarn

```bash
yarn prisma dev
```

#### npm

```bash
npx prisma dev
```

It prints a `DATABASE_URL` you copy into `.env`; migrations and queries then run against your machine. [Local Postgres](https://www.prisma.io/docs/local-development/postgres) covers instances, background mode, and management commands.

This `.env` wiring is hand-wired configuration, and it belongs to the direct dev-server loop: when you deploy an app configured this way, you swap `DATABASE_URL` for a hosted [Prisma Postgres](https://www.prisma.io/docs/postgres) connection string, with no application code changes. A Composer app declares the wiring instead. The service depends on [`postgres()`](https://www.prisma.io/docs/composer/databases) and reads its connection string as `db.url` from `service.load()`, so the same declaration resolves to a local database under `dev` and a hosted one on deploy, and there is no variable to swap.

## Run the app with `dev` [#run-the-app-with-dev]

Apps deploy to Compute as [Prisma Composer](https://www.prisma.io/docs/composer) apps: you declare your services in TypeScript and `deploy` stands them up. The same declarations run locally. One command brings the whole app up, whether it is one service or several, with its databases and buckets wired together:

  

#### bun

```bash
bun run build
bunx prisma dev module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma dev module.ts
```

#### yarn

```bash
yarn build
yarn prisma dev module.ts
```

#### npm

```bash
npm run build
npx prisma dev module.ts
```

`dev` runs the same pipeline a deploy runs, but against local emulators standing in for Prisma Compute and Prisma Postgres. No cloud credentials are involved, and the local databases and buckets persist between runs until you pass `--fresh`. When the app runs locally, [deploying it](https://www.prisma.io/docs/prisma-compute/deploy) is the same declarations against the hosted platform.

[Local development in Composer](https://www.prisma.io/docs/composer/local-development) documents the full workflow: warm restarts, log filtering, and what is local versus what is real.

## Next steps [#next-steps]

* [Local Postgres](https://www.prisma.io/docs/local-development/postgres): the local database in detail.
* [Local storage](https://www.prisma.io/docs/local-development/storage): S3-compatible clients against local and hosted buckets.
* [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy): take the locally built app to a live URL.

## Related pages

- [`Local Postgres`](https://www.prisma.io/docs/local-development/postgres): Set up and use Prisma Postgres for local development
- [`Local storage`](https://www.prisma.io/docs/local-development/storage): Use S3-compatible client libraries against Prisma object storage, locally with stand-in buckets and deployed on Prisma Compute.

# Local development (/docs/local-development)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

Location: Local development

Local development with Prisma means running the stack you deploy, on your machine. You build and test against local pieces, then ship the same code to [Prisma Compute](https://www.prisma.io/docs/compute) and [Prisma Postgres](https://www.prisma.io/docs/postgres) without changing application logic.

Each piece of the platform has a local counterpart:

* **Your app** runs with your framework's dev server or with Bun directly. Prisma Compute runs deployed apps on Bun, so there is no platform emulator to install: the runtime you develop against is the runtime you ship. See [Local app](https://www.prisma.io/docs/local-development/app-development).
* **Your storage** is S3-compatible, so the same client code works against a hosted bucket and a local stand-in. See [Local storage](https://www.prisma.io/docs/local-development/storage).
* **Your database** runs as a local Prisma Postgres instance, started with one command and no Postgres install. See [Local Postgres](https://www.prisma.io/docs/local-development/postgres).

Apps deploy to Compute as [Prisma Composer](https://www.prisma.io/docs/composer) apps, and the pipeline a deploy runs is the same one you run locally: `dev` brings your app up, whether it is one service or several, against local stand-ins for Compute and Prisma Postgres, with no cloud credentials. See [Local development in Composer](https://www.prisma.io/docs/composer/local-development).

- [Local app](https://www.prisma.io/docs/local-development/app-development): Iterate with your framework's dev loop and run the whole app with `dev`.

- [Local storage](https://www.prisma.io/docs/local-development/storage): Use S3-compatible clients against local stand-in buckets and hosted buckets alike.

- [Local Postgres](https://www.prisma.io/docs/local-development/postgres): Start a local Prisma Postgres database with `prisma dev` and manage named instances.

## From local to deployed [#from-local-to-deployed]

The local stack is designed so that switching to the hosted platform is a configuration change, not a code change:

1. [Deploy your app](https://www.prisma.io/docs/prisma-compute/deploy) with `deploy`: the same declarations that ran against local stand-ins provision hosted services, [Prisma Postgres](https://www.prisma.io/docs/postgres) databases, and buckets on the platform.
2. For connections you wired by hand, point `DATABASE_URL` at a hosted Prisma Postgres database and swap local bucket credentials for a minted [access key](https://www.prisma.io/docs/storage).

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Overview`](https://www.prisma.io/docs/cli): Prisma CLI reference

# Local Postgres (/docs/local-development/postgres)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up and use Prisma Postgres for local development

Location: Local Development > Local Postgres

[Prisma Postgres](https://www.prisma.io/docs/postgres) is a hosted database for your staging and production environments. For local iteration and isolated testing, you can run a *local* Prisma Postgres instance (powered by [PGlite](https://pglite.dev)) with the `prisma dev` command. This page explains how to launch and manage a local Prisma Postgres database.

## Setting up local development for Prisma Postgres [#setting-up-local-development-for-prisma-postgres]

Follow these steps to set up local Prisma Postgres for development.

Node.js v20 or later is required for local Prisma Postgres.

### 1. Launching local Prisma Postgres [#1-launching-local-prisma-postgres]

Navigate into your project and start the local Prisma Postgres server using the following command:

  

#### bun

```bash
bunx prisma dev
```

#### pnpm

```bash
pnpm prisma dev
```

#### yarn

```bash
yarn prisma dev
```

#### npm

```bash
npx prisma dev
```

This starts a local Prisma Postgres server that you can connect to using Prisma ORM or another tool. The output of the command looks like this:

```text
$ npx prisma dev
Loaded Prisma config from prisma.config.ts.

✔  Your local Prisma Postgres server default is now running 👍
                                                                                                                                                                                               
🔌 To connect with Prisma ORM use the following connection strings:

   DATABASE_URL="postgres://postgres:postgres@localhost:51214/template1?sslmode=disable&connection_limit=10&connect_timeout=0&max_idle_connection_lifetime=0&pool_timeout=0&socket_timeout=0"
   SHADOW_DATABASE_URL="postgres://postgres:postgres@localhost:51215/template1?sslmode=disable&connection_limit=10&connect_timeout=0&max_idle_connection_lifetime=0&pool_timeout=0&socket_timeout=0"

🐘 You can also use the DATABASE_URL with the pg or postgres.js JavaScript drivers as well as your favorite DB gui.

   For the best experience, set the maximum number of connections to 10, connect timeout to 0 and
   idle timeout to the smallest positive value supported.

🌊 Prisma Streams is available at:

   PRISMA_STREAM_URL="http://127.0.0.1:51216/v1/stream/prisma-wal"

┌─────────────────┐
│ Press q to quit │
└─────────────────┘
```

You may:

* <kbd>q</kbd> to quit

If you want to connect via Prisma ORM, hit <kbd>h</kbd> on your keyboard and copy both `DATABASE_URL` and `SHADOW_DATABASE_URL` into your `.env` file. Prisma ORM connects through the first one. Prisma Migrate uses the second one as the [shadow database](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database) when it checks for drift. Without it, the first `prisma migrate dev` run works but later runs fail with a `relation "..." already exists` error.

```text title=".env"
DATABASE_URL="postgres://postgres:postgres@localhost:51214/template1?sslmode=disable&connection_limit=10&connect_timeout=0&max_idle_connection_lifetime=0&pool_timeout=0&socket_timeout=0"
SHADOW_DATABASE_URL="postgres://postgres:postgres@localhost:51215/template1?sslmode=disable&connection_limit=10&connect_timeout=0&max_idle_connection_lifetime=0&pool_timeout=0&socket_timeout=0"
```

Then point the `datasource` block of your Prisma config at both variables:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
    shadowDatabaseUrl: process.env["SHADOW_DATABASE_URL"],
  },
});
```

Keep the local Prisma Postgres server running in the background while you work on your application.

Alternatively, you can run the server in detached mode to free up your terminal:

  

#### bun

```bash
bunx prisma dev --detach
```

#### pnpm

```bash
pnpm prisma dev --detach
```

#### yarn

```bash
yarn prisma dev --detach
```

#### npm

```bash
npx prisma dev --detach
```

This starts the server in the background. Use `prisma dev ls` to see running servers and `prisma dev stop` to stop them.

### 2. Applying migrations and seeding data [#2-applying-migrations-and-seeding-data]

Then in a separate terminal tab, run the `prisma migrate dev` command to create the database and run the migrations:

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

> [!NOTE]
> Make sure the local Prisma Postgres server is running before running the `prisma migrate dev` command.
> 
> If you must use a different port, append [`--port <number>`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#dev) (for example, `npx prisma migrate dev --port 5422`) and update your `DATABASE_URL` (or other connection settings) to match.

> [!NOTE]
> If the first `prisma migrate dev` run against a fresh instance fails with `Error: P1017 Server has closed the connection` before it creates any tables, you have hit [prisma/orm#29366](https://github.com/prisma/orm/issues/29366): the query that reads the `_prisma_migrations` table drops the connection when that table does not exist yet. Create the table yourself, then run the command again:
> 
> ```sql title="create-migrations-table.sql"
> CREATE TABLE "_prisma_migrations" (
>     "id"                  VARCHAR(36)  PRIMARY KEY NOT NULL,
>     "checksum"            VARCHAR(64)  NOT NULL,
>     "finished_at"         TIMESTAMPTZ,
>     "migration_name"      VARCHAR(255) NOT NULL,
>     "logs"                TEXT,
>     "rolled_back_at"      TIMESTAMPTZ,
>     "started_at"          TIMESTAMPTZ  NOT NULL DEFAULT now(),
>     "applied_steps_count" INTEGER      NOT NULL DEFAULT 0
> );
> ```
>
> 
>   
> 
>   #### bun

>     ```bash
>     bunx prisma db execute --file create-migrations-table.sql
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm prisma db execute --file create-migrations-table.sql
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn prisma db execute --file create-migrations-table.sql
>     ```
>
> 
>   #### npm

>     ```bash
>     npx prisma db execute --file create-migrations-table.sql
>     ```
>
> 
> 
> `prisma db push` does not read that table, so it works as an alternative if you do not need migration files yet.

This will create the database and run the migrations.

If you have a seeder script to seed the database, you should also run it in this step.

### 3. Running your application locally [#3-running-your-application-locally]

Start your application's development server. You can now perform queries against the local Prisma Postgres instance using Prisma ORM.

To transition to production, you only need to update the database URL in the `.env` file with a Prisma Postgres connection url without additional application logic changes.

## Using different local Prisma Postgres instances [#using-different-local-prisma-postgres-instances]

You can target a specific, local Prisma Postgres instance via the `--name` (`-n`) option of the `prisma dev` command, for example:

  

#### bun

```bash
bunx prisma dev --name="mydb1"
```

#### pnpm

```bash
pnpm prisma dev --name="mydb1"
```

#### yarn

```bash
yarn prisma dev --name="mydb1"
```

#### npm

```bash
npx prisma dev --name="mydb1"
```

Whenever you pass the `--name="mydb1"` to `prisma dev`, the command will return the same connection string pointing to a local instance called `mydb1`. This creates a named instance that you can later manage using the instance management commands.

## Starting existing Prisma Postgres instances in the background [#starting-existing-prisma-postgres-instances-in-the-background]

You can start existing Prisma Postgres instances in the background using:

  

#### bun

```bash
bunx prisma dev start <glob>
```

#### pnpm

```bash
pnpm prisma dev start <glob>
```

#### yarn

```bash
yarn prisma dev start <glob>
```

#### npm

```bash
npx prisma dev start <glob>
```

> [!NOTE]
> The `dev start` command only works with instances that already exist.

`<glob>` is a placeholder for a glob pattern to specify which local Prisma Postgres instances should be started, for example:

  

#### bun

```bash
bunx prisma dev start mydb # starts a DB called `mydb` in the background (only if it already exists)
```

#### pnpm

```bash
pnpm prisma dev start mydb # starts a DB called `mydb` in the background (only if it already exists)
```

#### yarn

```bash
yarn prisma dev start mydb # starts a DB called `mydb` in the background (only if it already exists)
```

#### npm

```bash
npx prisma dev start mydb # starts a DB called `mydb` in the background (only if it already exists)
```

To start all databases that begin with `mydb` (e.g. `mydb-dev` and `mydb-prod`), you can use a glob:

  

#### bun

```bash
bunx prisma dev start mydb* # starts all existing DBs starting with `mydb`
```

#### pnpm

```bash
pnpm prisma dev start mydb* # starts all existing DBs starting with `mydb`
```

#### yarn

```bash
yarn prisma dev start mydb* # starts all existing DBs starting with `mydb`
```

#### npm

```bash
npx prisma dev start mydb* # starts all existing DBs starting with `mydb`
```

Use this command to start instances in the background without the VS Code extension.

## Listing Prisma Postgres instances [#listing-prisma-postgres-instances]

You can view all your local Prisma Postgres instances using:

  

#### bun

```bash
bunx prisma dev ls
```

#### pnpm

```bash
pnpm prisma dev ls
```

#### yarn

```bash
yarn prisma dev ls
```

#### npm

```bash
npx prisma dev ls
```

This command lists all available instances on your system, showing their current status and configuration.

## Stopping Prisma Postgres instances [#stopping-prisma-postgres-instances]

You can stop a running Prisma Postgres instance with this command:

  

#### bun

```bash
bunx prisma dev stop <glob>
```

#### pnpm

```bash
pnpm prisma dev stop <glob>
```

#### yarn

```bash
yarn prisma dev stop <glob>
```

#### npm

```bash
npx prisma dev stop <glob>
```

`<glob>` is a placeholder for a glob pattern to specify which local Prisma Postgres instances should be stopped, for example:

  

#### bun

```bash
bunx prisma dev stop mydb # stops a DB called `mydb`
```

#### pnpm

```bash
pnpm prisma dev stop mydb # stops a DB called `mydb`
```

#### yarn

```bash
yarn prisma dev stop mydb # stops a DB called `mydb`
```

#### npm

```bash
npx prisma dev stop mydb # stops a DB called `mydb`
```

To stop all databases that begin with `mydb` (e.g. `mydb-dev` and `mydb-prod`), you can use a glob:

  

#### bun

```bash
bunx prisma dev stop mydb* # stops all DBs starting with `mydb`
```

#### pnpm

```bash
pnpm prisma dev stop mydb* # stops all DBs starting with `mydb`
```

#### yarn

```bash
yarn prisma dev stop mydb* # stops all DBs starting with `mydb`
```

#### npm

```bash
npx prisma dev stop mydb* # stops all DBs starting with `mydb`
```

> [!NOTE]
> The `stop` command is interactive and includes safety prompts to prevent accidental operations. You'll be asked to confirm the action by typing a confirmation phrase.

## Removing Prisma Postgres instances [#removing-prisma-postgres-instances]

Prisma Postgres saves the information and data from your local Prisma Postgres instances on your file system. To remove any trace from a database that's not in use any more, you can run the following command:

  

#### bun

```bash
bunx prisma dev rm <glob>
```

#### pnpm

```bash
pnpm prisma dev rm <glob>
```

#### yarn

```bash
yarn prisma dev rm <glob>
```

#### npm

```bash
npx prisma dev rm <glob>
```

`<glob>` is a placeholder for a glob pattern to specify which local Prisma Postgres instances should be removed, for example:

  

#### bun

```bash
bunx prisma dev rm mydb # removes a DB called `mydb`
```

#### pnpm

```bash
pnpm prisma dev rm mydb # removes a DB called `mydb`
```

#### yarn

```bash
yarn prisma dev rm mydb # removes a DB called `mydb`
```

#### npm

```bash
npx prisma dev rm mydb # removes a DB called `mydb`
```

To remove all databases that begin with `mydb` (e.g. `mydb-dev` and `mydb-prod`), you can use a glob:

  

#### bun

```bash
bunx prisma dev rm mydb* # removes all DBs starting with `mydb`
```

#### pnpm

```bash
pnpm prisma dev rm mydb* # removes all DBs starting with `mydb`
```

#### yarn

```bash
yarn prisma dev rm mydb* # removes all DBs starting with `mydb`
```

#### npm

```bash
npx prisma dev rm mydb* # removes all DBs starting with `mydb`
```

You can use the `--force` flag to stop any running servers before removing them:

  

#### bun

```bash
bunx prisma dev rm mydb --force
```

#### pnpm

```bash
pnpm prisma dev rm mydb --force
```

#### yarn

```bash
yarn prisma dev rm mydb --force
```

#### npm

```bash
npx prisma dev rm mydb --force
```

Without `--force`, the command will fail if any server is still running.

> [!NOTE]
> The `rm` command is interactive and includes safety prompts to prevent accidental data loss. You'll be asked to confirm the action by typing a confirmation phrase that hints at the risks involved.

## Using local Prisma Postgres with any ORM [#using-local-prisma-postgres-with-any-orm]

Local Prisma Postgres supports [direct PostgreSQL connections](https://www.prisma.io/docs/postgres/database/connecting-to-your-database), allowing you to connect to it via any tool.

In order to connect to your local Prisma Postgres instance, use the `postgres://` connection string that's returned by `prisma dev`.

## Managing local Prisma Postgres instances via the Prisma VS Code extension [#managing-local-prisma-postgres-instances-via-the-prisma-vs-code-extension]

The [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) has a dedicated UI managing Prisma Postgres instances.

To use it, install the VS Code extension and find the **Prisma logo** in the activity bar of your VS Code editor. It enables the following workflows:

* creating and deleting databases
* starting and stopping the server for a particular database
* "push to cloud": move a database from local to remote

## Manage local Prisma Postgres programmatically [#manage-local-prisma-postgres-programmatically]

You can start and stop a local Prisma Postgres server from Node.js without invoking the CLI. This uses undocumented, unstable APIs from `@prisma/dev` and may change without notice. Use it at your own risk. It's especially useful for integration tests that need an ephemeral local database per test or suite.

This is a complete runnable example that will print `[{abba: 1}]` when run:

```ts
import { Client } from "pg";
import { startPrismaDevServer } from "@prisma/dev";

async function startLocalPrisma(name: string) {
  return await startPrismaDevServer({
    name, // required, use a unique name if running tests in parallel
    port: 51213, // optional, defaults to 51213
    databasePort: 51214, // optional, defaults to 51214
    shadowDatabasePort: 51215, // optional, defaults to 51215
    persistenceMode: "stateless", // optional, defaults to 'stateless'. Use 'stateful' to persist data between runs
  });
}

// Usage in tests
const server = await startLocalPrisma(`my-tests-${Date.now()}`);
try {
  const client = new Client({
    connectionString: server.database.connectionString,
  });
  await client.connect();

  const res = await client.query(`SELECT 1 as "abba"`);
  console.log(res.rows);

  client.end();
} finally {
  await server.close!();
}
```

### API Arguments [#api-arguments]

The `startPrismaDevServer()` function accepts the following options:

| **Argument**                             | **Required** | **Description**                                                                                                                                                                                                                                                                                                                                                                                                                            | **Default**                                |
| ---------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------ |
| **`name`**                               | ❌            | Unique identifier for the local Prisma Postgres instance. Use distinct names if running multiple servers in parallel.                                                                                                                                                                                                                                                                                                                      | `'default'`                                |
| **`port`**                               | ❌            | Port for the Prisma engine server. Throws an error if the port is already in use.                                                                                                                                                                                                                                                                                                                                                          | `51213`                                    |
| **`databasePort`**                       | ❌            | Port for the embedded PostgreSQL database. Used for all Prisma ORM connections.                                                                                                                                                                                                                                                                                                                                                            | `51214`                                    |
| **`shadowDatabasePort`**                 | ❌            | Port for the shadow database used during migrations.                                                                                                                                                                                                                                                                                                                                                                                       | `51215`                                    |
| **`persistenceMode`**                    | ❌            | Defines how data is persisted:<br />• `'stateless'`: no data is retained between runs<br />• `'stateful'`: data persists locally                                                                                                                                                                                                                                                                                                           | `'stateless'`                              |
| **`debug`**                              | ❌            | Whether to enable debug logging.                                                                                                                                                                                                                                                                                                                                                                                                           | `false`                                    |
| **`dryRun`**                             | ❌            | Whether to run the server in dry run mode.                                                                                                                                                                                                                                                                                                                                                                                                 | `false`                                    |
| **`databaseConnectTimeoutMillis`**       | ❌            | Connection timeout in milliseconds for pending database connections. Starts ticking for every new client that attempts to connect. When exceeded, the pending client connection is evicted and closed. Use with caution, as it may lead to unexpected behavior. Best used with a pool client that retries connections.                                                                                                                     | `60000` (1 minute)                         |
| **`databaseIdleTimeoutMillis`**          | ❌            | Idle timeout in milliseconds for active database connections. Re-starts ticking after each message received on the active connection. When exceeded, the active client connection is closed, and a pending connection is promoted to active. Use with caution, as it may lead to unexpected disconnections. Best used with a pool client that can handle disconnections gracefully. Set it if you suffer from client hanging indefinitely. | Not applied by default                     |
| **`shadowDatabaseConnectTimeoutMillis`** | ❌            | Connection timeout in milliseconds for pending shadow database connections.                                                                                                                                                                                                                                                                                                                                                                | Defaults to `databaseConnectTimeoutMillis` |
| **`shadowDatabaseIdleTimeoutMillis`**    | ❌            | Idle timeout in milliseconds for active shadow database connections.                                                                                                                                                                                                                                                                                                                                                                       | Defaults to `databaseIdleTimeoutMillis`    |

> [!NOTE]
> You can import the type definition for better TypeScript support:
> 
> ```ts
> import { type ServerOptions } from "@prisma/dev";
> ```

Notes:

* Allocate unique ports and `name` values when running tests concurrently.
* Use `server.database.connectionString` to connect with Postgres clients or ORMs.
* Use this pattern for tests that require a local database.

## Troubleshooting [#troubleshooting]

### Start says "already running", but `ls` says `not_running` [#start-says-already-running-but-ls-says-not_running]

Starting an instance may fail with `A Prisma Dev server with the name <name> is already running`, while `npx prisma dev ls` reports that same instance as `not_running`. This happens when a previous run of the server crashed or was force-killed and left its lock file behind: the start command saw only the held lock, while `ls` checked whether the server was actually alive.

Recent versions of `prisma` detect that the previous owner is dead, take over the leftover lock, and start normally. Projects whose installed `prisma` predates the fix can still hit this. Tools that embed the local server (such as Prisma Composer) run the `@prisma/dev` version installed in your project, so the fix reaches you by updating the project's `prisma` dependency.

To recover on an affected version, remove the stuck instance and start it again:

  

#### bun

```bash
bunx prisma dev rm <name>
```

#### pnpm

```bash
pnpm prisma dev rm <name>
```

#### yarn

```bash
yarn prisma dev rm <name>
```

#### npm

```bash
npx prisma dev rm <name>
```

Note that `rm` deletes the instance's stored data along with the leftover lock.

## Known limitations [#known-limitations]

### Single connection only [#single-connection-only]

The local Prisma Postgres database server accepts one connection at a time. Additional connection attempts queue until the active connection closes. This constraint is sufficient for most local development and testing scenarios.

### No HTTPS connections [#no-https-connections]

The local Prisma Postgres server doesn't use HTTPS. We advise against self-hosting it.

## Related pages

- [`Local app`](https://www.prisma.io/docs/local-development/app-development): Run your app locally on the runtime Prisma Compute deploys, wire it to a local database, and bring up the whole app with Composer.
- [`Local storage`](https://www.prisma.io/docs/local-development/storage): Use S3-compatible client libraries against Prisma object storage, locally with stand-in buckets and deployed on Prisma Compute.

# Local storage (/docs/local-development/storage)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Use S3-compatible client libraries against Prisma object storage, locally with stand-in buckets and deployed on Prisma Compute.

Location: Local Development > Local storage

[Object Store buckets](https://www.prisma.io/docs/storage) speak the S3 API. Because your app talks to storage through an ordinary S3 client, the same code runs against a local stand-in bucket during development and a hosted bucket on [Prisma Compute](https://www.prisma.io/docs/compute). Nothing in your upload or download paths knows which one it is using.

## Local buckets with `dev` [#local-buckets-with-dev]

Apps deploy to Compute as [Prisma Composer](https://www.prisma.io/docs/composer) apps, and `dev` provisions a local stand-in bucket with working credentials, so upload code runs locally without an account or cloud credentials. Declare the bucket as a dependency and the service receives `{ url, bucket, accessKeyId, secretAccessKey }` from `service.load()`, the standard S3 config set, whether the bucket is local or hosted. Those four values are what your S3 client needs: pass them as its endpoint, bucket name, and credentials rather than reading them from environment variables. See [Object storage in Composer](https://www.prisma.io/docs/composer/object-storage) and [Local development in Composer](https://www.prisma.io/docs/composer/local-development).

You can also develop against a hosted bucket directly: create one with the [`bucket` CLI commands](https://www.prisma.io/docs/cli/bucket) and mint a scoped access key. The key's credentials work from your machine during development the same way they work from a deployment.

## S3-compatible clients on Compute [#s3-compatible-clients-on-compute]

Any S3 client or SDK works with buckets. The examples below use direct access-key configuration through environment variables, the shape that fits a hosted bucket with a minted key. In a Composer service, feed the client the values from `load()` instead; the client setup is otherwise identical.

### Bun's built-in S3 client [#buns-built-in-s3-client]

Compute runs deployed apps on Bun, and Bun ships an [S3 client](https://bun.com/docs/api/s3) that reads `S3_ENDPOINT`, `S3_BUCKET`, `S3_ACCESS_KEY_ID`, and `S3_SECRET_ACCESS_KEY` from the environment. With those four variables set, reading, writing, and presigning need no client configuration and no dependency:

```ts title="src/storage.ts"
// Write an object, then hand out a time-boxed download URL.
await Bun.s3.file("uploads/hello.txt").write("hello from a bucket");

const url = Bun.s3.file("uploads/hello.txt").presign({ expiresIn: 3600 });
```

[Object storage on Compute](https://www.prisma.io/docs/compute/object-storage) builds this into a deployed upload-and-serve route end to end.

### AWS SDK (`@aws-sdk/client-s3`) [#aws-sdk-aws-sdkclient-s3]

If your app already uses the AWS SDK, point it at the bucket's endpoint and credentials. These are the same four values Bun reads from the environment; in a Composer service they arrive through `load()` and slot into the same fields:

```ts title="src/storage.ts"
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";

const s3 = new S3Client({
  endpoint: process.env.S3_ENDPOINT,
  region: "auto",
  credentials: {
    accessKeyId: process.env.S3_ACCESS_KEY_ID!,
    secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
  },
});

await s3.send(
  new PutObjectCommand({
    Bucket: process.env.S3_BUCKET,
    Key: "uploads/hello.txt",
    Body: "hello from a bucket",
  }),
);
```

The SDK requires a `region`; S3-compatible endpoints ignore it, so `"auto"` is fine. Other S3-compatible libraries, such as `minio`, configure the same way: endpoint, bucket name, key id, secret.

## Next steps [#next-steps]

* [Storage](https://www.prisma.io/docs/storage): buckets, access keys, and management surfaces.
* [Object storage on Compute](https://www.prisma.io/docs/compute/object-storage): a deployed upload-and-serve route, step by step.
* [Object storage in Composer](https://www.prisma.io/docs/composer/object-storage): the declarative `bucket()` resource.

## Related pages

- [`Local app`](https://www.prisma.io/docs/local-development/app-development): Run your app locally on the runtime Prisma Compute deploys, wire it to a local database, and bring up the whole app with Composer.
- [`Local Postgres`](https://www.prisma.io/docs/local-development/postgres): Set up and use Prisma Postgres for local development

# Coming from Prisma ORM 7 (/docs/orm/coming-from-prisma-orm-7)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

What each Prisma ORM 7 schema attribute, command, and query is called in Prisma ORM 8, and what is not available.

Location: ORM > Coming from Prisma ORM 7

If you know Prisma ORM 7, this page tells you what each thing you already use is called in Prisma ORM 8. Two renamed things to know before the tables: the schema file is now called the contract (the same file, renamed), and generating the client types is now called `emit`. This page is a lookup table, not a tutorial: one table each for the schema, the command-line tool, and the query API, and a final section on what is missing.

To move a running application, follow [Migrate from Prisma ORM 7 to 8](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql) instead. It runs both versions side by side against the same database and moves one part of the app at a time. To decide whether to move at all, see [Release status](https://www.prisma.io/docs/orm/release-status).

All examples use PostgreSQL.

## Before you start [#before-you-start]

If you are adding Prisma ORM 8 to an application that runs Prisma ORM 7, do not run the new-project commands further down in that project, because `npm install prisma` installs version 8 in place of the version 7 command-line tool. Follow [Migrate from Prisma ORM 7 to 8](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql) instead. It runs both versions side by side against your existing database without changing its data, and ends with Prisma ORM 8 managing its migrations.

On PostgreSQL, the following command moves Prisma ORM 7 to the `prisma7` command and `prisma7.config.ts`, and sets up Prisma ORM 8 to read your `schema.prisma` as its contract:

  

#### bun

```bash
bunx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
```

#### yarn

```bash
yarn dlx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
```

#### npm

```bash
npx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
```

It does not change `prisma/` or the database. [`orm init` on a Prisma ORM 7 project](https://www.prisma.io/docs/cli/orm-init#on-a-prisma-orm-7-project) lists what it changes. Then run `npx prisma db sign` and continue with [phase 3 of the guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#3-migrate-one-route), moving routes one at a time to the client in `src/prisma/db.ts`. Prisma ORM 7 keeps owning your migrations until the guide's [phase 4](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#4-transfer-migration-ownership), where Prisma ORM 8 takes them over. Phase 4 needs a contract file written for Prisma ORM 8. Before you start it, create one with the guide's steps 2.3 to 2.5, and set `contract` in `prisma.config.ts` to that file's path.

To set up Prisma ORM 8 in a new project, install `prisma` and `@prisma/orm-postgres`, then run `orm init`:

  

#### bun

```bash title="Terminal"
bun add --dev prisma
bun add @prisma/orm-postgres
bunx prisma orm init --write-env
```

#### pnpm

```bash title="Terminal"
pnpm add --save-dev prisma
pnpm add @prisma/orm-postgres
pnpm prisma orm init --write-env
```

#### yarn

```bash title="Terminal"
yarn add --dev prisma
yarn add @prisma/orm-postgres
yarn prisma orm init --write-env
```

#### npm

```bash title="Terminal"
npm install --save-dev prisma
npm install @prisma/orm-postgres
npx prisma orm init --write-env
```

`orm init` writes `prisma.config.ts`, a starter `src/prisma/contract.prisma`, `src/prisma/db.ts`, and `.env`. Put your connection string in `.env` as `DATABASE_URL`, write your models in the contract, and run `npx prisma contract emit`; `db.ts` imports the two files it writes.

Commands are written as `prisma ...` in the tables below. Run them as `npx prisma ...`.

## `schema.prisma` is now `contract.prisma` [#schema]

`schema.prisma` is now `src/prisma/contract.prisma`. It is the same file, renamed: you still describe your models in it. In Prisma ORM 8, "schema" means a PostgreSQL schema, the namespace your tables live in, usually `public`.

The biggest visible change is in field types. Where Prisma ORM 7 wrote a Prisma type plus a `@db.` attribute, such as `String @db.VarChar(255)`, Prisma ORM 8 writes the database type as the field type: `VarChar(255)`.

| Prisma ORM 7                                                                                      | Prisma ORM 8                                                                             | Notes                                                                                                                                                                                                                                              |
| ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `schema.prisma`                                                                                   | `contract.prisma`                                                                        |                                                                                                                                                                                                                                                    |
| (nothing)                                                                                         | `// use prisma-8` as the first line                                                      | required in every Prisma ORM 8 `.prisma` contract file; see the note below the table                                                                                                                                                               |
| `generator client { ... }`                                                                        | removed                                                                                  | `emit` is the new word for `generate`. `prisma contract emit` writes two files next to your contract, `contract.json` and `contract.d.ts`. Commit both                                                                                             |
| `datasource db { ... }`                                                                           | the `orm` section of `prisma.config.ts`                                                  | the connection string and file paths live in the config file, not the schema. Example below                                                                                                                                                        |
| `String @db.Text`                                                                                 | `String`                                                                                 | `String` is already stored as `text`. A known bug in one error message suggests `Text`; there is no such type                                                                                                                                      |
| `String @db.VarChar(255)`                                                                         | `VarChar(255)`                                                                           | the same for every other `@db.` type: the attribute name becomes the field type. [PSL syntax](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#models-and-fields) lists them                                                                                     |
| `Decimal @db.Decimal(10, 2)`                                                                      | `Numeric(10, 2)`                                                                         | `Decimal` on its own still exists and is a `numeric` column without a fixed precision                                                                                                                                                              |
| `Int`, `Boolean`, `Float`, `BigInt`, `Bytes`                                                      | unchanged                                                                                |                                                                                                                                                                                                                                                    |
| `String @db.Uuid`                                                                                 | `Uuid`                                                                                   |                                                                                                                                                                                                                                                    |
| `DateTime`, `DateTime @db.Timestamptz`                                                            | `DateTime`                                                                               | same name, and it is already a `timestamptz` column. Values come back as `Temporal.Instant`, not JavaScript `Date`; `new Date(value.epochMilliseconds)` converts one. See the note below the table                                                 |
| `updatedAt DateTime @updatedAt`                                                                   | `updatedAt temporal.updatedAt()`                                                         | write `temporal.updatedAt()` where the type would go. It declares a `DateTime` field and sets it on every create and update. Any field name works. `temporal.` is part of the contract syntax; there is nothing to import                          |
| `createdAt DateTime @default(now())`                                                              | the same, or `createdAt temporal.createdAt()`                                            | both work. `@default(now())` is a database default. `temporal.createdAt()` is set by Prisma ORM from your application's clock and gives the column no database default                                                                             |
| `String @default(cuid())`                                                                         | `String @default(cuid(2))`                                                               | `2` is the cuid version. Plain `cuid()` is rejected                                                                                                                                                                                                |
| `@default(dbgenerated("gen_random_uuid()"))`                                                      | ``@default(sql`gen_random_uuid()`)``                                                     | `dbgenerated` is rejected. Write any SQL expression as `` sql`...` `` instead, but keep writing `now()` and `autoincrement()` as plain functions. [Default values](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#default-values) covers every kind of default |
| `Json`                                                                                            | `Jsonb`                                                                                  | Prisma ORM 7's `Json` stored a PostgreSQL `jsonb` column, so write `Jsonb`. In Prisma ORM 8, `Json` means PostgreSQL's older `json` type, which you almost certainly do not want                                                                   |
| `Json @default("{}")`                                                                             | ``Jsonb @default(json`{}`)``                                                             | write a JSON default as `` json`...` ``. A quoted string is text, and a JSON column does not accept it                                                                                                                                             |
| `enum Role { ADMIN USER }`, in a new database                                                     | `enum Role { ADMIN USER }`                                                               | same syntax. You can give members explicit values (`ADMIN = "admin"`). The column is stored as text, not as a PostgreSQL enum type                                                                                                                 |
| `enum Role { ADMIN USER }` with a field `role Role`, in an existing Prisma ORM 7 database         | `native_enum Role { ADMIN = "ADMIN" USER = "USER" }` with the field `role pg.enum(Role)` | your database already has a PostgreSQL enum type for it, and `native_enum` keeps it. See the note below the table                                                                                                                                  |
| `String[]`                                                                                        | `String[]`                                                                               | unchanged on PostgreSQL. The list filters (`has`, `hasEvery`, `hasSome`, `isEmpty`) are not available; filter on a list with raw SQL for now (see below)                                                                                           |
| `@@schema("billing")`                                                                             | `namespace billing { model ... }`                                                        | a `namespace` block is a PostgreSQL schema; wrap the models in it. They become `db.orm.billing.Invoice` and so on                                                                                                                                  |
| implicit many-to-many (`Post[]` on `Tag` and `Tag[]` on `Post`, with no model for the join table) | the same two list fields, plus a model for the join table                                | you write the join table as a model yourself. Example below                                                                                                                                                                                        |
| `@id`, `@unique`, `@default`, `@relation`, `@map`, `@@map`, `@@index`, `@@id`, `@@unique`         | unchanged                                                                                | a model without `@@map` names its table after the model, exactly as written, as in Prisma ORM 7                                                                                                                                                    |
| a required relation field over an optional foreign key, or the reverse                            | rejected                                                                                 | since `8.0.0-rc.10`, `contract emit` reports `PSL_RELATION_NULLABILITY_MISMATCH`. Give the relation field and its `@relation(fields: [...])` columns the same `?`, or none                                                                         |

> [!NOTE]
> The first line of a contract file
> 
> Every Prisma ORM 8 `.prisma` contract file must start with `// use prisma-8`. `prisma orm init` writes the line for you, so you add it yourself only when you create a contract file by hand. `prisma contract emit` reads only the `.prisma` files that start with this line and skips the others without a warning, and the [Prisma editor extension](https://www.prisma.io/docs/orm/contract-authoring/editor-support) does not recognize a file without it.

> [!NOTE]
> Enums in a database that Prisma ORM 7 created
> 
> Prisma ORM 7 stored each `enum` as a PostgreSQL enum type. To keep that type, declare the enum with `native_enum`, give every member an explicit value, and write the field's type as `pg.enum(Role)`. Like `temporal.`, `pg.` is part of the contract syntax, so there is nothing to import.
> 
> ```prisma title="src/prisma/contract.prisma (excerpt)"
> native_enum Role {
>   ADMIN = "ADMIN"
>   USER  = "USER"
> }
>
> model User {
>   id   Int           @id @default(autoincrement())
>   role pg.enum(Role)
> }
> ```
>
> A `pg.enum(...)` field supports the `eq` and `in` filters, not `like` or `ilike`. You can switch to a plain `enum` later, but that changes the column type, so it needs a migration.

> [!NOTE]
> DateTime values and Node.js versions
> 
> The `DateTime` type reads and writes its values as `Temporal.Instant` objects. If you would rather work with the timestamp as a string, write `TimestamptzString` in place of `DateTime`.
> 
> `Temporal` is built into Node.js 26 and later, but not in Node.js 22 or 24. On those versions, install `temporal-polyfill` and add this line at the top of `src/prisma/db.ts`:
> 
> ```ts
> import "temporal-polyfill/full/global";
> ```
>
> Homebrew's build of Node.js 26 leaves `Temporal` out, so check with `node -p "typeof Temporal"`; if it prints `undefined`, add the polyfill.

A many-to-many relation keeps the two list fields and adds a model for the join table. Its primary key must be the two foreign keys and nothing else, as `@@id([postId, tagId])` below:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model Post {
  id   Int    @id @default(autoincrement())
  tags Tag[]
}

model Tag {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model PostTag {
  postId Int
  tagId  Int
  post   Post @relation(fields: [postId], references: [id])
  tag    Tag  @relation(fields: [tagId], references: [id])

  @@id([postId, tagId])
}
```

That is complete as written: you do not need a `PostTag[]` field on `Post` or `Tag`. `.include("tags")` gives you `post.tags` as a `Tag[]`, and `connect` and `disconnect` work on it. `set` does not; see [Not available](#not-available-yet) below.

If the join table already exists from Prisma ORM 7, it is named `_PostToTag` with columns `A` and `B`. Keep the table by mapping the model to those names: `@@map("_PostToTag")` on the model, `@map("A")` on the field that points at the model whose name sorts first alphabetically (`postId`), and `@map("B")` on the other (`tagId`).

The config file replaces the `generator` and `datasource` blocks. This one is for PostgreSQL:

```ts title="prisma.config.ts"
import "dotenv/config";
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./src/prisma/contract.prisma",
    db: {
      connection: process.env.DATABASE_URL!,
    },
  }),
});
```

The `orm` section takes these keys:

* `contract`: the path to your contract file, or a glob for a [contract in several files](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#split-the-contract-across-several-files). On PostgreSQL it can also be `prisma7Schema("prisma/schema.prisma")`, with `prisma7Schema` imported from `@prisma/orm-postgres/config` next to `defineConfig`. The schema stays in Prisma ORM 7 syntax, so the changes in the table above do not apply to it, and it needs no `// use prisma-8` line. `contract emit` fails on any part of it that Prisma ORM 8 cannot read, such as a `view` block, and the error names the line and suggests a change to the Prisma ORM 7 schema; see [Use a Prisma ORM 7 schema](https://www.prisma.io/docs/cli/configuration#use-a-prisma-orm-7-schema).
* `db`: the connection.
* `output` (optional): where `contract.json` and `contract.d.ts` are written. Default: next to the contract.
* `extensions` (optional): database extensions, for example `extensions: [pgvector]` with `import pgvector from "@prisma/orm-extension-pgvector/control"`. See [Using extensions](https://www.prisma.io/docs/orm/extensions/using-extensions).
* `migrations` (optional): `{ dir: "migrations" }`, relative to `prisma.config.ts`. Your own migrations go in `migrations/app/` under it.

There is no `provider` setting; importing from `@prisma/orm-postgres/config` is what selects PostgreSQL.

## Commands [#commands]

The Prisma ORM 8 command-line tool groups commands by what they act on: `contract` for your contract file, `db` for the database you are connected to, and `migration` for the migration files in your repository.

| Prisma ORM 7                                                             | Prisma ORM 8                                                                                                                                           | Notes                                                                                                                                                                                                                                                                                                        |
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `prisma generate`                                                        | `prisma contract emit`                                                                                                                                 | run it after every change to the contract. It writes `contract.json` and `contract.d.ts`; commit both                                                                                                                                                                                                        |
| `prisma migrate dev`                                                     | `prisma db update`, or `prisma migration plan` then `prisma db migrate`                                                                                | see the paragraph below the table                                                                                                                                                                                                                                                                            |
| `prisma migrate deploy`                                                  | `prisma db migrate`                                                                                                                                    | applies the migration files in your repository                                                                                                                                                                                                                                                               |
| `prisma db push`                                                         | `prisma db init` the first time, on an empty database; `prisma db update` after that                                                                   | `db init` creates the tables; `db update` changes existing tables to match the contract. For a database that already has your Prisma ORM 7 tables, run neither; see [step 4 of the migration guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#4-transfer-migration-ownership). See [`db update`](https://www.prisma.io/docs/cli/db-update) |
| `prisma db pull`                                                         | `prisma contract infer`                                                                                                                                | writes a first draft of a contract from an existing database                                                                                                                                                                                                                                                 |
| `prisma migrate diff`                                                    | `prisma db update --dry-run` to see what would change in the database, or `prisma migration show <migration name>` to print what a migration file does | `<migration name>` is a folder name under `migrations/app/`, for example `20260911T1030_add_bio`. To diff two migrations into a new migration file, `prisma migration plan --from <migration name> --to <migration name>`                                                                                    |
| `prisma migrate resolve --applied`                                       | see [Rollbacks and recovery](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery)                                                                                   | for a migration that failed half way                                                                                                                                                                                                                                                                         |
| `prisma migrate resolve` for a database that already matches your schema | [step 4 of the migration guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#4-transfer-migration-ownership)                                                  | the guide records which contract the database matches, both in the database and in your repository. Follow it rather than running the commands by hand                                                                                                                                                       |
| `prisma migrate reset`                                                   | none                                                                                                                                                   | drop and recreate the database with your database tools, then `prisma db init`                                                                                                                                                                                                                               |
| `prisma db seed`                                                         | none                                                                                                                                                   | there is no seed command. Write a script that imports `db` from `src/prisma/db.ts` and calls `.create(...)`, and run it the way you run any TypeScript file, for example `npx tsx src/prisma/seed.ts`                                                                                                        |
| `prisma studio`                                                          | none in the Prisma ORM 8 tool                                                                                                                          | run Studio from the Prisma ORM 7 tool, from a directory outside your project, with the connection string spelled out: `cd /tmp && npx prisma@7 studio --url "postgresql://user:password@localhost:5432/mydb"`. See [Studio with Prisma ORM](https://www.prisma.io/docs/studio/prisma-next)                                             |
| `prisma format`                                                          | `prisma contract format`                                                                                                                               |                                                                                                                                                                                                                                                                                                              |
| `prisma validate`                                                        | none                                                                                                                                                   | `prisma contract emit` fails if the contract is invalid, and `prisma db verify` checks it against the database                                                                                                                                                                                               |

Day to day, the loop that replaces `prisma migrate dev` is: edit the contract, run `prisma contract emit`, then `prisma db update` to apply the change to your development database. `db update --dry-run` shows what it would change, and `db update` asks before it drops anything. When you want a migration file to commit, run `prisma migration plan` instead of `db update`; it writes a folder under `migrations/app/` with a `migration.ts` you can read, edit, and commit. Then `prisma db migrate` applies it. See [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration).

Four new commands you will meet first:

* `prisma orm init` sets up Prisma ORM 8 in a project: config file, starter contract, and `db.ts` (see [Before you start](#before-you-start)).
* `prisma db init` creates the tables for your contract in an empty database. (`db update` is for a database that already has tables.)
* `prisma db verify` checks whether the database still matches your contract.
* `prisma db sign` records in the database that it matches your contract. Step 4 of the migration guide runs it for your existing database; you will rarely type it yourself.

The rest are in the [CLI reference](https://www.prisma.io/docs/cli).

## `src/prisma/db.ts` replaces `PrismaClient` [#srcprismadbts-replaces-prismaclient]

There is no generated `PrismaClient`: you create the client once, in `src/prisma/db.ts`, from the two files `prisma contract emit` wrote:

```ts title="src/prisma/db.ts"
import "dotenv/config";
import postgres from "@prisma/orm-postgres/runtime";
import type { Contract } from "./contract.d";
import contractJson from "./contract.json" with { type: "json" };

export const db = postgres<Contract>({
  contractJson,
  url: process.env.DATABASE_URL!,
});
```

`prisma orm init` writes this file for you. Every example on this page imports `db` from it.

`db` has these parts:

* `db.orm`: your models, by model name (`db.orm.public.User`).
* `db.sql`: the [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder). It holds your tables by table name, as in `db.sql.public.User`, and a table's name is its model's name unless you set `@@map`. On this page, the raw SQL examples use it only to give each column's type.
* `db.raw.sql`: lets you write a SQL query as text.
* `db.runtime()`: the connection. It runs raw queries.
* `db.transaction`: runs several queries in one transaction.

To add middleware, add a `middleware: [...]` key to the `postgres({ ... })` call above. A middleware is a plain object with a name and one or more hook functions, for example `{ name: "log", async beforeQuery(plan) { console.log(plan.sql); } }`. [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works) lists the hooks.

## Queries [#queries]

A query is a chain of calls that you `await` as a whole. The last call (`.all()`, `.first()`, `.create(...)`, and so on) says what you want back, instead of one method with one big options object.

| Prisma ORM 7                                                                                   | Prisma ORM 8                                                                                                                                                                                                                                                                                                                  |
| ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `new PrismaClient()`                                                                           | `db`, from `src/prisma/db.ts` above. The examples below assume they live in a file directly inside `src/`, so the import path is `./prisma/db`                                                                                                                                                                                |
| `prisma.user`                                                                                  | `db.orm.public.User` (`public` is the PostgreSQL schema; unless you set one up, every table is in `public`)                                                                                                                                                                                                                   |
| `findMany({ where })`                                                                          | `.where(...).all()`                                                                                                                                                                                                                                                                                                           |
| `findFirst({ where })`                                                                         | `.where(...).first()`. Returns `null` when nothing matches. `.first({ id: 1 })` is a shortcut for `.where({ id: 1 }).first()`                                                                                                                                                                                                 |
| `findUnique({ where })`                                                                        | `.where(...).first()`, and check for `null`. There is no separate unique lookup                                                                                                                                                                                                                                               |
| `where: { id: 1, active: true }`                                                               | `.where({ id: 1, active: true })`; for comparisons, `.where((u) => u.age.gt(18))`. [Filter conditions and operators](https://www.prisma.io/docs/orm/reference/orm-client#filter-conditions-and-operators) lists them all                                                                                                                                |
| `select: { id: true, email: true }`                                                            | `.select("id", "email")`                                                                                                                                                                                                                                                                                                      |
| `include: { posts: { where: ... } }`                                                           | `.include("posts")`, or `.include("posts", (posts) => posts.where({ published: true }))` to filter or sort the related records                                                                                                                                                                                                |
| `where: { name: { contains: "ali" } }`                                                         | `.where((u) => u.name.like("%ali%"))`; see [Not available](#not-available-yet) for `startsWith` and case-insensitive matching                                                                                                                                                                                                 |
| `orderBy: { createdAt: "desc" }`                                                               | `.orderBy((u) => u.createdAt.desc())`                                                                                                                                                                                                                                                                                         |
| `take` / `skip`                                                                                | `.limit(n)` / `.offset(n)`                                                                                                                                                                                                                                                                                                    |
| `distinct: ["country"]`                                                                        | `.distinct("country")`                                                                                                                                                                                                                                                                                                        |
| `create({ data: { ... } })`                                                                    | `.create({ ... })`, without the `data` wrapper                                                                                                                                                                                                                                                                                |
| `create({ data: { ..., posts: { create: [...] } } })`                                          | `.create({ ..., posts: (p) => p.create([...]) })`; `connect` works the same way                                                                                                                                                                                                                                               |
| `createMany({ data: [...] })`                                                                  | `.createAll([...])` to get the rows back, or `.createAndCount([...])` to get a count                                                                                                                                                                                                                                          |
| `createMany({ data: [...], skipDuplicates: true })`                                            | `.createAll([...], { onConflict: "skip" })` or `.createAndCount([...], { onConflict: "skip" })`                                                                                                                                                                                                                               |
| `where: { title: { search: "cat & dog" } }`, with the `fullTextSearchPostgres` preview feature | `.where((p) => p.title.fullTextMatches(toTsquery("cat & dog")))`. See [Full-text search](#full-text-search) below                                                                                                                                                                                                             |
| `update({ where, data })`                                                                      | `.where(...).update({ ... })`                                                                                                                                                                                                                                                                                                 |
| `updateMany({ where, data })`                                                                  | `.where(...).updateAll({ ... })` for the rows, or `.updateAndCount({ ... })` for a count                                                                                                                                                                                                                                      |
| `delete({ where })`                                                                            | `.where(...).delete()`                                                                                                                                                                                                                                                                                                        |
| `deleteMany({ where })`                                                                        | `.where(...).deleteAll()` for the rows, or `.deleteAndCount()` for a count                                                                                                                                                                                                                                                    |
| `upsert({ where, create, update })`                                                            | `.upsert({ create: { email: "a@b.c", name: "A" }, update: { name: "A" }, conflictOn: { email: "a@b.c" } })`. `create` is the row to insert. `conflictOn` takes a unique column with its value; if a row with that value exists, `update` is applied to it instead of inserting. Leave `conflictOn` out to use the primary key |
| `count({ where })`                                                                             | `.where(...).aggregate((agg) => ({ total: agg.count() }))`, which returns one object, `{ total: 5 }`                                                                                                                                                                                                                          |
| `aggregate({ _sum, _avg })`                                                                    | `.aggregate((agg) => ({ total: agg.sum("views"), average: agg.avg("views") }))`                                                                                                                                                                                                                                               |
| `groupBy({ by, _count })`                                                                      | `.groupBy("userId").aggregate((agg) => ({ count: agg.count() }))`                                                                                                                                                                                                                                                             |
| `$transaction(async (tx) => ...)`                                                              | `db.transaction(async (tx) => ...)`; inside, query through `tx.orm` instead of `db.orm`                                                                                                                                                                                                                                       |
| `$queryRaw`                                                                                    | see the raw SQL example below                                                                                                                                                                                                                                                                                                 |
| `$executeRaw`                                                                                  | see the raw SQL example below                                                                                                                                                                                                                                                                                                 |
| `$connect()`                                                                                   | `db.connect()`. You rarely need it: the client connects on the first query                                                                                                                                                                                                                                                    |
| `$disconnect()`                                                                                | `db.close()`                                                                                                                                                                                                                                                                                                                  |

### Find with a filter [#find-with-a-filter]

```ts title="Prisma ORM 7"
const users = await prisma.user.findMany({
  where: { active: true },
  select: { id: true, email: true },
  orderBy: { createdAt: "desc" },
  take: 10,
});
```

```ts title="Prisma ORM 8"
import { db } from "./prisma/db";

const users = await db.orm.public.User
  .where({ active: true })
  .select("id", "email")
  .orderBy((u) => u.createdAt.desc())
  .limit(10)
  .all();
```

### Create a record [#create-a-record]

```ts title="Prisma ORM 7"
const user = await prisma.user.create({
  data: { email: "alice@prisma.io", name: "Alice" },
});
```

```ts title="Prisma ORM 8"
const user = await db.orm.public.User.create({
  email: "alice@prisma.io",
  name: "Alice",
});
```

### Raw SQL [#raw-sql]

```ts title="Prisma ORM 7"
const rows = await prisma.$queryRaw`SELECT id, email FROM "User" WHERE active = true`;
await prisma.$executeRaw`UPDATE "User" SET active = false WHERE id = ${id}`;
```

```ts title="Prisma ORM 8"
// A query that returns rows must say what type each column is.
const user = db.sql.public.User;
const select = db.raw.sql`SELECT id, email FROM "User" WHERE active = true`
  .returnsRow({ id: user.columns.id, email: user.columns.email })
  .build();
const rows = await db.runtime().query(select);

// A statement that changes rows: ask for the count.
const update = db.raw.sql`UPDATE "User" SET active = false WHERE id = ${id}`
  .affectedCount()
  .build();
await db.runtime().execute(update);
```

The table is `User`, because a model without `@@map` names its table after the model. As in Prisma ORM 7, a value you put in the SQL with `${...}`, such as `${id}`, is sent to the database as a query parameter.

Every raw query that returns rows needs `.returnsRow(...)` with a type per column, and you take the type from the table, as above. A computed column has no table column to take it from, so write the type name as a string instead: for `SELECT count(*) AS total FROM "User"`, write `.returnsRow({ total: "pg/int8@1" })`. [Raw queries](https://www.prisma.io/docs/orm/reference/raw-queries) lists the type names. Finish the query with `.build()` and pass it to `db.runtime().query()` for rows, or to `db.runtime().execute()` for the number of rows a write changed. On PostgreSQL, `db.runtime()` returns the connection directly, so it needs no `await`.

### Transaction [#transaction]

```ts title="Prisma ORM 7"
const [user, post] = await prisma.$transaction([
  prisma.user.create({ data: { email: "jane@prisma.io" } }),
  prisma.post.create({ data: { title: "Hello" } }),
]);
```

```ts title="Prisma ORM 8"
const result = await db.transaction(async (tx) => {
  const user = await tx.orm.public.User.create({ email: "jane@prisma.io" });
  const post = await tx.orm.public.Post.create({ title: "Hello", authorId: user.id });
  return { user, post };
});
```

### Full-text search [#full-text-search]

Import the functions that build a search query from `@prisma/orm-postgres/target/full-text`. `toTsquery` takes PostgreSQL's operator syntax as written, such as `cat & dog`, and fails on text that is not valid syntax, so use it only for text your application writes. For text a user types into a search box, use `websearchToTsquery`, which accepts quoted phrases, `or`, and `-` in front of a word to exclude it. To sort by relevance, pass the same query to `fullTextRank`:

```ts title="Prisma ORM 8"
import { websearchToTsquery } from "@prisma/orm-postgres/target/full-text";

const query = websearchToTsquery('"cat food" -dog');
const posts = await db.orm.public.Post
  .where((p) => p.title.fullTextMatches(query))
  .orderBy((p) => p.title.fullTextRank(query).desc())
  .all();
```

Add `@@fullTextIndex([title], name: "post_title_search")` to the `Post` model so PostgreSQL can use an index for the search. [Full-text search](https://www.prisma.io/docs/orm/reference/orm-client#full-text-search) covers the other options.

## Not available [#not-available-yet]

Prisma ORM 7 features that have no direct form in Prisma ORM 8, with what to do instead. The status column says whether each feature is not available, available in a different form, or, for `$extends`, replaced by middleware.

| Prisma ORM 7 feature                                                | Status                        | What to do instead                                                                                                                                                                                                                                                                                                                                                                              |
| ------------------------------------------------------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `skipDuplicates` on `createMany`                                    | available in a different form | `.createAll(rows, { onConflict: "skip" })` or `.createAndCount(rows, { onConflict: "skip" })`. See the note below the table                                                                                                                                                                                                                                                                     |
| `{ increment: n }` / `{ decrement: n }` in an update                | not available                 | write the arithmetic as raw SQL (see the example above), or read the value and write it back inside `db.transaction(...)`                                                                                                                                                                                                                                                                       |
| `findUniqueOrThrow` / `findFirstOrThrow`                            | not available on the query    | the usual form is `.first()` and a `null` check. If you want the throw, write `await db.orm.public.User.where({ id }).all().firstOrThrow()`. It throws an error with code `RUNTIME.NO_ROWS` when nothing matches. Avoid it on a filter that can match many rows; it reads them all first                                                                                                        |
| `mode: "insensitive"`                                               | available in a different form | on PostgreSQL, `.ilike("%alice%")` on a text field. You write the `%` wildcards yourself                                                                                                                                                                                                                                                                                                        |
| `contains` / `startsWith` / `endsWith`                              | available in a different form | `.like("%alice%")`, `.like("alice%")`, `.like("%alice")`; you write the `%` wildcards yourself                                                                                                                                                                                                                                                                                                  |
| filtering inside JSON (`path`, `string_contains`, `array_contains`) | not available                 | a `Jsonb` field can only be compared as a whole (`eq`, `neq`, `in`, `notIn`) or checked for null. Write the query as raw SQL (see the example above)                                                                                                                                                                                                                                            |
| `$transaction([...])` with an array of queries                      | available in a different form | `db.transaction(async (tx) => ...)`; the queries inside run one after another                                                                                                                                                                                                                                                                                                                   |
| `Prisma.User` and `Prisma.UserGetPayload<...>`                      | available in a different form | `contract.d.ts` exports a `Models` namespace with one type per model. `Scalars<Models.public_User>` is the row a plain query returns, `Shape<Models.public_User, { posts: { "+": "id" \| "title" } }>` is a row with chosen relations, and `ResultType<typeof query>` is what a query you already wrote returns. See [Model and result types](https://www.prisma.io/docs/orm/reference/orm-client#model-and-result-types) |
| implicit many-to-many relations                                     | available in a different form | write the join table as a model; see the example under [Schema](#schema)                                                                                                                                                                                                                                                                                                                        |
| `@@map` on an `enum`                                                | not available                 | `contract emit` rejects it with `Unknown attribute "@@map" in "enum" block`. A plain `enum` is stored as text, so there is nothing to name. If you need a PostgreSQL enum type with a specific name, declare it with `native_enum`, which does accept `@@map`                                                                                                                                   |
| `$use` middleware                                                   | available in a different form | pass `middleware: [...]` when you create the client in `db.ts` (example in the `db.ts` section above). [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works) lists the hooks                                                                                                                                                                                                             |
| `$extends`                                                          | replaced by middleware        | `$extends` will not be added. Middleware replaces it and can do more; see [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works)                                                                                                                                                                                                                                                          |

> [!NOTE]
> Skipping duplicate rows
> 
> With `{ onConflict: "skip" }`, `.createAll(...)` and `.createAndCount(...)` skip each row that collides with any unique constraint on the table, and `createAll` returns only the rows the database wrote. To watch only one unique constraint, list its fields in `conflictOn`:
> 
> ```ts title="Prisma ORM 8"
> const created = await db.orm.public.User.createAll(rows, {
>   onConflict: "skip",
>   conflictOn: ["email"],
> });
> ```
>
> Here `conflictOn` is a list of field names. In `upsert` it is an object of fields and values instead. A contract emitted by a release before `8.0.0-rc.12` makes the call fail with `ORM.CAPABILITY_MISSING`, so if your project used Prisma ORM 8 before that release, run `prisma contract emit` again before you use `onConflict`.

Also not available today:

* Nested writes other than `create`, `connect`, and `disconnect`: `connectOrCreate`, nested `update`, `updateMany`, `upsert`, `delete`, `deleteMany`, and `set` on a relation. Change the related rows through their own model instead, for example `db.orm.public.Post.where({ authorId }).updateAll({ ... })`, inside `db.transaction(...)` if it must be atomic.
* The list filters `has`, `hasEvery`, `hasSome`, and `isEmpty` on `String[]` and other list fields. The fields themselves work, and you can filter on them with a raw SQL query written the same way as the [raw SQL example](#raw-sql) above. For a `Post` model with a `tags String[]` field:

  ```ts title="Prisma ORM 8"
  const post = db.sql.public.Post;
  const query = db.raw.sql`SELECT id FROM "Post" WHERE ${tag} = ANY(tags)`
    .returnsRow({ id: post.columns.id })
    .build();
  const rows = await db.runtime().query(query);
  ```
* Transaction options: `isolationLevel`, `timeout`, `maxWait`, and transactions inside transactions.
* `omit`, `relationLoadStrategy`, `Prisma.skip`, and the automatic batching of `findUnique` calls.
* The `P2002` / `P2025` style error codes. Errors carry a `code` such as `RUNTIME.NO_ROWS` instead, and a database error such as a unique-constraint violation carries the standard SQL state code in `error.sqlState` (`23505` for a unique violation, on every database), so catch it with `if (error instanceof Error && "sqlState" in error && error.sqlState === "23505")`. See the [error reference](https://www.prisma.io/docs/orm/reference/error-reference).
* `Prisma.sql`, `Prisma.join`, `Prisma.raw`, `Prisma.empty`, and TypedSQL. Use `db.raw.sql` (example above); [Raw queries](https://www.prisma.io/docs/orm/reference/raw-queries) covers building a query from pieces.
* Soft delete, validation rules in the schema, lifecycle hooks on models, and read replicas. For soft delete, add a nullable `deletedAt` field and filter on it. Validate in your application code. Use middleware for hooks. For read replicas, create one client per database.

## Where to go next [#where-to-go-next]

* [Migrate from Prisma ORM 7 to 8](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql), the step-by-step migration for a running PostgreSQL application.
* [Core concepts](https://www.prisma.io/docs/orm/core-concepts), for what a contract is and what `contract emit` does.
* [ORM client reference](https://www.prisma.io/docs/orm/reference/orm-client), for every query method.
* [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data) and [Writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data), for the query API in full.
* [Release status](https://www.prisma.io/docs/orm/release-status), for how close Prisma ORM 8 is to its final release, and how to stay on Prisma ORM 7.

## Related pages

- [`Core concepts`](https://www.prisma.io/docs/orm/core-concepts): The ideas every Prisma ORM command and API builds on: contracts, emitting, plans, the database signature, codecs, and the migration graph.
- [`Extensions`](https://www.prisma.io/docs/orm/extensions): Every package that plugs into Prisma ORM: database packages, column types, indexes, query operations, and middleware, by Prisma and the community.
- [`Overview`](https://www.prisma.io/docs/orm/data-modeling): Describe the data your application needs with models, primary keys, scalar fields, and relations.
- [`Prisma 7`](https://www.prisma.io/docs/orm/v7): Prisma ORM is a next-generation Node.js and TypeScript ORM that provides type-safe database access, migrations, and a visual data editor.
- [`Prisma ORM`](https://www.prisma.io/docs/orm/v6): Learn about Prisma ORM

# Core concepts (/docs/orm/core-concepts)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The ideas every Prisma ORM command and API builds on: contracts, emitting, plans, the database signature, codecs, and the migration graph.

Location: ORM > Core concepts

Prisma ORM 8 is the current major version. To meet the evolving needs of developers, it has been rebuilt in TypeScript according to one idea: your application and database follow an explicit, checkable agreement of how all data is structured.

This idea relies upon a small vocabulary which repeats throughout: in the CLI, in the query APIs, and in error messages. The sections below define each term in plain language; each also links to relevant in-depth information.

## The contract and the schema [#the-contract-and-the-schema]

The contract is your description of the data your application needs: the models, their fields, how they relate, and how they map to database tables or collections. You author it in PSL (the Prisma schema language) in a `.prisma` file, or in TypeScript:

```prisma title="prisma/contract.prisma"
// use prisma-8

model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  published Boolean @default(false)
  userId    Int

  user User @relation(fields: [userId], references: [id])
}
```

The schema differs in that it is the actual structure of the database: the tables or collections, plus their indexes, that exist right now. The contract lives in your repository; the schema lives in the database. Everything Prisma ORM does is a relationship between the two: queries are typed against the contract, migrations move the schema toward the contract, and verification checks that the schema still satisfies it.

> [!NOTE]
> Contract vs. schema
> 
> Other tools use "schema" to refer to the file that you write. However, in Prisma ORM, you author a **contract** and the **schema** is held by the database; therefore, be aware that when a command or error message mentions the "schema", this refers to the database side.

Read more in [The data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract), and author it [in PSL](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax) or [in TypeScript](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder).

## Emitting: from source to artifacts [#emitting-from-source-to-artifacts]

Emitting is the build step that compiles your contract source into two plain files:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

1. `contract.json`: a canonical JSON description of your models, storage layout, and required capabilities.
2. `contract.d.ts`: the TypeScript types derived from it, which is what makes your queries type-safe.

Every other part of the toolchain reads these artifacts, not your source file: the query APIs read `contract.d.ts` for types, the migration planner diffs two `contract.json` files, and the runtime verifies `contract.json` against the database. That is why `contract emit` comes first in almost every workflow: after any contract change, emit before you plan, migrate, or run.

Emission is deterministic: the same source always produces byte-identical artifacts, so both files are committed to version control and diff cleanly in code review. Think of the pair like `package.json` and `package-lock.json`: the source is what you ask for, the artifacts are the exact resolved result.

See [contract.json and contract.d.ts](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact) for what is inside each file.

## Hashes and the database signature [#hashes-and-the-database-signature]

A hash is a short fingerprint computed from a file's content: the same content always produces the same hash, while any change will produce a different one. Because emission is deterministic, hashing `contract.json` gives an identifier for that exact contract state, the way a Git commit hash identifies an exact state of your code. Contract hashes appear throughout the CLI; a migration, for example, records the hash it starts from and the hash it produces.

The database carries the other half of the agreement: a **signature**, a small marker record stored in the database itself that names the contract hash the database currently satisfies. [`db sign`](https://www.prisma.io/docs/cli/db-sign) writes it, and [`db migrate`](https://www.prisma.io/docs/cli/db-migrate) updates it each time it applies a migration.

The two halves make the agreement checkable from either side:

1. Before executing queries, the runtime can compare the contract that your application was built with against the database's signature and stop when it encounters a mismatch, for example a deploy against an unmigrated database, before it produces incorrect results.
2. Before applying a migration, the runner checks that the database's signature matches the contract hash the migration starts from.

When the contract and the database disagree, the resulting state is called **drift**. [`db verify`](https://www.prisma.io/docs/cli/db-verify) is the read-only command that reports it.

## Queries compile to plans [#queries-compile-to-plans]

A **plan** is the compiled form of a query: a plain data object holding the statement to run, its parameters, and metadata about what the query touches. Every query, whichever API produced it, becomes a plan before it executes; running the plan is a separate step.

With the SQL query builder, the two steps are visible in your code:

```typescript
import { db } from "./prisma/db";

const plan = db.sql.public.Post
  .select("id", "title", "userId")
  .where((f, fns) => fns.eq(f.published, true))
  .limit(10)
  .build();

const publishedPosts = await db.runtime().query(plan);
```

Plans matter for two reasons:

1. **Every query goes through the same pipeline.** However a query is written (the ORM client, a query builder, a raw fragment, or an API that an extension added), it reaches the database as a plan. Middleware sees every query in the same shape, execution works the same way for all of them, and the query APIs can be mixed freely. In addition, one policy (an authorization check, for instance) can sit in one place and see everything.
2. **A plan is data.** The statement and its parameters exist as an object before anything touches the database: middleware can check them, telemetry can record them, and a failed query can report exactly what it ran.

## The query APIs [#the-query-apis]

All query APIs are typed against the contract and all produce plans. They differ in how much of the statement you write yourself.

The **ORM client** is where you start on both databases: model-based queries such as `db.orm.public.User.where(...)`. It is more than a query builder; for example, the `.include()` operation coordinates several queries on your behalf to serve higher-order needs, relation traversal above all, and hands back one typed result. For more information, start with [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data).

Beneath it, each database family has a typed builder for the queries that the ORM client cannot express, and a raw escape hatch below that. A builder plan compiles to exactly one statement, so what you build is what runs:

|                  | PostgreSQL                                                                                                                             | MongoDB                                                                              |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| Typed builder    | [The SQL query builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries): composable joins, grouping, projections                                   | [The pipeline builder](https://www.prisma.io/docs/orm/reference/pipeline-builder): typed aggregation pipelines |
| Raw escape hatch | [Raw SQL](https://www.prisma.io/docs/orm/reference/raw-queries): `fns.raw` fragments spliced into builder queries, or whole statements written with `db.raw.sql` | [Raw commands](https://www.prisma.io/docs/orm/reference/raw-queries) sent to the driver                        |

Raw queries are still plans, so middleware and telemetry see them as any other query. A whole `db.raw.sql` statement declares its row shape with `.returnsRow(spec)`, so its rows come back decoded. `fns.raw` fragments and MongoDB raw commands carry no result shape, so you must handle those values yourself; the [raw queries reference](https://www.prisma.io/docs/orm/reference/raw-queries) explains what that means for different databases.

## The stack behind one package [#the-stack-behind-one-package]

One facade package connects your code to your database. A PostgreSQL project installs `@prisma/orm-postgres`, and its config helper wires up everything underneath: the database **family** (SQL), the **target** dialect (PostgreSQL), the **adapter** that translates plans into that dialect, and the **driver** that holds the network connection. These four names recur in error messages and extension docs; day to day, you configure the one facade package and move on.

Prisma ORM's layering exists for extensibility. Our core remains small, because it is focused; everything around it, including PostgreSQL support, plugs in through the same public interfaces. A new database is supported by writing a new target, adapter and driver, without any need to change the core.

## Capabilities [#capabilities]

A **capability** is a specific feature that a database may or may not support, such as `RETURNING` clauses or vector indexes. Your contract declares the capabilities it needs; the adapter reports what the connected database provides. Prisma ORM compares the two at startup, so a missing feature surfaces as one clear error when the app boots, instead of as a failed query later. See [Supported database features](https://www.prisma.io/docs/orm/contract-authoring/capabilities) for more information.

## Codecs [#codecs]

A **codec** converts values between JavaScript and the database's wire format, in both directions. Every column type in your contract is backed by one: a PostgreSQL `timestamptz` column has a codec that produces a JavaScript `Date` when you read and encodes it back when you write. This means that when you pick a column type in PSL, you are also picking the codec that will handle every value that column carries.

Extensions bring codecs for the types they add: with pgvector installed, a `Vector(1536)` column comes back as a typed vector rather than a string. Raw fragments and raw commands skip this conversion step, so with those you convert the values yourself.

## Extensions [#extensions]

An extension is an installable package that plugs new pieces into the toolchain: column types and their codecs, query operations, index kinds, capabilities, and, at the widest, support for an entire database. One package extends the contract language, the emitted types, the query builders, and migrations together.

Extensions are declared in `prisma.config.ts` and registered on the client:

```ts title="prisma.config.ts"
import { definePrismaConfig } from 'prisma/config';
import pgvector from '@prisma/orm-extension-pgvector/control';
import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';

export default definePrismaConfig({
  orm: ormConfig({
    contract: './src/prisma/contract.prisma',
    extensions: [pgvector],
    db: {
      connection: process.env['DATABASE_URL']!,
    },
  }),
});
```

Subsequently, `pgvector.Vector(1536)` is a column type in your contract, vector operators appear in the query builder, and `migration plan` knows how to create vector indexes. See [Using extensions](https://www.prisma.io/docs/orm/extensions/using-extensions).

## Middleware [#middleware]

A middleware is a plain object with a name and one or more hooks that run around every query, following the same principles as in Express or Koa. You need only register it once, in the `middleware` option of your client setup. Because every query is a plan, middleware gets a structured object to inspect: it can log it, enforce limits on it, or reject it, without changing how queries are written. That makes middleware the place for one policy that must cover the whole app, such as an authorization rule that examines every plan before it runs.

Three middleware ship with Prisma ORM at present, and they are in the early stages: treat them as working demonstrations of the pattern rather than finished products. [Budgets](https://www.prisma.io/docs/orm/middleware/built-in-budgets) caps row counts and surfaces slow queries, [lints](https://www.prisma.io/docs/orm/middleware/built-in-lints) blocks risky query shapes, and [cache](https://www.prisma.io/docs/orm/middleware/built-in-cache) serves repeated reads from memory. For policy that your app depends on, [write your own](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware); the middleware API is the durable surface. Start by exploring [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works).

## Migrations: a graph of contracts [#migrations-a-graph-of-contracts]

A **migration** is a recorded change to your database. Most migrations change the database schema from what one contract describes to what another describes, so each one records which contract hash it starts `from` and which it ends at, `to`. A migration that only changes rows, such as a backfill, starts and ends at the same contract state. On disk, a migration is a directory in your repository that holds the change as editable TypeScript (`migration.ts`), the compiled operations that Prisma ORM runs (`ops.json`), and that `from` and `to` metadata (`migration.json`).

Of the commands that work with migrations, only [`db migrate`](https://www.prisma.io/docs/cli/db-migrate) changes a database: it applies the recorded migrations to it. The `migration ...` commands create and inspect the migration files in your repository. Of those, only `migration status` and `migration log` connect to a database, and they only read it.

Because every migration records its `from` and `to` hashes, the migrations in a repository form a **graph**: contracts are the nodes, migrations are the edges. When two branches each add a migration and both merge, the graph has a fork and a join, and `db migrate` works out which migrations to run, given the contract state the database matches and the one you name. No renumbering, no rebasing migration files.

A **ref** is a named pointer at a contract, such as `production` or `staging`, managed with [`migration ref`](https://www.prisma.io/docs/cli/migration-ref). Refs let deployment commands target an environment by name: `db migrate --to production`.

If you know Git, the whole vocabulary maps across:

| Git                     | Prisma ORM                         |
| ----------------------- | ---------------------------------- |
| A commit                | A contract, identified by its hash |
| A patch between commits | A migration                        |
| A branch or tag         | A ref                              |
| `HEAD`                  | The database signature             |
| `git checkout <commit>` | `db migrate --to <contract>`       |

Start with [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work), then [The migration graph](https://www.prisma.io/docs/orm/migrations/the-migration-graph) for the branching story.

## How the CLI commands combine [#how-the-cli-commands-combine]

One rule divides the whole [CLI](https://www.prisma.io/docs/cli): `db ...` commands connect to a live database and can change it, while `contract ...` and `migration ...` commands work on the files in your repository. The one exception is `contract infer`, which reads a live database, changing nothing in it, to write a starter contract file. If you are unsure what a command might touch, its first word provides the answer: only `db` can change a database.

The commands compose into four everyday workflows.

**The development loop.** Edit your contract, emit it, turn the change into a reviewable migration, apply it:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_user_phone
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_user_phone
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_user_phone
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_user_phone
npx prisma db migrate --advance-ref db
```

`--advance-ref db` records what you just applied, so the next `migration plan` starts from there. [The db ref](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-db-ref-skipping---from) explains it.

**Prototyping without migration files.** While a schema is still in flux, skip the migration directory and reconcile the database directly. [`db update`](https://www.prisma.io/docs/cli/db-update) diffs the live schema against the emitted contract and applies the difference; `--dry-run` previews it first:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma db update --db "$DATABASE_URL" --dry-run
bunx prisma db update --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma db update --db "$DATABASE_URL" --dry-run
pnpm prisma db update --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma db update --db "$DATABASE_URL" --dry-run
yarn prisma db update --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma contract emit
npx prisma db update --db "$DATABASE_URL" --dry-run
npx prisma db update --db "$DATABASE_URL"
```

When the shape settles, switch to `migration plan` so changes become reviewable files.

**Adopting an existing database.** [`contract infer`](https://www.prisma.io/docs/cli/contract-infer) writes a starter contract from a live schema. Review and edit it, emit, then bring the database under contract management: [`db init`](https://www.prisma.io/docs/cli/db-init) applies only additive changes and writes the first signature. If the database already matches the contract exactly, [`db sign`](https://www.prisma.io/docs/cli/db-sign) records the signature without changing anything:

  

#### bun

```bash
bunx prisma contract infer --db "$DATABASE_URL"
bunx prisma contract emit
bunx prisma db init --db "$DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma contract infer --db "$DATABASE_URL"
pnpm prisma contract emit
pnpm prisma db init --db "$DATABASE_URL"
```

#### yarn

```bash
yarn prisma contract infer --db "$DATABASE_URL"
yarn prisma contract emit
yarn prisma db init --db "$DATABASE_URL"
```

#### npm

```bash
npx prisma contract infer --db "$DATABASE_URL"
npx prisma contract emit
npx prisma db init --db "$DATABASE_URL"
```

**Deploying.** Give each environment a ref, such as `production`, that names the contract state the environment should reach. When a change is ready to ship, point the ref at the new state with [`migration ref set`](https://www.prisma.io/docs/cli/migration-ref), such as `npx prisma migration ref set production <hash>`, and commit the ref file it writes under `migrations/app/refs/`. The deploy pipeline then migrates the environment to its ref by name, and that one command is all it needs. `db migrate` refuses to run a migration whose files no longer match its hash, so the pipeline needs no separate check:

  

#### bun

```bash
bunx prisma db migrate --db "$DATABASE_URL" --to production
```

#### pnpm

```bash
pnpm prisma db migrate --db "$DATABASE_URL" --to production
```

#### yarn

```bash
yarn prisma db migrate --db "$DATABASE_URL" --to production
```

#### npm

```bash
npx prisma db migrate --db "$DATABASE_URL" --to production
```

[`migration check`](https://www.prisma.io/docs/cli#other-commands) runs the same file checks offline, which is useful before you commit a migration you edited by hand, and [`db verify`](https://www.prisma.io/docs/cli/db-verify) checks, without changing anything, whether a database satisfies the contract.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects scaffolded with `create-prisma@latest` install [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. Ask your agent to:

* "Using the prisma-8 skill, explain the difference between our contract and the database schema."
* "Show me the plan the SQL query builder produces for this query."
* "Which of our CLI scripts touch the live database, and which are offline?"

## Next steps [#next-steps]

* [The data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract): the concept that this whole page hangs off, in depth.
* [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data): put the ORM client to work against your contract.
* [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work): change your contract, then plan, review, and apply the migration, hands-on.

## Related pages

- [`Coming from Prisma ORM 7`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7): What each Prisma ORM 7 schema attribute, command, and query is called in Prisma ORM 8, and what is not available.
- [`Extensions`](https://www.prisma.io/docs/orm/extensions): Every package that plugs into Prisma ORM: database packages, column types, indexes, query operations, and middleware, by Prisma and the community.
- [`Overview`](https://www.prisma.io/docs/orm/data-modeling): Describe the data your application needs with models, primary keys, scalar fields, and relations.
- [`Prisma 7`](https://www.prisma.io/docs/orm/v7): Prisma ORM is a next-generation Node.js and TypeScript ORM that provides type-safe database access, migrations, and a visual data editor.
- [`Prisma ORM`](https://www.prisma.io/docs/orm/v6): Learn about Prisma ORM

# Prisma ORM (/docs/orm)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma ORM 8 is the next major version, with a TypeScript runtime, contract-based data models, a new query API, and a revised migration workflow.

Location: Prisma ORM

Prisma ORM 8 rewrites Prisma ORM in TypeScript. The schema-first workflow and model-first queries from earlier versions stay, but what changes is what your schema produces and how queries run. This page gives you the mental model, and the [quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql) gets you to a running query.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release, as a release candidate. Prisma ORM 7 remains fully supported; its docs live at [/orm/v7](https://www.prisma.io/docs/orm/v7) and its setup paths at [/v7/getting-started](https://www.prisma.io/docs/v7/getting-started).
> 
> For what release candidate means, when the final release is expected, and how to stay on version 7, see [Release status](https://www.prisma.io/docs/orm/release-status). For the Prisma ORM 8 name of every Prisma ORM 7 API, see [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7).

## Your schema becomes a contract [#your-schema-becomes-a-contract]

You still author models in a Prisma schema file (or in TypeScript), but instead of generating a client package, Prisma ORM emits the schema as a **contract**: a JSON document plus TypeScript types that your application, the migration tools, and coding agents all read. The contract is a plain artifact you can inspect and diff.

The workflow has three steps:

1. **Author your schema**: define your models in a Prisma schema (`.prisma`) or directly in TypeScript.
2. **Emit the contract**: a lightweight build step turns the schema into a deterministic JSON contract plus TypeScript types.
3. **Query with a composable DSL**: write queries inline against the typed contract. Each query compiles to a verifiable plan at runtime, with no hidden client methods.

## What changed for developers [#what-changed-for-developers]

* **Better queries**: simpler nested queries, custom collection methods on your models, results you can iterate a record at a time, and a low-level type-safe SQL builder when you need raw control.
* **Extensible by design**: a minimal core exposed through a public SPI. Everything around it, including Postgres support itself, is an extension, so you can add databases, query builders, data types, and middleware.
* **Rethought migrations**: [graph-based migrations](https://www.prisma.io/docs/orm/migrations/the-migration-graph) that resolve branch conflicts automatically and make partial failures safe to retry, with both schema and data migrations written in TypeScript and validated against your contract.
* **AI-agent friendly**: the contract is machine-readable and each query produces an inspectable plan, which gives coding agents something concrete to check their work against. The installers also register agent skills for your editor's AI assistant.

### Supported databases [#supported-databases]

Prisma ORM ships first-class support for **PostgreSQL** (the primary target), **MongoDB**, and **SQLite** (`@prisma/orm-sqlite`). **MySQL** support is planned next.

## Get started [#get-started]

Scaffold a new project in one command:

  

#### bun

```bash
bun create prisma@latest
```

#### pnpm

```bash
pnpm create prisma@latest
```

#### yarn

```bash
yarn create prisma@latest
```

#### npm

```bash
npm create prisma@latest
```

- [Quickstart with PostgreSQL](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql): Scaffold a Prisma ORM app with PostgreSQL, seed it, and run your first query.

- [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql): Add Prisma ORM to an existing app with the `orm init` command.

- [The full stack path](https://www.prisma.io/docs): Prisma ORM with Prisma Postgres and a Prisma Compute deploy, with guide and agent options.

## Go deeper [#go-deeper]

- [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): Read, write, and relate data with the ORM, run transactions, and reach for advanced queries when you need them.

- [The data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract): Learn how your schema becomes a verifiable contract, authored in PSL or TypeScript.

- [CLI reference](https://www.prisma.io/docs/cli): The contract, database, and migration commands in the Prisma ORM CLI.

- [See your migrations in Studio](https://www.prisma.io/docs/studio/prisma-next): Read your applied migration history in Prisma Studio: a visual diff, the executed SQL, and a schema diff per migration.

- [Deploy the application](https://www.prisma.io/docs/prisma-compute/deploy): Deploy your Prisma ORM app to Prisma Compute, next to your Prisma Postgres database.

## Learn more about the design of Prisma ORM [#learn-more-about-the-design-of-prisma-orm]

The thinking behind Prisma ORM is documented on the [Prisma blog](https://www.prisma.io/blog). Start with these:

* **[The Next Evolution of Prisma ORM](https://www.prisma.io/blog/the-next-evolution-of-prisma-orm)**: why Prisma is being rebuilt, with a tour of the new query API, extensibility model, migrations, and AI-friendly design.
* **[Rethinking Database Migrations](https://www.prisma.io/blog/rethinking-database-migrations)**: how graph-based migrations replace timestamp ordering with schema state hashes.
* **[Prisma 8 Is \~90% As Fast as Raw PG](https://www.prisma.io/blog/prisma-next-performance-benchmark)**: benchmarks against the raw PostgreSQL driver.

The full series also covers [TypeScript migrations](https://www.prisma.io/blog/typescript-migrations-in-prisma-next), [data migrations](https://www.prisma.io/blog/data-migrations-in-prisma-next), [the extension API](https://www.prisma.io/blog/prisma-next-call-for-extension-authors), the [roadmap](https://www.prisma.io/blog/prisma-next-roadmap), and the [early-access launch](https://www.prisma.io/blog/prisma-next-early-access-write-your-contract-prompt-your-agent-ship-your-app). The source lives on [GitHub](https://github.com/prisma/orm).

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# Release status (/docs/orm/release-status)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Where Prisma ORM 8 stands today, what you get when you install it, and how to stay on Prisma ORM 7.

Location: ORM > Release status

Prisma ORM 8 is a **release candidate**: you can install it and build with it today. Until the final release, some details of the API may still change, so code you write now may need small edits later. Each release candidate fixes bugs found in the previous one. What Prisma ORM 8 changes, and why, is on the [Prisma ORM overview](https://www.prisma.io/docs/orm).

It needs Node.js 22.18 or newer (on the 24 line, 24.11 or newer; 24.0 to 24.10 do not work) and TypeScript 5.9 or newer.

Before you decide, read [what is not available yet](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#not-available-yet). Today that includes `$extends`, filtering inside JSON columns, atomic `increment`, most nested writes, transaction isolation levels, and the `P2002`-style error codes.

## When the final release is expected [#when-the-final-release-is-expected]

General availability is expected in October 2026.

## Prisma ORM 7 is supported for 18 months after the final release [#prisma-orm-7-is-supported-for-18-months-after-the-final-release]

Prisma ORM 7 keeps receiving bug fixes and security updates for 18 months from the day Prisma ORM 8 reaches general availability. Its documentation stays at [/orm/v7](https://www.prisma.io/docs/orm/v7).

## Prisma ORM 6 receives security patches until 19 November 2026 [#prisma-orm-6-receives-security-patches-until-19-november-2026]

Prisma ORM 6 receives security patches, but no other updates, for 12 months after the release of Prisma ORM 7, a period that ends on 19 November 2026. Its documentation stays at [/orm/v6](https://www.prisma.io/docs/orm/v6).

## What you get when you install today [#what-you-get-when-you-install-today]

Prisma ORM 8 is two packages: the command-line tool, and a library your app imports. There is one library per database; for PostgreSQL it is `@prisma/orm-postgres`.

  

#### bun

```bash
bun add --dev prisma
bun add @prisma/orm-postgres
```

#### pnpm

```bash
pnpm add --save-dev prisma
pnpm add @prisma/orm-postgres
```

#### yarn

```bash
yarn add --dev prisma
yarn add @prisma/orm-postgres
```

#### npm

```bash
npm install --save-dev prisma
npm install @prisma/orm-postgres
```

For MongoDB the library is `@prisma/orm-mongo`. [Supported databases](https://www.prisma.io/docs/orm/supported-databases) lists every database and its status.

The two packages have different version numbers, and that is normal: they are released separately, and the command-line tool gets more frequent releases. Install both at `latest`; any two `latest` versions work together, and you do not pair the numbers yourself.

| Package                                   | `latest` on 28 September 2026 |
| ----------------------------------------- | ----------------------------- |
| `prisma` (the command-line tool)          | `8.0.0-rc.17`                 |
| `@prisma/orm-postgres` (the library)      | `8.0.0-rc.13`                 |
| `@prisma/orm-mongo` (the MongoDB library) | `8.0.0-rc.13`                 |

To see the `latest` version of each package today, run `npm view prisma dist-tags`, `npm view @prisma/orm-postgres dist-tags`, and `npm view @prisma/orm-mongo dist-tags`, and read the `latest` entry in each result. You need all three commands because the command-line tool and the libraries are versioned separately.

`@prisma/client`, the library that Prisma ORM 7 apps import, stays at `7.10.0`, because it belongs to Prisma ORM 7 and is not part of Prisma ORM 8.

> [!WARNING]
> If you have a Prisma ORM 7 project
> 
> `npm install prisma` and `npx prisma` now give you the Prisma ORM 8 command-line tool, which does not read `schema.prisma` and has no `generate`, `migrate dev`, or `db push` commands. If your project is on Prisma ORM 7, run `npm install --save-dev prisma@7` now, and lock the version in `package.json` as shown below. If version 8 is already installed, that same command downgrades it. To see what you have now, run `npm ls prisma @prisma/client`.

## How to stay on Prisma ORM 7 [#how-to-stay-on-prisma-orm-7]

Lock both packages to version 7 in `package.json`:

```json title="package.json"
{
  "devDependencies": {
    "prisma": "^7"
  },
  "dependencies": {
    "@prisma/client": "^7"
  }
}
```

Anywhere you run the tool without a locked version, for example in CI or in a one-off command, write `npx prisma@7` instead of `npx prisma`.

The Prisma ORM 7 documentation is at [/orm/v7](https://www.prisma.io/docs/orm/v7), its setup guides at [/v7/getting-started](https://www.prisma.io/docs/v7/getting-started), and its command reference at [/cli/v7](https://www.prisma.io/docs/cli/v7).

## Next steps [#next-steps]

* To move an existing Prisma ORM 7 app, follow [Migrate from Prisma ORM 7 to 8](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql). It runs both versions side by side and moves one part of the app at a time.
* To see what each Prisma ORM 7 command and query is called now, and what is not available yet, see [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7).

## Related pages

- [`Coming from Prisma ORM 7`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7): What each Prisma ORM 7 schema attribute, command, and query is called in Prisma ORM 8, and what is not available.
- [`Core concepts`](https://www.prisma.io/docs/orm/core-concepts): The ideas every Prisma ORM command and API builds on: contracts, emitting, plans, the database signature, codecs, and the migration graph.
- [`Extensions`](https://www.prisma.io/docs/orm/extensions): Every package that plugs into Prisma ORM: database packages, column types, indexes, query operations, and middleware, by Prisma and the community.
- [`Overview`](https://www.prisma.io/docs/orm/data-modeling): Describe the data your application needs with models, primary keys, scalar fields, and relations.
- [`Prisma 7`](https://www.prisma.io/docs/orm/v7): Prisma ORM is a next-generation Node.js and TypeScript ORM that provides type-safe database access, migrations, and a visual data editor.

# Supported databases (/docs/orm/supported-databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Which databases Prisma ORM 8 supports today, what each one gets, which hosted providers work, and which databases are coming.

Location: ORM > Supported databases

Prisma ORM 8 ships one library per database, and installing the one that matches yours brings the config, the client, contract authoring, and migrations with it. Today there are two you can build on, and an experimental third.

| Database                              | Status                    | Library                | Install                            |
| ------------------------------------- | ------------------------- | ---------------------- | ---------------------------------- |
| PostgreSQL, including Prisma Postgres | Release candidate         | `@prisma/orm-postgres` | `npm install @prisma/orm-postgres` |
| MongoDB                               | Early access              | `@prisma/orm-mongo`    | `npm install @prisma/orm-mongo`    |
| MySQL                                 | Coming soon, planned next |                        |                                    |
| MariaDB                               | Coming soon               |                        |                                    |
| SQLite                                | Experimental              | `@prisma/orm-sqlite`   | `npm install @prisma/orm-sqlite`   |
| Microsoft SQL Server                  | Coming soon               |                        |                                    |
| CockroachDB                           | Coming soon               |                        |                                    |

`npm create prisma@latest -- my-app` asks which database you use and installs the right library for you. See the [PostgreSQL quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql) or the [MongoDB quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/mongodb).

## What the labels mean [#what-the-labels-mean]

**Release candidate.** Install it and build with it today. Until the final release, some details of the API may still change, so code you write now may need small edits later. Each release candidate fixes bugs found in the last one. [Release status](https://www.prisma.io/docs/orm/release-status) has the dates and what `npm install` gives you.

**Early access.** The library works and you can build with it, but some of what the PostgreSQL library does is not there yet. The table below and the reference pages say what works on MongoDB, and [what is not available yet](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#not-available-yet) lists the gaps. Report what you hit on [GitHub](https://github.com/prisma/orm/issues).

**Experimental.** SQLite is published as an experimental package, [`@prisma/orm-sqlite`](https://www.prisma.io/extensions/sqlite), without a quickstart yet. `db.transaction(...)` works the same way as on PostgreSQL.

**Coming soon.** There is no Prisma ORM 8 library for the database yet. Prisma ORM 7 supports it, and Prisma ORM 7 keeps receiving bug fixes and security updates for 18 months after Prisma ORM 8 reaches general availability. [How to stay on Prisma ORM 7](https://www.prisma.io/docs/orm/release-status#how-to-stay-on-prisma-orm-7) shows how to lock the version.

## What each database supports [#what-each-database-supports]

The ORM client works the same on both databases. The lower-level query APIs follow the database's own query model.

| Feature                                                               | PostgreSQL | MongoDB                     |
| --------------------------------------------------------------------- | ---------- | --------------------------- |
| [ORM client](https://www.prisma.io/docs/orm/reference/orm-client)                               | Yes        | Yes                         |
| [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder)                 | Yes        | No                          |
| [Pipeline builder](https://www.prisma.io/docs/orm/reference/pipeline-builder)                   | No         | Yes                         |
| [Raw queries](https://www.prisma.io/docs/orm/reference/raw-queries)                             | Raw SQL    | Raw commands                |
| [Transactions](https://www.prisma.io/docs/orm/fundamentals/transactions)                        | Yes        | Not yet                     |
| [Migrations](https://www.prisma.io/docs/orm/migrations/how-migrations-work)                     | Yes        | Yes                         |
| [Extensions](https://www.prisma.io/docs/orm/extensions) (pgvector, PostGIS, ParadeDB, and more) | Yes        | Not yet                     |
| [Middleware](https://www.prisma.io/docs/orm/middleware/how-middleware-works)                    | Yes        | Yes, except `beforeCompile` |

`db.transaction()` exists on the PostgreSQL client only, because Prisma ORM does not support MongoDB transactions yet. For multi-document writes on MongoDB, [use the MongoDB driver's session API](https://www.prisma.io/docs/orm/fundamentals/transactions#transactions-on-mongodb) alongside the client.

Middleware hooks are the same on both databases apart from `beforeCompile`, which rewrites the SQL query before it runs and so exists only on PostgreSQL. The built-in `lints` and `budgets` middleware inspect SQL and run on PostgreSQL. The `cache` middleware runs on both. See [which databases a middleware runs on](https://www.prisma.io/docs/orm/middleware/how-middleware-works#which-databases-a-middleware-runs-on).

Every extension in the [directory](https://www.prisma.io/extensions) lists the databases it targets. Today every extension that adds column types, operators, or index types targets PostgreSQL, and the only entries that list MongoDB are the database libraries and the `cache` middleware.

## Managed and hosted databases [#managed-and-hosted-databases]

Prisma ORM connects with a standard connection string, so any host that gives you one works.

| Provider                                               | Database   | Notes                                                                                                                                                  |
| ------------------------------------------------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Prisma Postgres](https://www.prisma.io/docs/postgres)                           | PostgreSQL | The default in `npm create prisma@latest`. Provisioned from the CLI, with connection pooling built in.                                                 |
| Supabase                                               | PostgreSQL | The [Supabase extension](https://www.prisma.io/extensions/supabase) adds the auth and storage tables and role-bound clients.                           |
| Neon, Railway, Render, AWS RDS, Cloud SQL, self-hosted | PostgreSQL | Any PostgreSQL server. Extensions such as pgvector and PostGIS need the server-side extension to be installable, which most managed providers include. |
| MongoDB Atlas, self-hosted MongoDB                     | MongoDB    | Any MongoDB deployment reachable with a `mongodb://` or `mongodb+srv://` URL.                                                                          |

## Databases that are coming [#databases-that-are-coming]

MySQL is planned next and is not part of the Prisma ORM release candidate. MariaDB, Microsoft SQL Server, and CockroachDB have no Prisma ORM 8 library yet either. To stay on a supported path for those databases today, use [Prisma ORM 7](https://www.prisma.io/docs/orm/v7/reference/supported-databases), which supports all of them.

Add a 👍 to the GitHub issue for the database you need, or open one if there is none, because the number of reactions is one of the inputs to what gets built next. Organizations that need a database sooner can talk to [Prisma enterprise support](https://www.prisma.io/enterprise).

Because a database library is an extension, a community package can add a database Prisma does not ship. If you publish one, [submit it to the directory](https://www.prisma.io/extensions/submit) and name the database it adds in the submission.

## Next steps [#next-steps]

* The quickstart sets up a project on [PostgreSQL](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql) or [MongoDB](https://www.prisma.io/docs/prisma-orm/quickstart/mongodb).
* [Release status](https://www.prisma.io/docs/orm/release-status) covers versions, dates, and staying on Prisma ORM 7.
* [Prisma ORM 7 supported databases](https://www.prisma.io/docs/orm/v7/reference/supported-databases) has the full matrix for the current generally available release.
* [Extensions](https://www.prisma.io/docs/orm/extensions) lists what you can add to PostgreSQL.

## Related pages

- [`Coming from Prisma ORM 7`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7): What each Prisma ORM 7 schema attribute, command, and query is called in Prisma ORM 8, and what is not available.
- [`Core concepts`](https://www.prisma.io/docs/orm/core-concepts): The ideas every Prisma ORM command and API builds on: contracts, emitting, plans, the database signature, codecs, and the migration graph.
- [`Extensions`](https://www.prisma.io/docs/orm/extensions): Every package that plugs into Prisma ORM: database packages, column types, indexes, query operations, and middleware, by Prisma and the community.
- [`Overview`](https://www.prisma.io/docs/orm/data-modeling): Describe the data your application needs with models, primary keys, scalar fields, and relations.
- [`Prisma 7`](https://www.prisma.io/docs/orm/v7): Prisma ORM is a next-generation Node.js and TypeScript ORM that provides type-safe database access, migrations, and a visual data editor.

# Best Postgres for AI apps (/docs/postgres/best-postgres-for-ai-apps)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Why Prisma Postgres works well for AI and LLM workloads: built-in pooling, edge connectivity, pgvector, and MCP support.

Location: Postgres > Best Postgres for AI apps

AI apps have a different database profile than traditional web apps. Requests burst unpredictably, inference runs at the edge, and agents increasingly need direct database access. Most managed Postgres services weren't designed with those patterns in mind.

## Built-in connection pooling [#built-in-connection-pooling]

Serverless inference endpoints open a new database connection per invocation. At any meaningful load, that exhausts your Postgres connection limit fast. Prisma Postgres includes connection pooling by default, so there is no PgBouncer to configure and no sidecar to run. Your connection string already points to the pooler.

## Edge-native connectivity [#edge-native-connectivity]

Standard Postgres TCP drivers don't work in Cloudflare Workers, Vercel Edge Functions, or Deno Deploy. Prisma Postgres ships `@prisma/ppg`, a serverless driver that connects over HTTP.

See [Serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver) for setup.

## pgvector for embeddings [#pgvector-for-embeddings]

Prisma Postgres supports the `pgvector` extension for storing and querying vector embeddings natively in Postgres. You can keep your embeddings alongside your application data without a separate vector store.

See [Postgres extensions](https://www.prisma.io/docs/postgres/database/postgres-extensions) for how to enable it.

## MCP server for agent workflows [#mcp-server-for-agent-workflows]

AI agents (Claude, Cursor, or custom) can connect to Prisma Postgres via the Prisma MCP server to introspect schemas, run queries, apply migrations, and manage environments, without raw SQL access.

See [Prisma MCP server](https://www.prisma.io/docs/ai/tools/mcp-server) for setup.

## At a glance [#at-a-glance]

|                                 | Prisma Postgres           | Neon                            | Supabase                        |
| ------------------------------- | ------------------------- | ------------------------------- | ------------------------------- |
| **Built-in connection pooling** | Yes, included by default  | Yes, PgBouncer-compatible       | Yes, Supavisor pooler           |
| **Serverless / edge driver**    | Yes, `@prisma/ppg`        | Yes, `@neondatabase/serverless` | Partial, requires configuration |
| **pgvector support**            | Yes                       | Yes                             | Yes                             |
| **MCP server**                  | Yes, official first-party | Yes, Neon MCP server            | Yes, Supabase MCP server        |
| **Database branching**          | No                        | Yes                             | Limited                         |
| **Free tier**                   | Yes                       | Yes                             | Yes                             |

## Get started [#get-started]

  

#### bun

```bash
bun create prisma@latest
```

#### pnpm

```bash
pnpm create prisma@latest
```

#### yarn

```bash
yarn create prisma@latest
```

#### npm

```bash
npm create prisma@latest
```

Or provision from the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres) and grab your connection string.

* [Connect to Prisma Postgres](https://www.prisma.io/docs/postgres/database/connecting-to-your-database)
* [Use the serverless driver at the edge](https://www.prisma.io/docs/postgres/database/serverless-driver)
* [Enable pgvector](https://www.prisma.io/docs/postgres/database/postgres-extensions)
* [Set up the Prisma MCP server](https://www.prisma.io/docs/ai/tools/mcp-server)

## Related pages

- [`create-db`](https://www.prisma.io/docs/postgres/npx-create-db): Learn how to provision temporary Prisma Postgres databases with create-db
- [`Database`](https://www.prisma.io/docs/postgres/database): Overview of Prisma Postgres database operations, connections, pooling, backups, and query analysis.
- [`Error reference`](https://www.prisma.io/docs/postgres/error-reference): Error reference documentation for Prisma Postgres
- [`Import from existing database`](https://www.prisma.io/docs/postgres/import-from-existing-database): Choose the right path to import data from PostgreSQL or MySQL into Prisma Postgres.
- [`Migrate from Early Access`](https://www.prisma.io/docs/postgres/migrate-from-ea-to-ga): Move your Prisma Postgres Early Access database to a new PostgreSQL 17 database with dump and restore.

# Error reference (/docs/postgres/error-reference)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Error reference documentation for Prisma Postgres

Location: Postgres > Error reference

Prisma Postgres reports failures with specific error codes. This page explains what each code means, why it occurs, and how to resolve it.

## `P6009` (`ResponseSizeLimitExceeded`) [#p6009-responsesizelimitexceeded]

This error is triggered when the response size from a database query exceeds the configured query response size limit. We've implemented this restriction to safeguard your application performance, as retrieving data over `5MB` can significantly slow down your application due to multiple network layers.

Typically, transmitting more than `5MB` of data is common when conducting ETL (Extract, Transform, Load) operations. However, for other scenarios such as transactional queries, real-time data fetching for user interfaces, bulk data updates, or aggregating large datasets for analytics outside of ETL contexts, it should generally be avoided. These use cases can usually be adjusted to work within the configured query response size limit.

### Possible causes for `P6009` [#possible-causes-for-p6009]

See the [`P6009` entry in the Prisma ORM error reference](https://www.prisma.io/docs/orm/v7/reference/error-reference#p6009-responsesizelimitexceeded) for the full description.

#### Transmitting images/files in response [#transmitting-imagesfiles-in-response]

This error may arise if images or files stored within your table are being fetched, resulting in a large response size. Storing assets directly in the database is generally discouraged because it significantly impacts database performance and scalability. In addition to performance, it makes database backups slow and significantly increases the cost of storing routine backups.

**Suggested solution:** Configure the query response size limit to be larger. If the limit is still exceeded, consider storing the image or file in a BLOB store like [Cloudflare R2](https://developers.cloudflare.com/r2/), [AWS S3](https://aws.amazon.com/pm/serv-s3/), or [Cloudinary](https://cloudinary.com/). These services allow you to store assets optimally and return a URL for access. Instead of storing the asset directly in the database, store the URL, which will substantially reduce the response size.

#### Over-fetching of data [#over-fetching-of-data]

In certain cases, a large number of records or fields are unintentionally fetched, which results in exceeding the configured query response size limit. This could happen when [the `where` clause](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#where) in the query is incorrect or entirely missing.

**Suggested solution:** Configure the query response size limit to be larger. If the limit is still exceeded, double-check that the `where` clause is filtering data as expected. To prevent fetching too many records, consider using [pagination](https://www.prisma.io/docs/orm/v7/prisma-client/queries/pagination). Use the [`select`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#select) clause to return only the necessary fields, reducing the response size.

#### Fetching a large volume of data [#fetching-a-large-volume-of-data]

In many data processing workflows, especially those involving ETL (Extract-Transform-Load) processes or scheduled CRON jobs, there's a need to extract large amounts of data from data sources (like databases, APIs, or file systems) for analysis, reporting, or further processing. If you are running an ETL/CRON workload that fetches a huge chunk of data for analytical processing then you might run into this limit.

**Suggested solution:** Configure the query response size limit to be larger. If the limit is exceeded, consider splitting your query into batches. This approach ensures that each batch fetches only a portion of the data, preventing you from exceeding the size limit for a single operation.

## `P6004` (`QueryTimeout`) [#p6004-querytimeout]

This error occurs when a database query fails to return a response within the configured query timeout limit. The query timeout limit includes the duration of waiting for a connection from the pool, network latency to the database, and the execution time of the query itself. We enforce this limit to prevent unintentional long-running queries that can overload system resources.

> [!NOTE]
> The time for Prisma Postgres's cross-region networking is excluded from the configured query timeout limit.

### Possible causes for `P6004` [#possible-causes-for-p6004]

See the [`P6004` entry in the Prisma ORM error reference](https://www.prisma.io/docs/orm/v7/reference/error-reference#p6004-querytimeout) for the full description.

This error could be caused by numerous reasons. Some of the prominent ones are:

#### High traffic and insufficient connections [#high-traffic-and-insufficient-connections]

If the application is receiving very high traffic and there are not a sufficient number of connections available to the database, then the queries would need to wait for a connection to become available. This situation can lead to queries waiting longer than the configured query timeout limit for a connection, ultimately triggering a timeout error if they do not get serviced within this duration.

**Suggested solution**: Review and possibly increase the `connection_limit` specified in the connection string parameter when setting up Accelerate in a platform environment. This limit should match your database's maximum number of connections.

By default, the connection limit is set to 10 unless a different `connection_limit` is specified in your database connection string.

#### Long-running queries [#long-running-queries]

Queries may be slow to respond, hitting the configured query timeout limit even when connections are available. This could happen if a very large amount of data is being fetched in a single query or if appropriate indexes are missing from the table.

**Suggested solution**: Configure the query timeout limit to be larger. If the limit is exceeded, identify the slow-running queries and fetch only the necessary data. Use the `select` clause to retrieve specific fields and avoid fetching unnecessary data. Consider adding appropriate indexes to improve query efficiency. You might also isolate long-running queries into separate environments to prevent them from affecting transactional queries.

#### Database resource contention [#database-resource-contention]

A common yet challenging issue is when other services operating on the same database perform heavy analytics or data processing tasks, significantly consuming database resources. These operations can monopolize database connections and processing power, leading to a scenario where even simple queries cannot be executed in a timely manner. This "busy" or "noisy" database environment can cause queries that are typically fast to run slowly or even timeout, particularly during periods of high activity from other services.

Users often rely on CPU and memory usage metrics to gauge database load, which can be misleading. While these are important indicators, they might not fully represent the database's operational state. Direct metrics like the number of reads, writes, and wait times offer a clearer view of the database's performance and should be monitored closely. A noticeable degradation in these metrics, especially in the absence of changes to the queries or data model, suggests that external pressures are affecting database performance.

**Suggested solution**: If normally quick queries are intermittently slow or timing out without any modifications to them, it's probable that competing queries are exerting pressure on the same database tables. To diagnose this, use monitoring tools or your database's own statistics to observe reads, writes, and wait times. The activity patterns or spikes that line up with the performance dips point at the competing workload.

Periodically review and refine your essential queries and verify that their tables are properly indexed, so those queries are less exposed to slowdowns from competing workloads.

## `P6008` (`ConnectionError|EngineStartError`) [#p6008-connectionerrorenginestarterror]

This error indicates that Prisma ORM cannot establish a connection to your Prisma Postgres database, potentially due to several reasons.

### Possible causes for `P6008` [#possible-causes-for-p6008]

See the [`P6008` entry in the Prisma ORM error reference](https://www.prisma.io/docs/orm/v7/reference/error-reference#p6008-connectionerrorenginestarterror) for the full description.

#### Unreachable Database Host/Port [#unreachable-database-hostport]

If the database's server address (hostname) and port are incorrect or unreachable then you may encounter this error.

**Suggested solution:** Verify the hostname/port of the database connection string that was provided while creating the project. Then try to connect to the database using a Database GUI tool (e.g., [Prisma Studio](https://www.prisma.io/studio), [TablePlus](https://tableplus.com/), or [DataGrip](https://www.jetbrains.com/datagrip/)) for further investigation.

#### Incorrect username/password/database name [#incorrect-usernamepassworddatabase-name]

This error can happen when the wrong credentials are provided, preventing it from establishing a connection to your database.

**Suggested solution:** Verify the correctness of your database's username, password, and name in the connection string provided to Prisma Postgres. Ensure that these credentials match those required by your database. Testing the connection using a direct database GUI tool can also help in confirming if the provided credentials are correct.

## `P5011` (`TooManyRequests`) [#p5011-toomanyrequests]

This error occurs when Prisma Postgres detects a high volume of requests that surpasses allowable thresholds. This protects both Prisma Postgres and your underlying database from excessive load.

### Possible causes for `P5011` [#possible-causes-for-p5011]

See the [`P5011` entry in the Prisma ORM error reference](https://www.prisma.io/docs/orm/v7/reference/error-reference#p5011-too-many-requests) for the full description.

#### Aggressive retry loops [#aggressive-retry-loops]

If your application retries queries immediately or with minimal delay, especially after receiving certain errors, the rapid accumulation of requests can surpass the threshold.

**Suggested solution:**

* Implement an exponential backoff strategy. Rather than retrying immediately or with a fixed delay, gradually increase the delay period after each failed attempt.

#### Sudden traffic spikes [#sudden-traffic-spikes]

Unpredicted traffic surges (for example, during product launches, flash sales, or viral growth events) can cause the threshold to be met and result into `P5011`.

**Suggested solution:**

* Monitor traffic and resource usage. If you anticipate a surge, please contact [support](https://www.prisma.io/docs/console/more/support) for capacity planning and potential configuration adjustments.

#### Prolonged or planned high workloads [#prolonged-or-planned-high-workloads]

Certain processes, such as bulk data imports, ETL operations, or extended CRON jobs, can generate continuous high query volume over time.

**Suggested solution:**

* Use batching or chunking techniques to break large operations into smaller parts.
* Establish throttling or scheduling to distribute the load more evenly.

## Related pages

- [`Best Postgres for AI apps`](https://www.prisma.io/docs/postgres/best-postgres-for-ai-apps): Why Prisma Postgres works well for AI and LLM workloads: built-in pooling, edge connectivity, pgvector, and MCP support.
- [`create-db`](https://www.prisma.io/docs/postgres/npx-create-db): Learn how to provision temporary Prisma Postgres databases with create-db
- [`Database`](https://www.prisma.io/docs/postgres/database): Overview of Prisma Postgres database operations, connections, pooling, backups, and query analysis.
- [`Import from existing database`](https://www.prisma.io/docs/postgres/import-from-existing-database): Choose the right path to import data from PostgreSQL or MySQL into Prisma Postgres.
- [`Migrate from Early Access`](https://www.prisma.io/docs/postgres/migrate-from-ea-to-ga): Move your Prisma Postgres Early Access database to a new PostgreSQL 17 database with dump and restore.

# Prisma Postgres FAQ (/docs/postgres/faq)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Common questions and answers about Prisma Postgres

Location: Postgres > Prisma Postgres FAQ

Common questions about how Prisma Postgres works, how queries are billed, and how it integrates with the Prisma ORM.

## General [#general]

### Can I use Prisma Postgres without Prisma ORM? [#can-i-use-prisma-postgres-without-prisma-orm]

Yes, you can use Prisma Postgres with any database library or tool via a [direct connection](https://www.prisma.io/docs/postgres/database/connection-pooling).

You can find examples of using Prisma Postgres with various ORMs below:

* [Prisma ORM](https://github.com/prisma/prisma-examples/tree/latest/databases/prisma-postgres)
* [Drizzle](https://github.com/prisma/prisma-examples/tree/latest/databases/drizzle-prisma-postgres)
* [Kysely](https://github.com/prisma/prisma-examples/tree/latest/databases/kysely-prisma-postgres)
* [TypeORM](https://github.com/prisma/prisma-examples/tree/latest/databases/typeorm-prisma-postgres)

### How do I switch from GitHub login to email and password login? [#how-do-i-switch-from-github-login-to-email-and-password-login]

If you previously signed up using GitHub and want to switch to email and password login, follow these steps:

1. Verify Your GitHub Email Address
   * Check the primary email address associated with your GitHub account (e.g., from your GitHub profile or notification settings).
2. Create a New Email/Password Account
   * Go to the email/password sign-up page.
   * Use the *same email address* linked to your GitHub account to create the new account.
   * Our system will automatically connect your new email/password account to your existing data.
3. Test Your Login
   * Log out and try logging in with your email and the password you just created.

If you encounter any issues, please contact our support team for help linking your accounts.

### VS Code does not recognize the `$extends` method [#vs-code-does-not-recognize-the-extends-method]

If you add the Prisma Client extension for Accelerate to an existing project that is currently open in VS Code, the editor might not immediately recognize the `$extends` method.

This might be an issue with the TypeScript server not yet recognizing the regenerated Prisma Client. To resolve this, you need to restart TypeScript.

1. In VS Code, open the Command Palette. You can do so when you press F1 or select **View** > **Command Palette**.
2. Enter `typescript` and select and run the **TypeScript: Restart TS server** command.

VS Code should now recognize the `$extends` method.

## What regions is Prisma Postgres available in? [#what-regions-is-prisma-postgres-available-in]

Prisma Postgres is currently available in the following regions:

| Region Code      | Location       |
| ---------------- | -------------- |
| `us-west-1`      | San Francisco  |
| `us-east-1`      | North Virginia |
| `eu-west-3`      | Paris          |
| `eu-central-1`   | Frankfurt      |
| `ap-northeast-1` | Tokyo          |
| `ap-southeast-1` | Singapore      |

We're continuously working to expand regional support. If you'd like to request a specific region, reach out to us via [Discord](https://pris.ly/discord).

## Pricing [#pricing]

Prisma Postgres bills based on *operations* and *storage* consumed. It does not charge for egress traffic. Visit the [pricing page](https://www.prisma.io/pricing) for details and our [blog post explaining operations-based billing](https://www.prisma.io/blog/operations-based-billing) for a detailed explanation on what an operation is and how this pricing model works.

### What is an operation? [#what-is-an-operation]

An operation is counted each time you interact with your database. A read or a write, simple or complex, counts as one operation.

An operation can be:

* a Prisma ORM query (when using Prisma ORM)
* a SQL query (when using a [direct connection](https://www.prisma.io/docs/postgres/database/connecting-to-your-database))

### Does query execution time affect pricing in Prisma Postgres? [#does-query-execution-time-affect-pricing-in-prisma-postgres]

No, cost for Prisma Postgres is based solely on the *number of operations*, not the amount of compute required to execute them.

Whether a query takes 10ms or 10sec to execute, its pricing impact remains the same.

### How does pricing differ between using Prisma ORM and direct TCP connections? [#how-does-pricing-differ-between-using-prisma-orm-and-direct-tcp-connections]

The fundamental principle of operations-based pricing remains the same for Prisma ORM and [direct connections](https://www.prisma.io/docs/postgres/database/connecting-to-your-database). However, depending on whether you use Prisma ORM or direct SQL to interact with your database, an operation is something different:

* when using Prisma ORM: a query sent with Prisma Client (e.g. `prisma.user.findMany()`)
* when using another tool: a SQL query sent via the direct connection (e.g. `SELECT * from "User"`)

Note that a single Prisma ORM query may translate into multiple SQL queries which may make using Prisma ORM more economical than direct SQL.

### Do read and write queries cost the same? [#do-read-and-write-queries-cost-the-same]

Yes, read and write queries are counted equally as *operations* and are billed the same way.

### Does a `SELECT 1` query count as a billable operation? [#does-a-select-1-query-count-as-a-billable-operation]

Yes, a query like `SELECT 1` counts as an operation and will be billed accordingly (even if no actual data is accessed in the query).

### How can I estimate the number of operations in Prisma ORM? [#how-can-i-estimate-the-number-of-operations-in-prisma-orm]

You can estimate your operation usage in Prisma ORM by integrating an application performance monitoring tool like Prometheus.

### What strategies can I use to optimize cost per operation? [#what-strategies-can-i-use-to-optimize-cost-per-operation]

Prisma Postgres bills by operation. The more you can perform using a single operation, the lower your bill. Some tips to reduce the number of operations:

* [**Batch your writes**](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#bulk-operations) with `createMany`, `updateMany`, or `deleteMany` instead of looping over single-row calls.

  ```ts
  // One operation, three users
  await prisma.user.createMany({
    data: [{ name: "Alice" }, { name: "Bob" }, { name: "Carol" }],
  });
  ```

* **Use nested-relation helpers** such as [`connectOrCreate`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#connectorcreate) or [`set`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#set) to create or link related records in a single operation.

  ```ts
  // Post and (if needed) its author, all in one request
  await prisma.post.create({
    data: {
      title: "Hello World",
      author: {
        connectOrCreate: {
          where: { email: "alice@example.com" },
          create: { name: "Alice", email: "alice@example.com" },
        },
      },
    },
  });
  ```

* **Prefer regular (array) [transactions](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#transaction-api) over [interactive transactions](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#interactive-transactions)** when the individual queries don't depend on each other.

  ```ts
  // Interactive transaction: counted as 2 operations
  await prisma.$transaction(async (tx) => {
    await tx.user.create({ data: { name: "Alice" } });
    await tx.post.create({ data: { title: "Hello", authorId: 1 } });
  });

  // Array transaction: counted as 1 operation
  await prisma.$transaction([
    prisma.user.create({ data: { name: "Alice" } }),
    prisma.post.create({ data: { title: "Hello", authorId: 1 } }),
  ]);
  ```

If a later query needs the result of an earlier one (for example, you need the user ID you just created), stick with an interactive transaction for correctness. Otherwise, batching and array transactions let you collapse multiple queries into a single billed operation, keeping both your operation count, and your cost down.

### Is there a sample workload to estimate my expected charges? [#is-there-a-sample-workload-to-estimate-my-expected-charges]

We will demonstrate three example workloads and estimate bills for small, medium, and large workloads. Each combine a realistic number of monthly active users (MAUs), a typical level of daily activity per user, and a rounded storage footprint.

We will use the following equations to estimate the monthly bill:

```
total_ops            = MAUs x actions_per_user_per_day x 30
billable_ops         = total_ops - included_ops_for_plan
ops_cost             = (billable_ops ÷ 1_000_000) x plan_rate

billable_storage_GB  = storage_used_GB - free_storage_for_plan
storage_cost         = billable_storage_GB x storage_rate_for_plan

total_monthly_cost   = ops_cost + storage_cost + base_plan_fee
```

> [!NOTE]
> You can use your own MAU count, activity level, and storage used to project costs on any plan using the equations above.

We will associate each workload with a paid plan and its corresponding pricing details, for example, the **Starter plan** for the small workload, the **Pro plan** for the medium workload, and the **Business plan** for the large workload. Then we will apply the equations to the example workloads to generate a rough estimate of a monthly bill. For example:

> [!NOTE]
> Pricing details
> 
> Here are the details for each pricing plan:
> 
> * **Starter plan** - $8 per million operations
>   * Base plan fee - $10 per month
>   * Included operations - 1,000,000
>   * Storage - 10 GB free then $2 per additional GB
> * **Pro plan** - $2 per million operations
>   * Base plan fee - $49.00 per month
>   * Included operations - 10,000,000
>   * Storage - 50 GB free then $1.5 per additional GB
> * **Business plan** - $1 per million operations
>   * Base plan fee - $129.00 per month
>   * Included operations - 50,000,000
>   * Storage - 100 GB free then $1 per additional GB
> 
> We also have a Free plan, but we are leaving it out in the following calculations because it's intended for evaluation only and is not meant for production workloads. You can also learn more about the pricing details for each plan on the [pricing page](https://www.prisma.io/pricing?utm_source=docs).

**Example of a small workload on the Starter plan**:

A hobby or early-stage side-project with \~`500` MAUs. Each user performs \~`10` actions per day, and the entire database uses \~`0.5` GB of storage. Based on the assumptions, you would calculate the monthly bill using the following equations:

* `total_ops` = `500` x `10` x `30` = `150000`
* `billable_ops` = `0` (150,000 operations is below the 1 million free operations)
* `ops_cost` = $`0`
* `storage_cost` = $`0` (0.5 GB is below the 10 GB storage already included)
* `base_plan_fee` = $`10`

`total_monthly_cost` = $`10.00` per month

**Example of a medium workload on the Pro plan**:

A growing SaaS product serving \~`5000` MAUs. Power users average \~`40` actions per day, and the app stores \~`6` GB of data. Based on the assumptions, you would calculate the monthly bill using the following equations:

* `total_ops` = `5000` x `40` x `30` = `6000000`
* `billable_ops` = `0` (6 million operations is below the 10 million free operations)
* `ops_cost` = $`0`
* `storage_cost` = $`0` (6 GB is below the 50 GB storage already included)
* `base_plan_fee` = $`49.00`

`total_monthly_cost` = $`49.00` per month

**Example of a large workload on the Business plan**:

A production-grade, consumer-facing application handling \~`50000` MAUs. Heavy usage with \~`60` actions per user per day drives significant traffic, and the dataset reaches \~`40` GB. Based on the assumptions, you would calculate the monthly bill using the following equations:

* `total_ops` = `50000` x `60` x `30` = `90000000`
* `billable_ops` = `90000000` - `50000000` = `40000000`
* `ops_cost` = (`40000000` ÷ `1000000`) = `40.00` x $`1` = $`40.00`
* `storage_cost` = $`0.00` (40 GB is below the 100 GB storage already included)
* `base_plan_fee` = $`129.00`

`total_monthly_cost` = $`40.00` + $`129.00` = $`169.00` per month

### How do I upgrade my plan if I am using Prisma Postgres via Vercel? [#how-do-i-upgrade-my-plan-if-i-am-using-prisma-postgres-via-vercel]

If you installed Prisma Postgres through the [Vercel Marketplace integration](https://www.prisma.io/docs/guides/postgres/vercel), the same [Prisma Postgres pricing plans](https://www.prisma.io/pricing) apply and your usage is billed through your Vercel account. To upgrade your plan via Vercel, follow these steps:

* Open your [Vercel](https://vercel.com/) Dashboard.
* Go to the **Integrations** tab in your Vercel Team.
* Click **Manage** on the Prisma Integration.
* Navigate to the **Settings** tab.
* Under Current Installation Plan Level, click **Change Plan**.
* Select the plan you want to upgrade to.

## Caching [#caching]

### Does Prisma Postgres cache query results? [#does-prisma-postgres-cache-query-results]

Prisma Postgres includes connection pooling but has no query cache of its own, and query caching is not on our immediate roadmap. `cacheStrategy` works with a Prisma Postgres database only through a hosted Accelerate connection.

If your application passes `cacheStrategy` through a hosted Accelerate connection, that connection will be retired on December 1, 2026. [Connect to Prisma Postgres without Accelerate](https://www.prisma.io/docs/postgres/database/switch-from-accelerate) shows how to remove the caching APIs and replace the connection. After the switch, cached queries become ordinary database queries. A query served from the cache already counted as one operation, so removing caching does not change how operations are counted. Database load and response latency can change, so test the affected paths under representative traffic.

## Connection pooling [#connection-pooling]

#### Can I increase the query duration and response size limits for my Prisma Postgres instance? [#can-i-increase-the-query-duration-and-response-size-limits-for-my-prisma-postgres-instance]

Yes, you can increase your Prisma Postgres limits based on your subscription plan. Here are the configurable limits:

| Limit                                | Free             | Starter          | Pro Plan         | Business Plan    |
| ------------------------------------ | ---------------- | ---------------- | ---------------- | ---------------- |
| **Query timeout**                    | Up to 10 seconds | Up to 10 seconds | Up to 20 seconds | Up to 60 seconds |
| **Interactive transactions timeout** | Up to 15 seconds | Up to 15 seconds | Up to 30 seconds | Up to 90 seconds |
| **Response size**                    | Up to 5 MB       | Up to 5 MB       | Up to 10 MB      | Up to 20 MB      |

Check the [pricing page](https://www.prisma.io/pricing) for more details on the available plans and their corresponding limits.

> [!WARNING]
> While you can increase these limits based on your subscription plan, it's *still* recommended to optimize your database operations. [Learn more in our troubleshooting guide.](https://www.prisma.io/docs/postgres/error-reference)

## Query Insights [#query-insights]

[Query Insights](https://www.prisma.io/docs/query-insights) is built into Prisma Postgres and helps you identify slow queries, understand their cost, and decide what to fix.

### I only see raw SQL. How do I see my Prisma ORM queries? [#i-only-see-raw-sql-how-do-i-see-my-prisma-orm-queries]

By default, Query Insights shows raw SQL. To also see the Prisma ORM operation that generated each query (model name, action, and query shape), install the `@prisma/sqlcommenter-query-insights` package:

```bash
npm install @prisma/sqlcommenter-query-insights
```

Then pass it to the `comments` option in your `PrismaClient` constructor:

```ts
import { prismaQueryInsights } from "@prisma/sqlcommenter-query-insights";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient({
  adapter: myAdapter,
  comments: [prismaQueryInsights()],
});
```

This annotates every query with a SQL comment containing the model, action, and parameterized query shape. Query Insights uses these annotations to map SQL back to the Prisma call that generated it.

#### Let your AI agent handle setup [#let-your-ai-agent-handle-setup]

Copy this prompt into your AI coding assistant:

```
Install and configure @prisma/sqlcommenter-query-insights in my project so I can
see Prisma ORM queries in Query Insights. Docs: https://www.prisma.io/docs/query-insights
```

### Does Query Insights alter my queries or schema? [#does-query-insights-alter-my-queries-or-schema]

No. Query Insights is read-only: it observes query behavior but does not rewrite queries or modify your Prisma schema.

### Can I use Query Insights in production? [#can-i-use-query-insights-in-production]

Query Insights is designed primarily for development and debugging. Running it in production is possible but not recommended, as the SQL comment annotations add a small overhead to every query.

## Related pages

- [`Best Postgres for AI apps`](https://www.prisma.io/docs/postgres/best-postgres-for-ai-apps): Why Prisma Postgres works well for AI and LLM workloads: built-in pooling, edge connectivity, pgvector, and MCP support.
- [`create-db`](https://www.prisma.io/docs/postgres/npx-create-db): Learn how to provision temporary Prisma Postgres databases with create-db
- [`Database`](https://www.prisma.io/docs/postgres/database): Overview of Prisma Postgres database operations, connections, pooling, backups, and query analysis.
- [`Error reference`](https://www.prisma.io/docs/postgres/error-reference): Error reference documentation for Prisma Postgres
- [`Import from existing database`](https://www.prisma.io/docs/postgres/import-from-existing-database): Choose the right path to import data from PostgreSQL or MySQL into Prisma Postgres.

# Import from existing database (/docs/postgres/import-from-existing-database)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Choose the right path to import data from PostgreSQL or MySQL into Prisma Postgres.

Location: Postgres > Import from existing database

Use this page to choose the right import path for moving an existing database into Prisma Postgres.

## Choose your source database [#choose-your-source-database]

* [Import from PostgreSQL](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql)
* [Import from MySQL](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-mysql)

## Before you start [#before-you-start]

* Create a Prisma Postgres database first.
* Gather the connection details for your existing database.
* Use a [direct connection](https://www.prisma.io/docs/postgres/database/connecting-to-your-database) when importing data into Prisma Postgres.

## Related pages [#related-pages]

* [Connecting to your database](https://www.prisma.io/docs/postgres/database/connecting-to-your-database)
* [Prisma Postgres overview](https://www.prisma.io/docs/postgres)
* [Create a database with `create-db`](https://www.prisma.io/docs/postgres/npx-create-db)

## Related pages

- [`Best Postgres for AI apps`](https://www.prisma.io/docs/postgres/best-postgres-for-ai-apps): Why Prisma Postgres works well for AI and LLM workloads: built-in pooling, edge connectivity, pgvector, and MCP support.
- [`create-db`](https://www.prisma.io/docs/postgres/npx-create-db): Learn how to provision temporary Prisma Postgres databases with create-db
- [`Database`](https://www.prisma.io/docs/postgres/database): Overview of Prisma Postgres database operations, connections, pooling, backups, and query analysis.
- [`Error reference`](https://www.prisma.io/docs/postgres/error-reference): Error reference documentation for Prisma Postgres
- [`Migrate from Early Access`](https://www.prisma.io/docs/postgres/migrate-from-ea-to-ga): Move your Prisma Postgres Early Access database to a new PostgreSQL 17 database with dump and restore.

# Prisma Postgres (/docs/postgres)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Connect to Prisma Postgres from Prisma ORM, serverless runtimes, and PostgreSQL clients.

Location: Prisma Postgres

[Prisma Postgres](https://www.prisma.io/postgres?utm_source=docs) is a managed PostgreSQL database with built-in connection pooling and edge runtime support.

To your application it is a regular PostgreSQL database behind a connection string:

```text no-copy
Your application
      ↓ DATABASE_URL
Prisma Postgres
```

Any PostgreSQL client works: Prisma ORM, `psql`, Kysely, Drizzle, `node-postgres`, or anything else that speaks Postgres.

## Getting started [#getting-started]

### 1. Create a database [#1-create-a-database]

The fastest way, with no account required:

  

#### bun

```bash
bunx create-db@latest
```

#### pnpm

```bash
pnpm dlx create-db@latest
```

#### yarn

```bash
yarn dlx create-db@latest
```

#### npm

```bash
npx create-db@latest
```

`create-db` creates a temporary Prisma Postgres database and prints a connection string plus a claim URL. Open the claim URL to keep the database in your workspace. See [create-db](https://www.prisma.io/docs/postgres/npx-create-db) for details. You can also create databases in the [Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres) or with the [Prisma CLI](https://www.prisma.io/docs/cli/postgres) (`npx prisma postgres create`).

### 2. Copy the connection string [#2-copy-the-connection-string]

`create-db` prints it once. For an existing database, open it in [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres) and click **Connect to your database**. Store it where your app reads configuration:

```text title=".env"
DATABASE_URL="postgres://...@db.prisma.io:5432/postgres?sslmode=require"
```

### 3. Connect and run a query [#3-connect-and-run-a-query]

Pick the client you use; each quickstart takes you from connection string to a first query:

- [Prisma ORM quickstart](https://www.prisma.io/docs/prisma-postgres/quickstart/prisma-orm): Define a data contract and query with Prisma ORM.

- [Prisma ORM 7 quickstart](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres): Connect with the current GA release of Prisma ORM.

- [Kysely quickstart](https://www.prisma.io/docs/prisma-postgres/quickstart/kysely): Connect Prisma Postgres from Kysely.

- [Drizzle ORM quickstart](https://www.prisma.io/docs/prisma-postgres/quickstart/drizzle-orm): Connect Prisma Postgres from Drizzle ORM.

Also available: the [TypeORM quickstart](https://www.prisma.io/docs/prisma-postgres/quickstart/typeorm) and [Connecting to your database](https://www.prisma.io/docs/postgres/database/connecting-to-your-database), which covers connection strings for `psql`, GUI tools, and serverless runtimes.

If you work with a coding agent, copy this prompt:

```text
Create a Prisma Postgres database for this project.

1. Run `npx create-db@latest`. It creates a temporary Prisma Postgres database without an account and prints a connection string plus a claim URL.
2. Put the connection string in `.env` as DATABASE_URL and wire it into whichever of Prisma ORM, Kysely, Drizzle, TypeORM, or node-postgres the project already uses (detect it from package.json; if none, ask me). Verify the connection with one trivial query such as `select 1`.
3. Remind me to open the claim URL to keep the database in my Prisma workspace.

Current docs: https://www.prisma.io/docs/postgres.md.
```

## What's included [#whats-included]

Each Prisma Postgres database includes the following, with no extra services to configure:

* **Connection pooling**: a dedicated PgBouncer instance runs alongside your database, with nothing to set up or manage. It also works for serverless and edge deployments. See [Connection pooling](https://www.prisma.io/docs/postgres/database/connection-pooling).
* **Edge and serverless support**: connect from Cloudflare Workers, Vercel Edge Functions, and other edge runtimes via the [serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver), which uses HTTP instead of TCP.
* **Automated backups** (Starter, Pro, and Business plans): daily snapshots, kept for 7 or 30 days depending on the plan. See [Backups](https://www.prisma.io/docs/postgres/database/backups).

## Local development [#local-development]

Run Prisma Postgres locally with `prisma dev`, then switch to cloud when ready.

* [Local Postgres](https://www.prisma.io/docs/local-development/postgres)

## Use with the rest of Prisma [#use-with-the-rest-of-prisma]

Each integration is optional. Prisma Postgres works with any PostgreSQL client.

* If you use [Prisma ORM](https://www.prisma.io/docs/prisma-orm), the quickstart provisions a database and connects it to your data contract.
* If you deploy on [Prisma Compute](https://www.prisma.io/docs/compute), each branch of a Compute project can have its own Prisma Postgres database; pass the connection string through [environment variables](https://www.prisma.io/docs/compute/environment-variables).
* For a multi-service application, [Prisma Composer](https://www.prisma.io/docs/composer/databases) declares a database as a service dependency and injects the connection at runtime.

## Manage [#manage]

* [Connecting to your database](https://www.prisma.io/docs/postgres/database/connecting-to-your-database)
* [Connection pooling](https://www.prisma.io/docs/postgres/database/connection-pooling)
* [Backups](https://www.prisma.io/docs/postgres/database/backups)
* [PostgreSQL extensions](https://www.prisma.io/docs/postgres/database/postgres-extensions)
* [Troubleshooting](https://www.prisma.io/docs/postgres/troubleshooting)
* [FAQ](https://www.prisma.io/docs/postgres/faq)

## Billing and limits [#billing-and-limits]

Prisma Postgres uses usage-based pricing and includes spend controls.

* [Pricing](https://www.prisma.io/pricing)
* [Operations-based billing explained](https://www.prisma.io/blog/operations-based-billing?utm_source=docs)
* [FAQ: estimating costs](https://www.prisma.io/docs/postgres/faq#is-there-a-sample-workload-to-estimate-my-expected-charges)

In Prisma Console, you can track usage, set spend limits, and view billing details.

![Billing and Usage dashboard metrics.](https://www.prisma.io/img/postgres/billing-metrics.png)

## Technical details [#technical-details]

Prisma Postgres is based on **PostgreSQL v17** and uses a unikernel-based architecture.

Learn more: [Prisma Postgres: Building a modern PostgreSQL service](https://pris.ly/ppg-early-access?utm_source=docs).

> [!NOTE]
> Note
> 
> Postgres, PostgreSQL, and the Slonik Logo are trademarks or registered trademarks of the PostgreSQL Community Association of Canada and are used with permission.

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# Migrate from Early Access (/docs/postgres/migrate-from-ea-to-ga)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Move your Prisma Postgres Early Access database to a new PostgreSQL 17 database with dump and restore.

Location: Postgres > Migrate from Early Access

Prisma Postgres is now generally available, running PostgreSQL 17 on a platform built for production reliability. Early Access (EA) databases run on the earlier PostgreSQL 16 setup and can't be upgraded in place, so moving over means creating a new database and bringing your schema and data with you. This guide walks you through it, and you don't need to upgrade Prisma ORM along the way.

EA databases will be deleted on **1 November 2026 at 00:00 UTC**, so plan to finish your migration before then. If anything is getting in the way, [let us know](#need-a-hand) and we'll help you get moved over.

## Before you start [#before-you-start]

Plan a maintenance window. Writes must remain paused through export, restore, verification, and application cutover, so choose a time when you can pause application writes and background jobs.

## 1. Prepare your databases and tools [#1-prepare-your-databases-and-tools]

* Create a new, empty Prisma Postgres database in your workspace in [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres). Do not run schema migrations or seed it before restoring.
* Get the [direct connection strings](https://www.prisma.io/docs/postgres/database/connecting-to-your-database#get-your-connection-strings) for your EA database (source) and your new database (destination). If you cannot obtain a direct connection for your EA database, [ask for help](#need-a-hand).
* Install [PostgreSQL 17 command-line tools](https://www.prisma.io/docs/postgres/database/backups#1-install-postgresql-command-line-tools) and have enough local disk space for the dump. These commands should report `17.x`:

```bash title="Terminal"
pg_dump --version
pg_restore --version
psql --version
```

Replace the placeholders with each database's direct URL. `EA_DIRECT_URL` is your source; `NEW_DIRECT_URL` is your destination. Keep the single quotes:

```bash title="Terminal"
export EA_DIRECT_URL='postgresql://EA_USER:EA_PASSWORD@EA_HOST:5432/postgres?sslmode=require'
export NEW_DIRECT_URL='postgresql://NEW_USER:NEW_PASSWORD@NEW_HOST:5432/postgres?sslmode=require'
```

Use PostgreSQL URLs, not pooled connections or `prisma://` URLs. Confirm the source reports PostgreSQL 16 and the destination reports PostgreSQL 17:

```bash title="Terminal"
psql "$EA_DIRECT_URL" -X --set ON_ERROR_STOP=1 --command="SHOW server_version;"
psql "$NEW_DIRECT_URL" -X --set ON_ERROR_STOP=1 --command="SHOW server_version;"
```

If either connection fails or reports a different major version than expected, [ask for help](#need-a-hand) before exporting.

Before pausing writes, run the [extension and policy checks](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql#1-inspect-the-source-database) with `EA_DIRECT_URL` as the source URL. Resolve unsupported extensions before the final dump. If policies reference roles that exist only in the EA database, plan target-compatible replacements before the maintenance window.

## 2. Pause writes and export your EA database [#2-pause-writes-and-export-your-ea-database]

A dump captures a snapshot: writes made after that snapshot are not included. Stop new application writes, background workers, scheduled jobs, and other writers. Drain in-flight requests and transactions, then confirm all EA writes have stopped before starting `pg_dump`. Keep writes paused until you have verified and switched your application to your new database.

Export all application schemas and data, including migration history:

```bash title="Terminal"
# Create a fresh, private dump file for this export
umask 077

EA_DUMP_FILE="$(mktemp ./prisma-postgres-ea.XXXXXX)" &&
pg_dump \
  --format=custom \
  --quote-all-identifiers \
  --no-privileges \
  --verbose \
  --dbname="$EA_DIRECT_URL" \
  --file="$EA_DUMP_FILE"
```

Wait for the export to complete successfully before restoring, so you use a complete archive. Keep this file private: it contains your database's data.

Each export creates a new file in your current directory, leaving earlier dumps untouched. Keep this terminal open and stay in the same directory for the restore; `EA_DUMP_FILE` holds the archive path.

## 3. Restore into your new database [#3-restore-into-your-new-database]

If the policy check found source-only roles, use `pg_restore --list "$EA_DUMP_FILE" > postgres-restore.list` and follow the import guide's [policy filtering instructions](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql#3-stop-source-writes-and-export-the-final-snapshot) before restoring. Add `--use-list=postgres-restore.list` to the command below. Recreate each omitted policy with target-compatible roles and verify access before resuming traffic.

Restore the archive into the empty database you created:

```bash title="Terminal"
pg_restore \
  --no-owner \
  --no-privileges \
  --single-transaction \
  --exit-on-error \
  --verbose \
  --dbname="$NEW_DIRECT_URL" \
  "$EA_DUMP_FILE"
```

A restore error rolls back the transaction, leaving your new database unchanged. Resolve the reported error before retrying the restore. If an extension or role is missing, consult the [PostgreSQL import guide](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql) or [ask for help](#need-a-hand).

After the restore completes successfully, refresh query-planner statistics:

```bash title="Terminal"
psql "$NEW_DIRECT_URL" -X --set ON_ERROR_STOP=1 --command="ANALYZE;"
```

## 4. Verify and reconnect your application [#4-verify-and-reconnect-your-application]

1. With EA writes still paused, compare schemas, table row counts, and important records between both databases. The [import verification steps](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql#5-verify-the-imported-data) provide a row-count comparison; use your EA database's URL as the source and your new database's URL as the destination.
2. Update connection settings for your application, deployment, workers, and migration tools to use your new database. Follow the [connection guidance for your runtime](https://www.prisma.io/docs/postgres/database/connecting-to-your-database). If you use Accelerate, follow the [application reconnection steps](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql#6-connect-your-application).
3. Redeploy or restart your application with the new settings while production traffic remains paused. Test a read and a disposable or rolled-back write against your new database.
4. Once verification succeeds, resume traffic and writers against your new database only. Keep EA writes stopped.

Keep your EA database and local dump until verification succeeds. If checks fail, keep traffic paused while you resolve the issue or [ask for help](#need-a-hand).

## Need a hand? [#need-a-hand]

We want this move to be as smooth as possible, and every setup is different. If something is getting in the way, [contact us](mailto\:ppg-ea@prisma.io) and tell us what's blocking you. It might be an error you can't get past, a large database, a downtime window to plan around, or not enough time before 1 November.

It helps to include your workspace and project, the name or ID of the EA database, what's blocking you (including any error messages), and any timing constraints on your side. Please keep passwords, connection strings, and database dumps out of your message.

We'll help you work out the next steps. The shutdown date still applies unless we confirm a different date.

## Related pages

- [`Best Postgres for AI apps`](https://www.prisma.io/docs/postgres/best-postgres-for-ai-apps): Why Prisma Postgres works well for AI and LLM workloads: built-in pooling, edge connectivity, pgvector, and MCP support.
- [`create-db`](https://www.prisma.io/docs/postgres/npx-create-db): Learn how to provision temporary Prisma Postgres databases with create-db
- [`Database`](https://www.prisma.io/docs/postgres/database): Overview of Prisma Postgres database operations, connections, pooling, backups, and query analysis.
- [`Error reference`](https://www.prisma.io/docs/postgres/error-reference): Error reference documentation for Prisma Postgres
- [`Import from existing database`](https://www.prisma.io/docs/postgres/import-from-existing-database): Choose the right path to import data from PostgreSQL or MySQL into Prisma Postgres.

# create-db (/docs/postgres/npx-create-db)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to provision temporary Prisma Postgres databases with create-db

Location: Postgres > create-db

[`create-db`](https://create-db.prisma.io/) is an open-source CLI tool that provisions temporary [Prisma Postgres](https://www.prisma.io/docs/postgres) databases with a single command.

* **Fast setup:** No sign-up required to create a temporary production-ready Prisma Postgres database.
* **Lifetime:** Each database is available for *24 hours* by default.
* **Keep for free:** You can *claim* a database (via the URL provided in the CLI output) to make it permanent.

## Prerequisites [#prerequisites]

To use `npx create-db`, you need:

* **Node.js** version `16` or higher (we recommend the latest LTS version).
* **npm** (comes with Node.js) to run `npx` commands.

**A Prisma Data Platform account is not required** to create a temporary database. However, if you want to keep a database permanently, you can claim it ([details below](#claiming-your-database)).

### Option 1: Using the web interface (recommended) [#option-1-using-the-web-interface-recommended]

The [create-db web application](https://create-db.prisma.io) provides a browser-based interface for creating and managing your databases.

#### Key features: [#key-features]

* No installation required - works directly in your web browser
* Visual interface for database management
* Connection string display and copying
* Built-in schema viewer and editor
* Direct integration with Prisma Studio
* Database claiming workflow

#### Getting started: [#getting-started]

1. Visit [create-db.prisma.io](https://create-db.prisma.io) in your web browser
2. Click "Create with the web interface"
3. Modify your schema and interact with the Studio
4. Copy the provided connection strings for your project
5. Claim your database to make it permanent

### Option 2: Using the CLI [#option-2-using-the-cli]

You can create a database using one of the following options:

#### Option 1: Quick start with default settings [#option-1-quick-start-with-default-settings]

Run the following command in your terminal:

  

#### bun

```bash
bunx create-db@latest
```

#### pnpm

```bash
pnpm dlx create-db@latest
```

#### yarn

```bash
yarn dlx create-db@latest
```

#### npm

```bash
npx create-db@latest
```

<br />

* The `@latest` tag automatically downloads and runs the latest version of the tool, so no global installation is required.
* After a few seconds, you'll receive **connection strings** for both Prisma ORM projects and standard PostgreSQL.
* By default, `create-db` detects your approximate location and provisions the database in the closest available region, falling back to `us-east-1` if detection fails. To choose a region yourself, use the `--region` flag. See [the section below](#available-cli-options) to view all the CLI options.

#### Option 2: Choose a region interactively [#option-2-choose-a-region-interactively]

If you want to select a region manually:

  

#### bun

```bash
bunx create-db@latest --interactive
```

#### pnpm

```bash
pnpm dlx create-db@latest --interactive
```

#### yarn

```bash
yarn dlx create-db@latest --interactive
```

#### npm

```bash
npx create-db@latest --interactive
```

<br />

* This opens a region selection menu (for example, `us-east-1`, `eu-west-3`).
* Alternatively, you can use the shorthand `-i`:

  

#### bun

```bash
bunx create-db@latest -i
```

#### pnpm

```bash
pnpm dlx create-db@latest -i
```

#### yarn

```bash
yarn dlx create-db@latest -i
```

#### npm

```bash
npx create-db@latest -i
```

To view all options and regions:

  

#### bun

```bash
bunx create-db@latest --help
```

#### pnpm

```bash
pnpm dlx create-db@latest --help
```

#### yarn

```bash
yarn dlx create-db@latest --help
```

#### npm

```bash
npx create-db@latest --help
```

#### CLI output walkthrough [#cli-output-walkthrough]

Here is an example output:

```
┌  🚀 Creating a Prisma Postgres database
│
│  Provisioning a temporary database in us-east-1...
│  It will be automatically deleted in 24 hours, but you can claim it.
◇  Database created successfully!
│
●  Database Connection
│    Connection String:
│    postgresql://<username>:<password>@db.prisma.io:5432/postgres
│
◆  Claim your database →
│    Keep your database for free:
│    https://create-db.prisma.io?projectID=proj_...
└
```

Once you have the output, take the connection string and add it to your `.env` file as `DATABASE_URL`:

```text
DATABASE_URL="postgresql://<username>:<password>@db.prisma.io:5432/postgres"
```

You can now follow the [Prisma Postgres quickstart guide](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres) to connect your Prisma project to this database.

If you're using other tools or libraries, use the standard PostgreSQL connection string with any PostgreSQL-compatible client, such as `psql`, `pgAdmin`, `node-postgres`, or an ORM of your choice. Detailed instructions are available in [Connecting to your database](https://www.prisma.io/docs/postgres/database/connecting-to-your-database).

## Claiming your database [#claiming-your-database]

By default, databases created with `npx create-db` are **temporary** and will be automatically deleted after **24 hours**.

You can prevent this by **claiming the database** using the claim URL shown in the CLI output:

```
◆  Claim your database →
│
│    Want to keep your database? Claim for free:
│
│    https://create-db.prisma.io?projectID=proj_...
│
│    Your database will be deleted on 7/24/2025, 2:25:41 AM if not claimed.
```

To claim your database and make it permanent:

1. Copy the **claim URL** from the CLI output.
2. Open it in your browser and click **Claim database**.
3. Sign in to your [Prisma Data Platform account](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres) (or create one if you don't have it yet).
4. Choose a **Workspace** that has capacity for creating new projects.
5. Click **Authorize Prisma Create DB** to confirm.
6. You'll be redirected to a success page. Then, click **Go use your database** to view and manage the claimed database in your workspace.

When you claim a database:

* It's moved into your Prisma Data Platform account workspace.
* It's no longer auto-deleted after 24 hours.
* You can continue using it as a permanent database instance.

## Available CLI options [#available-cli-options]

Here are the CLI flags for the `npx create-db` command:

| Flag            | Shorthand | Description                                                                                                                                    |
| --------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `--region`      | `-r`      | Specify a region. <br /> &#x2A;*Available regions:** `ap-southeast-1`, `ap-northeast-1`, `eu-central-1`, `eu-west-3`, `us-east-1`, `us-west-1` |
| `--interactive` | `-i`      | Run in interactive mode (select region from a list).                                                                                           |
| `--json`        | `-j`      | Output machine-readable JSON and exit.                                                                                                         |
| `--help`        | `-h`      | Show this help message.                                                                                                                        |

To view all CLI options use the `--help` or `-h` flag:

  

#### bun

```bash
bunx create-db@latest --help
```

#### pnpm

```bash
pnpm dlx create-db@latest --help
```

#### yarn

```bash
yarn dlx create-db@latest --help
```

#### npm

```bash
npx create-db@latest --help
```

```
npx create-db@latest [options]

Options:
  --region <region>, -r <region>  Specify a region
                                  Available regions:
                                  ap-southeast-1, ap-northeast-1,
                                  eu-central-1, eu-west-3,
                                  us-east-1, us-west-1

  --interactive, -i               Run in interactive mode

  --help, -h                      Show this help message
```

## Related pages

- [`Best Postgres for AI apps`](https://www.prisma.io/docs/postgres/best-postgres-for-ai-apps): Why Prisma Postgres works well for AI and LLM workloads: built-in pooling, edge connectivity, pgvector, and MCP support.
- [`Database`](https://www.prisma.io/docs/postgres/database): Overview of Prisma Postgres database operations, connections, pooling, backups, and query analysis.
- [`Error reference`](https://www.prisma.io/docs/postgres/error-reference): Error reference documentation for Prisma Postgres
- [`Import from existing database`](https://www.prisma.io/docs/postgres/import-from-existing-database): Choose the right path to import data from PostgreSQL or MySQL into Prisma Postgres.
- [`Migrate from Early Access`](https://www.prisma.io/docs/postgres/migrate-from-ea-to-ga): Move your Prisma Postgres Early Access database to a new PostgreSQL 17 database with dump and restore.

# Troubleshooting (/docs/postgres/troubleshooting)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Resolve common issues with Prisma Postgres

Location: Postgres > Troubleshooting

This guide helps resolve common issues when working with Prisma Postgres.

## The `--db` option is not recognized when running `prisma init` [#the---db-option-is-not-recognized-when-running-prisma-init]

### Problem [#problem]

Running the following command fails because the `--db` option is not recognized:

  

#### bun

```bash
bunx --bun prisma init --db
```

#### pnpm

```bash
pnpm prisma init --db
```

#### yarn

```bash
yarn prisma init --db
```

#### npm

```bash
npx prisma init --db
```

### Cause [#cause]

This can occur due to npx caching. If you've previously run `npx prisma init`, your machine may be using an outdated cached version that doesn't recognize the `--db` flag because it was only introduced in a later version of Prisma ORM.

### Solution [#solution]

Explicitly run the Prisma ORM 7 CLI through its `prev` dist-tag:

  

#### bun

```bash
bunx --bun prisma@prev init --db
```

#### pnpm

```bash
pnpm dlx prisma@prev init --db
```

#### yarn

```bash
yarn dlx prisma@prev init --db
```

#### npm

```bash
npx prisma@prev init --db
```

This runs the latest Prisma ORM 7 CLI, which supports the flag, preventing issues with outdated command syntax.

## Workspace plan limit reached when running `prisma init --db` [#workspace-plan-limit-reached-when-running-prisma-init---db]

### Problem [#problem-1]

When running the command:

  

#### bun

```bash
bunx --bun prisma@prev init --db
```

#### pnpm

```bash
pnpm dlx prisma@prev init --db
```

#### yarn

```bash
yarn dlx prisma@prev init --db
```

#### npm

```bash
npx prisma@prev init --db
```

You may encounter the following error message in your logs:

```
Workspace plan limit reached for feature "Project".
```

### Cause [#cause-1]

Your default [workspace](https://www.prisma.io/docs/console/concepts#workspace) project limit has been reached.

### Solution [#solution-1]

To resolve this issue, consider the following options:

* Configure a different Workspace as your default, one that has available capacity for additional projects.
* Delete unused projects or databases from your current default Workspace to free up space.
* Ensure that you are logged into the correct account in the Prisma CLI. For more details on authentication and account management, please refer to the [Prisma CLI documentation](https://www.prisma.io/docs/cli/v7/console).
* [Upgrade to a plan](https://www.prisma.io/docs/postgres#billing-and-limits) that supports more projects in your default Workspace.

## Related pages

- [`Best Postgres for AI apps`](https://www.prisma.io/docs/postgres/best-postgres-for-ai-apps): Why Prisma Postgres works well for AI and LLM workloads: built-in pooling, edge connectivity, pgvector, and MCP support.
- [`create-db`](https://www.prisma.io/docs/postgres/npx-create-db): Learn how to provision temporary Prisma Postgres databases with create-db
- [`Database`](https://www.prisma.io/docs/postgres/database): Overview of Prisma Postgres database operations, connections, pooling, backups, and query analysis.
- [`Error reference`](https://www.prisma.io/docs/postgres/error-reference): Error reference documentation for Prisma Postgres
- [`Import from existing database`](https://www.prisma.io/docs/postgres/import-from-existing-database): Choose the right path to import data from PostgreSQL or MySQL into Prisma Postgres.

# Query Insights (/docs/query-insights)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Inspect slow queries, connect Prisma calls to SQL, and apply focused fixes with Prisma Postgres.

Location: Query Insights

Query Insights is built into Prisma Postgres and helps you understand which queries are slow, why they are expensive, and what to change next. It does not automatically rewrite your queries or schema.

> [!NOTE]
> Query Insights replaces Prisma Optimize and is now included with Prisma Postgres at no extra cost. You can try it today in the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=query-insights).

## Dashboard [#dashboard]

The main Query Insights view gives you a live summary of query activity for your database.

At the top of the page, you can inspect:

* Average latency over the selected period
* Queries per second
* A time-based chart for each metric
* Hover values for exact timestamps and measurements
* Playback controls for stepping through captured activity

This makes it easier to see whether a problem is steady, bursty, or tied to a short window of activity.

## Query list [#query-list]

Below the charts, Query Insights shows a list of grouped queries.

Each row includes:

* Latency
* Executions
* Reads
* Last seen
* The SQL statement shape

You can use the controls above the table to:

* Filter results by table
* Sort the list to surface the most important queries first
* Focus on repeated, high-read, or recently executed statements

Use this view to decide which query patterns to investigate first.

## Query detail [#query-detail]

Selecting a query opens a detail view for that statement.

The detail view shows:

* A stat summary describing the query's table, execution count, average latency, and reads per call
* The full SQL statement
* An AI-generated analysis explaining whether the query needs optimization and why
* A copyable prompt you can paste directly into your editor or an AI coding assistant to apply the suggested fix

The AI analysis describes the likely cause of the performance issue, the specific change it recommends, and the expected impact. The copyable prompt includes your actual query along with context, so you can paste it into your editor or a tool like Cursor, Copilot, or Claude and get a concrete code change without switching context.

> [!NOTE]
> Treat the AI analysis as a starting point, not a final answer. Review any suggested change before shipping it.

## Prisma ORM attribution [#prisma-orm-attribution]

When using Prisma ORM, Query Insights can trace the full chain from your application code to the SQL it generates. This means you can see which `prisma.*` call produced a slow query, even when a single Prisma call expands into multiple SQL statements.

For raw SQL or queries issued outside Prisma ORM, Query Insights still shows full SQL behavior, but ORM-level attribution requires the steps below.

### Setup [#setup]

To enable ORM attribution, install the `@prisma/sqlcommenter-query-insights` package:

```bash
npm install @prisma/sqlcommenter-query-insights
```

Then pass it to the `comments` option in your `PrismaClient` constructor:

```ts
import "dotenv/config";
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
import { prismaQueryInsights } from "@prisma/sqlcommenter-query-insights";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
});

export const prisma = new PrismaClient({
  adapter: adapter,
  comments: [prismaQueryInsights()],
})

```

This adds SQL comment annotations to queries so Query Insights can map SQL statements back to the Prisma calls that generated them. It is built on top of the [SQL comments](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/sql-comments) feature in Prisma Client.

## Availability [#availability]

Query Insights is included with Prisma Postgres at no extra cost. You can try it today in the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=query-insights).

## Typical issues [#typical-issues]

Query Insights is most useful when it connects a database symptom to a concrete code change.

| Issue              | What you might see                   | Typical fix                                 |
| ------------------ | ------------------------------------ | ------------------------------------------- |
| N+1 queries        | High query count for one request     | Use nested reads, batching, or joins        |
| Missing indexes    | High reads relative to rows returned | Add the right index for the filter pattern  |
| Over-fetching      | Wide rows or large payloads          | Use `select` to fetch fewer fields          |
| Offset pagination  | Reads grow on deeper pages           | Switch to cursor pagination                 |
| Large nested reads | High reads and large payloads        | Limit fields, limit depth, or split queries |
| Repeated queries   | The same statement shape runs often  | Cache or reuse results when appropriate     |

## How to use it [#how-to-use-it]

When an endpoint gets slow, Query Insights gives you a practical workflow:

1. Open Query Insights and scan the latency and queries-per-second charts.
2. Sort or filter the query list to isolate the expensive statement.
3. Open the query detail view.
4. Read the AI analysis and inspect the SQL.
5. Copy the suggested prompt and paste it into your editor.
6. Review the suggested change, then apply it in code or schema.
7. Re-run the workload and compare the same signals again.

In most cases, the next change falls into one of these buckets:

* Change the Prisma query shape
* Add or adjust an index
* Return fewer fields or fewer rows
* Cache repeated work

## Example [#example]

A common example is an N+1 pattern:

```ts
const users = await prisma.user.findMany({
  select: { id: true, name: true, email: true },
});

for (const user of users) {
  await prisma.post.findMany({
    where: { authorId: user.id },
    select: { id: true, title: true },
  });
}
```

Query Insights would typically show:

* One query to load users
* Many repeated queries to load posts
* A high execution count for the same statement shape
* More reads and latency than the route should need

In this case, the likely fix is to load the related posts in one nested read:

```ts
const usersWithPosts = await prisma.user.findMany({
  select: {
    id: true,
    name: true,
    email: true,
    posts: {
      select: {
        id: true,
        title: true,
      },
    },
  },
});
```

The same pattern applies to other issues. Query Insights helps you identify the expensive query shape, understand why it is expensive, and choose the next change to verify.

## Next steps [#next-steps]

* Review [Connection pooling](https://www.prisma.io/docs/postgres/database/connection-pooling) for high-concurrency workloads
* Use [Connecting to your database](https://www.prisma.io/docs/postgres/database/connecting-to-your-database) when choosing connection strings for other tools
* See [Prisma Client query optimization](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance) for related Prisma ORM patterns

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# Storage (/docs/storage)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

S3-compatible object-store buckets that live inside your Prisma project.

Location: Storage

Object Store buckets are S3-compatible file storage that lives inside a Prisma project, next to its Prisma Postgres databases and Compute apps. You manage buckets from the [Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=storage), the [CLI](https://www.prisma.io/docs/cli/bucket), or the [REST API](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets); your app reads and writes objects with any S3 client or SDK.

A bucket belongs to a project. At creation you can associate it with a branch (by branch ID or git branch name); omit both and it attaches to the project's default branch. Projects start with no buckets.

## Names [#names]

A bucket has two names:

1. A display name you choose (1-100 characters, auto-generated when omitted). It appears in the Console, CLI, and API.
2. A provider-assigned S3 bucket name, returned as `providerName` by the API and as `bucketName` with new access keys. This is the value S3 clients use. It is opaque and never derived from the display name.

There is no rename: the API has no update endpoint for buckets.

## Access keys [#access-keys]

Access is through bucket-scoped access keys. A key has a role, `read` or `read_write`; a write with a `read` key fails with `AccessDenied`. Keys are scoped to their bucket only: a leaked key cannot reach any other bucket.

Creating a key returns everything an S3 client needs: `accessKeyId`, `secretAccessKey`, `endpoint`, and `bucketName`. The `secretAccessKey` is returned exactly once and never stored; copy it immediately. If you lose it, revoke the key and create a new one. Deleting a key revokes it immediately.

Use the `endpoint` value returned with the key rather than hardcoding a host.

## Using a bucket from your app [#using-a-bucket-from-your-app]

Any S3 client or SDK works. On [Prisma Compute](https://www.prisma.io/docs/compute), Bun's built-in S3 client reads `S3_ENDPOINT`, `S3_BUCKET`, `S3_ACCESS_KEY_ID`, and `S3_SECRET_ACCESS_KEY` from the environment, so uploads and presigned GET URLs work with no explicit client configuration. See [Object storage on Compute](https://www.prisma.io/docs/compute/object-storage) for a worked example, and [Object storage in Composer](https://www.prisma.io/docs/composer/object-storage) for the declarative `bucket()` resource with local stand-in buckets in `dev`. For using buckets during development, see [Local storage](https://www.prisma.io/docs/local-development/storage).

## Managing buckets [#managing-buckets]

From the CLI (see the [`bucket` reference](https://www.prisma.io/docs/cli/bucket) for details):

  

#### bun

```bash
bunx prisma bucket create --name my-bucket
bunx prisma bucket key create <bucket-id>
```

#### pnpm

```bash
pnpm prisma bucket create --name my-bucket
pnpm prisma bucket key create <bucket-id>
```

#### yarn

```bash
yarn prisma bucket create --name my-bucket
yarn prisma bucket key create <bucket-id>
```

#### npm

```bash
npx prisma bucket create --name my-bucket
npx prisma bucket key create <bucket-id>
```

| Command                                  | Purpose                                                 |
| ---------------------------------------- | ------------------------------------------------------- |
| `bucket list`                            | List object-store buckets                               |
| `bucket create`                          | Create a bucket (`--name` sets the display name)        |
| `bucket delete <bucket-id>`              | Delete a bucket and all its access keys                 |
| `bucket key list <bucket-id>`            | List access keys for a bucket                           |
| `bucket key create <bucket-id>`          | Create an access key and print its one-time credentials |
| `bucket key delete <bucket-id> <key-id>` | Revoke and delete an access key                         |

The [REST API](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets) exposes the same operations: list, create, get, and delete buckets, and list, create, and delete access keys. Bucket creation is synchronous; the response comes back with `"status": "ready"`. The Prisma MCP server also carries bucket tools (`list_object_store_buckets`, `create_object_store_bucket`, `delete_object_store_bucket`, `create_object_store_bucket_key`, `delete_object_store_bucket_key`) for AI agents.

In the Console, each bucket has a file browser with upload, download, and per-object delete, a keys page with a reveal-once credentials dialog, and a settings page for deletion with type-the-name confirmation.

## Deleting a bucket [#deleting-a-bucket]

Deleting a bucket permanently removes the bucket, all objects stored in it, and all its access keys in one call. It succeeds on a non-empty bucket and cannot be undone.

## Pricing [#pricing]

Bucket pricing and plan limits are not published yet.

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# Using API Clients (/docs/rest-api/api-clients)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Use the REST API with popular API clients like Postman, Insomnia, and Yaak

Location: REST API > Using API Clients

This guide shows you how to configure popular API clients to work with the REST API using OAuth 2.0 authentication.

<a href="/docs/prisma-rest-api.postman_collection.json" download="prisma-rest-api.postman_collection.json">Download the Postman collection</a> to import all endpoints with OAuth2 auth pre-configured. Compatible with Postman, Yaak, Insomnia, and other clients that support the Postman Collection v2.1 format.

## Postman [#postman]

Postman is a popular API client with testing, collaboration, and automation features for working with REST APIs.

### Prerequisites [#prerequisites]

Before you begin, make sure you have:

* A [Prisma Console account](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api)
* [Postman installed](https://www.postman.com/downloads/)

### 1. Create an OAuth2 Application [#1-create-an-oauth2-application]

Register an OAuth2 application in Prisma Console so Postman can request tokens on your behalf:

1. Navigate to [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api) and log in
2. Click the **🧩 Integrations** tab in the left sidebar
3. Under the "Published Applications" section, click **New Application**
4. Fill in your application details:
   * **Name**: Postman API Client
   * **Description*&#x2A;: Brief description of your application &#x2A;(Optional)*
   * **Redirect URI**: `https://oauth.pstmn.io/v1/callback`
5. Click **Continue**
6. **Important**: Copy your Client ID and Client Secret immediately and store them securely

> [!NOTE]
> The redirect URI `https://oauth.pstmn.io/v1/callback` is Postman's default callback URL when using the "Authorize using browser" option.

### 2. Configure OAuth 2.0 in Postman [#2-configure-oauth-20-in-postman]

Configure Postman to request a token from Prisma Auth:

1. Open Postman and create a new HTTP request
2. Set the request method to **POST**
3. Set the URL to `https://api.prisma.io/v1/projects`
4. Navigate to the **Authorization** tab
5. Set **Auth Type** to **OAuth 2.0**
6. Under **Configure New Token**, enter the following values:

| Parameter            | Value                                |
| -------------------- | ------------------------------------ |
| Token Name           | REST API Token                       |
| Grant Type           | Authorization Code                   |
| Callback URL         | `https://oauth.pstmn.io/v1/callback` |
| Authorize in Browser | `true&#x60; &#x2A;(checked)*         |
| Auth URL             | `https://auth.prisma.io/authorize`   |
| Access Token URL     | `https://auth.prisma.io/token`       |
| Client ID            | `your-client-id`                     |
| Client Secret        | `your-client-secret`                 |
| Scope                | `workspace:admin`                    |

7. Click **Get New Access Token**
8. A browser window opens for you to complete the authorization flow
9. Return to Postman and click **Use Token** to attach it to your request
10. Verify that your new token appears under **Current Token** at the top of the Authorization tab

### 3. Make your first request [#3-make-your-first-request]

With authentication configured, you can now create a project:

1. In the request body, select **raw** and **JSON** format
2. Add the following JSON payload:

```json
{
  "name": "My Postman Database",
  "region": "us-east-1"
}
```

3. Click **Send**

A successful response contains the new project's details.

## Insomnia [#insomnia]

Insomnia is an open-source API client with a clean interface for testing and debugging HTTP requests.

### Prerequisites [#prerequisites-1]

Before you begin, make sure you have:

* A [Prisma Console account](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api)
* [Insomnia installed](https://insomnia.rest/download/)

### 1. Create an OAuth2 Application [#1-create-an-oauth2-application-1]

Register an OAuth2 application in Prisma Console so Insomnia can request tokens on your behalf:

1. Navigate to [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api) and log in
2. Click the **🧩 Integrations** tab in the left sidebar
3. Under the "Published Applications" section, click **New Application**
4. Fill in your application details:
   * **Name**: Insomnia API Client
   * **Description*&#x2A;: Brief description of your application &#x2A;(Optional)*
   * **Redirect URI**: `https://app.insomnia.rest/oauth/redirect`
5. Click **Continue**
6. **Important**: Copy your Client ID and Client Secret immediately and store them securely

> [!NOTE]
> Insomnia uses `https://app.insomnia.rest/oauth/redirect` as the default OAuth callback URL for local authentication flows.

### 2. Configure OAuth 2.0 in Insomnia [#2-configure-oauth-20-in-insomnia]

Configure Insomnia to request a token from Prisma Auth:

1. Open Insomnia and create a new HTTP request
2. Set the request method to **POST**
3. Set the URL to `https://api.prisma.io/v1/projects`
4. Navigate to the **Auth** tab
5. Set the authentication type to **OAuth 2.0**
6. Under **Configuration**, enter the following values:

| Parameter                             | Value                                      |
| ------------------------------------- | ------------------------------------------ |
| Grant Type                            | Authorization Code                         |
| Authorization URL                     | `https://auth.prisma.io/authorize`         |
| Access Token URL                      | `https://auth.prisma.io/token`             |
| Client ID                             | `your-client-id`                           |
| Client Secret                         | `your-client-secret`                       |
| Redirect URL                          | `https://app.insomnia.rest/oauth/redirect` |
| Scope &#x2A;(Under Advanced Options)* | `workspace:admin`                          |

7. Click **Fetch Tokens**
8. A browser window opens for you to complete the authorization flow
9. Return to Insomnia and verify that the access token has been retrieved
10. The token will be automatically attached to your requests

### 3. Make your first request [#3-make-your-first-request-1]

With authentication configured, you can now create a project:

1. Navigate to the **Body** tab and select **JSON** format
2. Add the following JSON payload:

```json
{
  "name": "My Insomnia Database",
  "region": "us-east-1"
}
```

3. Click **Send**

A successful response contains the new project's details.

## Yaak [#yaak]

Yaak is a lightweight, open-source, and offline API client that works with Git.

### Prerequisites [#prerequisites-2]

Before you begin, make sure you have:

* A [Prisma Console account](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api)
* [Yaak installed](https://yaak.app)

### 1. Create an OAuth2 Application [#1-create-an-oauth2-application-2]

Register an OAuth2 application in Prisma Console so Yaak can request tokens on your behalf:

1. Navigate to [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api) and log in
2. Click the **🧩 Integrations** tab in the left sidebar
3. Under the "Published Applications" section, click **New Application**
4. Fill in your application details:
   * **Name**: Yaak API Client
   * **Description*&#x2A;: Brief description of your application &#x2A;(Optional)*
   * **Redirect URI**: `https://devnull.yaak.app/callback`
5. Click **Continue**
6. **Important**: Copy your Client ID and Client Secret immediately and store them securely

> [!NOTE]
> The redirect URI can be any valid URL. Yaak intercepts the OAuth callback regardless of the redirect URI, as long as it matches what's registered with the provider.

### 2. Configure OAuth 2.0 in Yaak [#2-configure-oauth-20-in-yaak]

Configure Yaak to request a token from Prisma Auth:

1. Open Yaak and create a new HTTP request
2. Set the request method to **POST**
3. Set the URL to `https://api.prisma.io/v1/projects`
4. Navigate to the **Auth** tab
5. Set the authentication type to **OAuth 2.0**
6. Enter the following values:

| Parameter         | Value                               |
| ----------------- | ----------------------------------- |
| Grant Type        | Authorization Code                  |
| Authorization URL | `https://auth.prisma.io/authorize`  |
| Token URL         | `https://auth.prisma.io/token`      |
| Client ID         | `your-client-id`                    |
| Client Secret     | `your-client-secret`                |
| Redirect URL      | `https://devnull.yaak.app/callback` |
| Scope             | `workspace:admin`                   |

7. Click **Get Token**
8. A browser window opens for you to complete the authorization flow
9. Return to Yaak and verify that the access token has been retrieved
10. The token will be automatically attached to your requests

### 3. Make your first request [#3-make-your-first-request-2]

With authentication configured, you can now create a project:

1. Navigate to the **Body** tab and select **JSON** format
2. Add the following JSON payload:

```json
{
  "name": "My Yaak Database",
  "region": "us-east-1"
}
```

3. Click **Send**

A successful response contains the new project's details.

## Related pages

- [`Authentication`](https://www.prisma.io/docs/rest-api/authentication): Learn how to authenticate with the Prisma REST API using service tokens or OAuth 2.0
- [`Getting Started`](https://www.prisma.io/docs/rest-api/getting-started): Get started with the Prisma REST API by creating your first project and database
- [`Partner Integration`](https://www.prisma.io/docs/rest-api/partner-integration): Build partner integrations that provision and transfer Prisma Postgres databases to users
- [`SDK`](https://www.prisma.io/docs/rest-api/sdk): A TypeScript SDK for the Prisma Data Platform REST API. Use the simple client for direct API access, or the full SDK with built-in OAuth authentication and automatic token refresh

# Authentication (/docs/rest-api/authentication)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to authenticate with the Prisma REST API using service tokens or OAuth 2.0

Location: REST API > Authentication

The REST API supports two authentication methods:

* **Service Tokens** - Bearer tokens for scripts, CI/CD pipelines, and backend services
* **OAuth 2.0** - For user-facing applications requiring user consent

## Service tokens [#service-tokens]

A service token is a bearer token you create once in Prisma Console and pass in the `Authorization` header. Use one for scripts, CI/CD pipelines, and backend services, where no user is present to grant consent.

### Creating a Service token [#creating-a-service-token]

1. Navigate to [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api) and log in
2. Select your workspace
3. Go to **Settings → Service Tokens**
4. Click **New Service Token**
5. Copy the generated token immediately and store it securely

### Using a Service token [#using-a-service-token]

Include the token in the `Authorization` header:

```bash
curl -X GET "https://api.prisma.io/v1/workspaces" \
  -H "Authorization: Bearer your-service-token"
```

Or with the SDK:

```typescript
import { createManagementApiClient } from "@prisma/management-api-sdk";

const client = createManagementApiClient({
  token: "your-service-token",
});
```

> [!WARNING]
> Service tokens never expire
> 
> Service tokens do not have an expiration date. That suits long-running integrations, but a leaked token stays valid until you revoke it. Store tokens in a secrets manager and revoke any token you no longer need.

## OAuth 2.0 [#oauth-20]

OAuth 2.0 is required for applications that act on behalf of users. The API implements OAuth 2.0 with PKCE.

### PKCE Support [#pkce-support]

The OAuth implementation supports Proof Key for Code Exchange (PKCE) using the S256 code challenge method:

* **Public clients** (no client secret): PKCE is **mandatory**
* **Confidential clients** (with client secret): PKCE is **optional**, but if you start the flow with PKCE, it must be completed with PKCE

PKCE lets mobile and single-page applications, which cannot keep a client secret private, complete the flow without one.

### Creating an OAuth Application [#creating-an-oauth-application]

1. Navigate to [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api) and log in
2. Click the **Integrations** tab in the left sidebar
3. Under "Published Applications", click **New Application**
4. Fill in your application details:
   * **Name**: Your application name
   * **Description*&#x2A;: Brief description &#x2A;(optional)*
   * **Redirect URI**: Your callback URL (e.g., `https://your-app.com/auth/callback`)
5. Click **Continue**
6. Copy your **Client ID** and **Client Secret** immediately

> [!NOTE]
> Development redirect URIs
> 
> For local development, the following redirect URIs are accepted with any port via wildcard matching:
> 
> * `localhost` (e.g., `http://localhost:3000/callback`)
> * `127.0.0.1` (e.g., `http://127.0.0.1:3000/callback`)
> * `[::1]` - IPv6 loopback (e.g., `http://[::1]:3000/callback`)

### OAuth Endpoints [#oauth-endpoints]

| Endpoint      | URL                                                             |
| ------------- | --------------------------------------------------------------- |
| Authorization | `https://auth.prisma.io/authorize`                              |
| Token         | `https://auth.prisma.io/token`                                  |
| Discovery     | `https://auth.prisma.io/.well-known/oauth-authorization-server` |

> [!NOTE]
> The discovery endpoint provides OAuth server metadata that can be used for automatic client configuration. Many OAuth libraries support automatic discovery using this endpoint.

### Available Scopes [#available-scopes]

| Scope             | Description                                    |
| ----------------- | ---------------------------------------------- |
| `workspace:admin` | Full access to workspace resources             |
| `offline_access`  | Enables refresh tokens for long-lived sessions |

### Token Lifetimes [#token-lifetimes]

| Token Type     | Expiration |
| -------------- | ---------- |
| Access tokens  | 1 hour     |
| Refresh tokens | 90 days    |

### OAuth Authorization Flow [#oauth-authorization-flow]

#### 1. Redirect users to authorize [#1-redirect-users-to-authorize]

Redirect users to the authorization endpoint with the following query parameters:

| Parameter       | Description                                                         |
| --------------- | ------------------------------------------------------------------- |
| `client_id`     | Your OAuth application's Client ID                                  |
| `redirect_uri`  | The callback URL where users will be redirected after authorization |
| `response_type` | Must be `code` for the authorization code flow                      |
| `scope`         | Permissions to request (e.g., `workspace:admin`)                    |

```
https://auth.prisma.io/authorize?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&response_type=code&scope=workspace:admin
```

This will redirect the user to the Prisma authorization page where they can grant your application access to their workspace.

#### 2. Receive the authorization code [#2-receive-the-authorization-code]

After authorization, users are redirected to your callback URL with a `code` parameter:

```
https://your-app.com/callback?code=abc123...
```

#### 3. Exchange the code for an access token [#3-exchange-the-code-for-an-access-token]

```bash
curl -X POST https://auth.prisma.io/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=$CLIENT_ID" \
  -d "client_secret=$CLIENT_SECRET" \
  -d "code=$CODE" \
  -d "grant_type=authorization_code" \
  -d "redirect_uri=$REDIRECT_URI"
```

The response will include an access token that can be used to make authenticated requests to the REST API:

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

#### 4. Use the access token [#4-use-the-access-token]

```bash
curl -X GET "https://api.prisma.io/v1/workspaces" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

### Token Refresh [#token-refresh]

If you requested the `offline_access` scope, you'll receive a refresh token. Use it to obtain new access tokens:

```bash
curl -X POST https://auth.prisma.io/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=$CLIENT_ID" \
  -d "client_secret=$CLIENT_SECRET" \
  -d "refresh_token=$REFRESH_TOKEN" \
  -d "grant_type=refresh_token"
```

> [!NOTE]
> Refresh token rotation
> 
> Refresh tokens use single-use rotation with replay attack detection. When you exchange a refresh token for a new access token, you'll receive a new refresh token in the response. The old refresh token is immediately invalidated. If an invalidated refresh token is used again, it indicates a potential security breach, and the system will revoke all tokens associated with that authorization.

### Using OAuth with the SDK [#using-oauth-with-the-sdk]

The SDK handles the OAuth flow automatically. See the [SDK documentation](https://www.prisma.io/docs/rest-api/sdk#oauth-authentication-flow) for implementation details.

## Using API Clients [#using-api-clients]

You can also authenticate using popular API clients like Postman, Insomnia, or Yaak. See the [Using API Clients](https://www.prisma.io/docs/rest-api/api-clients) guide for step-by-step instructions.

## Related pages

- [`Getting Started`](https://www.prisma.io/docs/rest-api/getting-started): Get started with the Prisma REST API by creating your first project and database
- [`Partner Integration`](https://www.prisma.io/docs/rest-api/partner-integration): Build partner integrations that provision and transfer Prisma Postgres databases to users
- [`SDK`](https://www.prisma.io/docs/rest-api/sdk): A TypeScript SDK for the Prisma Data Platform REST API. Use the simple client for direct API access, or the full SDK with built-in OAuth authentication and automatic token refresh
- [`Using API Clients`](https://www.prisma.io/docs/rest-api/api-clients): Use the REST API with popular API clients like Postman, Insomnia, and Yaak

# Getting Started (/docs/rest-api/getting-started)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Get started with the Prisma REST API by creating your first project and database

Location: REST API > Getting Started

This guide walks you through setting up a basic TypeScript project that uses the REST API to create a new Prisma Console project with a Prisma Postgres database, and print out all connection details.

You'll authenticate via a service token, set up your environment, and run a script to interact with the API.

## Prerequisites [#prerequisites]

* Node.js and `npm` installed
* A [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api) account

## 1. Create a service token in Prisma Console [#1-create-a-service-token-in-prisma-console]

Create a service token so your script can authenticate with the REST API:

1. Open the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api)
2. Navigate to the **Settings** page of your workspace and select **Service Tokens**
3. Click **New Service Token**
4. Copy the generated service token and store it securely. You add it to `.env` in step 2.2.

## 2. Set up your project directory [#2-set-up-your-project-directory]

### 2.1. Create a basic TypeScript project [#21-create-a-basic-typescript-project]

Create the project directory and move into it:

```bash
mkdir rest-api-demo
cd rest-api-demo
```

Next, initialize npm and install dependencies required for using TypeScript:

  

#### bun

```bash
bun init
bun add tsx typescript @types/node --dev
touch index.ts
```

#### pnpm

```bash
pnpm init
pnpm add tsx typescript @types/node --save-dev
touch index.ts
```

#### yarn

```bash
yarn init
yarn add tsx typescript @types/node --dev
touch index.ts
```

#### npm

```bash
npm init
npm install tsx typescript @types/node --save-dev
touch index.ts
```

You now have an `index.ts` file that you can execute with `npx tsx index.ts`. It is still empty. You add code to it in step 3.

### 2.2. Configure service token environment variable [#22-configure-service-token-environment-variable]

Create your `.env` file:

```bash
touch .env
```

Next, install the [`dotenv`](https://github.com/motdotla/dotenv) library for loading environment variables from the `.env` file:

  

#### bun

```bash
bun add dotenv
```

#### pnpm

```bash
pnpm add dotenv
```

#### yarn

```bash
yarn add dotenv
```

#### npm

```bash
npm install dotenv
```

Finally, add your service token (from step 1.) to `.env`:

```bash
PRISMA_SERVICE_TOKEN="ey..."
```

### 2.3. Install the `axios` library for HTTP request [#23-install-the-axios-library-for-http-request]

This guide uses [`axios`](https://github.com/axios/axios/tree/main) as the HTTP client for the REST API. Install it:

  

#### bun

```bash
bun add axios
```

#### pnpm

```bash
pnpm add axios
```

#### yarn

```bash
yarn add axios
```

#### npm

```bash
npm install axios
```

With the token, environment, and HTTP client in place, the next step creates a project and provisions a Prisma Postgres database.

## 3. Programmatically create a new project with a database [#3-programmatically-create-a-new-project-with-a-database]

Paste the following code into `index.ts`:

```ts
import axios from "axios";
import dotenv from "dotenv";

// Load environment variables
dotenv.config();

const API_URL = "https://api.prisma.io/v1";
const SERVICE_TOKEN = process.env.PRISMA_SERVICE_TOKEN;

if (!SERVICE_TOKEN) {
  throw new Error("PRISMA_SERVICE_TOKEN is not set in the environment");
}

// Set HTTP headers to be used in this script
const headers = {
  Authorization: `Bearer ${SERVICE_TOKEN}`,
  "Content-Type": "application/json",
};

async function main() {
  // Create a new project in your Prisma Console workspace
  const projectName = `demo-project-${Date.now()}`;
  const region = "us-east-1";
  const createProjectRes = await axios.post(
    `${API_URL}/projects`,
    { name: projectName, region },
    { headers },
  );
  const project = createProjectRes.data;
  console.log("Created project: \n", project);

  // Log the database details
  const apiKeys = project.databases[0].apiKeys || [];
  for (const key of apiKeys) {
    console.log(`\nDatabase details`);
    console.log(`- ID: ${key.id}`);
    console.log(`- Created at: ${key.createdAt}`);
    console.log(`- API key: ${key.apiKey}`);
    console.log(`- Prisma Postgres connection string: ${key.connectionString}`);

    if (key.ppgDirectConnection) {
      console.log(`- Direct TCP connection: ${key.ppgDirectConnection.host}`);
      console.log(`  - Host: ${key.ppgDirectConnection.host}`);
      console.log(`  - Username: ${key.ppgDirectConnection.user}`);
      console.log(`  - Password: ${key.ppgDirectConnection.pass}`);
    }
  }
}

main().catch((e) => {
  console.error(e.response?.data || e);
  process.exit(1);
});
```

Run the script:

  

#### bun

```bash
bunx tsx index.ts
```

#### pnpm

```bash
pnpm dlx tsx index.ts
```

#### yarn

```bash
yarn dlx tsx index.ts
```

#### npm

```bash
npx tsx index.ts
```

```text no-copy
Created project:
 {
  createdAt: '2025-07-09T11:52:15.341Z',
  id: 'cmcvwftgs00v5zq0vh3kp7pms',
  name: 'demo-project-1752061932800',
  databases: [
    {
      createdAt: '2025-07-09T11:52:15.341Z',
      id: 'cmcvwftgs00v1zq0v0qrtrg8t',
      name: 'demo-project-1752061932800',
      connectionString: 'prisma+postgres://accelerate.prisma-data.net/?api_key=<api_key>',
      region: 'us-east-1',
      status: 'ready',
      apiKeys: [Array],
      isDefault: true
    }
  ]
}

Database details
- ID: cmcvwftgs00v2zq0vj3v0104j
- Created at: 2025-07-09T11:52:15.341Z
- API key: ey...<actual_api_key>
- Prisma Postgres connection string: prisma+postgres://accelerate.prisma-data.net/?api_key=ey...<actual_api_key>
- Direct TCP connection: db.prisma.io:5432
  - Host: db.prisma.io:5432
  - Username: <username>
  - Password: <password>
```

The output should look similar to the above.

## Conclusion [#conclusion]

You have now set up a TypeScript project that interacts with the REST API, creates a new project and database, and prints out all connection strings. You can extend this script to manage more resources or automate other tasks using the REST API.

## Related pages

- [`Authentication`](https://www.prisma.io/docs/rest-api/authentication): Learn how to authenticate with the Prisma REST API using service tokens or OAuth 2.0
- [`Partner Integration`](https://www.prisma.io/docs/rest-api/partner-integration): Build partner integrations that provision and transfer Prisma Postgres databases to users
- [`SDK`](https://www.prisma.io/docs/rest-api/sdk): A TypeScript SDK for the Prisma Data Platform REST API. Use the simple client for direct API access, or the full SDK with built-in OAuth authentication and automatic token refresh
- [`Using API Clients`](https://www.prisma.io/docs/rest-api/api-clients): Use the REST API with popular API clients like Postman, Insomnia, and Yaak

# REST API (/docs/rest-api)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Programmatically manage your Prisma Postgres databases, projects, and workspaces with the REST API

Location: REST API

## Base URL [#base-url]

```
https://api.prisma.io/v1
```

Append an endpoint path to construct the full URL. For example: `https://api.prisma.io/v1/projects/{projectId}`

An interactive [OpenAPI 3.1 specification](https://api.prisma.io/v1/swagger-editor) is available for exploring endpoints and request/response formats.

## Getting Started [#getting-started]

* **[Getting Started](https://www.prisma.io/docs/rest-api/getting-started)** - Create your first project and database
* **[Authentication](https://www.prisma.io/docs/rest-api/authentication)** - OAuth 2.0 and service tokens setup
* **[SDK](https://www.prisma.io/docs/rest-api/sdk)** - TypeScript SDK with built-in OAuth and automatic token refresh
* **[Using API Clients](https://www.prisma.io/docs/rest-api/api-clients)** - Use with Postman, Insomnia, and Yaak
* **[Partner Integration](https://www.prisma.io/docs/rest-api/partner-integration)** - Build integrations that provision and transfer databases

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# Partner Integration (/docs/rest-api/partner-integration)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Build partner integrations that provision and transfer Prisma Postgres databases to users

Location: REST API > Partner Integration

This guide walks you through building a partner integration with the REST API to power experiences like the [`npx create-db`](https://create-db.prisma.io/) command.

You provision a Prisma Postgres database in your own workspace as a partner, then transfer it to a user's workspace so they can "claim" the database. The transfer is authorized with OAuth2, so only the intended user can claim it.

The examples come from the `npx create-db` CLI and its Cloudflare Workers. The [create-db repository](https://github.com/prisma/create-db) contains that implementation; use it as a reference for calling the REST API from your own project.

> [!NOTE]
> Where this logic lives in your app
> 
> The two Cloudflare Workers in this guide are reference examples. You would typically build this logic into your own backend or serverless functions.
> 
> Similarly, the `npx create-db` CLI is a demo. In your product, trigger the same API calls from your own UI or onboarding flow.

## Core concepts [#core-concepts]

The integration uses these concepts:

* **REST API**: A set of endpoints that allow you to programmatically provision and manage Prisma Postgres databases.
* **Projects vs Databases**: A project is a container that can hold multiple databases. You can use this to organize databases you create e.g. by user. Projects can then be transferred to users, including all databases they contain.
* **Authentication**: All API requests require authentication. As a partner, you authenticate provisioning calls with a service token for your workspace, and use OAuth 2 to obtain an access token for the user during the claim flow.
* **Tokens**: There are two main types of tokens:
  * **Service token**: Issued to your partner integration, scoped to provision and manage databases on your own workspace.
  * **OAuth 2 access token**: Obtained via OAuth 2 when a user authenticates with your app; it is scoped to the user's workspace and used to transfer project/database ownership to that workspace.

## How to become a partner [#how-to-become-a-partner]

To use the Prisma Postgres REST API, you first need to set up as a partner:

1. **Request access to the REST API**: Contact the Prisma team from the [Prisma Partners page](https://www.prisma.io/partners) to request access to the REST API. You will be guided through the onboarding process.
2. **Obtain OAuth credentials**: You can obtain your OAuth credentials in the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api). See the [next section](#get-oauth-credentials) for details.

For a complete list of available endpoints and details on request/response formats, see the [Prisma REST API documentation](https://www.prisma.io/docs/rest-api).

## Get OAuth credentials [#get-oauth-credentials]

To obtain a client ID and client secret, create an OAuth app in Prisma Console:

1. Open the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=rest-api).
2. Click the 🧩 **Integrations** tab in the sidenav.
3. In the **Published Applications** section, click **New Application** button to start the flow for creating a new OAuth app.
4. Enter a **Name**, **Description** and **Callback URL** for your OAuth app.
5. Click **Continue**.

On the next screen, you can access and save the client ID and client secret for your OAuth app.

## Provisioning a database as a Partner [#provisioning-a-database-as-a-partner]

To provision a new Prisma Postgres database for your users as a partner, follow these steps:

1. **Gather required information**: Prepare the necessary details for provisioning, such as region, database name, and any other options your application requires. This information may come from user input or be determined by your application logic.
2. **Authenticate your integration**: Use your service token to authenticate API requests from your backend. This token authenticates your app as an approved partner.
3. **Send a database provisioning request**: Make a `POST` request to the REST API endpoint to create a new project with a default database. For example:
   ```ts
   const prismaResponse = await fetch("https://api.prisma.io/v1/projects", {
     method: "POST",
     headers: {
       "Content-Type": "application/json",
       Authorization: `Bearer <YOUR_SERVICE_TOKEN>`,
     },
     body: JSON.stringify({ region, name }),
   });
   ```
4. **Handle the response**: If successful, the API will return the new project's details, including database connection strings and a `project_id`. Store these securely and display them to your user as needed.
5. **(Optional) Store project metadata**: You may want to associate the `project_id` with your user in your own database for future reference.

## Database claim flow [#database-claim-flow]

Once a database is provisioned, you may want to transfer ownership to your user at a later point so they can manage it in their own Prisma workspace and go beyond the free database usage limits. This is done via the claim flow, which consists of three main steps:

### How the claim flow works [#how-the-claim-flow-works]

When a user wants to claim a database, your app will:

1. Trigger the OAuth2 flow, redirecting the user to Prisma Auth. This gives your app permission to transfer the database into the user's workspace.
2. The user authenticates and selects a workspace.
3. Your backend receives an authorization code, exchanges it for a user access token, and calls the REST API transfer endpoint with both your integration token and the user's token.

Only the user who completed the OAuth2 flow can claim the database.

### 1. Triggering the claim flow [#1-triggering-the-claim-flow]

When your user wants to take ownership of a database you provisioned for them, they need to transfer it to their own Prisma Postgres workspace. This gives them full control over it.

To initiate this process, provide a button or link in your app (e.g., "Claim Database" or "Transfer to My Workspace"). When clicked, your backend should:

* Generate a secure `state` value to track the session and prevent CSRF attacks.
* Construct an OAuth2 authorization URL with your client ID, redirect URI, and required scopes.
* Redirect the user to this URL to begin the authentication flow.

Example:

```ts
const authParams = new URLSearchParams({
  client_id: YOUR_CLIENT_ID,
  redirect_uri: "https://your-app.com/auth/callback", // Your callback endpoint
  response_type: "code",
  scope: "workspace:admin", // The scope of the OAuth2 authorization
  state: generateState(), // Securely track the session
});
const authUrl = `https://auth.prisma.io/authorize?${authParams.toString()}`;
// Redirect the user to authUrl
```

### 2. Authenticating the user [#2-authenticating-the-user]

The user will be prompted to log in (if not already authenticated) and select the workspace where they want to claim the database. After successful authentication and workspace selection, Prisma Auth will redirect back to your callback endpoint with a `code` and `state` (and, in some cases, a `project_id`).

### 3. Finishing the claim flow [#3-finishing-the-claim-flow]

Your backend should now:

1. **Exchange the authorization code for a user access token**:

```ts
const tokenResponse = await fetch("https://auth.prisma.io/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "authorization_code",
    code: code, // The code received from the callback
    redirect_uri: "https://your-app.com/auth/callback", // Must match the redirect_uri used in step 1
    client_id: YOUR_CLIENT_ID,
    client_secret: YOUR_CLIENT_SECRET,
  }).toString(),
});
const tokenData = await tokenResponse.json();
```

2. **Call the REST API transfer endpoint** to move the project to the selected workspace. You will need the `project_id` and the user's access token:

```ts
const transferResponse = await fetch(`https://api.prisma.io/v1/projects/${project_id}/transfer`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${PRISMA_SERVICE_TOKEN}`,
  },
  body: JSON.stringify({ recipientAccessToken: tokenData.access_token }),
});
```

If the transfer is successful, the database is now owned by the user's workspace.

## Conclusion [#conclusion]

By following this guide, you have learned how to:

* Set up as a Prisma Postgres Partner and obtain the necessary credentials
* Provision a new database for your users using the REST API
* Implement a secure claim flow that allows users to claim ownership of a database in their own workspace using OAuth2

For further details, see the [create-db](https://github.com/prisma/create-db) repo for a reference implementation, or consult the [Prisma REST API documentation](https://www.prisma.io/docs/rest-api).

## Related pages

- [`Authentication`](https://www.prisma.io/docs/rest-api/authentication): Learn how to authenticate with the Prisma REST API using service tokens or OAuth 2.0
- [`Getting Started`](https://www.prisma.io/docs/rest-api/getting-started): Get started with the Prisma REST API by creating your first project and database
- [`SDK`](https://www.prisma.io/docs/rest-api/sdk): A TypeScript SDK for the Prisma Data Platform REST API. Use the simple client for direct API access, or the full SDK with built-in OAuth authentication and automatic token refresh
- [`Using API Clients`](https://www.prisma.io/docs/rest-api/api-clients): Use the REST API with popular API clients like Postman, Insomnia, and Yaak

# SDK (/docs/rest-api/sdk)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A TypeScript SDK for the Prisma Data Platform REST API. Use the simple client for direct API access, or the full SDK with built-in OAuth authentication and automatic token refresh

Location: REST API > SDK

## Overview [#overview]

The [`@prisma/management-api-sdk`](https://www.npmjs.com/package/@prisma/management-api-sdk) is a TypeScript SDK for the [Prisma Data Platform REST API](https://www.prisma.io/docs/rest-api). Use the simple client for direct API access, or the full SDK with built-in OAuth authentication and automatic token refresh.

Based on the [public OpenAPI 3.1 specification](https://api.prisma.io/v1/swagger-editor).

## Installation [#installation]

  

#### bun

```bash
bun add @prisma/management-api-sdk
```

#### pnpm

```bash
pnpm add @prisma/management-api-sdk
```

#### yarn

```bash
yarn add @prisma/management-api-sdk
```

#### npm

```bash
npm install @prisma/management-api-sdk
```

## Basic usage [#basic-usage]

For usage with an existing access or [service token](https://www.prisma.io/docs/rest-api/authentication#service-tokens).

### Making API calls [#making-api-calls]

The client provides fully typed methods for all API endpoints:

```typescript
import { createManagementApiClient } from "@prisma/management-api-sdk";

const client = createManagementApiClient({
  token: "your-access-token",
});

// List workspaces
const { data: workspaces, error } = await client.GET("/v1/workspaces");

// Get a specific project
const { data: project } = await client.GET("/v1/projects/{id}", {
  params: { path: { id: "project-id" } },
});

// Create a new project
const { data: newProject } = await client.POST("/v1/workspaces/{workspaceId}/projects", {
  params: { path: { workspaceId: "workspace-id" } },
  body: { name: "My New Project" },
});

// Create a new database
const { data: newDatabase } = await client.POST("/v1/projects/{projectId}/databases", {
  params: { path: { projectId: "project-id" } },
  body: {
    name: "my-new-db-instance",
    region: "us-east-1",
    isDefault: true,
  },
});

// Delete a database
const { error: deleteError } = await client.DELETE("/v1/databases/{databaseId}", {
  params: { path: { databaseId: "database-id" } },
});
```

### Customizing the client [#customizing-the-client]

You can override any `ClientOptions` from `openapi-fetch`, including `baseUrl`, `headers`, and other fetch options:

```typescript
import { createManagementApiClient } from "@prisma/management-api-sdk";

// Override baseUrl and add custom headers
const client = createManagementApiClient({
  token: "your-access-token",
  baseUrl: "https://api.example.com",
  headers: {
    "X-Custom-Header": "value",
  },
});
```

> [!NOTE]
> If you provide both `token` and `headers.Authorization`, the `headers.Authorization` takes precedence. The `baseUrl` defaults to `https://api.prisma.io` if not provided.

## Advanced usage [#advanced-usage]

For applications that need [OAuth authentication](#oauth-authentication-flow), automatic token refresh, and token storage management, use the full SDK.

### OAuth authentication flow [#oauth-authentication-flow]

The SDK uses OAuth 2.0 with PKCE. The flow is stateless, so you are responsible for storing the `state` and `verifier` between generating the login URL and handling the callback.

#### 1. Create the SDK instance [#1-create-the-sdk-instance]

```typescript
import { createManagementApiSdk, type TokenStorage } from "@prisma/management-api-sdk";

// Implement token storage for your environment
const tokenStorage: TokenStorage = {
  async getTokens() {
    const stored = localStorage.getItem("prisma-tokens");
    return stored ? JSON.parse(stored) : null;
  },
  async setTokens(tokens) {
    localStorage.setItem("prisma-tokens", JSON.stringify(tokens));
  },
  async clearTokens() {
    localStorage.removeItem("prisma-tokens");
  },
};

// Create the SDK instance
const api = createManagementApiSdk({
  clientId: "your-oauth-client-id",
  redirectUri: "https://your-app.com/auth/callback",
  tokenStorage,
});
```

#### 2. Initiate login [#2-initiate-login]

Generate the OAuth login URL. The returned `state` and `verifier` must be stored (e.g., in a session or cookie) for use when handling the callback:

```typescript
const { url, state, verifier } = await api.getLoginUrl({
  scope: "workspace:admin offline_access",
  additionalParams: {
    utm_source: "my-app",
    utm_medium: "login",
  },
});

// Store state and verifier for the callback (e.g., in session storage)
sessionStorage.setItem("oauth-state", state);
sessionStorage.setItem("oauth-verifier", verifier);

// Redirect user to the login URL
window.location.href = url;
```

#### 3. Handle the callback [#3-handle-the-callback]

When the user is redirected back to your app, retrieve the stored `state` and `verifier` and pass them to `handleCallback`. On success, tokens are automatically stored via your `tokenStorage` implementation:

```typescript
// In your callback route handler
const callbackUrl = window.location.href;

// Retrieve the stored values
const expectedState = sessionStorage.getItem("oauth-state");
const verifier = sessionStorage.getItem("oauth-verifier");

// Clean up stored values
sessionStorage.removeItem("oauth-state");
sessionStorage.removeItem("oauth-verifier");

try {
  await api.handleCallback({
    callbackUrl,
    verifier,
    expectedState,
  });

  // Tokens are now stored in tokenStorage and the client is ready to use
  console.log("Login successful!");
} catch (error) {
  if (error instanceof AuthError) {
    console.error("Authentication failed:", error.message);
  }
}
```

#### 4. Make API calls [#4-make-api-calls]

The client automatically includes authentication headers and refreshes tokens when they expire. Use `api.client` with the same methods shown in [Basic usage](#making-api-calls).

#### 5. Logout [#5-logout]

```typescript
await api.logout(); // Clears stored tokens
```

### Token storage interface [#token-storage-interface]

Implement this interface to handle token persistence in your environment:

```typescript
interface TokenStorage {
  /** Provide the stored tokens to the SDK */
  getTokens(): Promise<Tokens | null>;
  /** Store new or updated tokens when the SDK has successfully authenticated or refreshed tokens */
  setTokens(tokens: Tokens): Promise<void>;
  /** Clear the tokens when the user logs out or the refresh token is invalid */
  clearTokens(): Promise<void>;
}

type Tokens = {
  /** The workspace ID that these tokens are valid for (extracted from the access token) */
  workspaceId: string;
  /** The access token for API requests */
  accessToken: string;
  /** The refresh token for obtaining new access tokens (only present if scope includes 'offline_access') */
  refreshToken?: string;
};
```

#### Example: VS Code Extension [#example-vs-code-extension]

```typescript
const tokenStorage: TokenStorage = {
  async getTokens() {
    const workspaceId = await context.secrets.get("workspaceId");
    const accessToken = await context.secrets.get("accessToken");
    const refreshToken = await context.secrets.get("refreshToken");

    if (!workspaceId || !accessToken) return null;

    return { workspaceId, accessToken, refreshToken: refreshToken || undefined };
  },
  async setTokens(tokens) {
    await context.secrets.store("workspaceId", tokens.workspaceId);
    await context.secrets.store("accessToken", tokens.accessToken);
    if (tokens.refreshToken) {
      await context.secrets.store("refreshToken", tokens.refreshToken);
    }
  },
  async clearTokens() {
    await context.secrets.delete("workspaceId");
    await context.secrets.delete("accessToken");
    await context.secrets.delete("refreshToken");
  },
};
```

#### Example: Node.js CLI [#example-nodejs-cli]

```typescript
import { readFile, writeFile, unlink } from "node:fs/promises";
import { homedir } from "node:os";
import { join } from "node:path";

const tokenPath = join(homedir(), ".prisma", "credentials.json");

const tokenStorage: TokenStorage = {
  async getTokens() {
    try {
      const data = await readFile(tokenPath, "utf-8");
      return JSON.parse(data);
    } catch {
      return null;
    }
  },
  async setTokens(tokens) {
    await writeFile(tokenPath, JSON.stringify(tokens, null, 2));
  },
  async clearTokens() {
    await unlink(tokenPath).catch(() => {});
  },
};
```

For other environments:

* **VS Code extensions** - Use `context.secrets` for secure storage
* **Stateless web servers** - Store PKCE state/verifier in encrypted cookies or a database

### Automatic token refresh [#automatic-token-refresh]

The SDK automatically handles token refresh when a refresh token is available (requires `offline_access` scope):

* When a request returns 401, the SDK refreshes the access token using the refresh token
* Concurrent requests during refresh are queued and resolved once refresh completes
* If refresh fails due to an invalid refresh token, tokens are cleared and `AuthError` is thrown with `refreshTokenInvalid: true`
* If no refresh token is available, an `AuthError` is thrown with the message "No refresh token available. Please log in again."

## API reference [#api-reference]

### `createManagementApiClient(options)` [#createmanagementapiclientoptions]

Creates a raw API client without authentication handling. Useful if you want to manage authentication yourself or use a service token.

**Parameters:**

* `options.token?: string` - Access token (automatically converted to `Authorization: Bearer ${token}` header)
* `options.baseUrl?: string` - Base URL for API requests (defaults to `https://api.prisma.io`)
* `options.headers?: Record<string, string>` - Additional headers
* Other `ClientOptions` from `openapi-fetch` are also supported

**Returns:** A typed API client for making requests.

### `createManagementApiSdk(config)` [#createmanagementapisdkconfig]

Creates a REST API SDK instance with OAuth authentication and automatic token refresh.

**Parameters:**

```typescript
type ManagementApiClientConfig = {
  // Required
  clientId: string; // OAuth client ID
  redirectUri: string; // OAuth redirect URI
  tokenStorage: TokenStorage;

  // Optional (with defaults)
  apiBaseUrl?: string; // Default: 'https://api.prisma.io'
  authBaseUrl?: string; // Default: 'https://auth.prisma.io'
};
```

**Returns:** An object with:

* `client` - The typed API client for making requests
* `getLoginUrl(options)` - Generate OAuth login URL with specified scope
* `handleCallback(options)` - Handle OAuth callback and store tokens via `tokenStorage`
* `logout()` - Clear stored tokens

## Error handling [#error-handling]

The SDK exports two error classes:

### `AuthError` [#autherror]

Thrown for authentication-related errors:

* OAuth callback errors (includes `error_description` when available)
* Invalid or missing tokens
* Token refresh failures

```typescript
import { AuthError } from "@prisma/management-api-sdk";

try {
  await api.handleCallback({ callbackUrl, verifier, expectedState });
} catch (error) {
  if (error instanceof AuthError) {
    if (error.refreshTokenInvalid) {
      // Token is invalid/expired, user needs to log in again
      const { url } = await api.getLoginUrl({ scope: "workspace:admin offline_access" });
      // redirect to url...
    } else {
      // Other auth errors (e.g., "access_denied: User cancelled")
      console.error("Auth error:", error.message);
    }
  }
}
```

### `FetchError` [#fetcherror]

Thrown for network-related errors. Includes the original error as `cause` for debugging:

```typescript
import { FetchError } from "@prisma/management-api-sdk";

try {
  const { data } = await client.GET("/v1/workspaces");
} catch (error) {
  if (error instanceof FetchError) {
    console.error("Network error:", error.message);
    console.error("Cause:", error.cause); // Original error for debugging
  }
}
```

## TypeScript types [#typescript-types]

The SDK exports all API types generated from the OpenAPI spec:

```typescript
import type { paths, components } from "@prisma/management-api-sdk";

// Access response types
type Workspace = components["schemas"]["Workspace"];
type Project = components["schemas"]["Project"];
```

## Related pages

- [`Authentication`](https://www.prisma.io/docs/rest-api/authentication): Learn how to authenticate with the Prisma REST API using service tokens or OAuth 2.0
- [`Getting Started`](https://www.prisma.io/docs/rest-api/getting-started): Get started with the Prisma REST API by creating your first project and database
- [`Partner Integration`](https://www.prisma.io/docs/rest-api/partner-integration): Build partner integrations that provision and transfer Prisma Postgres databases to users
- [`Using API Clients`](https://www.prisma.io/docs/rest-api/api-clients): Use the REST API with popular API clients like Postman, Insomnia, and Yaak

# Getting Started (/docs/studio/getting-started)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to set up and use Prisma Studio to manage your database

Location: Studio > Getting Started

## Installation [#installation]

Prisma Studio comes bundled with the Prisma CLI. Make sure you have Node.js installed, then install the Prisma CLI:

  

#### bun

```bash
bun add --global prisma@prev
```

#### pnpm

```bash
pnpm add -g prisma@prev
```

#### yarn

```bash
yarn global add prisma@prev
```

#### npm

```bash
npm install -g prisma@prev
```

## Launching Studio [#launching-studio]

### With a Prisma Project [#with-a-prisma-project]

If you have an existing Prisma project, navigate to your project directory and run:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

This will start the Studio server and open it in your default browser at `http://localhost:5555`.

### Without a Prisma Project [#without-a-prisma-project]

You can also use Studio with any database by providing a connection string:

  

#### bun

```bash
bunx prisma studio --url="postgresql://user:password@localhost:5432/yourdb"
```

#### pnpm

```bash
pnpm prisma studio --url="postgresql://user:password@localhost:5432/yourdb"
```

#### yarn

```bash
yarn prisma studio --url="postgresql://user:password@localhost:5432/yourdb"
```

#### npm

```bash
npx prisma studio --url="postgresql://user:password@localhost:5432/yourdb"
```

This is also how you launch Studio for a [Prisma ORM](https://www.prisma.io/docs/orm) project, which has no `schema.prisma` to read. See [Studio with Prisma ORM](https://www.prisma.io/docs/studio/prisma-next).

## Connecting to your database [#connecting-to-your-database]

1. **Using environment variables**:
   Create a `.env` file in your project root with your database URL:

   ```
   DATABASE_URL="postgresql://user:password@localhost:5432/yourdb"
   ```

   Then run: `npx prisma studio`

2. **Using command line**:
   ```bash
   npx prisma studio --url="your-database-connection-string"
   ```

## Basic Usage [#basic-usage]

### Browsing Data [#browsing-data]

* The left sidebar lists all your database tables
* Click on a table to view its data
* Use the search bar to find tables or columns

### Editing Data [#editing-data]

* **Edit cells**: Double-click any cell to edit its value
* **Add records**: Click the "+" button to add a new record
* **Delete records**: Select records using checkboxes and click the trash icon

### Filtering and Sorting [#filtering-and-sorting]

* Click the filter icon to add filters
* Click on column headers to sort the table
* Use the search box to filter records by any field

## Common Tasks [#common-tasks]

### Viewing Table Relationships [#viewing-table-relationships]

* Related tables are shown as expandable rows
* Click the "+" icon to view related records

### Exporting Data [#exporting-data]

* Use the export button to download data as CSV or JSON
* Select specific columns to include in the export

## Next Steps [#next-steps]

* Use Studio with a [Prisma ORM project](https://www.prisma.io/docs/studio/prisma-next) to read your applied migration history in the Migrations view
* Learn how to [embed Studio in your application](https://www.prisma.io/docs/studio/integrations/embedding)
* Discover [VS Code integration](https://www.prisma.io/docs/studio/integrations/vscode-integration) features

## Related pages

- [`Studio with Prisma ORM`](https://www.prisma.io/docs/studio/prisma-next): Apply migrations to Prisma Postgres with Prisma ORM, then inspect the migration history, schema changes, executed SQL, and data in Prisma Studio.

# Prisma Studio (/docs/studio)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A visual database editor for viewing and managing your data with Prisma

Location: Prisma Studio

[Prisma Studio](https://www.prisma.io/studio) works with or without Prisma ORM and supports the following workflows:

* Viewing and editing data in a spreadsheet-like interface
* Real-time schema introspection
* Reading the applied migration history of a [Prisma ORM](https://www.prisma.io/docs/orm) database
* Embedding directly into your Next.js applications
* VS Code integration for in-editor database management

## Supported databases [#supported-databases]

* PostgreSQL
* MySQL
* SQLite

## Quick start [#quick-start]

  

#### bun

```bash
# With Prisma project
bunx prisma studio

# With direct database connection
bunx prisma studio --url="postgresql://user:password@localhost:5432/dbname"
```

#### pnpm

```bash
# With Prisma project
pnpm prisma studio

# With direct database connection
pnpm prisma studio --url="postgresql://user:password@localhost:5432/dbname"
```

#### yarn

```bash
# With Prisma project
yarn prisma studio

# With direct database connection
yarn prisma studio --url="postgresql://user:password@localhost:5432/dbname"
```

#### npm

```bash
# With Prisma project
npx prisma studio

# With direct database connection
npx prisma studio --url="postgresql://user:password@localhost:5432/dbname"
```

## Getting started [#getting-started]

* [Getting Started](https://www.prisma.io/docs/studio/getting-started) - Learn how to set up and use Prisma Studio to manage your database
* [Studio with Prisma ORM](https://www.prisma.io/docs/studio/prisma-next) - Apply migrations to Prisma Postgres and read your migration history in the Migrations view
* [Embed Studio](https://www.prisma.io/docs/studio/integrations/embedding) - Learn how to embed Prisma Studio in your own applications
* [Studio in VS Code](https://www.prisma.io/docs/studio/integrations/vscode-integration) - Learn how to use Prisma Studio directly in VS Code

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Introduction to Prisma ORM`](https://www.prisma.io/docs/prisma-orm): Prisma ORM 8 is the current release.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.

# Studio with Prisma ORM (/docs/studio/prisma-next)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Apply migrations to Prisma Postgres with Prisma ORM, then inspect the migration history, schema changes, executed SQL, and data in Prisma Studio.

Location: Studio > Studio with Prisma ORM

Prisma Studio shows the migration history of your [Prisma ORM](https://www.prisma.io/docs/orm) database as a visual timeline. Select any applied migration to see the models it changed, the SQL it executed, and a diff of the schema before and after.

This guide takes you from an empty directory to inspecting your own migration history. For browsing, editing, and filtering data in general, see [Getting Started](https://www.prisma.io/docs/studio/getting-started).

The Migrations view requires `@prisma/studio-core` 0.32.0 or later, which ships in the stable Prisma CLI since 7.9. Run Studio with `npx prisma@prev studio`. See the [Prisma ORM docs](https://www.prisma.io/docs/orm).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) installed
* A Prisma ORM project on PostgreSQL

Create the project, and answer No to `Deploy to Prisma now?`:

  

#### bun

```bash
bun create prisma@latest
```

#### pnpm

```bash
pnpm create prisma@latest
```

#### yarn

```bash
yarn create prisma@latest
```

#### npm

```bash
npm create prisma@latest
```

To skip the prompts:

  

#### bun

```bash
bun create prisma@latest my-app --yes --provider postgres --authoring psl --template minimal
```

#### pnpm

```bash
pnpm create prisma@latest my-app --yes --provider postgres --authoring psl --template minimal
```

#### yarn

```bash
yarn create prisma@latest my-app --yes --provider postgres --authoring psl --template minimal
```

#### npm

```bash
npm create prisma@latest -- my-app --yes --provider postgres --authoring psl --template minimal
```

This scaffolds a [data model](https://www.prisma.io/docs/orm/data-modeling) at `src/prisma/contract.prisma`, authored in [PSL](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax).

Next, create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database and export its connection string. The generated scripts and the CLI read the environment variable, not `.env`:

  

#### bun

```bash
bunx create-db@latest
```

#### pnpm

```bash
pnpm dlx create-db@latest
```

#### yarn

```bash
yarn dlx create-db@latest
```

#### npm

```bash
npx create-db@latest
```

```bash
export DATABASE_URL="<the connection string create-db printed>"
```

The database expires after 24 hours unless you claim it; `create-db` prints a claim URL to keep it and attach it to your Prisma Console account.

## Apply the first migration [#apply-the-first-migration]

The scaffolded [contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) defines a `User` and a `Post` model. Compile it, [plan a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration), and [apply it](https://www.prisma.io/docs/orm/migrations/applying-a-migration):

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name init_users_posts
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name init_users_posts
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name init_users_posts
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name init_users_posts
npx prisma db migrate --advance-ref db
```

The CLI confirms the apply:

```text
Applied 6 operation(s) across 1 contract space
```

`--advance-ref db` records where your database is by advancing a [ref](https://www.prisma.io/docs/orm/migrations/the-migration-graph#name-important-states-with-refs), so the next plan produces a delta instead of recreating everything.

## Update the data model [#update-the-data-model]

Add an enum and two fields to `src/prisma/contract.prisma`:

```prisma title="src/prisma/contract.prisma"
enum Role {
  USER
  EDITOR
  ADMIN
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  username  String?
  name      String?
  bio       String?
  role      Role     @default(USER)
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt temporal.updatedAt()
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt DateTime @default(now())
  updatedAt temporal.updatedAt()
}
```

## Create and apply another migration [#create-and-apply-another-migration]

Compile the updated contract, plan, and apply:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_roles_and_publishing
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_roles_and_publishing
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_roles_and_publishing
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_roles_and_publishing
npx prisma db migrate --advance-ref db
```

Because the `db` ref was advanced in the previous step, the planner produces a delta: four `ALTER TABLE` operations that add the new columns and the enum's check constraint. To edit a planned migration before it runs, for example to add a backfill, see [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration).

> [!WARNING]
> Plans start from empty without a starting point
> 
> Without a `db` ref and without `--from`, `migration plan` compares against an empty database and recreates every table. If that happens, delete the planned migration directory and re-plan with `--from <previous-migration-dir>`, for example `--from 20260716T1155_init_users_posts`. See [The db ref](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-db-ref-skipping---from).

## Seed the database [#seed-the-database]

Migration history is easier to read next to real rows. The scaffold seeds sample users automatically the first time the app queries the database, so run the app once and hit its endpoint:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open the URL the command prints; the seeded users come back through the Prisma ORM client. Then stop the dev server. See [Writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data) for the query API.

## Open Prisma Studio [#open-prisma-studio]

A Prisma ORM 8 project has no `schema.prisma`, so pass the [connection string](https://www.prisma.io/docs/postgres/database/connecting-to-your-database) with `--url`. Run Studio from a directory outside the project: the Prisma ORM 7 CLI that ships Studio cannot read the Prisma ORM 8 `prisma.config.ts` and fails if it finds one:

```bash
cd .. && npx prisma@prev studio --url "$DATABASE_URL"
```

Studio prints the local URL it serves on. Once the database has at least one applied migration, a **Migrations** item appears in the left navigation.

> [!NOTE]
> History lives in your database
> 
> Studio reads migration history from the connected database, not from your local `migrations/` directory. Migrations applied from CI or another machine appear automatically.

## Inspect migration history [#inspect-migration-history]

Open **Migrations**. The timeline lists every applied migration, newest first, with its name, apply time, operation count, and chips summarizing the change: `+1 model`, `~2 models`, `+3 fields`, `+1 enum`, `−1 field`. A ⚠️ marker flags migrations that contain a destructive change, so a dropped column is visible before you select anything. If a destructive migration needs undoing, see [Rollbacks and recovery](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery).

![The Prisma Studio Migrations view showing a timeline of six applied migrations and a visual diff canvas of the selected migration.](https://www.prisma.io/img/studio/prisma-next-migrations/studio-migrations-timeline.png)

The selected migration is part of the URL, so you can link a teammate straight to it:

```
http://localhost:5555/#view=migrations&migration=3
```

## Review schema changes [#review-schema-changes]

Select a migration to see the schema as that migration changed it:

* **NEW** (green): a model the migration added.
* **UPDATED** (amber): a model whose table changed, with `+`, `−`, and `~` glyphs on the affected fields and `before → after` pills for changed types, nullability, or defaults.
* **UNCHANGED** (dimmed): neighboring models drawn for context.
* Enum cards, and [relation](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins) edges between visible models.

Amber always means the migration changed that model's table. A model that only gained a back-relation, where the foreign key lives on the other table, stays dimmed, and the new relation edge is emphasized instead.

![The diff canvas for a migration that added a Category model and a relation, showing Category as NEW, Post as UPDATED, and User dimmed as UNCHANGED.](https://www.prisma.io/img/studio/prisma-next-migrations/studio-migrations-add-model-relation.png)

By default the view shows only the models the migration touched plus their direct neighbors. Toggle **All models** to see the entire schema as it stood at that point in history, including unchanged enums.

![The Migrations view with the All models toggle enabled, showing every model and enum in the schema at that migration.](https://www.prisma.io/img/studio/prisma-next-migrations/studio-migrations-all-models.png)

## Review executed SQL [#review-executed-sql]

Open the **SQL** panel to see the operations exactly as they ran, each labelled `additive` or `destructive`. This is the same SQL the migration runner executed; [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work) explains how those operations are planned and checked.

![The SQL panel showing the ALTER TABLE statements and check constraint executed by a migration, each labelled with its operation class.](https://www.prisma.io/img/studio/prisma-next-migrations/studio-migrations-sql-panel.png)

## Compare schema versions [#compare-schema-versions]

Open the **Schema** panel to see a Prisma-schema diff between the migration's before and after state. Long unchanged runs collapse into folds you can click to expand.

![The Schema panel showing a color-coded diff of the Prisma schema before and after a migration, with collapsed unchanged sections.](https://www.prisma.io/img/studio/prisma-next-migrations/studio-migrations-schema-diff.png)

The diff is built for stable comparison and is not a copy of your source file. It uses a fixed field order and renders some attributes in expanded form, such as `@default(dbgenerated("autoincrement()"))`.

## Browse the resulting data [#browse-the-resulting-data]

Your tables are in the same Studio session under **Tables**. Move between what a migration changed and the rows it produced without leaving the app. [Getting Started](https://www.prisma.io/docs/studio/getting-started) covers editing, filtering, and exporting.

![The Prisma Studio table view showing rows in the post table, including the published column added by a migration.](https://www.prisma.io/img/studio/prisma-next-migrations/studio-post-table-data.png)

## How migration history works [#how-migration-history-works]

Prisma ORM records every apply in two tables in your database:

* `prisma_contract.ledger`: one row per applied migration, with its name, apply time, executed operations, and the schema versions it moved between.
* `prisma_contract.contract`: each schema version, stored once and keyed by hash.

Studio joins the two to build the timeline and the diffs. Because everything is read from the database, the history of any database you connect to is complete, including migrations you never ran yourself. These table names are also where to look if you inspect the history over SQL.

The hashes are the same ones that make Prisma ORM migrations [a graph rather than a numbered list](https://www.prisma.io/docs/orm/migrations/the-migration-graph); the design story is in [Rethinking Database Migrations](https://www.prisma.io/blog/rethinking-database-migrations).

## Availability [#availability]

| Surface                                                                                                                | Available                                                       |
| ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| Local Studio (`npx prisma@prev studio`)                                                                                | Yes, with `@prisma/studio-core` 0.32.0 or later                 |
| [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=studio) (embedded Studio) | Yes, for databases with an applied Prisma ORM migration history |
| Prisma ORM projects using `prisma migrate`                                                                             | No                                                              |

In Prisma Console, open your database's Studio tab and select **Migrations**. The view is the same as local Studio, the selected migration is part of the Console URL, and no local setup is required.

The stable Prisma CLI bundles the Migrations view since 7.9 (`@prisma/studio-core` 0.33.0). Run `npx prisma@prev studio` from a directory outside your Prisma ORM 8 project; the Prisma ORM 7 CLI cannot read the Prisma ORM 8 `prisma.config.ts`.

## Limitations [#limitations]

* **Prisma ORM 8 on PostgreSQL only.** Prisma ORM 7 projects using `prisma migrate` record history in a different format, and [Studio does not support MongoDB](https://www.prisma.io/docs/studio), where Prisma ORM 8 [stores its history differently](https://www.prisma.io/docs/orm/migrations/the-migration-graph#database-specific-details).
* **Applied migrations only.** A planned but unapplied migration is not in the database, so it does not appear.
* **An empty history hides the view.** The **Migrations** item appears only after the first applied migration.
* **Older databases lose the diffs.** If the database was migrated by a Prisma ORM 8 version that predates schema snapshots, the timeline and SQL panel still work, and the diff canvas asks you to update Prisma ORM. Migrations applied after the update render normally.

## Related pages

- [`Getting Started`](https://www.prisma.io/docs/studio/getting-started): Learn how to set up and use Prisma Studio to manage your database

# Deploy your first app (/docs/prisma-compute/deploy)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Take a TypeScript app from your terminal to a live URL on Prisma Compute with Prisma Composer, starting from scratch or from an app you already have.

Location: Prisma Compute > Deploy your first app

[Prisma Compute](https://www.prisma.io/docs/compute) is serverless hosting for TypeScript apps. It runs your app right next to your Prisma Postgres database, so the trip from app to data stays short. Apps are declared and deployed with [Prisma Composer](https://www.prisma.io/docs/composer): you describe your app's services in TypeScript, and one command stands them up on Compute. By the end of this page you have a live URL.

Start from wherever you are:

* **You're starting from scratch.** [Declare a new app](#start-from-scratch) and run it locally, then deploy it.
* **You already have an app.** [Add a declaration around your server code](#bring-an-app-you-already-have), then deploy it.

Both paths meet in the same [deploy step](#2-deploy), because Composer treats every app the same way. A deployed app becomes a **project**, deploying with no flags targets **production**, and `--stage <name>` deploys an isolated copy of the whole app as a [preview branch](https://www.prisma.io/docs/compute/branching) of the same project. Local runs never talk to the platform, so you need credentials only when you deploy. For the platform's resource model, see [Compute](https://www.prisma.io/docs/compute#the-model).

## Prerequisites [#prerequisites]

Before you start, make sure you have:

* **Node.js 22.18 or newer.** Composer hands your TypeScript entry file straight to Node, and running `.ts` files directly needs 22.18.0 or later. On older versions, Composer commands stop at `ERR_UNKNOWN_FILE_EXTENSION`.
* **[Bun](https://bun.sh).** Prisma Compute runs deployed apps on Bun, so your server code targets it, and `bun build` produces the self-contained entry file a deploy needs.
* **A [Prisma Data Platform account](https://pris.ly/pdp)**, free to create. You only need it for the deploy step; [local development](https://www.prisma.io/docs/local-development) runs without an account.

## 1. Get an app declared with Composer [#1-get-an-app-declared-with-composer]

A Composer app is your server code plus a small declaration: what each service is called, how it is built, and what it depends on. Pick the path that matches your starting point.

### Start from scratch [#start-from-scratch]

Set up the project as in [Composer getting started, step 1](https://www.prisma.io/docs/composer/getting-started#1-set-up-the-project): install `@prisma/composer` and `@prisma/composer-prisma-cloud`, pin the `effect` family, and add the `tsconfig.json`. Then a minimal one-service app is four files.

The **server** is ordinary Bun code. The one Composer-specific line reads the port from `service.port()`; bind `0.0.0.0`, because Compute routes external HTTP to the VM and a loopback-only listener would be unreachable:

```ts title="src/server.ts"
import service from "./service.ts";

Bun.serve({
  port: service.port(),
  hostname: "0.0.0.0",
  fetch: () => new Response("Hello from Prisma Compute"),
});
```

The **service declaration** names the service and points at your built output:

```ts title="src/service.ts"
import node from "@prisma/composer/node";
import { compute } from "@prisma/composer-prisma-cloud";

export default compute({
  name: "web",
  deps: {},
  build: node({ module: import.meta.url, entry: "../dist/server.mjs" }),
});
```

The **root module** is the app: it provisions the service. The **deploy config** next to it is read only by the CLI:

```ts title="module.ts"
import { module } from "@prisma/composer";
import webService from "./src/service.ts";

export default module("my-app", ({ provision }) => {
  provision(webService);
});
```

```ts title="prisma-composer.config.ts"
import { defineConfig } from "@prisma/composer/config";
import { nodeBuild } from "@prisma/composer/node/control";
import { prismaCloud, prismaState } from "@prisma/composer-prisma-cloud/control";

export default defineConfig({
  extensions: [prismaCloud(), nodeBuild()],
  state: prismaState(),
});
```

You own the build; Composer assembles what you built. Add a build script that produces one self-contained file per service:

```json title="package.json"
{
  "scripts": {
    "build": "bun build src/server.ts --target=bun --outfile dist/server.mjs"
  }
}
```

Now run the app on your machine. No account or credentials are involved:

  

#### bun

```bash
bun run build
bunx prisma dev module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma dev module.ts
```

#### yarn

```bash
yarn build
yarn prisma dev module.ts
```

#### npm

```bash
npm run build
npx prisma dev module.ts
```

`dev` prints the service's local URL; `curl` it and you get `Hello from Prisma Compute`. See [Local development](https://www.prisma.io/docs/local-development) for the local database, storage, and log workflow.

From here the app grows by declaration: `deps: { db: postgres() }` gives the service a [Prisma Postgres database](https://www.prisma.io/docs/composer/databases), [`bucket()`](https://www.prisma.io/docs/composer/object-storage) gives it object storage, and a second service with a [typed contract](https://www.prisma.io/docs/composer/getting-started) turns cross-service calls into checked function calls. When the app runs locally, continue to [Deploy](#2-deploy).

### Bring an app you already have [#bring-an-app-you-already-have]

Porting an app does not mean rewriting it. Your server code stays the server, your build stays the build, and you add a declaration around them. The steps below port a two-service app, a notes API on Postgres and an uploads service on S3 credentials, to a Composer app that provisions its own database and bucket. For a Next.js service, use the `nextjs` build adapter with `output: "standalone"` instead; [Port an existing app](https://www.prisma.io/docs/composer/porting-an-app) covers that variant.

**1. Install the Composer packages.** Same as [step 1 of the scratch path](https://www.prisma.io/docs/composer/getting-started#1-set-up-the-project): install `@prisma/composer` and `@prisma/composer-prisma-cloud`, and pin `effect` to the version your installed `@prisma/composer` requires.

**2. Declare each service.** A `service.ts` next to each server names the service, declares what it consumes as dependencies, and points at your built output. A Postgres connection becomes `postgres()`; S3 credentials become `bucket()`:

```ts title="src/api/service.ts"
import node from "@prisma/composer/node";
import { compute, postgres } from "@prisma/composer-prisma-cloud";

export default compute({
  name: "api",
  deps: { db: postgres() },
  build: node({ module: import.meta.url, entry: "../../dist/api.mjs" }),
});
```

```ts title="src/files/service.ts"
import node from "@prisma/composer/node";
import { bucket, compute } from "@prisma/composer-prisma-cloud";

export default compute({
  name: "files",
  deps: { store: bucket() },
  build: node({ module: import.meta.url, entry: "../../dist/files.mjs" }),
});
```

**3. Provision everything in one module.** The root module owns the resources and wires them to the services; the deploy config next to it is the same one the scratch path uses:

```ts title="module.ts"
import { module } from "@prisma/composer";
import { bucket, postgres } from "@prisma/composer-prisma-cloud";
import apiService from "./src/api/service.ts";
import filesService from "./src/files/service.ts";

export default module("my-app", ({ provision }) => {
  const db = provision(postgres({ name: "database" }));
  const store = provision(bucket({ name: "uploads" }));
  provision(apiService, { deps: { db } });
  provision(filesService, { deps: { store } });
});
```

**4. Port the environment reads.** This is the only change to your server code, and it is what makes every environment work without hand-wired configuration:

1. **The port**: read `service.port()` instead of `process.env.PORT`, and bind `0.0.0.0`.
2. **Dependency values**: read `service.load()` instead of connection-string and credential env vars. The Postgres dependency delivers `db.url` for whatever client you already use; the bucket delivers the standard S3 set.
3. **Everything else** (flags, regions, external URLs, third-party credentials) becomes the service's [input schema](https://www.prisma.io/docs/composer/service-input).

```ts title="src/api/server.ts (the changed lines)"
import { SQL } from "bun";
import service from "./service.ts";

// before: new SQL({ url: process.env.DATABASE_URL })
const { db } = service.load();
const sql = new SQL({ url: db.url, max: 1, idleTimeout: 10 });

Bun.serve({ port: service.port(), hostname: "0.0.0.0", fetch: handler });
```

```ts title="src/files/server.ts (the changed lines)"
import service from "./service.ts";

// before: endpoint, bucket, and keys from four S3_* env vars
const { store } = service.load();
const s3 = new Bun.S3Client({
  endpoint: store.url,
  bucket: store.bucket,
  accessKeyId: store.accessKeyId,
  secretAccessKey: store.secretAccessKey,
});
```

**5. Build and verify locally.** Your build must produce one self-contained entry file per service; keep your own build if it already does, or use one `bun build --target=bun` line per service. Then run the whole declaration locally:

  

#### bun

```bash
bun run build
bunx prisma dev module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma dev module.ts
```

#### yarn

```bash
yarn build
yarn prisma dev module.ts
```

#### npm

```bash
npm run build
npx prisma dev module.ts
```

`dev` provisions a local Postgres and a local stand-in bucket with working credentials, and every service appears in the startup output with a local URL, so you can exercise the database and upload paths end-to-end before touching the platform. Then continue to [Deploy](#2-deploy): the same deploy command provisions the real database and bucket alongside the services.

## 2. Deploy [#2-deploy]

Sign in once. This is the only interactive step, because it opens your browser:

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

The session is stored on your machine and every later command reads it, including commands a coding agent runs in your directory. Confirm it any time with `auth whoami`. In CI or a headless environment, set `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` instead; see [Deploying](https://www.prisma.io/docs/composer/deploying#credentials).

`deploy` does not build for you, so build first, then deploy:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

The CLI creates a project named after your root module, provisions the services on Compute and any databases on Prisma Postgres, wires the dependencies, and starts everything. The project name identifies the app in your workspace: redeploying reuses the project this module created, and a same-name project whose hosted state the CLI cannot verify stops the command with `HostedStateBootstrapError`. Deploy under another name with `--name <unique-name>` when that happens.

## 3. Verify the deployment [#3-verify-the-deployment]

A deploy finishes by printing what it made: each service, the platform resource it became, and its public URL:

```text no-copy
my-app
└─ web   compute-service cps_abc123
         https://xyz.ewr.prisma.build
```

Request the printed URL to confirm the app responds:

```bash
curl https://xyz.ewr.prisma.build
```

You can also inspect everything in the [Console](https://pris.ly/pdp): projects, branches, services, deployments, and domains.

## 4. Ship changes and environments [#4-ship-changes-and-environments]

Re-deploying is idempotent: build again, deploy again, and the platform applies the difference instead of recreating everything. That includes removals: delete a provision from your module and the next deploy deletes the resource; see [Removing resources](https://www.prisma.io/docs/composer/deploying#removing-resources). Production and previews are separated by stages:

  

#### bun

```bash
bunx prisma deploy module.ts                  # production
bunx prisma deploy module.ts --stage staging  # a persistent staging environment
bunx prisma deploy module.ts --stage pr-42    # one environment per PR
```

#### pnpm

```bash
pnpm prisma deploy module.ts                  # production
pnpm prisma deploy module.ts --stage staging  # a persistent staging environment
pnpm prisma deploy module.ts --stage pr-42    # one environment per PR
```

#### yarn

```bash
yarn prisma deploy module.ts                  # production
yarn prisma deploy module.ts --stage staging  # a persistent staging environment
yarn prisma deploy module.ts --stage pr-42    # one environment per PR
```

#### npm

```bash
npx prisma deploy module.ts                  # production
npx prisma deploy module.ts --stage staging  # a persistent staging environment
npx prisma deploy module.ts --stage pr-42    # one environment per PR
```

A stage is a complete, isolated copy of the app: its own services, databases, and configuration, sharing only the code with production. In platform terms it is a [preview branch](https://www.prisma.io/docs/compute/branching) of the same project. Tearing a stage down needs the control API with service-token credentials, or a branch deletion in the Console; see [Destroying](https://www.prisma.io/docs/composer/deploying#destroying). [Deploying](https://www.prisma.io/docs/composer/deploying) covers CI, deploy state, and teardown in full.

## Hand it to your agent [#hand-it-to-your-agent]

You can let a coding agent do the work. Sign in once yourself ([step 2](#2-deploy)). The browser sign-in is the one step an agent can't do for you. After that, anything running in your environment inherits the session, including your agent. The `@prisma/composer` package ships an [agent skill](https://www.prisma.io/docs/cli/skills) that teaches your agent the installed version's API; [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) sets the project up so the skill stays in sync across upgrades. Paste this into your agent and fill in the blanks:

```text
Build [what you want] as a Prisma Composer app and deploy it to Prisma Compute using `npx prisma@latest`.

Notes:
- After installing @prisma/composer, install its agent skill so you use the real API: `npx prisma skills sync` (the skill ships inside the package; run `npx prisma skills list` to confirm).
- Before deploying, run `npx prisma auth whoami`; if I am not signed in, stop and ask me to run `npx prisma auth login` (it opens a browser).
- Composer needs Node.js 22.18 or newer, and server code targets Bun. Read the port with `service.port()` and bind 0.0.0.0. For a Next.js service, use the nextjs build adapter and set `output: "standalone"`.
- Composer does not build; produce one self-contained entry file per service (for example `bun build --target=bun`), then run it locally with `npx prisma dev module.ts` and verify each service's local URL responds.
- Deploy with `npx prisma deploy module.ts` and verify the printed public URL with curl.
- To give a service a database, declare `deps: { db: postgres() }` and build the client from the injected `db.url`; do not read connection strings from process.env.
- Current docs: https://www.prisma.io/docs/composer.md and https://www.prisma.io/docs/prisma-compute/deploy.md
```

For example:

```text
Build a Bun API with a /todos endpoint backed by an in-memory list as a Prisma Composer app and deploy it to Prisma Compute using `npx prisma@latest`.
```

## What's next [#whats-next]

* [Composer getting started](https://www.prisma.io/docs/composer/getting-started): the two-service version, with a typed contract between services.
* [Databases](https://www.prisma.io/docs/composer/databases): give a service a Prisma Postgres database, plain or typed by a Prisma ORM contract.
* [Deploying](https://www.prisma.io/docs/composer/deploying): stages, CI, deploy state, and teardown.
* [Local development](https://www.prisma.io/docs/local-development): run the app, database, and storage on your machine with the runtime you deploy.

# create-prisma (/docs/prisma-orm/create-prisma)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Scaffold a new Prisma ORM app with create-prisma, with Prisma Composer, Prisma Postgres, and a deploy path built in.

Location: Prisma ORM > create-prisma

`create-prisma` creates a new Prisma ORM project from an app template. It installs Prisma ORM, emits the contract, and generates a deployable [Prisma Composer](https://www.prisma.io/docs/composer) app. PostgreSQL projects use Composer's native Prisma Postgres provider, including migrations and a typed runtime client.

Use it when you want to start from a working app. If you already have an app, follow [Add Prisma ORM to an existing PostgreSQL project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql) or [Add Prisma ORM to an existing MongoDB project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/mongodb) instead.

> [!NOTE]
> Prisma ORM 7
> 
> `create-prisma@latest` scaffolds Prisma ORM 8. To scaffold a Prisma ORM 7 app, run `npm create prisma@stable` and follow the [Prisma ORM 7 setup paths](https://www.prisma.io/docs/v7/getting-started).

## Create a project [#create-a-project]

Run the CLI with your package manager and answer the prompts:

  

#### bun

```bash
bun create prisma@latest my-app
```

#### pnpm

```bash
pnpm create prisma@latest my-app
```

#### yarn

```bash
yarn create prisma@latest my-app
```

#### npm

```bash
npm create prisma@latest -- my-app
```

The prompts cover the project name, the app template, the database provider, the contract authoring style, the package manager, whether to install agent skill files for coding assistants, and whether to deploy right away. Skill files go into `.claude/`, `.cursor/`, `.agents/`, and `.devin/` by default; answer no, or pass `--skills none`, to skip them. To remove them later, set `skills: { agents: [] }` in `prisma.config.ts` and run `prisma skills sync`; see [Configuration](https://www.prisma.io/docs/cli/configuration). Generated Node.js projects expect Node.js 22.18 or newer (on the 24 line, 24.11 or newer); Node.js 24 is recommended.

The last prompt is:

```text
Deploy to Prisma now?
```

The prompt defaults to Yes. `--yes` accepts the defaults for the other prompts but answers No here, so `--yes` on its own never deploys; `--json` deploys unless you pass `--no-deploy`. Choose no to deploy later with the generated `deploy` script. When more than one Prisma workspace session is available, the CLI asks which workspace receives the deployment; pass `--workspace <id-or-name>` to pick one without a prompt, or omit it to use the active workspace. Choosing another workspace also updates the Prisma CLI's active workspace session.

## Skip the prompts [#skip-the-prompts]

Pass flags when you already know the project shape. `--yes` accepts the defaults for anything you leave out:

  

#### bun

```bash
bun create prisma@latest my-app --template next --provider postgres --yes
```

#### pnpm

```bash
pnpm create prisma@latest my-app --template next --provider postgres --yes
```

#### yarn

```bash
yarn create prisma@latest my-app --template next --provider postgres --yes
```

#### npm

```bash
npm create prisma@latest -- my-app --template next --provider postgres --yes
```

`create` is the default subcommand, so `npm create prisma@latest -- create my-app ...` and `npm create prisma@latest -- my-app ...` are the same command. Everything after `--` goes to `create-prisma`; without the separator npm keeps the flags for itself.

| Flag                                              | What it does                                                                                                                                                                                                        |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<name>` or `--name <name>`                       | The project name and directory.                                                                                                                                                                                     |
| `--template <name>`                               | Chooses the app template (see below).                                                                                                                                                                               |
| `--provider postgres\|postgresql\|mongo\|mongodb` | Chooses the database: PostgreSQL relational models or MongoDB document models.                                                                                                                                      |
| `--authoring psl\|typescript`                     | Chooses the [contract authoring](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) style.                                                                                                                                  |
| `--package-manager npm\|pnpm\|yarn\|bun\|deno`    | Chooses the package manager used to install dependencies.                                                                                                                                                           |
| `--skills <agents>\|none`                         | Which coding agents get skill files, or `none` to opt out. Same values and effect as [`prisma init --skills`](https://www.prisma.io/docs/cli/init); the choice is recorded in the [`skills` config section](https://www.prisma.io/docs/cli/configuration#agent-skills). |
| `--deploy` / `--no-deploy`                        | Deploys the generated app to Prisma immediately, or skips that step.                                                                                                                                                |
| `--workspace <id-or-name>`                        | The Prisma workspace to deploy into.                                                                                                                                                                                |
| `--yes`                                           | Skips prompts and accepts the default choices, which means no deploy.                                                                                                                                               |
| `--force`                                         | Scaffolds into a non-empty directory, overwriting the generated starter and Prisma files (config, contract, and `db.ts`). It refuses when the target has a non-empty `migrations/` directory.                       |
| `--verbose`                                       | Shows the full command output during setup. Not compatible with `--json`.                                                                                                                                           |
| `--json`                                          | Runs non-interactively and writes one JSON result object to stdout, for agents and automation. Deploys unless you pass `--no-deploy`.                                                                               |

## Templates [#templates]

| `--template`     | App                             |
| ---------------- | ------------------------------- |
| `minimal`        | A minimal server with one query |
| `next`           | Next.js                         |
| `hono`           | Hono                            |
| `elysia`         | Elysia                          |
| `nest`           | NestJS                          |
| `svelte`         | SvelteKit                       |
| `astro`          | Astro                           |
| `nuxt`           | Nuxt                            |
| `tanstack-start` | TanStack Start                  |

Every template supports PostgreSQL and MongoDB, PSL or TypeScript contract authoring, and npm, pnpm, Yarn, and Bun. Each [framework guide](https://www.prisma.io/docs/guides) walks the generated app from the first query to a deploy.

Deno is supported for local minimal PostgreSQL apps:

```bash
deno run -A --minimum-dependency-age=0 npm:create-prisma@latest my-deno-app --template minimal --provider postgres --package-manager deno --no-deploy
```

Deno 2.9 skips packages published in the previous 24 hours by default, so without `--minimum-dependency-age=0` a newly published `create-prisma` release resolves to an older cached version. Prisma Compute does not support Deno deployments yet, so Deno projects stop at a verified local run.

## Start the app [#start-the-app]

Set the connection string in your environment, then initialize the database and start the dev server. The generated `prisma.config.ts` reads `DATABASE_URL` for PostgreSQL and `MONGODB_URL` for MongoDB from the process environment and loads no dotenv file (Deno projects are the exception: their scripts pass `--env-file=.env`), so export the variable in the shell before running the scripts.

```bash
cd my-app
npm run db:init
npm run dev
```

Sample records are seeded on the app's first query. From there, evolve the contract under `src/prisma/`, run `npm run contract:emit`, and plan and apply the migration with `npx prisma migration plan` and `npx prisma db migrate`. The [quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql) covers that loop in detail, and the [MongoDB quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/mongodb) covers the MongoDB connection string.

### Generated scripts [#generated-scripts]

The scaffold adds these scripts to `package.json`:

| Script             | Runs                                                                           |
| ------------------ | ------------------------------------------------------------------------------ |
| `contract:emit`    | `prisma contract emit`                                                         |
| `db:init`          | `prisma db init`                                                               |
| `db:update`        | `prisma db update`                                                             |
| `db:verify`        | `prisma db verify`                                                             |
| `migration:plan`   | `prisma migration plan`                                                        |
| `migrate`          | `prisma db migrate`                                                            |
| `migration:status` | `prisma migration status`                                                      |
| `migration:show`   | `prisma migration show`                                                        |
| `skills:sync`      | `prisma skills sync \|\| exit 0`                                               |
| `postinstall`      | `prisma skills sync \|\| exit 0`, added by the `prisma init` the scaffold runs |
| `composer:dev`     | `prisma dev module.ts`                                                         |
| `composer:deploy`  | `prisma deploy module.ts`                                                      |
| `dev:composer`     | the build script, then `composer:dev`                                          |
| `deploy`           | the build script, then `composer:deploy`                                       |

Deno projects get the Prisma scripts only, each wrapped in `deno run -A npm:...`, without `skills:sync`, without `postinstall`, and without the Composer scripts. `--skills none` also leaves out `skills:sync` and `postinstall`.

## Telemetry [#telemetry]

Published builds may send anonymous usage telemetry. It never includes project names, file paths, or database URLs. Disable it by setting `DO_NOT_TRACK`, `CREATE_PRISMA_DISABLE_TELEMETRY`, or `CREATE_PRISMA_TELEMETRY_DISABLED` in your environment.

The CLI is open source at [prisma/create-prisma](https://github.com/prisma/create-prisma).

## Related pages

- [`From scratch`](https://www.prisma.io/docs/prisma-orm/from-scratch): Set up Prisma ORM with PostgreSQL by hand, with one config file, one contract, and one index.ts.

# From scratch (/docs/prisma-orm/from-scratch)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up Prisma ORM with PostgreSQL by hand, with one config file, one contract, and one index.ts.

Location: Prisma ORM > From scratch

By the end of this page you have a project with a `prisma.config.ts`, a `prisma/contract.prisma` holding one `User` model, and a single `index.ts` that writes, updates, and reads rows in PostgreSQL through Prisma ORM 8, plus a migration you planned and applied. No template generates anything: you create every file yourself and see what each one is for.

Use this path when you want to see every file Prisma ORM needs, or when you are adding Prisma ORM to a repository that already has its own layout. If you would rather have the files written for you, run `npm create prisma@latest` and follow the [PostgreSQL quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql).

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release, as a release candidate. Prisma ORM 7 remains fully supported; its docs live at [/orm/v7](https://www.prisma.io/docs/orm/v7) and its setup paths at [/v7/getting-started](https://www.prisma.io/docs/v7/getting-started).
> 
> For what release candidate means, when the final release is expected, and how to stay on version 7, see [Release status](https://www.prisma.io/docs/orm/release-status). For the Prisma ORM 8 name of every Prisma ORM 7 API, see [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7).

Two commands have new names in Prisma ORM 8. `contract emit` does what `prisma generate` did, and `migration plan` followed by `db migrate` does what `migrate dev` did. There is no `@prisma/client` package and no `db push`.

## Prerequisites [#prerequisites]

* Node.js 22.18 or newer (on the 24 line, 24.11 or newer); Node.js 24 is recommended.
* A connection string for an empty PostgreSQL database. Step 4 creates the tables and step 5 clears the `User` table on every run, so do not point this page at a database that holds data you need. Any PostgreSQL URL works. If you don't have one, `npx create-db@latest` creates a temporary Prisma Postgres database and prints its connection string, plus a claim URL if you want to keep it.

## 1. Create the project [#1-create-the-project]

Create an empty directory with a `package.json`, and switch it to ES modules, because the Prisma ORM packages and the `index.ts` below use `import` syntax. `npm init -y` writes `"type": "commonjs"`, and the second npm command changes it:

```bash
mkdir hello-prisma
cd hello-prisma
npm init -y
npm pkg set type=module
```

Install the runtime library, the command-line tool, and the tooling to run a TypeScript file:

  

#### bun

```bash
bun add @prisma/orm-postgres dotenv
bun add --dev prisma tsx typescript
```

#### pnpm

```bash
pnpm add @prisma/orm-postgres dotenv
pnpm add --save-dev prisma tsx typescript
```

#### yarn

```bash
yarn add @prisma/orm-postgres dotenv
yarn add --dev prisma tsx typescript
```

#### npm

```bash
npm install @prisma/orm-postgres dotenv
npm install --save-dev prisma tsx typescript
```

`@prisma/orm-postgres` is the library your code imports, and `prisma` is the command-line tool. `dotenv` loads `.env`, `tsx` runs `index.ts` without a build step, and `typescript` 5.9 or newer is a peer dependency of `@prisma/orm-postgres`. The two Prisma packages have different version numbers (for example, `prisma` 8.0.0-rc.17 and `@prisma/orm-postgres` 8.0.0-rc.13); that is normal, and any two `latest` versions work together.

## 2. Create the config file and `.env` [#2-create-the-config-file-and-env]

The command-line tool reads `prisma.config.ts` from the project root to find your contract and your database:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./prisma/contract.prisma",
    db: {
      connection: process.env["DATABASE_URL"]!,
    },
  }),
  skills: {
    check: false,
  },
});
```

`contract` is the path to the model file you write in the next step, and `db.connection` is the connection string the database commands use. The `skills` block turns off the notice that every command otherwise prints about installing agent skill files; remove it if you want those files. Every setting is documented on [Configuration](https://www.prisma.io/docs/cli/configuration).

Put the connection string in `.env`, which the first line of the config file loads:

```bash title=".env"
DATABASE_URL="postgresql://username:password@host:5432/database?sslmode=require"
```

Add `.env` to `.gitignore` so the credentials stay out of version control.

## 3. Create the contract [#3-create-the-contract]

The contract is Prisma ORM 8's name for the schema file. It replaces `schema.prisma`, and it has no `datasource` or `generator` blocks because the connection string lives in `prisma.config.ts`. Declare one model:

```prisma title="prisma/contract.prisma"
// use prisma-8
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
}
```

[Data modeling](https://www.prisma.io/docs/orm/data-modeling) covers field types, primary keys, and relations.

## 4. Generate the contract and create the table [#4-generate-the-contract-and-create-the-table]

`contract emit` reads `contract.prisma` and writes `prisma/contract.json` (read at run time) and `prisma/contract.d.ts` (read by TypeScript) next to it. This is the step that was `prisma generate`; run it again after every change to the contract.

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

```text
✔ Resolving contract source...
✔ Emitting contract...
│  contract:  prisma/contract.json
│  types:     prisma/contract.d.ts
✔ Emitted contract.json and contract.d.ts
```

`db init` creates the tables the contract declares in your database, then signs the database, which records which version of the contract it matches so later migrations know where to start from:

  

#### bun

```bash
bunx prisma db init
```

#### pnpm

```bash
pnpm prisma db init
```

#### yarn

```bash
yarn prisma db init
```

#### npm

```bash
npx prisma db init
```

```text
✔ Introspecting database schema
✔ Planning migration
✔ Initialising database across spaces
│  contract:  prisma/contract.json
│  database:  postgres://****:****@db.prisma.io:5432/postgres?sslmode=require
✔ Applied 2 operation(s) across 1 contract space
App space
├─ Create table "User"
├─ Add unique constraint on "User" (email)
└─ marker b5ae4e66fad1f0b7dd5590568f75a12a6f4576e9f367a787a69a4e729abac1fb
✔ Advanced ref "db" → b5ae4e66fad1f0b7dd5590568f75a12a6f4576e9f367a787a69a4e729abac1fb
```

The `marker` line in the output is the record that signing stores in the database: the hash that identifies the version of the contract the database now matches. `db init` also writes `migrations/app/refs/db.json`, called the `db` ref: a file that records which contract version your development database is at, so that `migration plan` in step 6 knows where to start. The `Advanced ref "db"` line in the output is `db init` writing it. Commit it, together with the snapshot of the contract that `db init` writes under `migrations/snapshots/`. If the command fails with `DRIVER.CONNECTION_FAILED`, `DATABASE_URL` in `.env` is wrong or the database is not reachable. A `SECURITY WARNING` about SSL modes comes from the `pg` driver and does not stop the command; change `sslmode=require` to `sslmode=verify-full` in `.env` to silence it.

## 5. Write and read data [#5-write-and-read-data]

Create `index.ts`, which builds the client from the two emitted files and then deletes, creates, updates, and reads rows on the `User` model:

```typescript title="index.ts"
import "dotenv/config";
import postgres from "@prisma/orm-postgres/runtime";
import type { Contract } from "./prisma/contract.d";
import contractJson from "./prisma/contract.json" with { type: "json" };

const db = postgres<Contract>({
  contractJson,
  url: process.env["DATABASE_URL"]!,
});

async function main() {
  // Start from an empty table so you can run this file more than once.
  await db.orm.public.User.where({}).deleteAll();

  // Write: insert one row.
  const alice = await db.orm.public.User.create({
    email: "alice@prisma.io",
    name: "Alice",
  });
  console.log("Created:", alice);

  // Update: change one row, picked by its primary key.
  const renamed = await db.orm.public.User
    .where({ id: alice.id })
    .update({ name: "Alice Smith" });
  console.log("Updated:", renamed);

  // Read: fetch every row.
  const users = await db.orm.public.User.all();
  console.log("All users:", users);

  await db.close();
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
```

`db.orm.public.User` is the model: `public` is the PostgreSQL schema, and every model in your contract appears under it. `.update()` and `.delete()` need a `.where()` first, and `.where({})` matches every row. [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data) and [Writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data) show the rest of the query API.

Run it:

  

#### bun

```bash
bunx tsx index.ts
```

#### pnpm

```bash
pnpm dlx tsx index.ts
```

#### yarn

```bash
yarn dlx tsx index.ts
```

#### npm

```bash
npx tsx index.ts
```

```text
Created: { email: 'alice@prisma.io', id: 1, name: 'Alice' }
Updated: { email: 'alice@prisma.io', id: 1, name: 'Alice Smith' }
All users: [ { email: 'alice@prisma.io', id: 1, name: 'Alice Smith' } ]
```

The `id` goes up by one each time you run the file, because the table is cleared but the sequence is not. If the run fails with `Cannot find module '.../prisma/contract.json'`, you skipped `contract emit` in step 4.

## 6. Change the schema and migrate [#6-change-the-schema-and-migrate]

Add an optional field to the model:

```prisma title="prisma/contract.prisma"
// use prisma-8
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  phone String?
}
```

Emit the contract again, then plan a migration. `migration plan` compares the emitted contract with the version the database was signed with and writes the difference as a migration directory, without connecting to the database:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_user_phone
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_user_phone
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_user_phone
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_user_phone
```

```text
✔ Planned baseline (3 operation(s)) + 1 operation(s)
migrations/app/20260917T1457_add_user_phone
└─ Add column "phone" to "User"
from:       b5ae4e66fad1f0b7dd5590568f75a12a6f4576e9f367a787a69a4e729abac1fb
to:         300832575ace8feebb3d3442d1bca52150c46628de3e4c6c32a61cb0ab21100f
baseline:   migrations/app/20260917T1456_baseline
app space:  migrations/app/20260917T1457_add_user_phone
ℹ DDL preview
ALTER TABLE "public"."User" ADD COLUMN "phone" text;
```

Two directories appear under `migrations/app/`: a baseline that records the table `db init` created, and your change. The baseline is never applied to this database, because the database is already signed at that state. Each migration directory holds a `migration.ts` you can read and edit; [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration) explains the files.

Apply the migration with `--advance-ref db`, which records that your development database is now at the new contract so the next `migration plan` starts from there:

  

#### bun

```bash
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma db migrate --advance-ref db
```

```text
✔ Applied 1 migration(s) (1 operation(s)) across 1 contract space(s)
App space
├─ Add column "phone" to "User"
└─ marker 300832575ace8feebb3d3442d1bca52150c46628de3e4c6c32a61cb0ab21100f
✔ Advanced ref "db" → 300832575ace8feebb3d3442d1bca52150c46628de3e4c6c32a61cb0ab21100f
```

If you do not want migration files for a throwaway database, [`db update`](https://www.prisma.io/docs/cli/db-update) applies the contract change directly instead of `migration plan` and `db migrate`.

Run `index.ts` again without changing it. The new column shows up in every row:

  

#### bun

```bash
bunx tsx index.ts
```

#### pnpm

```bash
pnpm dlx tsx index.ts
```

#### yarn

```bash
yarn dlx tsx index.ts
```

#### npm

```bash
npx tsx index.ts
```

```text
Created: { email: 'alice@prisma.io', id: 2, name: 'Alice', phone: null }
Updated: { email: 'alice@prisma.io', id: 2, name: 'Alice Smith', phone: null }
All users: [
  { email: 'alice@prisma.io', id: 2, name: 'Alice Smith', phone: null }
]
```

## Verify [#verify]

Check that the migration files on disk and the database agree:

  

#### bun

```bash
bunx prisma migration status
```

#### pnpm

```bash
pnpm prisma migration status
```

#### yarn

```bash
yarn prisma migration status
```

#### npm

```bash
npx prisma migration status
```

```text
○   3008325  @contract @db (db)
│↑  20260917T1457_add_user_phone  b5ae4e6 → 3008325  1 ops  ✓ applied
○   b5ae4e6
│↑  20260917T1456_baseline              ∅ → b5ae4e6  3 ops
○   ∅
✔ Up to date
```

From here, every schema change follows the same routine: edit `prisma/contract.prisma`, run `npx prisma contract emit`, run `npx prisma migration plan --name <name>`, and apply with `npx prisma db migrate --advance-ref db`.

## Next steps [#next-steps]

* [Data modeling](https://www.prisma.io/docs/orm/data-modeling) for relations, more field types, and indexes.
* [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration) for what is in a migration directory and how to edit one.
* [PostgreSQL quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql) if you want the same setup generated for you with a starter app.

## Related pages

- [`create-prisma`](https://www.prisma.io/docs/prisma-orm/create-prisma): Scaffold a new Prisma ORM app with create-prisma, with Prisma Composer, Prisma Postgres, and a deploy path built in.

# Introduction to Prisma ORM (/docs/prisma-orm)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma ORM 8 is the current release.

Location: Introduction to Prisma ORM

Prisma ORM 8 is a ground-up rebuild of Prisma ORM, from the runtime and query APIs to the migration flow and project setup.

> [!NOTE]
> Prisma ORM 7
> 
> Prisma ORM 8 is the current release, as a release candidate. Prisma ORM 7 remains fully supported; its docs live at [/orm/v7](https://www.prisma.io/docs/orm/v7) and its setup paths at [/v7/getting-started](https://www.prisma.io/docs/v7/getting-started).
> 
> For what release candidate means, when the final release is expected, and how to stay on version 7, see [Release status](https://www.prisma.io/docs/orm/release-status). For the Prisma ORM 8 name of every Prisma ORM 7 API, see [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7).

Prisma ORM 8 is the recommended starting point for new projects.

  

#### bun

```bash
bun create prisma@latest
```

#### pnpm

```bash
pnpm create prisma@latest
```

#### yarn

```bash
yarn create prisma@latest
```

#### npm

```bash
npm create prisma@latest
```

Start with the setup page when you want a guided first run, or read the [create-prisma reference](https://www.prisma.io/docs/prisma-orm/create-prisma) for every template and flag. To add Prisma ORM to a project by hand, without the template, follow [Set up Prisma ORM from scratch](https://www.prisma.io/docs/prisma-orm/from-scratch).

- [Deploy the full Prisma stack](https://www.prisma.io/docs/full-stack-tutorial): Scaffold, provision Prisma Postgres, query, and deploy to Prisma Compute in one sitting.

- [Choose a setup path](https://www.prisma.io/docs/getting-started): Pick a new-project quickstart or add Prisma ORM to an existing app.

## Use with your agent [#use-with-your-agent]

Copy this prompt, replace the placeholders, and hand it to your coding agent. Running [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) after the scaffold installs the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills) that ship inside the installed Prisma packages and keeps them current:

```text
Create a new [framework] application with Prisma ORM, seed it, and run it locally.

If I have not told you which framework, stop and ask before scaffolding. Valid --template values: minimal (the default), next, hono, nuxt, astro, nest, svelte, tanstack-start, elysia.

1. Scaffold the app: `npm create prisma@latest -- my-app --template [framework] --provider postgres --yes`. Then run `npx prisma@latest init` in the project directory so the Prisma agent skills are installed and stay current, and use them.
2. Get a database connection string: use the one I give you, or create a Prisma Postgres database in the project the app will deploy to: check `npx prisma auth whoami` (if I am not signed in, stop and ask me to run `npx prisma auth login`), then `npx prisma project create my-app` and `npx prisma postgres create mydb`, which prints the connection string once. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable.
3. From the project directory, apply the starter contract: `npm run db:init`. Sample users are seeded automatically on the app's first query; there is no separate seed script.
4. Edit the starter contract under `src/prisma/` into a small schema for my use case, then run `npm run contract:emit` and plan and apply the migration: `npx prisma migration plan`, then `npx prisma db migrate --yes`. Migration planning diffs the emitted contract, so the emit step is required.
5. Update the seed script under `src/prisma/` and the app routes to query the new schema, start `npm run dev` in the background (with `DATABASE_URL` exported), and verify with a request against the running app. For the `nest` template, if routes return 500s with `reading 'findAll'` in the logs, add explicit `@Inject()` tokens as shown in https://www.prisma.io/docs/guides/frameworks/nestjs.md.
6. Deploy with Prisma Compute. If the template is `svelte`, skip this step; Compute does not support SvelteKit yet. The scaffold declares the app for Prisma Composer in `module.ts` and `service.ts`, with the framework's build requirements (Next.js standalone output, Astro's node adapter, TanStack Start's Nitro build) already configured; the framework guide at https://www.prisma.io/docs/guides/frameworks/[guide].md has the details, where [guide] is the template name except: template `next` → guide `nextjs`, `nest` → `nestjs`. Check `npx prisma auth whoami`. If I am not signed in, stop and ask me to run `npx prisma auth login`, because that step opens a browser. Then run `npm run build` followed by `npx prisma deploy module.ts`, and verify the deployed URL with curl. The deployed app provisions and seeds its own Prisma Postgres database; do not pass the local DATABASE_URL. If the deploy fails with `HostedStateBootstrapError`, a project with the module's name exists in my workspace but its hosted state cannot be verified; re-run the deploy with `--name <a unique name>`.

Use the installed Prisma ORM skills and the current Prisma docs: https://www.prisma.io/docs/llms.txt (append `.md` to any docs URL for a markdown version).
```

## Add Prisma ORM to your framework [#add-prisma-orm-to-your-framework]

Each guide runs the same journey for a specific framework: scaffold, connect Prisma Postgres, query, and deploy where the framework is supported on Compute.

- [Next.js](https://www.prisma.io/docs/guides/frameworks/nextjs)

- [Hono](https://www.prisma.io/docs/guides/frameworks/hono)

- [TanStack Start](https://www.prisma.io/docs/guides/frameworks/tanstack-start)

- [NestJS](https://www.prisma.io/docs/guides/frameworks/nestjs)

- [Astro](https://www.prisma.io/docs/guides/frameworks/astro)

- [Nuxt](https://www.prisma.io/docs/guides/frameworks/nuxt)

- [SvelteKit](https://www.prisma.io/docs/guides/frameworks/sveltekit)

- [Bun](https://www.prisma.io/docs/guides/runtimes/bun)

- [Elysia](https://www.prisma.io/docs/guides/frameworks/elysia)

- [Deno](https://www.prisma.io/docs/guides/runtimes/deno)

## Learn the fundamentals [#learn-the-fundamentals]

Once you are connected, the Fundamentals section teaches the everyday query patterns.

- [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data): Filter with where, project with select, sort, and paginate.

- [Writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data): Create, update, delete, upsert, and the bulk write variants.

- [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins): Read related records with include on PostgreSQL and MongoDB.

- [Transactions](https://www.prisma.io/docs/orm/fundamentals/transactions): Make several writes succeed or fail together.

- [Advanced queries](https://www.prisma.io/docs/orm/fundamentals/advanced-queries): The SQL builder and the MongoDB pipeline builder for shapes the ORM can't express.

## Learn the concepts [#learn-the-concepts]

- [Prisma ORM overview](https://www.prisma.io/docs/orm): Learn the core ideas behind contracts, emitted artifacts, runtime clients, query styles, and migrations.

## Related pages

- [`Choose a Prisma ORM setup path`](https://www.prisma.io/docs/getting-started): Choose the fastest path to try Prisma ORM in a new or existing project.
- [`Console`](https://www.prisma.io/docs/console): Learn how to use the Console to manage and integrate Prisma products into your application.
- [`Deploy the full Prisma stack`](https://www.prisma.io/docs/full-stack-tutorial): A single tutorial from empty directory to live URL, with Prisma Composer, Prisma ORM, and Prisma Postgres.
- [`Local development`](https://www.prisma.io/docs/local-development): Run the whole Prisma stack on your machine, with your app on Bun, a local Prisma Postgres database, and local object storage.
- [`Overview`](https://www.prisma.io/docs/cli): Prisma CLI reference

# From the CLI (/docs/prisma-postgres/from-the-cli)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Start a Prisma ORM app with Prisma Postgres from the command line.

Location: Prisma Postgres > From the CLI

Use the CLI when you want Prisma ORM and Prisma Postgres set up without leaving the terminal.

## Start a new app [#start-a-new-app]

  

#### bun

```bash
bun create prisma@latest
```

#### pnpm

```bash
pnpm create prisma@latest
```

#### yarn

```bash
yarn create prisma@latest
```

#### npm

```bash
npm create prisma@latest
```

Choose PostgreSQL when prompted, and answer No to `Deploy to Prisma now?`. Setup adds `prisma-8.md`, installs project-level Prisma ORM skills for your coding agent, and writes the generated scripts used below.

## Create the database [#create-the-database]

Create a Prisma Postgres database from the terminal and export its connection string. The generated scripts read the environment variable, not `.env`:

  

#### bun

```bash
bunx create-db@latest
```

#### pnpm

```bash
pnpm dlx create-db@latest
```

#### yarn

```bash
yarn dlx create-db@latest
```

#### npm

```bash
npx create-db@latest
```

```bash
export DATABASE_URL="<the connection string create-db printed>"
```

The command also prints a claim URL; open it within 24 hours to keep the database in your account.

## Initialize the database [#initialize-the-database]

From the generated project directory, run:

  

#### bun

```bash
bun run db:init
```

#### pnpm

```bash
pnpm run db:init
```

#### yarn

```bash
yarn db:init
```

#### npm

```bash
npm run db:init
```

## Run the app [#run-the-app]

Sample users are seeded automatically on the app's first query.

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

## Add Prisma ORM to an existing app [#add-prisma-orm-to-an-existing-app]

If the app already exists, run Prisma ORM from the project root:

  

#### bun

```bash
bunx prisma@latest orm init
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init
```

#### yarn

```bash
yarn dlx prisma@latest orm init
```

#### npm

```bash
npx prisma@latest orm init
```

Choose PostgreSQL and set `DATABASE_URL` to your Prisma Postgres connection string. Init adds `prisma-8.md`, package scripts, and the Prisma ORM skills for your coding agent. Then follow the [PostgreSQL existing-project guide](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql).

## Import an existing database [#import-an-existing-database]

* Use [Import from PostgreSQL](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql) when your source database is PostgreSQL.
* Use [Import from MySQL](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-mysql) when your source database is MySQL.

## Related pages

- [`Import from MySQL`](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-mysql): Import an existing MySQL database into Prisma Postgres, then use it with Prisma ORM.
- [`Import from PostgreSQL`](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql): Move an existing PostgreSQL database to Prisma Postgres without changing your ORM version.

# Import from MySQL (/docs/prisma-postgres/import-from-existing-database-mysql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Import an existing MySQL database into Prisma Postgres, then use it with Prisma ORM.

Location: Prisma Postgres > Import from MySQL

Move an existing MySQL database into Prisma Postgres, then connect Prisma ORM to it.

## Prerequisites [#prerequisites]

You need:

* the connection URL for the MySQL database you are importing from
* a Prisma Data Platform account
* `pgloader`
* Node.js 24 or newer

## 1. Create a Prisma Postgres database [#1-create-a-prisma-postgres-database]

Create a Prisma Postgres database from Console or with the CLI. Copy the direct connection string. You will use it for the import and for `DATABASE_URL`.

## 2. Create a pgloader config [#2-create-a-pgloader-config]

Create `config.load`:

```text title="config.load"
LOAD DATABASE
    FROM mysql://USER:PASSWORD@HOST:PORT/DATABASE
    INTO postgres://USER:PASSWORD@db.prisma.io:5432/?sslmode=require

WITH quote identifiers,
     include drop,
     create tables,
     create indexes,
     reset sequences

ALTER SCHEMA 'DATABASE' RENAME TO 'public';
```

## 3. Import into Prisma Postgres [#3-import-into-prisma-postgres]

Run pgloader:

```shell
pgloader config.load
```

## 4. Add Prisma ORM [#4-add-prisma-orm]

From your app root, initialize Prisma ORM:

  

#### bun

```bash
bunx prisma@latest orm init
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init
```

#### yarn

```bash
yarn dlx prisma@latest orm init
```

#### npm

```bash
npx prisma@latest orm init
```

Choose PostgreSQL, set `DATABASE_URL` to the Prisma Postgres connection string, then infer and emit the contract:

  

#### bun

```bash
bunx prisma contract infer --output ./prisma/contract.prisma
bunx prisma contract emit
bunx prisma db sign
```

#### pnpm

```bash
pnpm prisma contract infer --output ./prisma/contract.prisma
pnpm prisma contract emit
pnpm prisma db sign
```

#### yarn

```bash
yarn prisma contract infer --output ./prisma/contract.prisma
yarn prisma contract emit
yarn prisma db sign
```

#### npm

```bash
npx prisma contract infer --output ./prisma/contract.prisma
npx prisma contract emit
npx prisma db sign
```

## Next steps [#next-steps]

* Review table and column names in the inferred contract.
* Use the [PostgreSQL existing-project guide](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql) for the first Prisma ORM query.
* Use the [full Prisma Postgres MySQL import guide](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-mysql) for deeper migration details.

## Related pages

- [`From the CLI`](https://www.prisma.io/docs/prisma-postgres/from-the-cli): Start a Prisma ORM app with Prisma Postgres from the command line.
- [`Import from PostgreSQL`](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql): Move an existing PostgreSQL database to Prisma Postgres without changing your ORM version.

# Import from PostgreSQL (/docs/prisma-postgres/import-from-existing-database-postgresql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Move an existing PostgreSQL database to Prisma Postgres without changing your ORM version.

Location: Prisma Postgres > Import from PostgreSQL

Move an existing PostgreSQL database to Prisma Postgres with `pg_dump` and `pg_restore`, then reconnect and verify your application.

This guide works with Prisma ORM 8, Prisma ORM 7, earlier Prisma ORM versions, and standard PostgreSQL clients. Moving your database does not require changing your ORM version.

> [!WARNING]
> This migration copies a snapshot
> 
> The final dump contains the database state from when `pg_dump` runs. For a production cutover, stop or drain source writes before the final dump and keep them stopped until validation succeeds and traffic switches to Prisma Postgres.

## Prerequisites [#prerequisites]

You need:

* a direct, non-pooled connection URL for the PostgreSQL database you are moving
* a new, empty [Prisma Postgres database](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29)
* the [direct and pooled Prisma Postgres connection strings](https://www.prisma.io/docs/postgres/database/connecting-to-your-database)
* enough local disk space for the compressed database dump
* PostgreSQL 17 command-line tools: `pg_dump`, `pg_restore`, and `psql`

Confirm that all three tools use PostgreSQL 17:

```bash title="Terminal"
pg_dump --version
pg_restore --version
psql --version
```

Each command should report version `17.x`. PostgreSQL 17 `pg_dump` can read older PostgreSQL databases, but it cannot dump a server newer than version 17. Moving from PostgreSQL 18 or later into Prisma Postgres requires a separate downgrade-compatible migration process.

## 1. Inspect the source database [#1-inspect-the-source-database]

Set the direct source connection URL. Keep the single quotes so your shell does not interpret special characters in the URL:

```bash title="Terminal"
export SOURCE_DATABASE_URL='postgresql://USER:PASSWORD@HOST:5432/DATABASE?sslmode=require'
```

Check the source version and database size before you create the dump:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT current_setting('server_version') AS server_version, pg_size_pretty(pg_database_size(current_database())) AS database_size;"
```

The command should print the server version and database size. Stop if the server is newer than PostgreSQL 17 or if you do not have enough local disk space for the dump.

List the application schemas and installed extensions:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema') AND schema_name NOT LIKE 'pg_%' ORDER BY schema_name;" \
  --command="SELECT extname FROM pg_extension ORDER BY extname;"
```

Compare the result with the [extensions supported by Prisma Postgres](https://www.prisma.io/docs/postgres/database/postgres-extensions). Stop and decide how to replace or remove an unsupported extension before continuing.

`pg_dump` does not copy PostgreSQL roles. Inspect policies that name roles so you can adapt them for the target database:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT schemaname, tablename, policyname, roles FROM pg_policies ORDER BY schemaname, tablename, policyname;"
```

If a policy depends on a source-only role, record its policy name. You will omit that policy during restore and recreate it for your Prisma Postgres access model before switching the application.

## 2. Create the Prisma Postgres destination [#2-create-the-prisma-postgres-destination]

Create a new Prisma Postgres database in [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29):

1. Open your project and select the database.
2. Click **Connect to your database**.
3. Click **Generate new connection string**.
4. Copy both the **direct** and **pooled** connection strings.

Set the direct connection string for the import:

```bash title="Terminal"
export PRISMA_POSTGRES_DIRECT_URL='postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require'
```

Confirm that the target is reachable and empty:

```bash title="Terminal"
psql "$PRISMA_POSTGRES_DIRECT_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT current_database(), current_setting('server_version');" \
  --command="SELECT schemaname, tablename FROM pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema') ORDER BY schemaname, tablename;"
```

The first query should report the Prisma Postgres database and PostgreSQL 17. The second query should not list any application tables. Create another Prisma Postgres database if this target already contains data you need to keep.

## 3. Stop source writes and export the final snapshot [#3-stop-source-writes-and-export-the-final-snapshot]

You can rehearse this process while the source remains active, but do not use a rehearsal dump for the production cutover. Before the final dump, stop or drain every application, worker, scheduled job, integration, and administrative operation that can write to the source. Confirm that writes have stopped, and keep the source frozen until step 7 switches traffic to Prisma Postgres.

If you cannot keep the source frozen for the dump, restore, and validation window, stop here. Use a separately tested migration process that durably captures and replays every post-snapshot write. This snapshot-only process does not provide a zero-downtime cutover.

Create a private, compressed archive containing all non-system schemas in the selected database. See the [PostgreSQL 17 `pg_dump` reference](https://www.postgresql.org/docs/17/app-pgdump.html) for the other options:

```bash title="Terminal"
umask 077

pg_dump \
  --format=custom \
  --verbose \
  --no-owner \
  --no-privileges \
  --dbname="$SOURCE_DATABASE_URL" \
  --file=postgres-to-prisma-postgres.dump
```

`pg_dump` should finish without an error and create `postgres-to-prisma-postgres.dump`. Treat this file as sensitive because it contains your application data.

Create the restore manifest and confirm that PostgreSQL can read the archive:

```bash title="Terminal"
pg_restore --list postgres-to-prisma-postgres.dump > postgres-restore.list
sed -n '1,20p' postgres-restore.list
```

You should see an archive header followed by database objects. If `pg_dump` reports a version mismatch, make sure the PostgreSQL 17 tools appear first in your `PATH`.

If the policy check found policies that reference source-only roles, list the policy entries:

```bash title="Terminal"
grep ' POLICY ' postgres-restore.list
```

In a text editor, prefix with `;` only the `POLICY` lines for the policy names you recorded. This omits the incompatible policies without omitting their tables or data. Recreate each omitted policy with target-compatible roles after the restore and before switching the application.

## 4. Restore into Prisma Postgres [#4-restore-into-prisma-postgres]

Restore the archive through the direct Prisma Postgres connection:

```bash title="Terminal"
pg_restore \
  --verbose \
  --single-transaction \
  --exit-on-error \
  --no-owner \
  --no-privileges \
  --use-list=postgres-restore.list \
  --dbname="$PRISMA_POSTGRES_DIRECT_URL" \
  postgres-to-prisma-postgres.dump
```

The command should finish with exit code `0`. The single transaction leaves the target unchanged if an error stops the restore. Do not ignore errors about missing extensions, roles, or incompatible database objects.

Refresh PostgreSQL's query-planner statistics after the restore:

```bash title="Terminal"
psql "$PRISMA_POSTGRES_DIRECT_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="ANALYZE;"
```

## 5. Verify the imported data [#5-verify-the-imported-data]

Create a reusable query that returns an exact row count for every non-system table:

```sql title="row-counts.sql"
\pset tuples_only on
\pset format unaligned

SELECT format(
  'SELECT %L || ''='' || count(*) FROM %I.%I;',
  schemaname || '.' || tablename,
  schemaname,
  tablename
)
FROM pg_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY schemaname, tablename
\gexec
```

With source writes still stopped, run the query against both databases and compare the results:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" -X --set ON_ERROR_STOP=1 --file=row-counts.sql > source-row-counts.txt
psql "$PRISMA_POSTGRES_DIRECT_URL" -X --set ON_ERROR_STOP=1 --file=row-counts.sql > target-row-counts.txt
diff -u source-row-counts.txt target-row-counts.txt
```

`diff` should print nothing and exit with code `0`. Also rerun the schema, extension, and policy queries from step 1 against `PRISMA_POSTGRES_DIRECT_URL`. Resolve every unexpected difference while source writes remain stopped. Do not send production traffic to Prisma Postgres yet.

## 6. Connect your application [#6-connect-your-application]

Choose the path that matches your application:

* [I already use Prisma ORM 8](#already-use-prisma-8)
* [I use Prisma ORM 7 or earlier](#use-prisma-7-or-earlier)
* [I do not use Prisma ORM](#do-not-use-prisma-orm)

Every path uses the two connection strings from step 2: the pooled URL for application queries and the direct URL for migrations and other CLI tools.

### Already use Prisma ORM 8 [#already-use-prisma-8]

Keep your existing contract, migrations, and application code. The dump copied the `prisma_contract` schema, so the imported database still carries the marker that ties it to your contract.

Set the pooled URL for runtime queries and the direct URL for Prisma CLI commands:

```bash title=".env"
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

If your `prisma.config.ts` sets `db.connection`, point it at `DIRECT_URL`.

Confirm that the imported database still matches your contract:

  

#### bun

```bash title="Terminal"
bunx prisma db verify --db "$DIRECT_URL"
```

#### pnpm

```bash title="Terminal"
pnpm prisma db verify --db "$DIRECT_URL"
```

#### yarn

```bash title="Terminal"
yarn prisma db verify --db "$DIRECT_URL"
```

#### npm

```bash title="Terminal"
npx prisma db verify --db "$DIRECT_URL"
```

The command exits with code `0` when the marker and schema match the contract. Exit code `4` means the database does not match. Check that the restore included the `prisma_contract` schema before you change anything else. Do not run `orm init` or `contract infer` against the new database; your existing contract already describes it.

### Use Prisma ORM 7 or earlier [#use-prisma-7-or-earlier]

Set the pooled URL for runtime queries and the direct URL for Prisma CLI commands:

```bash title=".env"
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

Prisma ORM 7 reads the CLI connection from `datasource.url` in `prisma.config.ts`. Point it at `DIRECT_URL` as shown in the [Prisma ORM 7 PostgreSQL setup](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql). Prisma ORM 6 and earlier read `url` and `directUrl` from the `datasource` block in `schema.prisma`.

If your application did not use Prisma Accelerate, run `npx prisma generate` and continue to step 7.

#### Remove Prisma Accelerate [#remove-prisma-accelerate]

If your application connected through Accelerate, remove it now. Prisma Postgres connection pooling replaces the Accelerate connection pool. It does not replace Accelerate query caching, so remove the cache calls as well.

Uninstall the extension:

  

#### bun

```bash title="Terminal"
bun remove @prisma/extension-accelerate
```

#### pnpm

```bash title="Terminal"
pnpm remove @prisma/extension-accelerate
```

#### yarn

```bash title="Terminal"
yarn remove @prisma/extension-accelerate
```

#### npm

```bash title="Terminal"
npm uninstall @prisma/extension-accelerate
```

In your Prisma Client setup, remove the `@prisma/extension-accelerate` import, `withAccelerate()`, and `accelerateUrl`. Remove `cacheStrategy` options from queries, and remove calls to `withAccelerateInfo`, `$accelerate.invalidate`, and `$accelerate.invalidateAll`.

Undo any build settings you added for Accelerate: imports from `@prisma/client/edge`, `engineType = "client"` in the generator block, and the `--no-engine`, `--accelerate`, or `--data-proxy` flags on `prisma generate`. For Prisma ORM 7, connect through the PostgreSQL driver adapter. For Prisma ORM 6 or earlier, use Prisma Client with its bundled query engine or a driver adapter your version supports.

Accelerate reached edge runtimes over HTTP. For an edge or TCP-constrained runtime, use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver). For a conventional Node.js or Bun runtime, use the Prisma Postgres pooled TCP connection.

Regenerate Prisma Client:

  

#### bun

```bash title="Terminal"
bunx prisma generate
```

#### pnpm

```bash title="Terminal"
pnpm prisma generate
```

#### yarn

```bash title="Terminal"
yarn prisma generate
```

#### npm

```bash title="Terminal"
npx prisma generate
```

Search your project for `@prisma/extension-accelerate` and `prisma://`. Neither should appear.

### Do not use Prisma ORM [#do-not-use-prisma-orm]

Keep your existing PostgreSQL client library. Point its runtime connection at the pooled URL, and use the direct URL for migrations, `pg_dump`, `pg_restore`, and other administrative tools:

```bash title=".env"
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

## 7. Verify and switch the application [#7-verify-and-switch-the-application]

Start the application with the new environment variables while production traffic remains paused, then run its existing test suite. At minimum, verify one read and one rolled-back or disposable write through the pooled connection.

Only after the database comparison and application checks succeed, route production traffic to Prisma Postgres and resume writes there. Do not re-enable writes on the source. Keep the source database available in a read-only state until the application is healthy on Prisma Postgres and the rollback window has ended.

## 8. Delete the local dump files [#8-delete-the-local-dump-files]

After you have verified the application and retained any audit evidence you need, delete the local dump and row-count files:

```bash title="Terminal"
rm postgres-to-prisma-postgres.dump postgres-restore.list row-counts.sql source-row-counts.txt target-row-counts.txt
```

## Recommended next step: adopt Prisma ORM [#recommended-next-step-adopt-prisma-orm]

Your database migration is complete. Prisma ORM 8 is the current release, but upgrading is a separate application change. Follow the [incremental Prisma ORM 7 to 8 guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql) after the application is stable on Prisma Postgres.

If you want to complete both changes on the same day, deploy and verify the Prisma Postgres connection first. Upgrade Prisma ORM in a separate commit or deployment so failures have one clear cause.

## Provider-specific guides [#provider-specific-guides]

* [Migrate from Supabase to Prisma Postgres](https://www.prisma.io/docs/guides/switch-to-prisma-postgres/from-supabase)
* [Migrate from Neon to Prisma Postgres](https://www.prisma.io/docs/guides/switch-to-prisma-postgres/from-neon)

## Related pages

- [`From the CLI`](https://www.prisma.io/docs/prisma-postgres/from-the-cli): Start a Prisma ORM app with Prisma Postgres from the command line.
- [`Import from MySQL`](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-mysql): Import an existing MySQL database into Prisma Postgres, then use it with Prisma ORM.

# Prisma 7 setup paths (/docs/v7/getting-started)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Choose the fastest path to start using Prisma ORM 7, Prisma Postgres, or Prisma Compute in a new or existing TypeScript project.

Location: v7 > Prisma 7 setup paths

Prisma 7 remains fully supported; [Prisma 8](https://www.prisma.io/docs/getting-started) is the current release of Prisma ORM. Scaffold a new Prisma 7 app with `npx create-prisma@stable`, or add it to an existing project with `npx prisma@prev init`. This page collects the Prisma 7 starting points: start a new project, add Prisma to an existing one, then deploy.

> [!NOTE]
> For a new project, [Prisma 8](https://www.prisma.io/docs/prisma-orm) is the recommended path. It is the current major version of Prisma ORM. To start with Prisma 8, see the [getting started page](https://www.prisma.io/docs).

## Start a new project [#start-a-new-project]

The recommended path is the [Quickstart with Prisma Postgres](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres): it provisions a managed PostgreSQL database for you and gets you from install to first query in about five minutes.

To work with a specific database instead, pick its quickstart:

* [Quickstart with PostgreSQL](https://www.prisma.io/docs/v7/prisma-orm/quickstart/postgresql)
* [Quickstart with SQLite](https://www.prisma.io/docs/v7/prisma-orm/quickstart/sqlite) for a lightweight local setup
* [Quickstart with MySQL](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mysql)
* [Quickstart with MongoDB](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mongodb)

## Add Prisma to an existing project [#add-prisma-to-an-existing-project]

Use these guides if you already have an application or database and want to add Prisma ORM:

* [Add Prisma ORM to an existing PostgreSQL project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql)
* [Add Prisma ORM to an existing MySQL project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mysql)
* [Add Prisma ORM to an existing SQLite project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/sqlite)
* [Add Prisma ORM to an existing MongoDB project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mongodb)
* [Add Prisma ORM to an existing Prisma Postgres project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/prisma-postgres)

## Deploy to Prisma Compute [#deploy-to-prisma-compute]

Once your app runs locally, [Prisma Compute](https://www.prisma.io/docs/compute) runs it next to your Prisma Postgres database:

1. Port the app to [Prisma Composer](https://www.prisma.io/docs/composer): add a small TypeScript declaration around your server code, read the port from `service.port()`, and bind credentials like `DATABASE_URL` with `envSecret` in the service's [input schema](https://www.prisma.io/docs/composer/service-input). [Port an existing app](https://www.prisma.io/docs/composer/porting-an-app) covers the changes with complete declarations.
2. Sign in with `npx prisma@latest auth login`.
3. Build your server bundle, then run `npx prisma@latest deploy module.ts` with `DATABASE_URL` exported; the first deploy copies input values from your shell up to the deployment. See [Deploying](https://www.prisma.io/docs/composer/deploying).
4. Keep deploying from the CLI, or [connect GitHub](https://www.prisma.io/docs/compute/github) to deploy on push.

For a worked example, from scratch or from an app you already have, follow [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy).

## Use with your agent [#use-with-your-agent]

To hand the full Prisma 7 stack to your coding agent, copy this prompt. The commands below install Prisma 7, not Prisma 8:

```text
Set up the Prisma 7 stack: Prisma ORM 7, Prisma Postgres, and Prisma Compute.

If I have not told you which framework template to use, stop and ask.

1. Scaffold a new app non-interactively: `npx create-prisma@stable --name my-app --template [next|hono|nuxt|astro|nest|svelte|tanstack-start|elysia|turborepo] --provider postgresql --no-deploy`. Or add Prisma 7 to an existing app with `npx prisma@prev init --db`, which provisions a Prisma Postgres database and may open a browser to sign in; if it does, stop and ask me to complete the sign-in.
2. From the project directory, define a small schema in `prisma/schema.prisma`, then run `npx prisma@prev migrate dev --name init` and `npx prisma@prev generate`. If migrate dev asks to reset the database, stop and ask me first.
3. Update the seed and app code to query the schema, and verify locally with the dev script.
4. Deploy with Prisma Compute: port the app to Prisma Composer following https://www.prisma.io/docs/composer/porting-an-app.md — declare the service around the existing server, read the port from `service.port()` and bind 0.0.0.0, bind `DATABASE_URL` with `envSecret` in the service input, and produce one self-contained entry file. Check `npx prisma@latest auth whoami`. If I am not signed in, stop and ask me to run `npx prisma@latest auth login`, because that step opens a browser. Then run the build followed by `npx prisma@latest deploy module.ts` with `DATABASE_URL` exported so the first deploy copies it up, and verify the deployed URL with curl.

Current docs: https://www.prisma.io/docs/v7/getting-started.md and https://www.prisma.io/docs/llms.txt.
```

## Next steps [#next-steps]

After setup, these pages are usually the next ones people need:

* [Prisma Client overview](https://www.prisma.io/docs/orm/v7/prisma-client)
* [Prisma Migrate getting started](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started)
* [Prisma schema overview](https://www.prisma.io/docs/orm/v7/prisma-schema/overview)
* [Open Prisma Studio](https://www.prisma.io/docs/studio/getting-started) to inspect and edit data visually
* [Review pricing](https://www.prisma.io/pricing) if you're evaluating Prisma Postgres for a team

# Astro + Prisma (/docs/ai/prompts/astro)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an Astro.js project

Location: AI > Prompts > Astro + Prisma

## How to use [#how-to-use]

Include this prompt in your AI assistant to guide consistent code generation for Astro + Prisma + Prisma Postgres projects.

* **GitHub Copilot**: Type `#<filename>` to reference the prompt file.
* **Cursor**: Use `@Files` and select your prompt file.
* **Zed**: Use `/file` followed by your prompt's path.
* **Windsurf**: Use `@Files` and choose your prompt file from the list.

## Prompt [#prompt]

````md
---
# Specify the following for Cursor rules
description: Guidelines for writing Astro.js apps with Prisma Postgres
alwaysApply: false
---

# Bootstrap Astro app with Prisma Postgres

## Overview of implementing Prisma with Astro

1. Install Prisma and required dependencies
2. Initialize Prisma with custom output path
3. Configure schema with correct provider
4. Create global Prisma client instance with Accelerate
5. Use Prisma client in API routes with proper error handling

## 🚨 CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS 🚨

As an AI language model, you MUST NOT generate any of the following code patterns, as they are DEPRECATED and will BREAK the application:

```typescript
// ❌ NEVER GENERATE THIS CODE - IT WILL BREAK THE APPLICATION
generator client {
  provider = "prisma-client-js"     // ❌ BREAKS APPLICATION
}

// ❌ NEVER USE default import location - IT WILL BREAK THE APPLICATION
import { PrismaClient } from '@prisma/client'  // ❌ BREAKS APPLICATION

// ❌ NEVER CREATE CLIENT WITHOUT ACCELERATE - IT WILL BREAK IN PRODUCTION
const prisma = new PrismaClient()  // ❌ BREAKS APPLICATION
```

Instead, you MUST ALWAYS generate ONLY this pattern:

```typescript
// ✅ ALWAYS GENERATE THIS EXACT PATTERN
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

// ✅ ALWAYS USE THIS IMPORT PATH
import { PrismaClient } from "../generated/prisma/client"
import { withAccelerate } from "@prisma/extension-accelerate"

// ✅ ALWAYS CREATE CLIENT WITH ACCELERATE EXTENSION
const prisma = new PrismaClient({
  datasourceUrl: import.meta.env.DATABASE_URL,
}).$extends(withAccelerate())

export default prisma
```

## ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION

1. You MUST use `provider = "prisma-client"` (not "prisma-client-js")
2. You MUST use custom output: `output = "../src/generated/prisma"`
3. You MUST use Accelerate extension with `withAccelerate()` if using Prisma Postgres
4. You MUST create `lib/prisma.ts` as a global singleton instance
5. You MUST wrap all database calls in try-catch blocks
6. You MUST import from `'../generated/prisma/client'` (not `'@prisma/client'`)
7. You MUST use `import.meta.env.DATABASE_URL` in Astro (not `process.env`)
8. You MUST use `npx prisma init --output ../src/generated/prisma` before editing the Prisma schema. If you need Prisma Postgres, run `npx create-db` and update `.env` with the returned `postgres://...` value

## CORRECT INSTALLATION

```bash
# Dev dependencies
npm install prisma@prev tsx --save-dev

# Production dependencies
npm install @prisma/extension-accelerate @prisma/client@7
```

## CORRECT PRISMA INITIALIZATION

```npm
npx prisma init --output ../src/generated/prisma
```

## CORRECT SCHEMA CONFIGURATION

```prisma
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model YourModel {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
```

## CORRECT GLOBAL PRISMA CLIENT

**src/lib/prisma.ts**:

```typescript
import { PrismaClient } from "../generated/prisma/client";
import { withAccelerate } from "@prisma/extension-accelerate";

const prisma = new PrismaClient({
  datasourceUrl: import.meta.env.DATABASE_URL,
}).$extends(withAccelerate());

export default prisma;
```

## CORRECT API ROUTE IMPLEMENTATION

All API routes MUST follow this pattern with proper error handling:

```typescript
import type { APIRoute } from "astro";
import prisma from "../../../lib/prisma";

export const GET: APIRoute = async () => {
  try {
    const data = await prisma.yourModel.findMany();
    return new Response(JSON.stringify(data), {
      status: 200,
      headers: { "Content-Type": "application/json" },
    });
  } catch (error) {
    console.error("Error:", error);
    return new Response(JSON.stringify({ error: "Failed to fetch data" }), {
      status: 500,
      headers: { "Content-Type": "application/json" },
    });
  }
};

export const POST: APIRoute = async ({ request }) => {
  try {
    const body = await request.json();

    // Validate required fields
    if (!body.requiredField) {
      return new Response(JSON.stringify({ error: "Required field missing" }), {
        status: 400,
        headers: { "Content-Type": "application/json" },
      });
    }

    const result = await prisma.yourModel.create({
      data: body,
    });

    return new Response(JSON.stringify(result), {
      status: 201,
      headers: { "Content-Type": "application/json" },
    });
  } catch (error) {
    console.error("Error:", error);
    return new Response(JSON.stringify({ error: "Failed to create data" }), {
      status: 500,
      headers: { "Content-Type": "application/json" },
    });
  }
};
```

## CORRECT USAGE IN ASTRO PAGES

Server-side data fetching in Astro pages:

```astro
---
import prisma from '../lib/prisma'

// Fetch data on the server
const data = await prisma.yourModel.findMany()
---

<html>
  <body>
    {data.map(item => (
      <div>{item.name}</div>
    ))}
  </body>
</html>
```

## AI MODEL VERIFICATION STEPS

Before generating any code, you MUST verify:

1. Are you using `provider = "prisma-client"` (not "prisma-client-js")? If not, STOP and FIX.
2. Are you using `output = "../src/generated/prisma"`? If not, STOP and FIX.
3. Are you importing from `'../generated/prisma/client'`? If not, STOP and FIX.
4. Are you using `withAccelerate()` extension? If not, STOP and FIX.
5. Are you wrapping database operations in try-catch? If not, STOP and FIX.
6. Are you using `import.meta.env` (not `process.env`)? If not, STOP and FIX.
7. Did you use `--generator-provider prisma-client` (NOT `postgresql`)? If not, STOP and FIX.

## CONSEQUENCES OF INCORRECT IMPLEMENTATION

If you generate code using:

- `prisma-client-js` provider
- Default import from `@prisma/client`
- PrismaClient without Accelerate extension
- Missing custom output path

The implementation will:

1. Break in production
2. Cause connection pool exhaustion
3. Fail to maintain proper database connections
4. Result in import errors
5. Cause performance issues

## USEFUL COMMANDS

```npm
npx prisma generate              # Regenerate client after schema changes
```

```npm
npx prisma migrate dev --name X  # Create and apply migration
```

```npm
npx prisma studio                # Open visual database editor
```

```npm
npx prisma db push               # Push schema without migration
```

## AI MODEL RESPONSE TEMPLATE

When asked about Prisma + Astro implementation, you MUST:

1. ONLY use code from this guide
2. NEVER suggest deprecated approaches
3. ALWAYS use the exact patterns shown above
4. VERIFY your response against the patterns shown here
5. ALWAYS include error handling in API routes
6. ALWAYS use the global prisma instance from `lib/prisma.ts`

Remember: There are NO EXCEPTIONS to these rules.
````

## Running the application [#running-the-application]

Run the application locally in three steps:

**1. Generate the Prisma Client:**

```bash
npx prisma generate --no-engine
```

**2. View your database in Prisma Studio:**

```bash
npm run db:studio
```

Prisma Studio opens at `localhost:5555` where you can inspect your `User` table and see the test user stored in your database.

**3. Start your Next.js development server:**

```bash
npm run dev
```

Open `http://localhost:3000`. The page shows the first user fetched from your Prisma Postgres database.

## Related pages

- [`Migrate to Prisma v7`](https://www.prisma.io/docs/ai/prompts/prisma-7): Step-by-step guide for migration your app to use the version 7 of Prisma ORM
- [`Next.js + Prisma`](https://www.prisma.io/docs/ai/prompts/nextjs): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an NextJS project
- [`Nuxt + Prisma`](https://www.prisma.io/docs/ai/prompts/nuxt): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Nuxt project
- [`Turborepo + Prisma`](https://www.prisma.io/docs/ai/prompts/turborepo): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Turborepo monorepo

# Next.js + Prisma (/docs/ai/prompts/nextjs)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an NextJS project

Location: AI > Prompts > Next.js + Prisma

## Prerequisites [#prerequisites]

Before using this prompt, you need to create a new Next.js project:

```bash
npx create-next-app@latest my-app
cd my-app
```

When prompted, select the following recommended options:

* **TypeScript**: Yes
* **ESLint**: Yes
* **Tailwind CSS**: Yes (optional)
* **`src/` directory**: No
* **App Router**: Yes
* **Turbopack**: Yes (optional)
* **Import alias**: Use default (`@/*`)

Once your Next.js project is created, you can use the prompt below with your AI assistant to add Prisma and Prisma Postgres.

## How to use [#how-to-use]

Include this prompt in your AI assistant to guide consistent code generation for NextJS + Prisma + Prisma Postgres projects.

* **GitHub Copilot**: Type `#<filename>` to reference the prompt file.
* **Cursor**: Use `@Files` and select your prompt file.
* **Zed**: Use `/file` followed by your prompt's path.
* **Windsurf**: Use `@Files` and choose your prompt file from the list.

## Video Tutorial [#video-tutorial]

Watch this step-by-step walkthrough showing this prompt in action:

[Watch video](https://www.youtube.com/watch?v=Aqkc95jtHzM)

## Prompt [#prompt]

````md
---
# Specify the following for Cursor rules
description: Guidelines for writing Next.js apps with Prisma Postgres
alwaysApply: false
---

# Bootstrap Next.js app with Prisma Postgres (Prisma v7)

> **Note**: This guide is updated for **Prisma ORM 7**. Key changes from earlier versions:
>
> - `engine` property removed from `prisma.config.ts`
> - `url` removed from datasource in `schema.prisma` (now only in `prisma.config.ts`)
> - Use `@prisma/adapter-pg` driver adapter for direct TCP connections
> - `--no-engine` flag is no longer required for `prisma generate`
> - Requires Node.js 20.19+ and TypeScript 5.4.0+

## Overview of implementing Prisma with Next.js

1. Install Prisma and required dependencies (including dotenv)
2. Initialize Prisma and configure schema
3. Configure dotenv for environment variables
4. Create global Prisma client instance with Pg Adapter
5. Add npm scripts for testing and database management
6. Create test script to verify setup
7. Use Prisma client in API routes and pages with proper error handling

## 🚨 CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS 🚨

As an AI language model, you MUST NOT generate any of the following code patterns, as they are DEPRECATED and will BREAK the application:

```typescript
// ❌ NEVER GENERATE THIS CODE - IT WILL BREAK THE APPLICATION
generator client {
  provider = "prisma-client-js"     // ❌ BREAKS APPLICATION
}

// ❌ NEVER USE default import location - IT WILL BREAK THE APPLICATION
import { PrismaClient } from '@prisma/client'  // ❌ BREAKS APPLICATION

// ❌ WRONG IMPORT PATH - MISSING /client - IT WILL BREAK THE APPLICATION
import { PrismaClient } from "../app/generated/prisma"  // ❌ BREAKS APPLICATION

// ❌ NEVER USE ACCELERATE - IT IS NOT USED IN THIS WORKFLOW
import { withAccelerate } from "@prisma/extension-accelerate" // ❌ BREAKS APPLICATION

// ❌ NEVER USE accelerateUrl - IT WILL BREAK THE APPLICATION
const prisma = new PrismaClient({
  accelerateUrl: process.env.DATABASE_URL,  // ❌ BREAKS APPLICATION - use adapter
})

// ❌ NEVER include url in datasource block - IT WILL BREAK THE APPLICATION
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")  // ❌ BREAKS APPLICATION - moved to prisma.config.ts
}

// ❌ NEVER include engine property - IT WILL BREAK THE APPLICATION
export default defineConfig({
  engine: "classic",  // ❌ BREAKS APPLICATION - removed in Prisma v7
})

// ❌ NEVER use Prisma Postgres HTTP URLs - ONLY use TCP URLs
DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/..."  // ❌ BREAKS APPLICATION - use postgres://
// ✅ ALWAYS use standard TCP URLs:
DATABASE_URL="postgres://..."  // ✅ CORRECT
```

Instead, you MUST ALWAYS generate ONLY this pattern:

```typescript
// ✅ ALWAYS GENERATE THIS EXACT PATTERN
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

// ✅ CRITICAL: MUST include /client at the end of import path
import { PrismaClient } from "../app/generated/prisma/client"
import { PrismaPg } from "@prisma/adapter-pg"

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
})

const globalForPrisma = global as unknown as { prisma: PrismaClient }

const prisma = globalForPrisma.prisma || new PrismaClient({
  adapter,
})

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma

export default prisma
```

## ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION

1. You MUST use `provider = "prisma-client"` (not "prisma-client-js")
2. You MUST use custom output: `output = "../app/generated/prisma"`
3. You MUST use `@prisma/adapter-pg` driver adapter
4. You MUST create `lib/prisma.ts` as a global singleton instance
5. You MUST wrap all database calls in try-catch blocks
6. You MUST import from `'../app/generated/prisma/client'` (not `'@prisma/client'` or `'../app/generated/prisma'`)
7. You MUST use `adapter` property in PrismaClient constructor
8. You MUST install `dotenv` and add `import "dotenv/config"` to `prisma.config.ts`
9. You MUST add npm scripts for `db:test` and `db:studio` to package.json
10. You MUST create a test script at `scripts/test-database.ts` to verify setup
11. You MUST NOT include `url` in the datasource block of `schema.prisma`
12. You MUST NOT include `engine` property in `prisma.config.ts`
13. You MUST use `npx prisma init --output ../app/generated/prisma` to scaffold Prisma, then `npx create-db` to create a real cloud database
14. You MUST use standard TCP URLs (`postgres://...`) in .env
15. You MUST NOT use `accelerateUrl` or `withAccelerate`

## VERSION REQUIREMENTS

- **Node.js**: 20.19 or higher (Node.js 18 is NOT supported)
- **TypeScript**: 5.4.0 or higher (5.9.x recommended)
- **Prisma**: 7.0.0 or higher

## CORRECT INSTALLATION

```bash
# Dev dependencies
npm install prisma@prev tsx --save-dev

# Production dependencies
npm install @prisma/adapter-pg @prisma/client@7 dotenv
```

## CORRECT PRISMA INITIALIZATION

> **FOR AI ASSISTANTS**: `npx prisma init` is not interactive. Run it yourself if your environment allows it. If you need a real Prisma Postgres database, either run `npx create-db` or ask the user to run it and update `DATABASE_URL` before you continue.

```bash
# Initialize Prisma and scaffold the Prisma files
npx prisma init --output ../app/generated/prisma

# Then create a Prisma Postgres database
npx create-db
```

This step:

- Generates `prisma/schema.prisma` with the correct output path
- Generates `prisma.config.ts`
- Generates `.env` with a local `DATABASE_URL`
- Requires `npx create-db` if you want a real Prisma Postgres database

**IMPORTANT**: After `npx create-db`, replace the generated `DATABASE_URL` in `.env` with the returned `postgres://...` connection string.

```text
DATABASE_URL="postgres://..."
```

## CORRECT PRISMA CONFIG (prisma.config.ts)

When using `npx prisma init`, the `prisma.config.ts` is **auto-generated** with the correct configuration:

```typescript
import "dotenv/config"; // ✅ Auto-included by prisma init
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  // ✅ NO engine property - removed in Prisma v7
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

**Note**: If you need to manually create this file, ensure `import "dotenv/config"` is at the top.

## CORRECT SCHEMA CONFIGURATION (prisma/schema.prisma)

Update the generated `prisma/schema.prisma` file:

```prisma
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
  // ✅ NO url here - now configured in prisma.config.ts
}

// Example User model for testing
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
```

## CORRECT GLOBAL PRISMA CLIENT

Create `lib/prisma.ts` file:

```typescript
import { PrismaClient } from "../app/generated/prisma/client"; // ✅ CRITICAL: Include /client
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const globalForPrisma = global as unknown as { prisma: PrismaClient };

const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    adapter,
  });

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

export default prisma;
```

## ADD NPM SCRIPTS TO PACKAGE.JSON

Update your `package.json` to include these scripts:

```json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint",
    "db:test": "tsx scripts/test-database.ts",
    "db:studio": "prisma studio"
  }
}
```

## CREATE TEST SCRIPT

Create `scripts/test-database.ts` to verify your setup:

```typescript
import "dotenv/config"; // ✅ CRITICAL: Load environment variables
import prisma from "../lib/prisma";

async function testDatabase() {
  console.log("🔍 Testing Prisma Postgres connection...\n");

  try {
    // Test 1: Check connection
    console.log("✅ Connected to database!");

    // Test 2: Create a test user
    console.log("\n📝 Creating a test user...");
    const newUser = await prisma.user.create({
      data: {
        email: "demo@example.com",
        name: "Demo User",
      },
    });
    console.log("✅ Created user:", newUser);

    // Test 3: Fetch all users
    console.log("\n📋 Fetching all users...");
    const allUsers = await prisma.user.findMany();
    console.log(`✅ Found ${allUsers.length} user(s):`);
    allUsers.forEach((user) => {
      console.log(`   - ${user.name} (${user.email})`);
    });

    console.log("\n🎉 All tests passed! Your database is working perfectly.\n");
  } catch (error) {
    console.error("❌ Error:", error);
    process.exit(1);
  }
}

testDatabase();
```

## CORRECT API ROUTE IMPLEMENTATION (App Router)

Create `app/api/users/route.ts` with GET and POST handlers:

```typescript
import { NextRequest, NextResponse } from "next/server";
import prisma from "../../../lib/prisma";

export async function GET(request: NextRequest) {
  try {
    const users = await prisma.user.findMany();
    return NextResponse.json(users);
  } catch (error) {
    console.error("Error fetching users:", error);
    return NextResponse.json({ error: "Failed to fetch users" }, { status: 500 });
  }
}

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const user = await prisma.user.create({
      data: {
        email: body.email,
        name: body.name,
      },
    });
    return NextResponse.json(user, { status: 201 });
  } catch (error) {
    console.error("Error creating user:", error);
    return NextResponse.json({ error: "Failed to create user" }, { status: 500 });
  }
}
```

## CORRECT USAGE IN SERVER COMPONENTS

Update `app/page.tsx` to display users from the database:

```typescript
import prisma from "../lib/prisma";

export default async function Home() {
    let users: Array<{
        id: number;
        email: string;
        name: string | null;
        createdAt: Date;
        updatedAt: Date;
    }> = [];
    let error = null;

    try {
        users = await prisma.user.findMany({
            orderBy: {
                createdAt: "desc",
            },
        });
    } catch (e) {
        console.error("Error fetching users:", e);
        error =
            "Failed to load users. Make sure your DATABASE_URL is configured.";
    }

    return (
        <main className="p-8">
            <h1 className="text-2xl font-bold mb-4">Users from Database</h1>
            {error ? (
                <p className="text-red-500">{error}</p>
            ) : users.length === 0 ? (
                <p>No users yet. Create one using the API at /api/users</p>
            ) : (
                <ul className="space-y-2">
                    {users.map((user) => (
                        <li key={user.id} className="border p-4 rounded">
                            <p className="font-semibold">
                                {user.name || "No name"}
                            </p>
                            <p className="text-sm text-gray-600">
                                {user.email}
                            </p>
                        </li>
                    ))}
                </ul>
            )}
        </main>
    );
}
```

## COMPLETE SETUP WORKFLOW

User should follow these steps (AI should provide these instructions):

1. **Install dependencies**:

   ```npm
   npm install prisma@prev tsx --save-dev
   ```

   ```npm
   npm install @prisma/adapter-pg @prisma/client@7 dotenv
   ```

2. **Initialize Prisma, then create Prisma Postgres:**

   > **AI ASSISTANT**: You can run `npx prisma init` yourself. If you should not provision cloud resources automatically, ask the user to run `npx create-db` and update `DATABASE_URL` before continuing.

   ```npm
   npx prisma init --output ../app/generated/prisma
   npx create-db
   ```

   This creates `prisma/schema.prisma`, `prisma.config.ts`, and `.env`, then returns a `postgres://...` connection string for Prisma Postgres.

   **If you asked the user to run `npx create-db`, wait for them to share or paste the returned connection string before proceeding.**

3. **Verify `.env` was created** - Replace the generated `DATABASE_URL` with the `postgres://...` connection string returned by `npx create-db`.

   ```text
   DATABASE_URL="postgres://..."
   ```

   **Do NOT invent this URL. Use the one returned by `npx create-db`.**

4. **Update `prisma/schema.prisma`** - Add the User model (generator and datasource are already configured):

   ```prisma
   model User {
     id        Int      @id @default(autoincrement())
     email     String   @unique
     name      String?
     createdAt DateTime @default(now())
     updatedAt DateTime @updatedAt
   }
   ```

5. **Create `lib/prisma.ts`** with correct import path including `/client` and using `@prisma/adapter-pg`.

6. **Add npm scripts** to `package.json` for `db:test` and `db:studio`

7. **Create `scripts/test-database.ts`** test script

8. **Push schema to database**:

   ```npm
   npx prisma db push
   ```

9. **Generate Prisma Client**:

   ```npm
   npx prisma generate
   ```

10. **Test the setup**:

    ```bash
    npm run db:test
    ```

11. **Start development server**:
    ```bash
    npm run dev
    ```

## AI MODEL VERIFICATION STEPS

Before generating any code, you MUST verify:

1. Are you using `provider = "prisma-client"` (not "prisma-client-js")? If not, STOP and FIX.
2. Are you using `output = "../app/generated/prisma"`? If not, STOP and FIX.
3. Are you importing from `'../app/generated/prisma/client'` (with `/client`)? If not, STOP and FIX.
4. Did you add `import "dotenv/config"` to `prisma.config.ts`? If not, STOP and FIX.
5. Did you add `import "dotenv/config"` to `scripts/test-database.ts`? If not, STOP and FIX.
6. Are you using `@prisma/adapter-pg`? If not, STOP and FIX.
7. Are you using `adapter` property in PrismaClient constructor? If not, STOP and FIX.
8. Are you wrapping database operations in try-catch? If not, STOP and FIX.
9. Did you create the test script at `scripts/test-database.ts`? If not, STOP and FIX.
10. Did you add `db:test` and `db:studio` scripts to package.json? If not, STOP and FIX.
11. Did you remove `url` from the datasource block in `schema.prisma`? If not, STOP and FIX.
12. Did you remove `engine` property from `prisma.config.ts`? If not, STOP and FIX.
13. Did you run `npx prisma init` with the documented output path? If not, STOP and FIX.
14. Is the DATABASE_URL a TCP URL (`postgres://...`)? If it's a `prisma+postgres://` URL, STOP and FIX.
15. Did Prisma generate the `.env` file? If you invented the URL manually, STOP and FIX.

## CONSEQUENCES OF INCORRECT IMPLEMENTATION

If you generate code using:

- `prisma-client-js` provider → **CLIENT GENERATION FAILS**
- Wrong import path (missing `/client`) → **MODULE NOT FOUND ERROR**
- Missing `import "dotenv/config"` in prisma.config.ts → **DATABASE_URL NOT FOUND ERROR**
- Missing `import "dotenv/config"` in test scripts → **ENVIRONMENT VARIABLE ERROR**
- Default import from `@prisma/client` → **IMPORT ERROR**
- Using `accelerateUrl` or `withAccelerate` → **UNNECESSARY ACCELERATE DEPENDENCY / CONFIG ERROR**
- Missing custom output path → **WRONG CLIENT GENERATED**
- Including `url` in datasource block → **DEPRECATED CONFIGURATION ERROR**
- Including `engine` property → **DEPRECATED CONFIGURATION ERROR**
- Using local URL (`postgres://localhost:...`) → **VERSION INCOMPATIBILITY ERRORS WITH Prisma v7**
- Using `npx prisma init` without `--db` → **NO DATABASE CREATED, ONLY LOCAL FILES**
- Manually inventing DATABASE_URL → **INVALID CONNECTION STRING ERRORS**

The implementation will:

1. Break immediately with module errors
2. Fail to read environment variables
3. Cause connection pool exhaustion in production
4. Result in import errors that prevent compilation
5. Cause performance issues and connection failures
6. Fail with "HTTP connection string is not supported" errors when using local URLs

## USEFUL COMMANDS

```bash
# After changing schema
npx prisma generate              # Regenerate client (--no-engine flag no longer needed)

# Push schema to database (no migrations)
npx prisma db push

# Test database connection
npm run db:test

# Open visual database editor
npm run db:studio

# Create and apply migrations (for production)
npx prisma migrate dev --name your_migration_name
```

## TESTING WORKFLOW

After setup, test with these steps:

1. **Test database connection**:

   ```bash
   npm run db:test
   ```

   Should create a demo user and display it.

2. **Open Prisma Studio**:

   ```bash
   npm run db:studio
   ```

   Visual interface at `localhost:5555` to view/edit data.

3. **Test API routes**:

   ```bash
   # Create a user via API
   curl -X POST http://localhost:3000/api/users \
     -H "Content-Type: application/json" \
     -d '{"email":"test@example.com","name":"Test User"}'

   # Get all users
   curl http://localhost:3000/api/users
   ```

4. **View in browser**:
   Open `localhost:3000` to see users displayed on the homepage.

## AI MODEL RESPONSE TEMPLATE

When asked about Prisma + Next.js implementation, you MUST:

1. ONLY use code patterns from this guide
2. NEVER suggest deprecated approaches
3. ALWAYS use the exact patterns shown above
4. ALWAYS include `/client` in import paths
5. ALWAYS add `import "dotenv/config"` to prisma.config.ts
6. ALWAYS add `import "dotenv/config"` to test scripts
7. ALWAYS create the test script at `scripts/test-database.ts`
8. ALWAYS add npm scripts for `db:test` and `db:studio`
9. ALWAYS include error handling in API routes and server components
10. ALWAYS use the global prisma instance from `lib/prisma.ts`
11. ALWAYS use `@prisma/adapter-pg` and `adapter` property
12. NEVER include `url` in the datasource block of schema.prisma
13. NEVER include `engine` property in prisma.config.ts
14. ALWAYS run `npx prisma init --output ../app/generated/prisma` before editing Prisma files. If you cannot provision cloud resources automatically, ask the user to run `npx create-db` and update `DATABASE_URL` before continuing
15. ALWAYS wait for user confirmation after they run `npx create-db` and share or apply the returned `postgres://...` connection string before proceeding
16. NEVER attempt to run interactive commands yourself - ask the user to do it
17. NEVER use `prisma+postgres://` URLs - ONLY `postgres://` TCP URLs
18. NEVER manually invent or fabricate DATABASE_URL values
19. ALWAYS let Prisma generate the `.env` file with the real DATABASE_URL (and ensure it's correct type)
20. VERIFY your response against ALL the patterns shown here before responding

Remember: There are NO EXCEPTIONS to these rules. Every requirement is MANDATORY for the setup to work.
````

## Related pages

- [`Astro + Prisma`](https://www.prisma.io/docs/ai/prompts/astro): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an Astro.js project
- [`Migrate to Prisma v7`](https://www.prisma.io/docs/ai/prompts/prisma-7): Step-by-step guide for migration your app to use the version 7 of Prisma ORM
- [`Nuxt + Prisma`](https://www.prisma.io/docs/ai/prompts/nuxt): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Nuxt project
- [`Turborepo + Prisma`](https://www.prisma.io/docs/ai/prompts/turborepo): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Turborepo monorepo

# Nuxt + Prisma (/docs/ai/prompts/nuxt)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Nuxt project

Location: AI > Prompts > Nuxt + Prisma

## Prerequisites [#prerequisites]

Before using this prompt, you need to create a new Nuxt project:

```bash
npx nuxi@latest init hello-prisma
cd hello-prisma
```

Once your Nuxt project is created, you can use the prompt below with your AI assistant to add Prisma and Prisma Postgres.

## How to use [#how-to-use]

Include this prompt in your AI assistant to guide consistent code generation for Nuxt + Prisma + Prisma Postgres projects.

* **GitHub Copilot**: Type `#<filename>` to reference the prompt file.
* **Cursor**: Use `@Files` and select your prompt file.
* **Zed**: Use `/file` followed by your prompt's path.
* **Windsurf**: Use `@Files` and choose your prompt file from the list.

## Prompt [#prompt]

````md
---
# Specify the following for Cursor rules
description: Guidelines for writing Nuxt apps with Prisma Postgres
alwaysApply: false
---

# Bootstrap Nuxt app with Prisma Postgres (Prisma v7)

**Purpose:** Set up Prisma ORM with Prisma Postgres in a Nuxt project using the correct Prisma v7 patterns.

---

## FIRST: Check for an existing Nuxt project

Before doing anything else, check whether the current directory already contains a Nuxt project by looking for `nuxt.config.ts`.

- **If `nuxt.config.ts` exists** → A project is already set up. Skip to "Overview" below.
- **If the directory does NOT contain `nuxt.config.ts`** → Create a new project first:

```bash
npx nuxi@latest init hello-prisma
cd hello-prisma
```

After the project is created, verify `nuxt.config.ts` exists before continuing.

---

> **Note**: This guide is updated for **Prisma ORM 7**. Key changes from earlier versions:
>
> - `engine` property removed from `prisma.config.ts`
> - `url` removed from datasource in `schema.prisma` (now only in `prisma.config.ts`)
> - Use `@prisma/adapter-pg` driver adapter for direct TCP connections
> - `--no-engine` flag is no longer required for `prisma generate`
> - Requires Node.js 20.19+ and TypeScript 5.4.0+

## Overview of implementing Prisma with Nuxt

1. Ensure a Nuxt project exists (see above)
2. Install Prisma and required dependencies (including dotenv and pg)
3. Initialize Prisma and configure schema
4. Configure dotenv for environment variables
5. Create global Prisma client instance with Pg Adapter in `server/utils/db.ts`
6. Create Nuxt API routes using `defineEventHandler`
7. Create a Vue page to display data
8. Add npm scripts for testing and database management
9. Create test script to verify setup

## 🚨 CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS 🚨

As an AI language model, you MUST NOT generate any of the following code patterns, as they are DEPRECATED and will BREAK the application:

```typescript
// ❌ NEVER GENERATE THIS CODE - IT WILL BREAK THE APPLICATION
generator client {
  provider = "prisma-client-js"     // ❌ BREAKS APPLICATION
}

// ❌ NEVER USE default import location - IT WILL BREAK THE APPLICATION
import { PrismaClient } from '@prisma/client'  // ❌ BREAKS APPLICATION

// ❌ WRONG IMPORT PATH - MISSING /client - IT WILL BREAK THE APPLICATION
import { PrismaClient } from "../../prisma/generated"  // ❌ BREAKS APPLICATION

// ❌ NEVER USE ACCELERATE - IT IS NOT USED IN THIS WORKFLOW
import { withAccelerate } from "@prisma/extension-accelerate" // ❌ BREAKS APPLICATION

// ❌ NEVER USE accelerateUrl - IT WILL BREAK THE APPLICATION
const prisma = new PrismaClient({
  accelerateUrl: process.env.DATABASE_URL,  // ❌ BREAKS APPLICATION - use adapter
})

// ❌ NEVER include url in datasource block - IT WILL BREAK THE APPLICATION
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")  // ❌ BREAKS APPLICATION - moved to prisma.config.ts
}

// ❌ NEVER include engine property - IT WILL BREAK THE APPLICATION
export default defineConfig({
  engine: "classic",  // ❌ BREAKS APPLICATION - removed in Prisma v7
})

// ❌ NEVER use Prisma Postgres HTTP URLs - ONLY use TCP URLs
DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/..."  // ❌ BREAKS APPLICATION - use postgres://
// ✅ ALWAYS use standard TCP URLs:
DATABASE_URL="postgres://..."  // ✅ CORRECT

// ❌ NEVER create PrismaClient without adapter - IT WILL BREAK THE APPLICATION
const prisma = new PrismaClient()  // ❌ BREAKS APPLICATION
```

Instead, you MUST ALWAYS generate ONLY this pattern:

```typescript
// ✅ ALWAYS GENERATE THIS EXACT PATTERN
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

// ✅ CRITICAL: MUST include /client at the end of import path
import { PrismaClient } from "../../prisma/generated/client"
import { PrismaPg } from "@prisma/adapter-pg"

const pool = new PrismaPg({ connectionString: process.env.DATABASE_URL! })

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined }

const prisma = globalForPrisma.prisma ?? new PrismaClient({ adapter: pool })

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma

export { prisma }
```

## ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION

1. You MUST use `provider = "prisma-client"` (not "prisma-client-js")
2. You MUST use custom output: `output = "./generated"` (relative to prisma directory)
3. You MUST use `@prisma/adapter-pg` driver adapter with `PrismaPg`
4. You MUST create `server/utils/db.ts` as a global singleton instance (Nuxt auto-imports from `server/utils/`)
5. You MUST wrap all database calls in try-catch blocks
6. You MUST import from `'../../prisma/generated/client'` (not `'@prisma/client'` or `'../../prisma/generated'`)
7. You MUST use `adapter` property in PrismaClient constructor
8. You MUST install `dotenv` and add `import "dotenv/config"` to `prisma.config.ts`
9. You MUST add npm scripts for `db:test` and `db:studio` to package.json
10. You MUST create a test script at `scripts/test-database.ts` to verify setup
11. You MUST NOT include `url` in the datasource block of `schema.prisma`
12. You MUST NOT include `engine` property in `prisma.config.ts`
13. You MUST use `npx prisma init --output ./generated` to scaffold Prisma, then `npx create-db` to create a real cloud database
14. You MUST use standard TCP URLs (`postgres://...`) in .env
15. You MUST NOT use `accelerateUrl` or `withAccelerate`
16. You MUST install `pg` and `@types/pg` as dependencies

## VERSION REQUIREMENTS

- **Node.js**: 20.19 or higher (Node.js 18 is NOT supported)
- **TypeScript**: 5.4.0 or higher (5.9.x recommended)
- **Prisma**: 7.0.0 or higher

## CORRECT INSTALLATION

```bash
# Production dependencies
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv

# Dev dependencies
npm install -D prisma@prev @types/pg tsx
```

## CORRECT PRISMA INITIALIZATION

> **FOR AI ASSISTANTS**: `npx prisma init` is not interactive. Run it yourself if your environment allows it. If you need a real Prisma Postgres database, either run `npx create-db` or ask the user to run it and update `DATABASE_URL` before you continue.

```bash
# Initialize Prisma and scaffold the Prisma files
npx prisma init --output ./generated

# Then create a Prisma Postgres database
npx create-db
```

This step:

- Generates `prisma/schema.prisma` with the correct output path
- Generates `prisma.config.ts`
- Generates `.env` with a local `DATABASE_URL`
- Requires `npx create-db` if you want a real Prisma Postgres database

**IMPORTANT**: After `npx create-db`, replace the generated `DATABASE_URL` in `.env` with the returned `postgres://...` connection string.

```text
DATABASE_URL="postgres://..."
```

## CORRECT PRISMA CONFIG (prisma.config.ts)

When using `npx prisma init`, the `prisma.config.ts` is **auto-generated** with the correct configuration:

```typescript
import "dotenv/config"; // ✅ Auto-included by prisma init
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "tsx ./prisma/seed.ts",
  },
  // ✅ NO engine property - removed in Prisma v7
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

**Note**: If you need to manually create this file, ensure `import "dotenv/config"` is at the top.

## CORRECT SCHEMA CONFIGURATION (prisma/schema.prisma)

Update the generated `prisma/schema.prisma` file:

```prisma
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider = "postgresql"
  // ✅ NO url here - now configured in prisma.config.ts
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}
```

## CORRECT GLOBAL PRISMA CLIENT

Create `server/utils/db.ts` file. Nuxt auto-imports exports from `server/utils/`, making `prisma` available in all server API routes without explicit imports:

```typescript
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../../prisma/generated/client"; // ✅ CRITICAL: Include /client

const prismaClientSingleton = () => {
  const pool = new PrismaPg({ connectionString: process.env.DATABASE_URL! });
  return new PrismaClient({ adapter: pool });
};

type PrismaClientSingleton = ReturnType<typeof prismaClientSingleton>;

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClientSingleton | undefined;
};

export const prisma = globalForPrisma.prisma ?? prismaClientSingleton();

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
```

## ADD NPM SCRIPTS TO PACKAGE.JSON

Update your `package.json` to include these scripts:

```json
{
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "prisma generate && nuxt prepare",
    "db:test": "tsx scripts/test-database.ts",
    "db:studio": "prisma studio"
  }
}
```

## CREATE TEST SCRIPT

Create `scripts/test-database.ts` to verify your setup:

```typescript
import "dotenv/config"; // ✅ CRITICAL: Load environment variables
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../prisma/generated/client";

const pool = new PrismaPg({ connectionString: process.env.DATABASE_URL! });
const prisma = new PrismaClient({ adapter: pool });

async function testDatabase() {
  console.log("🔍 Testing Prisma Postgres connection...\n");

  try {
    // Test 1: Check connection
    console.log("✅ Connected to database!");

    // Test 2: Create a test user
    console.log("\n📝 Creating a test user...");
    const newUser = await prisma.user.create({
      data: {
        email: "demo@example.com",
        name: "Demo User",
      },
    });
    console.log("✅ Created user:", newUser);

    // Test 3: Fetch all users
    console.log("\n📋 Fetching all users...");
    const allUsers = await prisma.user.findMany();
    console.log(`✅ Found ${allUsers.length} user(s):`);
    allUsers.forEach((user) => {
      console.log(`   - ${user.name} (${user.email})`);
    });

    console.log("\n🎉 All tests passed! Your database is working perfectly.\n");
  } catch (error) {
    console.error("❌ Error:", error);
    process.exit(1);
  }
}

testDatabase();
```

## CORRECT API ROUTE IMPLEMENTATION

Nuxt uses file-based API routing in `server/api/`. The `prisma` instance is auto-imported from `server/utils/db.ts`.

Create `server/api/users.get.ts` to fetch users:

```typescript
export default defineEventHandler(async () => {
  try {
    const users = await prisma.user.findMany({
      include: { posts: true },
    });
    return users;
  } catch (error) {
    console.error("Error fetching users:", error);
    throw createError({
      statusCode: 500,
      statusMessage: "Failed to fetch users",
    });
  }
});
```

Create `server/api/users.post.ts` to create a user:

```typescript
export default defineEventHandler(async (event) => {
  try {
    const body = await readBody<{ name: string; email: string }>(event);

    if (!body.email) {
      throw createError({
        statusCode: 400,
        statusMessage: "Email is required",
      });
    }

    const user = await prisma.user.create({
      data: {
        name: body.name,
        email: body.email,
      },
    });

    return user;
  } catch (error) {
    console.error("Error creating user:", error);
    throw createError({
      statusCode: 500,
      statusMessage: "Failed to create user",
    });
  }
});
```

## CORRECT USAGE IN VUE PAGES

Update `app.vue` to display users from the database:

```html
<template>
  <div>
    <h1>Users</h1>
    <ul v-if="users?.length">
      <li v-for="user in users" :key="user.id">
        {{ user.name }} ({{ user.email }})
      </li>
    </ul>
    <p v-else>No users yet.</p>
  </div>
</template>

<script setup>
const { data: users } = await useFetch("/api/users");
</script>
```

## COMPLETE SETUP WORKFLOW

User should follow these steps (AI should provide these instructions):

1. **Ensure a Nuxt project exists** — check for `nuxt.config.ts`. If missing, create one:

   ```bash
   npx nuxi@latest init hello-prisma
   cd hello-prisma
   ```

2. **Install dependencies**:

   ```bash
   npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
   ```

   ```bash
   npm install -D prisma@prev @types/pg tsx
   ```

3. **Initialize Prisma AND create Prisma Postgres database** (⚠️ USER MUST RUN MANUALLY):

   > **AI ASSISTANT**: You can run `npx prisma init` yourself. If you should not provision cloud resources automatically, ask the user to run `npx create-db` and update `DATABASE_URL` before continuing.

   ```bash
   npx prisma init --output ./generated
   npx create-db
   ```

   This creates `prisma/schema.prisma`, `prisma.config.ts`, and `.env`, then returns a `postgres://...` connection string for Prisma Postgres.

   **If you asked the user to run `npx create-db`, wait for them to share or paste the returned connection string before proceeding.**

4. **Verify `.env` was created** — Replace the generated `DATABASE_URL` with the `postgres://...` connection string returned by `npx create-db`.

   ```text
   DATABASE_URL="postgres://..."
   ```

   **Do NOT invent this URL. Use the one returned by `npx create-db`.**

5. **Update `prisma/schema.prisma`** — Add the User and Post models (generator and datasource are already configured):

   ```prisma
   model User {
     id    Int     @id @default(autoincrement())
     email String  @unique
     name  String?
     posts Post[]
   }

   model Post {
     id        Int      @id @default(autoincrement())
     title     String
     content   String?
     published Boolean  @default(false)
     author    User?    @relation(fields: [authorId], references: [id])
     authorId  Int?
   }
   ```

6. **Create `server/utils/db.ts`** with correct import path including `/client` and using `@prisma/adapter-pg`.

7. **Add npm scripts** to `package.json` for `db:test`, `db:studio`, and `postinstall`

8. **Create `scripts/test-database.ts`** test script

9. **Create API routes** — `server/api/users.get.ts` and `server/api/users.post.ts`

10. **Update `app.vue`** to display users

11. **Push schema to database**:

    ```bash
    npx prisma db push
    ```

12. **Generate Prisma Client**:

    ```bash
    npx prisma generate
    ```

13. **Test the setup**:

    ```bash
    npm run db:test
    ```

14. **Start development server**:

    ```bash
    npm run dev
    ```

## AI MODEL VERIFICATION STEPS

Before generating any code, you MUST verify:

1. Does the current directory contain `nuxt.config.ts`? If not, create the project first.
2. Are you using `provider = "prisma-client"` (not "prisma-client-js")? If not, STOP and FIX.
3. Are you using `output = "./generated"`? If not, STOP and FIX.
4. Are you importing from `'../../prisma/generated/client'` (with `/client`)? If not, STOP and FIX.
5. Did you add `import "dotenv/config"` to `prisma.config.ts`? If not, STOP and FIX.
6. Did you add `import "dotenv/config"` to `scripts/test-database.ts`? If not, STOP and FIX.
7. Are you using `@prisma/adapter-pg` with `PrismaPg`? If not, STOP and FIX.
8. Are you using `adapter` property in PrismaClient constructor? If not, STOP and FIX.
9. Are you wrapping database operations in try-catch? If not, STOP and FIX.
10. Did you create the Prisma client in `server/utils/db.ts` (not `lib/prisma.ts`)? If not, STOP and FIX.
11. Did you create the test script at `scripts/test-database.ts`? If not, STOP and FIX.
12. Did you add `db:test` and `db:studio` scripts to package.json? If not, STOP and FIX.
13. Did you remove `url` from the datasource block in `schema.prisma`? If not, STOP and FIX.
14. Did you remove `engine` property from `prisma.config.ts`? If not, STOP and FIX.
15. Did you run `npx prisma init` with the documented output path? If not, STOP and FIX.
16. Is the DATABASE_URL a TCP URL (`postgres://...`)? If it's a `prisma+postgres://` URL, STOP and FIX.
17. Did Prisma generate the `.env` file? If you invented the URL manually, STOP and FIX.
18. Are you using Nuxt auto-imports (`defineEventHandler`, `readBody`, `createError`, `prisma`)? If not, STOP and FIX.

## CONSEQUENCES OF INCORRECT IMPLEMENTATION

If you generate code using:

- `prisma-client-js` provider → **CLIENT GENERATION FAILS**
- Wrong import path (missing `/client`) → **MODULE NOT FOUND ERROR**
- Missing `import "dotenv/config"` in prisma.config.ts → **DATABASE_URL NOT FOUND ERROR**
- Missing `import "dotenv/config"` in test scripts → **ENVIRONMENT VARIABLE ERROR**
- Default import from `@prisma/client` → **IMPORT ERROR**
- Using `accelerateUrl` or `withAccelerate` → **UNNECESSARY ACCELERATE DEPENDENCY / CONFIG ERROR**
- Missing custom output path → **WRONG CLIENT GENERATED**
- Including `url` in datasource block → **DEPRECATED CONFIGURATION ERROR**
- Including `engine` property → **DEPRECATED CONFIGURATION ERROR**
- Using local URL (`postgres://localhost:...`) → **VERSION INCOMPATIBILITY ERRORS WITH Prisma v7**
- Using `npx prisma init` without `--db` → **NO DATABASE CREATED, ONLY LOCAL FILES**
- Manually inventing DATABASE_URL → **INVALID CONNECTION STRING ERRORS**
- Creating client in `lib/prisma.ts` instead of `server/utils/db.ts` → **NOT AUTO-IMPORTED IN NUXT SERVER ROUTES**
- Missing `pg` dependency → **ADAPTER INITIALIZATION FAILURE**

The implementation will:

1. Break immediately with module errors
2. Fail to read environment variables
3. Cause connection pool exhaustion in production
4. Result in import errors that prevent compilation
5. Cause performance issues and connection failures
6. Fail with "HTTP connection string is not supported" errors when using local URLs

## USEFUL COMMANDS

```bash
# After changing schema
npx prisma generate              # Regenerate client (--no-engine flag no longer needed)

# Push schema to database (no migrations)
npx prisma db push

# Test database connection
npm run db:test

# Open visual database editor
npm run db:studio

# Create and apply migrations (for production)
npx prisma migrate dev --name your_migration_name
```

## TESTING WORKFLOW

After setup, test with these steps:

1. **Test database connection**:

   ```bash
   npm run db:test
   ```

   Should create a demo user and display it.

2. **Open Prisma Studio**:

   ```bash
   npm run db:studio
   ```

   Visual interface at `localhost:5555` to view/edit data.

3. **Test API routes**:

   ```bash
   # Create a user via API
   curl -X POST http://localhost:3000/api/users \
     -H "Content-Type: application/json" \
     -d '{"email":"test@example.com","name":"Test User"}'

   # Get all users
   curl http://localhost:3000/api/users
   ```

4. **View in browser**:
   Open `localhost:3000` to see users displayed on the homepage.

## AI MODEL RESPONSE TEMPLATE

When asked about Prisma + Nuxt implementation, you MUST:

1. ONLY use code patterns from this guide
2. NEVER suggest deprecated approaches
3. ALWAYS use the exact patterns shown above
4. ALWAYS include `/client` in import paths
5. ALWAYS add `import "dotenv/config"` to prisma.config.ts
6. ALWAYS add `import "dotenv/config"` to test scripts
7. ALWAYS create the Prisma client in `server/utils/db.ts` (Nuxt auto-imports)
8. ALWAYS create the test script at `scripts/test-database.ts`
9. ALWAYS add npm scripts for `db:test` and `db:studio`
10. ALWAYS include error handling in API routes using `createError`
11. ALWAYS use the auto-imported `prisma` instance in server routes
12. ALWAYS use `@prisma/adapter-pg` with `PrismaPg` and `adapter` property
13. NEVER include `url` in the datasource block of schema.prisma
14. NEVER include `engine` property in prisma.config.ts
15. ALWAYS run `npx prisma init --output ./generated` before editing Prisma files. If you cannot provision cloud resources automatically, ask the user to run `npx create-db` and update `DATABASE_URL` before continuing
16. ALWAYS wait for user confirmation after they run `npx create-db` and share or apply the returned `postgres://...` connection string before proceeding
17. NEVER attempt to run interactive commands yourself - ask the user to do it
18. NEVER use `prisma+postgres://` URLs - ONLY `postgres://` TCP URLs
19. NEVER manually invent or fabricate DATABASE_URL values
20. ALWAYS let Prisma generate the `.env` file with the real DATABASE_URL (and ensure it's correct type)
21. VERIFY your response against ALL the patterns shown here before responding

Remember: There are NO EXCEPTIONS to these rules. Every requirement is MANDATORY for the setup to work.
````

## Related pages

- [`Astro + Prisma`](https://www.prisma.io/docs/ai/prompts/astro): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an Astro.js project
- [`Migrate to Prisma v7`](https://www.prisma.io/docs/ai/prompts/prisma-7): Step-by-step guide for migration your app to use the version 7 of Prisma ORM
- [`Next.js + Prisma`](https://www.prisma.io/docs/ai/prompts/nextjs): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an NextJS project
- [`Turborepo + Prisma`](https://www.prisma.io/docs/ai/prompts/turborepo): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Turborepo monorepo

# Migrate to Prisma v7 (/docs/ai/prompts/prisma-7)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Step-by-step guide for migration your app to use the version 7 of Prisma ORM

Location: AI > Prompts > Migrate to Prisma v7

## How to use [#how-to-use]

Include this prompt in your AI agent to upgrade to Prisma ORM 7.

* **GitHub Copilot**: Type `#<filename>` to reference the prompt file.
* **Cursor**: Use `@Files` and select your prompt file.
* **Zed**: Use `/file` followed by your prompt's path.
* **Windsurf**: Use `@Files` and choose your prompt file from the list.

## Video Tutorial [#video-tutorial]

Watch this video showing this prompt in action:

[Watch video](https://www.youtube.com/watch?v=643mBMCbHPU)

## Prompt [#prompt]

````md
---
# Specify the following for Cursor rules
description: Guidelines for migrating an app to Prisma ORM v7
alwaysApply: false
---

# Prisma v6 → v7 Migration Assistant

**Role:** You are a precise, changeset-oriented code migration assistant. Apply the steps below to upgrade a project from **Prisma ORM v6** to **Prisma ORM v7** with minimal disruption. Work in small, re-viewable steps and explain each change briefly. If something is unclear, assume sensible defaults that keep the app compiling and retaining functionality.

## Ground Rules

- Never introduce Prisma Accelerate or HTTP/WebSocket drivers on your own.
- Do **not** remove Prisma Accelerate automatically.
- **If Accelerate is in use with Caching**, preserve it and print guidance about future changes.
- **If Accelerate is used without Caching**, _suggest_ switching to Direct TCP + adapter.
- Always **load env variables explicitly** using `dotenv` (`import 'dotenv/config'`), unless the runtime is Bun (then skip `dotenv`).
- Keep TypeScript **ESM** compatible, and avoid CommonJS requires.
- Favor additive, reversible edits; do not remove user logic.
- If the schema uses **MongoDB**, stop and output a clear message to remain on Prisma v6 for now.

---

## 0) Detect Context & Plan

1. Identify:
   - Package manager and scripts.
   - Database: Postgres, SQLite, MySQL, SQL Server (MongoDB = halt).
   - Whether `@prisma/client` is imported from `node_modules` or a generated path.
   - Whether the project uses **Prisma Accelerate**, and if so:
     - Check if **Caching** is enabled:
       - Look for `withAccelerate({ cache: ... })`
       - Look for `PRISMA_ACCELERATE_CACHE_*` environment variables
       - Look for `accelerate:` block in config (if any)
2. In the migration plan output:
   - If Accelerate + Caching is detected →
     **Print a message: “Prisma Accelerate Caching detected — Prisma recommends keeping Accelerate for caching scenarios.”**
   - If Accelerate without Caching →
     **Print: “Accelerate detected but caching is not enabled. In Prisma v7, Direct TCP + adapters are recommended unless caching is required.”**
   - If no Accelerate → continue normally.

> **Do not modify or remove Accelerate code paths. Only describe recommendations.**

---

## 1) Dependencies

- Upgrade/install:
  - Dev: `prisma@prev`, `tsx`, `dotenv` (skip if Bun).
  - Runtime: `@prisma/client@7`.
  - **One** database adapter that matches the datasource:
    - Postgres: `@prisma/adapter-pg`
    - SQLite: `@prisma/adapter-better-sqlite3`
    - MySQL/mariaDB: `@prisma/adapter-mariadb`
    - D1: `@prisma/adapter-d1`
    - PlanetScale: `@prisma/adapter-planetscale`
    - MSSQL: `@prisma/adapter-mssql`
    - CockroachDB: `@prisma/adapter-pg`
    - Neon: `@prisma/adapter-neon`

- **Do not remove Accelerate packages automatically.**
- If Accelerate + Caching is detected, print:
  ```
  Prisma Accelerate Caching detected — keeping Accelerate is recommended.
  ```
- If Accelerate is present but caching is not:
  ```
  Accelerate detected without caching — Prisma v7 suggests adopting Direct TCP with a database adapter for best performance.
  ```
- Eliminate no user code; only output informational guidance.

> Produce installation commands based on the repo’s package manager.

---

## 2) Prisma Schema Changes

- In `schema.prisma`:
  - `generator client`:

    ```diff
    - provider = "prisma-client-js"
    + provider = "prisma-client"
      output   = "./generated"
    ```

  - Remove any `previewFeatures = ["driverAdapters"]` and any `engineType` attributes.

  - Update the `datasource db` block:
    - **Goal:** keep the existing `provider` value, but **remove any `url = …` entry**.

    - Example (for illustration only — do not insert comments into the user's schema):
      - Before:

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

      - After:

        ```prisma
        datasource db {
          provider = "postgresql"
        }
        ```

    - Rules:
      - Preserve the existing `provider` value exactly as-is (e.g. `"postgresql"`, `"mysql"`, `"sqlite"`, etc.).
      - Remove only the `url = ...` line from the `datasource db` block.
      - Preserve any other properties on the datasource (for example: `shadowDatabaseUrl`, `relationMode`, `schemas`, `extensions`, `directUrl`, etc.).
      - Do **not** add explanatory comments into the schema; comments in this prompt are hints for you, not code to emit.

- After edits, run `prisma generate`.

---

## 3) Introduce prisma.config.ts

Create **prisma.config.ts** at repo root (or prisma.config.mjs), centralizing Prisma CLI config and env management:

```tsx
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "tsx prisma/seed.ts",
  },
  datasource: {
    // Prefer DIRECT TCP via DATABASE_URL
    url: env("DATABASE_URL"),
    // Optionally support shadow DB if present:
    // shadowDatabaseUrl: env('SHADOW_DATABASE_URL'),
  },
});
```

- Remove any prisma.seed from package.json (the config above replaces it).

---

## 4) ESM & TS Baseline - Ensure **package.json**:

```json
{
  "type": "module",
  "scripts": {
    "dev": "tsx src/index.ts",
    "generate": "prisma generate",
    "migrate": "prisma migrate dev",
    "build": "tsc -p tsconfig.json"
  }
}
```

- Ensure **tsconfig.json** supports ESM:

```json
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true
  }
}
```

---

## 5) Refactor Client Import & Construction

If Prisma Accelerate is detected:

- If caching is enabled → **preserve the existing Accelerate setup**.
- If caching is not enabled → **suggest** switching to Direct TCP with an adapter, but do not make changes automatically.

Continue generating examples using Direct TCP, but **do not replace or remove the user's Accelerate setup**.

---

## 6) Seeding Script Update - Ensure prisma/seed.ts uses the same **adapter** and **dotenv** import as runtime:

```tsx
import "dotenv/config";
import { PrismaClient } from "../generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! });
const prisma = new PrismaClient({ adapter });

// seed…
```

- Set seed command via prisma.config.ts (no package.json#prisma.seed).

---

## 7) Middleware → Extensions

- If prisma.$use middleware exists, inform users that the API has been removed

---

## 8) Accelerate Messaging

### 🟩 If Accelerate Caching is detected

```
Prisma Accelerate Caching detected.
Prisma v7 fully supports caching scenarios via Accelerate.
Your existing Accelerate setup will be preserved.
```

### 🟨 If Accelerate is present but caching is NOT detected

```
Prisma Accelerate detected without caching.

Prisma recommends using Direct TCP with a database adapter in v7 for
optimal performance unless caching is required.

Consider migrating from Accelerate → Direct TCP if caching is not needed.
(No code changes were applied automatically.)
```

### 🟦 If Accelerate is not detected at all

```
Direct TCP is the recommended default for Prisma v7.
Your project will be migrated accordingly using the appropriate adapter.
```

---

## 9) Scripts & CI

- Verify scripts:
  - "generate": "prisma generate"
  - "migrate": "prisma migrate dev"
  - "dev"/"start" run with ESM and ensure dotenv/config is effective.
- In CI, ensure Node **≥ 20.19** and TypeScript **≥ 5.4**.

---

## 10) Run & Verify

1. prisma generate → should succeed and emit client to ./generated.
2. prisma migrate dev → runs against DATABASE_URL (direct TCP).
3. tsx prisma/seed.ts → inserts sample record(s) cleanly.
4. App boot: instantiate PrismaClient with adapter; confirm queries work.
5. If **P1017 / connection** errors: - Confirm DATABASE_URL and network reachability. - Confirm import 'dotenv/config' executes early.
6. If **module resolution** errors: - Confirm "type": "module", ESM imports, and re-generate client.

---

## 11) CLI Flag Changes

### `--schema` and `--url` flags removed from `prisma db execute`

The `--schema` and `--url` flags have been removed from `prisma db execute`. Configure your database connection in `prisma.config.ts` instead.

**Before (v6):**

```bash
# Using --schema
prisma db execute --file ./script.sql --schema prisma/schema.prisma

# Using --url
prisma db execute --file ./script.sql --url "$DATABASE_URL"
```

**After (v7):**

```bash
prisma db execute --file ./script.sql
```

The database URL is now read from `prisma.config.ts`.

### `prisma migrate diff` options changed

Several options have been removed and replaced:

| Removed Option             | Replacement                     |
| -------------------------- | ------------------------------- |
| `--from-url`               | `--from-config-datasource`      |
| `--to-url`                 | `--to-config-datasource`        |
| `--from-schema-datasource` | `--from-config-datasource`      |
| `--to-schema-datasource`   | `--to-config-datasource`        |
| `--shadow-database-url`    | Configure in `prisma.config.ts` |

**Before (v6):**

```bash
prisma migrate diff \
  --from-url "$DATABASE_URL" \
  --to-schema schema.prisma \
  --script
```

**After (v7):**

```bash
prisma migrate diff \
  --from-config-datasource \
  --to-schema schema.prisma \
  --script
```

### Migration Action

- Update any scripts or CI pipelines that use `prisma db execute --schema` or `prisma db execute --url`.
- Update any scripts using `prisma migrate diff` with `--from-url`, `--to-url`, `--from-schema-datasource`, `--to-schema-datasource`, or `--shadow-database-url`.
- Configure your database connection in `prisma.config.ts` instead.

---

## Safety Checks & Edge Cases

- **MongoDB provider** detected → stop and recommend staying on Prisma 6 until v7 MongoDB support returns.
- **Multiple entrypoints** (workers, scripts, tests): apply the same client/adapter/dotenv pattern everywhere.
- **Typed SQL** or custom extensions: keep as-is; ensure they compile after client re-generation.
- Preserve existing output path if the project uses custom locations.

---

## 11) Mapped Enum Breaking Change

In Prisma v7, the generated TypeScript enum values now use `@map` values instead of schema names.

### Example

Given this schema:

```prisma
enum SuggestionStatus {
  PENDING  @map("pending")
  ACCEPTED @map("accepted")
  REJECTED @map("rejected")
}
```

**v6 generated enum:**

```ts
export const SuggestionStatus = {
  PENDING: "PENDING",
  ACCEPTED: "ACCEPTED",
  REJECTED: "REJECTED",
} as const;
```

**v7 generated enum:**

```ts
export const SuggestionStatus = {
  PENDING: "pending",
  ACCEPTED: "accepted",
  REJECTED: "rejected",
} as const;
```

### Known Bug (as of v7.2.0)

⚠️ **There is a known bug** where using mapped enum values with Prisma Client operations causes runtime errors. The TypeScript types expect mapped values, but the engine expects schema names. Track this at [GitHub #28591](https://github.com/prisma/orm/issues/28591).

### Temporary Workarounds

1. **Use schema names as string literals** (causes TS error but works at runtime):

   ```ts
   await prisma.suggestion.create({
     data: {
       status: "PENDING" as any, // Use schema name, not mapped value
     },
   });
   ```

2. **Remove `@map` from enum values** temporarily if you don't strictly need different database values:

   ```prisma
   // Before: with @map directives
   enum SuggestionStatus {
     PENDING  @map("pending")
     ACCEPTED @map("accepted")
     REJECTED @map("rejected")
   }

   // After: without @map directives
   enum SuggestionStatus {
     PENDING
     ACCEPTED
     REJECTED
   }
   ```

   With this change, both the schema names and the database values will be `PENDING`, `ACCEPTED`, and `REJECTED`.

### Migration Action

- Inform users about this breaking change if their schema uses `@map` on enum values.
- Warn about the current bug and suggest workarounds until it's fixed.

---

## Deliverables

- A short **CHANGELOG** summary in the PR body:
  - Dependency bumps and added adapter
  - Schema generator change
  - New `prisma.config.ts`
  - Runtime refactor to adapter + optional Accelerate messaging
  - ESM/TS config updates
  - Seed script updates
  - No automatic removal of Accelerate
  - CLI flag changes (`--schema` and `--url` removal from `db execute`, `migrate diff` option changes)
  - Mapped enum breaking change warning (if applicable)
````

## Related pages

- [`Astro + Prisma`](https://www.prisma.io/docs/ai/prompts/astro): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an Astro.js project
- [`Next.js + Prisma`](https://www.prisma.io/docs/ai/prompts/nextjs): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an NextJS project
- [`Nuxt + Prisma`](https://www.prisma.io/docs/ai/prompts/nuxt): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Nuxt project
- [`Turborepo + Prisma`](https://www.prisma.io/docs/ai/prompts/turborepo): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Turborepo monorepo

# Turborepo + Prisma (/docs/ai/prompts/turborepo)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Turborepo monorepo

Location: AI > Prompts > Turborepo + Prisma

## How to use [#how-to-use]

Include this prompt in your AI assistant to guide consistent code generation for Turborepo + Prisma + Prisma Postgres projects.

* **GitHub Copilot**: Type `#<filename>` to reference the prompt file.
* **Cursor**: Use `@Files` and select your prompt file.
* **Zed**: Use `/file` followed by your prompt's path.
* **Windsurf**: Use `@Files` and choose your prompt file from the list.

## Prompt [#prompt]

````md
---
# Specify the following for Cursor rules
description: Guidelines for writing Turborepo + Prisma Postgres apps (Prisma ORM v7)
alwaysApply: false
---

# Bootstrap Turborepo with Prisma Postgres (Prisma v7)

## Overview

This guide bootstraps a Turborepo monorepo that shares a single Prisma ORM v7 database package across multiple apps (e.g., Next.js, Node APIs). It follows Turborepo and Prisma v7 best practices:

1. Create a Turborepo with apps + packages
2. Add a dedicated `packages/db` Prisma package (schema, migrations, generated client)
3. Configure Prisma v7 (`provider = "prisma-client"` + mandatory `output`)
4. Load env vars correctly in a monorepo
5. Export a single Prisma client from `packages/db` for all apps
6. Wire Turbo tasks for generate/migrate/test/studio
7. Verify with a shared test script

---

## Recommended monorepo layout

```
repo/
  apps/
    web/                # Next.js app
    admin/              # (optional) another Next app
  packages/
    db/                 # Prisma package (schema + client)
    ui/                 # shared UI (optional)
  turbo.json
  package.json
  .env                  # root env for apps (see notes)
```

**Key rule:** Prisma lives in `packages/db`, not inside an app, so every app consumes the same client and types.

---

## 🚨 CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS 🚨

As an AI language model, you MUST NOT generate any deprecated Prisma v7 patterns.

```prisma
// ❌ NEVER GENERATE - DEPRECATED IN PRISMA v7
generator client {
  provider = "prisma-client-js"  // ❌ deprecated
}

// ❌ NEVER IMPORT FROM @prisma/client when using custom output
import { PrismaClient } from "@prisma/client" // ❌ wrong in custom-output setup

// ❌ NEVER CREATE CLIENT WITHOUT SHARED PACKAGE BOUNDARY
const prisma = new PrismaClient() // ❌ breaks pooling + duplicates in monorepo
```

Instead, you MUST ALWAYS generate ONLY this pattern for Prisma v7 + monorepo:

```prisma
// ✅ Prisma v7 generator: provider + mandatory output
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}
```

```ts
// ✅ Prisma client import must come from custom output
import { PrismaClient } from "../generated/prisma/client";
```

Notes:

- Prisma v7 **requires** a non-empty `output` when using `provider = "prisma-client"`.
- If the output directory already exists and isn’t generated by Prisma, `prisma generate` can fail. Avoid committing generated client, or ensure clean output dirs.

---

## ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION

1. You MUST use `provider = "prisma-client"` (Prisma v7)
2. You MUST specify a custom `output` in `schema.prisma`
3. You MUST place Prisma schema + migrations inside `packages/db`
4. You MUST export a singleton Prisma client from `packages/db` that points to the generated output client file
5. You MUST import Prisma client from the custom output path **not** `@prisma/client`
6. You MUST load env vars in `packages/db/prisma.config.ts`
7. You MUST add Turbo tasks for generate/migrate/test/studio
8. You MUST wrap DB calls in try/catch in app code
9. You MUST ensure Turbo task hashing includes `DATABASE_URL`
10. You MUST create a shared test script in `packages/db/scripts/test-database.ts`

---

## Install dependencies

At repo root:

```bash
# Turborepo
npm install turbo --save-dev

# Prisma v7
npm install prisma@prev tsx --save-dev
npm install @prisma/client@7 dotenv
```

If using Prisma Postgres:

```npm
npm install @prisma/adapter-pg
```

---

## Initialize Prisma inside `packages/db`

```bash
cd packages/db
npx prisma init
```

This creates:

```
packages/db/
  prisma/
    schema.prisma
  prisma.config.ts
```

---

## Prisma v7 config (`packages/db/prisma.config.ts`)

**CRITICAL:** load env vars at the top.

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },

  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

---

## Prisma schema (`packages/db/prisma/schema.prisma`)

```prisma
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
```

---

## Shared Prisma client singleton (`packages/db/src/client.ts`)

```ts
import { PrismaClient } from "../generated/prisma/client";

//Prisma Driver Adapter for Postgres
import { PrismaPg } from "@prisma/adapter-pg";

// Create a new Driver Adapter instance for PrismaPostgres
const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const globalForPrisma = globalThis as unknown as {
  prisma?: PrismaClient;
};

export const prisma = globalForPrisma.prisma ?? new PrismaClient({ adapter });

if (process.env.NODE_ENV !== "production") {
  globalForPrisma.prisma = prisma;
}

export default prisma;
```

---

## Export DB package API (`packages/db/src/index.ts`)

```ts
export { prisma } from "./client";
export * from "../generated/prisma";
```

And in `packages/db/package.json`:

```json
{
  "name": "@repo/db",
  "private": true,
  "main": "src/index.ts",
  "types": "src/index.ts",
  "scripts": {
    "db:generate": "prisma generate",
    "db:push": "prisma db push",
    "db:migrate": "prisma migrate dev",
    "db:studio": "prisma studio",
    "db:test": "tsx scripts/test-database.ts"
  }
}
```

---

## Root Turbo pipeline (`turbo.json`)

```json
{
  "globalEnv": ["DATABASE_URL"],
  "tasks": {
    "dev": {
      "cache": false,
      "persistent": true,
      "dependsOn": ["^db:generate"]
    },
    "build": {
      "dependsOn": ["^db:generate"],
      "outputs": [".next/**", "dist/**"]
    },
    "db:generate": {
      "cache": false
    },
    "db:migrate": {
      "cache": false
    },
    "db:studio": {
      "cache": false
    },
    "db:test": {
      "cache": false,
      "dependsOn": ["db:generate"]
    }
  }
}
```

---

## Root scripts (`package.json`)

```json
{
  "scripts": {
    "dev": "turbo dev",
    "build": "turbo build",
    "lint": "turbo lint",
    "db:generate": "turbo run db:generate",
    "db:push": "turbo run db:push",
    "db:migrate": "turbo run db:migrate",
    "db:studio": "turbo run db:studio",
    "db:test": "turbo run db:test"
  }
}
```

---

## Shared test script (`packages/db/scripts/test-database.ts`)

```ts
import "dotenv/config";
import prisma from "../src/client";

async function testDatabase() {
  console.log("🔍 Testing Prisma Postgres connection...\n");

  try {
    console.log("✅ Connected to database!");

    console.log("\n📝 Creating a test user...");
    const newUser = await prisma.user.create({
      data: {
        email: "demo@example.com",
        name: "Demo User",
      },
    });
    console.log("✅ Created user:", newUser);

    console.log("\n📋 Fetching all users...");
    const allUsers = await prisma.user.findMany();
    console.log(`✅ Found ${allUsers.length} user(s):`);
    allUsers.forEach((user) => {
      console.log(`   - ${user.name} (${user.email})`);
    });

    console.log("\n🎉 All tests passed! Your database is working.\n");
  } catch (error) {
    console.error("❌ Error:", error);
    process.exit(1);
  } finally {
    await prisma.$disconnect();
  }
}

testDatabase();
```

---

## Using Prisma in apps (example: `apps/web` Next.js)

In any app, add a dependency on `@repo/db` (workspace):

```json
{
  "dependencies": {
    "@repo/db": "*"
  }
}
```

Then in server-side code:

```ts
import { prisma } from "@repo/db";
import { NextResponse } from "next/server";

export async function GET() {
  try {
    const users = await prisma.user.findMany();
    return NextResponse.json(users);
  } catch (e) {
    console.error(e);
    return NextResponse.json({ error: "Failed to fetch users" }, { status: 500 });
  }
}
```

---

## Complete setup workflow

1. **Create Turborepo** (or use existing):

   ```npm
   npx create-turbo@latest
   ```

2. **Add `packages/db`**, install Prisma v7 deps.

3. **Initialize Prisma in `packages/db`**:

   ```bash
   cd packages/db
   npx prisma init
   ```

4. **Update `prisma.config.ts`** to include `import "dotenv/config"`.

5. **Update schema** with Prisma v7 generator + output.

6. **Create `src/client.ts`** singleton and export via `src/index.ts`.

7. **Wire Turbo tasks** in `turbo.json`.

8. **Add `.env`** at root **and/or** `packages/db/.env`.

9. **Push schema**:

   ```bash
   npm run db:push
   ```

10. **Test**:

    ```bash
    npm run db:test
    ```

11. **Start dev**:
    ```bash
    npm run dev
    ```

---

## AI Model verification checklist

Before generating any code, verify:

1. `provider = "prisma-client"`?
2. `output   = "../src/generated/prisma"` present?
3. All Prisma files in `packages/db`?
4. Client imports from `../generated/prisma/client` (or via `@repo/db`)?
5. `import "dotenv/config"` in `packages/db/prisma.config.ts`?
6. Turbo tasks depend on `db:generate`?
7. `DATABASE_URL` listed in `globalEnv`?
8. All DB ops wrapped in try/catch?
9. Test script exists in `packages/db/scripts/test-database.ts`?

No exceptions. If any check fails, STOP and FIX.

---

## AI MODEL RESPONSE TEMPLATE (UPDATED FOR TURBOREPO + PRISMA v7)

When asked about implementing Prisma v7 inside a Turborepo monorepo (with any framework such as Next.js, Node, etc.), you MUST:

1. **Assume Prisma lives in a shared package**
   - Always place schema, config, and migrations in `packages/db`.
   - Never suggest adding Prisma directly into an app unless the user explicitly says they don’t want a shared package.

2. **Use only Prisma v7 generator patterns**
   - The schema MUST include:
     ```prisma
     generator client {
       provider = "prisma-client"
       output   = "./generated/prisma"
     }
     ```
   - Never use `prisma-client-js`.

3. **Use correct import paths for custom output**
   - Any PrismaClient import MUST come from the generated output:
     ```ts
     import { PrismaClient } from "./generated/prisma/client";
     ```
   - If importing from apps, you MUST import via the package boundary:
     ```ts
     import { prisma } from "@repo/db";
     ```
   - Never import from `@prisma/client` in this setup.

4. **Always include a shared singleton client in `packages/db`**
   - Provide a `packages/db/src/client.ts` with global caching for dev hot-reload.
   - If Accelerate is requested or implied, use `$extends(withAccelerate())`.
   - If Accelerate is not requested, omit it.

5. **Always load environment variables properly**
   - `packages/db/prisma.config.ts` MUST start with `import "dotenv/config"`.
   - Use `process.env.DATABASE_URL` in runtime code.
   - Remind users that `.env` should exist at root and/or `packages/db`.

6. **Always wire Turbo dependencies**
   - Turbo tasks `dev` and `build` MUST depend on `^db:generate`.
   - `DATABASE_URL` MUST be listed in `globalEnv` to ensure correct task hashing.

7. **Provide correct repo-level scripts**
   - Root scripts should proxy to Turbo (`turbo run db:*`).
   - The Prisma package `packages/db` should own `db:generate`, `db:migrate`, `db:studio`, and `db:test`.

8. **Include a real verification step**
   - Provide (or reference) `packages/db/scripts/test-database.ts`.
   - Ensure it imports dotenv and disconnects Prisma on completion.

9. **Use safe runtime patterns**
   - All DB calls in apps MUST be wrapped in try/catch.
   - In Next.js App Router examples, use server-only imports and return `NextResponse`.

10. **Self-verify before replying**

- Re-check all items in the “AI Model verification checklist.”
- If any item is missing or incorrect, STOP and FIX before responding.

Remember: There are NO exceptions to these rules. Every requirement is mandatory for a correct Turborepo + Prisma v7 setup.
````

## Running the application [#running-the-application]

Run the application locally:

**1. Generate the Prisma Client:**

```bash
npx turbo db:generate
```

**2. View your database in Prisma Studio:**

  

#### bun

```bash
bunx turbo db:studio
```

#### pnpm

```bash
pnpm dlx turbo db:studio
```

#### yarn

```bash
yarn dlx turbo db:studio
```

#### npm

```bash
npx turbo db:studio
```

Prisma Studio opens at `localhost:5555` where you can inspect your `User` table and see the test user stored in your database.

## Related pages

- [`Astro + Prisma`](https://www.prisma.io/docs/ai/prompts/astro): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an Astro.js project
- [`Migrate to Prisma v7`](https://www.prisma.io/docs/ai/prompts/prisma-7): Step-by-step guide for migration your app to use the version 7 of Prisma ORM
- [`Next.js + Prisma`](https://www.prisma.io/docs/ai/prompts/nextjs): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an NextJS project
- [`Nuxt + Prisma`](https://www.prisma.io/docs/ai/prompts/nuxt): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Nuxt project

# ChatGPT (/docs/ai/tools/chatgpt)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to add the Prisma MCP server to ChatGPT to manage your databases and Compute deployments.

Location: AI > AI Tools > ChatGPT

Connect [ChatGPT](https://openai.com/chatgpt) to the Prisma MCP server to manage Prisma Postgres databases, Prisma Compute deployments, and Object Storage.

This guide explains how to add the Prisma MCP server to ChatGPT and use it through natural language prompts.

## Features of the Prisma MCP server [#features-of-the-prisma-mcp-server]

With the Prisma MCP server connected, you can manage resources in your selected workspace from the chat interface. The server supports:

* **Database management**: Create, list, and delete your Prisma Postgres databases.
* **Connection strings**: Generate, list, and revoke database connection strings.
* **Backup and recovery**: List automated database backups and restore a backup into a new database.
* **Schema and data interaction**: Execute SQL queries and introspect your database schema to understand its structure.
* **Workspace information**: Fetch details about your Prisma workspace.
* **Compute deployments**: List apps and builds, read runtime logs, manage existing deployments, and set environment variables.
* **[Composer projects](https://www.prisma.io/docs/composer)**: Inspect how your services connect and get links to the project and apps in Prisma Console.
* **Object Storage**: Create, list, and delete buckets, and manage bucket access keys.

See the [full tool list](https://www.prisma.io/docs/ai/mcp-tools) and [sample prompts](https://www.prisma.io/docs/ai/tools/mcp-server#sample-prompts).

## Prerequisites [#prerequisites]

* A [Prisma account](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=ai) and access to a workspace.
* Access to ChatGPT's Developer mode. Check the [OpenAI documentation](https://developers.openai.com/api/docs/guides/developer-mode) for supported plans and access requirements.

## Enable Developer mode in ChatGPT [#enable-developer-mode-in-chatgpt]

1. Open [ChatGPT](https://chatgpt.com) and go to **Settings**.
2. Select **Security and login** and turn on **Developer mode**.

## Add the Prisma MCP server [#add-the-prisma-mcp-server]

1. Open [ChatGPT Plugins](https://chatgpt.com/plugins&#x29; and select the &#x2A;*+** button.
2. Enter `https://mcp.prisma.io/mcp` as the MCP server URL, name the connection `Prisma`, and select **OAuth** authentication.
3. Complete the connection prompts. When asked to authorize access, sign in with Prisma, select a workspace, and approve access.
4. Finish creating the plugin. It should appear in [your personal plugins](https://chatgpt.com/plugins?view=personal).

These steps follow [OpenAI's plugin setup guide](https://developers.openai.com/plugins/quickstart). If your ChatGPT interface differs, use that guide for the current navigation.

## Using the Prisma MCP server [#using-the-prisma-mcp-server]

1. Open `Prisma` in [your personal plugins](https://chatgpt.com/plugins?view=personal&#x29; and select &#x2A;*+** to install it.
2. Return to [ChatGPT](https://chatgpt.com), switch from **Chat** to **Work**, and start a new chat.
3. Type `@`, select `Prisma`, and ask: "List the databases in my Prisma workspace."

ChatGPT should call the database-list tool and return the databases in the workspace you selected, or an empty list if it has none.

Review the workspace and target resources before approving changes. Some tools can permanently delete data or stop a live deployment.

## Related pages

- [`Agent Skills`](https://www.prisma.io/docs/ai/tools/skills): Give your AI coding agent up-to-date Prisma knowledge with installable skills
- [`Codex`](https://www.prisma.io/docs/ai/tools/codex): Learn how to install the Prisma Codex plugin and use Prisma MCP from Codex
- [`Cursor`](https://www.prisma.io/docs/ai/tools/cursor): Learn tips and best practices for using Prisma ORM with the Cursor AI code editor
- [`GitHub Copilot`](https://www.prisma.io/docs/ai/tools/github-copilot): Learn about the features available with GitHub Copilot and Prisma ORM, plus best practices and tips
- [`MCP server`](https://www.prisma.io/docs/ai/tools/mcp-server): Manage Prisma Postgres databases, Prisma Compute deployments, and Object Storage with the Prisma MCP server.

# Codex (/docs/ai/tools/codex)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to install the Prisma Codex plugin and use Prisma MCP from Codex

Location: AI > AI Tools > Codex

[Codex](https://developers.openai.com/codex/) is an AI coding agent from OpenAI. You can use the Prisma Codex plugin to give Codex Prisma-specific guidance and connect it to the Prisma MCP server for Prisma Postgres workflows.

The Prisma Codex plugin includes:

* Prisma CLI guidance
* Prisma Client API guidance
* Database setup guidance
* Prisma Postgres guidance
* Prisma ORM upgrade guidance
* The remote Prisma MCP server configuration

## Install the Prisma Codex plugin [#install-the-prisma-codex-plugin]

Add the Prisma plugin marketplace to Codex:

```bash title="Terminal"
codex plugin marketplace add prisma/codex-plugin
```

Then restart Codex and install the plugin:

1. Open the Codex plugin directory.
2. Select the `Prisma` marketplace.
3. Install the `Prisma` plugin.

If your Codex CLI does not recognize the `plugin marketplace add` command, update Codex and try again.

## Prisma MCP server [#prisma-mcp-server]

The plugin configures the official remote Prisma MCP server:

```json title="Prisma MCP server"
{
  "mcpServers": {
    "prisma": {
      "type": "http",
      "url": "https://mcp.prisma.io/mcp"
    }
  }
}
```

When Codex first uses the Prisma MCP server, it authenticates with Prisma Console and asks you to choose the workspace Codex can access.

With the Prisma MCP server, Codex can help you:

* List Prisma Postgres databases in your workspace.
* Create Prisma Postgres databases.
* List automated backups and restore them into new databases.
* Create and manage connection strings.
* Execute SQL queries.
* Introspect database schemas.
* Manage Prisma Compute deployments, read app logs, and set environment variables.
* Manage Object Storage buckets and access keys.

## Example prompts [#example-prompts]

After installing the plugin, try prompts like:

```text
Set up Prisma ORM in this project with the right database adapter.
```

```text
Use Prisma MCP to list my Prisma Postgres databases.
```

```text
Inspect this project and upgrade it to Prisma ORM 7.
```

```text
Use Prisma MCP to inspect my database schema and plan a migration.
```

## Safety [#safety]

Prisma ORM includes safety checks for destructive commands run through AI coding agents. For example, Prisma blocks destructive commands such as `prisma migrate reset --force` unless the AI agent asks for explicit user consent and passes that consent back to Prisma.

This helps prevent accidental data loss when using Codex or another AI agent with Prisma projects.

## Related pages

- [`Agent Skills`](https://www.prisma.io/docs/ai/tools/skills): Give your AI coding agent up-to-date Prisma knowledge with installable skills
- [`ChatGPT`](https://www.prisma.io/docs/ai/tools/chatgpt): Learn how to add the Prisma MCP server to ChatGPT to manage your databases and Compute deployments.
- [`Cursor`](https://www.prisma.io/docs/ai/tools/cursor): Learn tips and best practices for using Prisma ORM with the Cursor AI code editor
- [`GitHub Copilot`](https://www.prisma.io/docs/ai/tools/github-copilot): Learn about the features available with GitHub Copilot and Prisma ORM, plus best practices and tips
- [`MCP server`](https://www.prisma.io/docs/ai/tools/mcp-server): Manage Prisma Postgres databases, Prisma Compute deployments, and Object Storage with the Prisma MCP server.

# Cursor (/docs/ai/tools/cursor)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn tips and best practices for using Prisma ORM with the Cursor AI code editor

Location: AI > AI Tools > Cursor

[Cursor](https://www.cursor.com/) is an AI code editor with an agent, inline edits, and project rules. This guide covers how to use it with Prisma to:

* Configure the Prisma MCP server for database workflows.
* Define project-specific Prisma guidance with Project Rules or `AGENTS.md`.
* Use Cursor's context-aware capabilities.
* Generate schemas, queries, and seed data tailored to your database.

> [!NOTE]
> While this guide is focused on Cursor, these patterns should work with any AI editor. [Let us know on X](https://pris.ly/x?utm_source=docs\&utm_medium=inline_text) if you'd like us to create guides for your preferred tool.

## Prisma Plugin [#prisma-plugin]

The [Prisma plugin for Cursor](https://cursor.com/marketplace/prisma) provides integration with the Prisma MCP server, various skills for working with Prisma ORM and Prisma Postgres, and automation for database development.

[Install the Prisma plugin for Cursor](https://cursor.com/marketplace/prisma)

## Prisma MCP server [#prisma-mcp-server]

Prisma provides its own [Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP) server that lets you manage Prisma Postgres databases, inspect schemas, and execute SQL queries. Learn more about how you can add it to [Cursor](https://www.prisma.io/docs/ai/tools/mcp-server#cursor). You can also add the Prisma MCP server to Cursor using the [one-click installation](https://docs.cursor.com/context/model-context-protocol#one-click-installation) by clicking on the following link:

[Install MCP Server](https://pris.ly/cursor-prisma-mcp-web)

This will prompt you to open the Cursor app in your browser. Once opened, you'll be guided to install the Prisma MCP server directly into your Cursor configuration.

## Define project-specific rules [#define-project-specific-rules]

[Cursor Rules](https://docs.cursor.com/context/rules) provide persistent instructions to Cursor's Agent and Inline Edit. For Prisma projects, prefer one of these current options:

* **Project Rules**: Create a version-controlled `.cursor/rules/prisma.mdc` file for structured rules.
* **`AGENTS.md`**: Create an `AGENTS.md` file in the project root for simple, readable agent instructions.

The legacy `.cursorrules` file is still supported by Cursor, but Cursor recommends Project Rules for new projects.

Below is a concise Project Rule you can add to `.cursor/rules/prisma.mdc`:

```markdown title=".cursor/rules/prisma.mdc"
---
description: Prisma ORM and Prisma Postgres guidance
globs: **/*.{ts,tsx,js,jsx,prisma,json}
alwaysApply: false
---

- Prefer current Prisma documentation from https://www.prisma.io/docs and the Prisma LLM feed at https://pris.ly/llms.txt.
- For Prisma ORM v7 projects, use the `prisma-client` generator with an explicit `output`.
- Keep database connection URLs in `prisma.config.ts`; do not add `url = env("DATABASE_URL")` to the Prisma schema unless the project is intentionally using older Prisma ORM conventions.
- Use `prisma.config.ts` with `datasource.url = env("DATABASE_URL")` for Prisma CLI commands.
- Instantiate Prisma Client with the correct driver adapter for the database, for example `@prisma/adapter-pg` for PostgreSQL.
- When creating or managing Prisma Postgres databases, prefer the Prisma MCP server tools instead of guessing CLI/API steps.
- Before changing Prisma setup, inspect `package.json`, `prisma.config.*`, `schema.prisma`, existing generated client imports, and the installed Prisma version.
- Preserve existing Prisma Accelerate usage unless explicitly asked to migrate it.

## Prisma application best practices

- Validate inputs at API boundaries before calling Prisma Client.
- Use `select` or scoped `include` to avoid over-fetching data.
- Use transactions for multi-step writes that must succeed or fail together.
- Handle known Prisma errors intentionally, especially constraint and validation errors.
- Prefer integration tests against the same database provider used in production when testing Prisma behavior.
- Mock Prisma Client only for isolated unit tests where database behavior is not under test.
- Review generated migrations before applying them to shared or production environments.
- Avoid exposing database-specific errors directly to end users.
- Keep Prisma-related database access separate from unrelated business logic when it improves maintainability.
```

For a simpler repo-wide setup, you can paste the same guidance into `AGENTS.md`.

## Using Cursor's context-aware capabilities [#using-cursors-context-aware-capabilities]

Cursor's [context-aware](https://docs.cursor.com/context/) capabilities let you add specific websites, files, folders or documentation to improve its understanding of your project. By adding your `schema.prisma` file as context, you enable Cursor to generate more accurate queries, tests, and seed data based on your database schema.

### Add Prisma docs `llm.txt` file as `@Docs` context [#add-prisma-docs-llmtxt-file-as-docs-context]

To improve Cursor's understanding of Prisma-related suggestions in your project, include the [`/llms.txt`](https://llmstxt.org/) markdown file as context. The file gives an overview of Prisma with links to the detailed documentation, formatted for LLM processing. Open the [url](https://pris.ly/llms.txt) and add it as a `@Docs` resource in your Cursor configuration.

### Adding additional Prisma documentation [#adding-additional-prisma-documentation]

Cursor may already have Prisma documentation available in its built-in docs context, but external documentation indexes can lag behind the latest Prisma release. Add the Prisma LLM feed explicitly when you need Cursor to follow the current recommended setup.

To stay updated with the latest changes or incorporate additional context, add these resources as `@Docs` context:

* [Prisma Changelog](https://www.prisma.io/changelog) for updates and new features.
* [Prisma Blog](https://www.prisma.io/blog) for practical guides and best practices.

To learn how to add and manage documentation context, visit the [Cursor documentation](https://docs.cursor.com/context/@-symbols/@-docs#docs).

### Using schema as context [#using-schema-as-context]

Add your `schema.prisma` file (or the entire codebase) as context using the [`@Files`](https://docs.cursor.com/context/@-symbols/@-files) syntax before requesting queries, tests, or seed scripts. This allows Cursor to generate precise, schema-driven outputs such as queries, tests, and seed data. For example, in [Cursor Chat](https://docs.cursor.com/chat/overview), you can include your schema by typing `@Files` followed by adding your `schema.prisma` file.

## Generating Prisma Schema [#generating-prisma-schema]

Cursor can generate a Prisma schema from a description. The more specific the prompt (models, fields, relations, defaults), the closer the result matches what you need. Here is an example prompt and its result:

> [!NOTE]
> If you run the prompts below, you may receive a different outputs because LLMs produce non-deterministic responses.

  

#### Prompt to generate Prisma schema

```text
"Create a Prisma schema for a SaaS app using PostgreSQL as a provider with `User`, `Organization`, and `Subscription` models, ensuring all models include `createdAt` and `updatedAt` DateTime fields with defaults, a soft-delete `deletedAt` field, and proper relationships between entities."
```

#### Result

```prisma title="schema.prisma" 
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider = "postgresql"
}

model User {
  id Int @id @default(autoincrement())
  email String @unique
  name String
  password String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  deletedAt DateTime?
  organization Organization @relation(fields: [organizationId], references: [id])
  organizationId Int
  role UserRole @default(MEMBER)
}

model Organization {
  id Int @id @default(autoincrement())
  name String
  slug String @unique
  subscription Subscription?
  users User[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  deletedAt DateTime?
}

model Subscription {
  id Int @id @default(autoincrement())
  organization Organization @relation(fields: [organizationId], references: [id])
  organizationId Int @unique
  plan SubscriptionPlan
  status SubscriptionStatus @default(ACTIVE)
  startDate DateTime
  endDate DateTime?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  deletedAt DateTime?
}

enum UserRole {
  ADMIN
  MEMBER
}

enum SubscriptionPlan {
  FREE
  BASIC
  PREMIUM
  ENTERPRISE
}

enum SubscriptionStatus {
  ACTIVE
  CANCELED
  EXPIRED
  PAST_DUE
}

```

## Generating Prisma queries [#generating-prisma-queries]

Cursor can write queries against your Prisma schema. State the fields to include, the conditions to apply, and the relations to traverse, and Cursor generates a query that type-checks against your schema. Here is an example prompt and its resulting query:

  

#### Prompt to generate a database query

```text
"Generate a query to retrieve all User records associated with an Organization that has an `active` Subscription, while excluding any records where the deletedAt field is set."
```

#### Result

```typescript
const activeUsers = await prisma.user.findMany({
  where: {
    deletedAt: null,
    organization: {
      deletedAt: null,
      subscription: {
        deletedAt: null,
        status: "ACTIVE",
      },
    },
  },
  include: {
    organization: {
      include: {
        subscription: true,
      },
    },
  },
  orderBy: {
    createdAt: "desc",
  },
  skip: 0,
  take: 10,
});
```

## Creating seed files with Cursor [#creating-seed-files-with-cursor]

Cursor can generate seed scripts that populate your database with realistic data, including the relations defined in your schema. Here is an example prompt and its resulting seed script:

  

#### Prompt to seed the database

```text
"Generate code to populate the Prisma schema with realistic data for the User, Organization, and Subscription models, ensuring all necessary fields are included."
```

#### Result

```ts title="seed.ts" 
import {
  PrismaClient,
  UserRole,
  SubscriptionPlan,
  SubscriptionStatus,
} from "../prisma/generated/client";

const prisma = new PrismaClient();

async function main() {
  // Clear existing data
  await prisma.user.deleteMany();
  await prisma.subscription.deleteMany();
  await prisma.organization.deleteMany();

  const organizations = [
    {
      name: "Tech Innovators",
      slug: "tech-innovators",
      subscription: {
        plan: SubscriptionPlan.ENTERPRISE,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-01-01"),
      },
      users: [
        {
          name: "Emma Thompson",
          email: "emma@techinnovators.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Michael Chen",
          email: "michael@techinnovators.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Digital Solutions",
      slug: "digital-solutions",
      subscription: {
        plan: SubscriptionPlan.PREMIUM,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-01-15"),
      },
      users: [
        {
          name: "Sarah Wilson",
          email: "sarah@digitalsolutions.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "James Miller",
          email: "james@digitalsolutions.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Cloud Systems",
      slug: "cloud-systems",
      subscription: {
        plan: SubscriptionPlan.BASIC,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-02-01"),
      },
      users: [
        {
          name: "David Garcia",
          email: "david@cloudsystems.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Lisa Wang",
          email: "lisa@cloudsystems.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Data Analytics Co",
      slug: "data-analytics",
      subscription: {
        plan: SubscriptionPlan.PREMIUM,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-01-10"),
      },
      users: [
        {
          name: "Alex Johnson",
          email: "alex@dataanalytics.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Rachel Kim",
          email: "rachel@dataanalytics.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Smart Solutions",
      slug: "smart-solutions",
      subscription: {
        plan: SubscriptionPlan.FREE,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-02-15"),
      },
      users: [
        {
          name: "Daniel Brown",
          email: "daniel@smartsolutions.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Maria Rodriguez",
          email: "maria@smartsolutions.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
  ];

  for (const org of organizations) {
    const createdOrg = await prisma.organization.create({
      data: {
        name: org.name,
        slug: org.slug,
        subscription: {
          create: {
            plan: org.subscription.plan,
            status: org.subscription.status,
            startDate: org.subscription.startDate,
          },
        },
      },
    });

    for (const user of org.users) {
      await prisma.user.create({
        data: {
          name: user.name,
          email: user.email,
          password: user.password,
          role: user.role,
          organizationId: createdOrg.id,
        },
      });
    }
  }

  console.log("Seed data created successfully");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

## Using the Prisma VS Code extension to manage your database [#using-the-prisma-vs-code-extension-to-manage-your-database]

The [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) also works in Cursor. It provides a UI for managing local and remote [Prisma Postgres](https://www.prisma.io/docs/postgres) instances: view, create, and delete instances, push local databases to the cloud, and visualize your schema.

### Database management UI [#database-management-ui]

With its built-in database management interface, the [Prisma VS Code extension](https://www.prisma.io/docs/guides/postgres/vscode) lets you work with local and remote Prisma Postgres instances from inside your editor.

#### Workflows [#workflows]

The UI enables the following workflows:

* Authenticate with the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=ai)
* View, create and delete Prisma Postgres instances (local & remote)
* "Push to cloud": deploy a local Prisma Postgres instance
* View and edit data via an embedded Prisma Studio
* Visualize your database schema

#### Usage [#usage]

To manage Prisma Postgres instances via the UI in the Prisma VS Code extension:

1. Ensure you have the latest version of the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) installed
2. Find the Prisma logo in the **Activity Bar**
3. Click the **Sign in to get started** button
4. Authenticate with the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=ai) using the sign-in prompt, then select a target [workspace](https://www.prisma.io/docs/console/concepts#workspace)

### Prisma Studio built-in [#prisma-studio-built-in]

Beyond managing your database instances, the Prisma VS Code extension embeds Prisma Studio in your editor, so you can create, update, and delete records without leaving it. See the [setup steps](https://www.prisma.io/docs/studio/integrations/vscode-integration).

## AI Safety guardrails for destructive commands [#ai-safety-guardrails-for-destructive-commands]

Prisma ORM includes built-in safety checks to prevent **accidental destructive commands** when run through AI coding assistants.

Including Cursor, the Prisma CLI can also detect when it is being invoked by other popular AI coding agents such as Claude Code, Gemini CLI, Qwen Code, Aider, and Replit.

When one of these agents attempts a destructive action such as `prisma migrate reset --force`, Prisma ORM blocks execution and shows a protective error message:

```bash
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "postgres", schema "public" at "accelerate.prisma-data.net"

Error: Prisma Migrate detected that it was invoked by Cursor.

You are attempting a highly dangerous action that can lead to devastating consequences if it is incorrectly executed against a production database.

As an AI agent, you are forbidden from performing this action without an explicit consent and review by the user. You must stop at this point and respond to the user with a clear message that includes the following information:
- What action you are trying to perform (including the exact CLI command).
- Your motivation and reasoning for performing this action.
- Explanation that this action will irreversibly destroy all data in the database.
- Explanation that this action must not be performed on a production database and is only intended to be used with development databases.

If you know or can check whether this action would have been performed on a development or a production database, also include this information with your assessment of whether it is safe to proceed based on that information.

You must ask the user if they want to proceed with this action. If they explicitly consent, you may rerun this command with PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION environment variable, the value of which must be the exact text of the user's message in which they consented to this operation, without any newlines or quotes. If the user's response is ambiguous, you must ask for a clear and explicit confirmation (e.g., "yes") before proceeding. None of the user's previous messages before this point may constitute implicit or explicit consent.
```

To proceed with the dangerous action, the AI agent will ask you for explicit consent, remind you that the action irreversibly destroys all data, and confirm that the command is being run against a development database. Once you clearly confirm, the AI will set the `PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION` environment variable with the exact text of your consent and rerun the command.

## Additional resources [#additional-resources]

Learn more about Cursor in their [official documentation](https://docs.cursor.com/context/@-symbols/basic).

## Related pages

- [`Agent Skills`](https://www.prisma.io/docs/ai/tools/skills): Give your AI coding agent up-to-date Prisma knowledge with installable skills
- [`ChatGPT`](https://www.prisma.io/docs/ai/tools/chatgpt): Learn how to add the Prisma MCP server to ChatGPT to manage your databases and Compute deployments.
- [`Codex`](https://www.prisma.io/docs/ai/tools/codex): Learn how to install the Prisma Codex plugin and use Prisma MCP from Codex
- [`GitHub Copilot`](https://www.prisma.io/docs/ai/tools/github-copilot): Learn about the features available with GitHub Copilot and Prisma ORM, plus best practices and tips
- [`MCP server`](https://www.prisma.io/docs/ai/tools/mcp-server): Manage Prisma Postgres databases, Prisma Compute deployments, and Object Storage with the Prisma MCP server.

# GitHub Copilot (/docs/ai/tools/github-copilot)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn about the features available with GitHub Copilot and Prisma ORM, plus best practices and tips

Location: AI > AI Tools > GitHub Copilot

GitHub Copilot is an AI coding assistant. With the GitHub Copilot extension in your editor, you can:

* Get Prisma-aware code suggestions as you edit your schema or invoke the client.
* Chat with Copilot about modeling patterns, troubleshoot queries, or explore migration strategies.
* Run common Prisma CLI commands (e.g. `prisma migrate dev`, `prisma db push`) via Copilot's command-palette interface.
* Scaffold Prisma schema models and generate Prisma Client code and run migrations directly from the Copilot chat interface.

GitHub Copilot allows you to query the official docs via the [**Prisma for GitHub Copilot** extension](https://github.com/apps/prisma-for-github-copilot) and also perform automated [actions in VS Code agent mode](https://www.prisma.io/docs/guides/postgres/vscode#agent-mode), such as scaffolding a Prisma schema, running seed scripts, and creating a Prisma Postgres database.

## Query Prisma docs with the Prisma for GitHub Copilot extension [#query-prisma-docs-with-the-prisma-for-github-copilot-extension]

The [Prisma for GitHub Copilot extension](https://github.com/apps/prisma-for-github-copilot) lets you fetch Prisma documentation directly in GitHub Copilot Chat. You can look up schema syntax, client methods, migration commands, and more from your editor.

### How to enable the extension [#how-to-enable-the-extension]

1. Install the **Prisma for Copilot** from the GitHub Marketplace.
2. Ensure [GitHub Copilot Chat is installed](https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/asking-github-copilot-questions-in-your-ide) and active in your code editor.
3. Open a file in your workspace and launch Copilot Chat.
4. In chat, prefix your question with the `@prisma-for-copilot` keyword:

```
@prisma-for-copilot How do I define a one-to-many relation?
```

1. Install the [Prisma for GitHub Copilot](https://github.com/apps/prisma-for-github-copilot) extension.
2. Open your IDE.
3. Install the [GitHub Copilot Chat extension](https://docs.github.com/en/copilot/managing-copilot/configure-personal-settings/installing-the-github-copilot-extension-in-your-environment).
4. Open Copilot Chat and switch to [**Ask** mode](https://code.visualstudio.com/docs/copilot/chat/chat-ask-mode).
5. Ask: "`@prisma-for-github-copilot` How do I define a one-to-many relation?" (If the `@prisma-for-github-copilot` namespace doesn't show up after a few seconds, reload the chat.)
6. When prompted, authorize the Prisma app in your browser, then return to the chat.
7. After returning to the chat, resend the question.
8. Copilot returns the answer pulled straight from the Prisma docs.

## Use GitHub Copilot's agent features [#use-github-copilots-agent-features]

GitHub Copilot Chat offers an **Agent** mode in VS Code that can run Prisma commands. You can use the agent chat to:

* Run and inspect migrations.
* Generate Prisma Client code.
* Create a new Prisma Postgres database and update your `.env` file.

You can type `Create a database named test-db and add its connection string to the .env file.` in the Copilot chat, and it will automatically create a new database named `test-db` and add the connection string to your `.env` file. To learn more about this, visit our [VS Code agent mode documentation](https://www.prisma.io/docs/guides/postgres/vscode#agent-mode).

## Customize GitHub Copilot with `copilot-instructions.md` [#customize-github-copilot-with-copilot-instructionsmd]

You can tailor Copilot Chat's behavior in your repository by [adding a `.github/copilot-instructions.md` file](https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot). This file injects your guidelines into every Copilot Chat session.

**Example `.github/copilot-instructions.md` for Prisma**

````text
# GitHub Copilot Instructions for Prisma Workspace

## General Guidelines

1. **Language**: English only.
2. **Types**: Declare explicit types; avoid `any`.
3. **Comments**: Use JSDoc for public methods and classes.
4. **Exports**: One export per file.
5. **Naming**:

   * **Classes/interfaces** → `PascalCase`
   * **Variables/functions** → `camelCase`
   * **Files/directories** → `kebab-case`
   * **Constants** → `UPPERCASE`
   * **Boolean flags** → verb-based (e.g., `isLoading`)

---

## Prisma-Specific Guidelines

### 1. Data Modeling

* **Domain-driven model names**: keep them singular (e.g. `User`, `OrderItem`).
* **Field naming**: use `camelCase` for fields (e.g. `createdAt`, `deletedAt`).
* **IDs & keys**:

  ```prisma
  model Post {
    id    Int    @id @default(autoincrement())
    uuid  String @unique @default(uuid())
  }
  /```
* **Composite keys & uniques**:

  ```prisma
  @@id([userId, role])
  @@unique([email, tenantId])
  /```
* **Enums & constrained values**: leverage `enum` for fixed domains.
* **Soft deletes & audit**:

  ```prisma
  model Base {
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
    deletedAt DateTime?
  }
  /```

### 2. Indexing & Constraints

* **Single-column indexes** for frequent lookups:

  ```prisma
  @@index([email])
  /```
* **Compound indexes** for multi-field filters/sorts:

  ```prisma
  @@index([status, createdAt])
  /```
* **Full-text search** (Postgres-only):

  ```prisma
  @@index([title, content], type: Brin)  // or Gin for JSONB
  /```

### 3. Migrations

* **Descriptive names**: `npx prisma migrate dev --name add-order-totals`
* **Idempotent steps**: avoid imperative SQL in migrations.
* **Shadow database**: enable in CI to catch drift.
* **Never edit** migration SQL after it’s applied to any environment.

### 4. Client Instantiation & Connection Management

* **Singleton pattern**

  ```ts
  // prisma.ts
  import { PrismaClient } from '../prisma/generated/client';
  export const prisma = global.prisma || new PrismaClient();
  if (process.env.NODE_ENV !== 'production') global.prisma = prisma;
  /```

### 5. Transactions & Batch Operations

* **Multi-step atomicity**:

  ```ts
  const result = await prisma.$transaction([
    prisma.user.create({ data: { /*…*/ } }),
    prisma.order.create({ data: { /*…*/ } }),
  ]);
  /```
* **Interactive transactions** for long-running flows.
* **Bulk writes**: chunk large inserts/updates to avoid timeouts.

### 6. Precise Queries & Performance

* **Select only needed fields**:

  ```ts
  await prisma.user.findUnique({
    where: { id },
    select: { id: true, email: true },
  });
  /```
* **Avoid N+1**: use `include` or batch `findMany` with `where: { id: { in: [...] } }` or use database joins in prisma.
* Use **Cursor-based pagination**

### 7. Raw Queries & Client Extensions

* **Raw SQL** when necessary, safely:

  ```ts
  const users = await prisma.$queryRaw`SELECT * FROM "User" WHERE email = ${email}`;
  /```
* **Sanitize inputs** with `Prisma.sql` for complex interpolations.
* **Client extensions**: use preview feature `clientExtensions` to add common helper methods.

### 8. Error Handling

* **Catch specific errors**:

  ```ts
  try {
    // …
  } catch (e) {
    if (e instanceof Prisma.PrismaClientKnownRequestError) {
      // P2002: Unique constraint
    }
  }
  /```
* **Wrap in service-level errors** to add context before bubbling up.

### 9. Testing

* **In-memory DB** (SQLite) or **Testcontainers** for integration tests.
* **Mock Prisma Client** for pure unit tests via `jest.mock()` or similar.

### 10. Logging, Monitoring & Metrics

* **Enable query logging** in dev:

  ```ts
  new PrismaClient({ log: ['query', 'warn', 'error'] });
  /```
* **APM integration** (Datadog, Sentry) – capture latency, errors.

### 11. Security & Best Practices

* **Never expose** raw Prisma client in HTTP controllers—wrap in a service layer.
* **Validate inputs** (e.g. with Zod) before any DB operation.
* **Least privilege** DB users: use separate roles for migrations vs. runtime.
* **Rotate credentials** and load from secure vault (AWS Secrets Manager, etc.).

### 12. Environment & Configuration

* **Centralize `DATABASE_URL`** and connection settings in `.env`.
* **Pin preview features** in `schema.prisma`:

  ```prisma
  generator client {
    previewFeatures = ["clientExtensions", "interactiveTransactions"]
  }
  /```
* **Version pinning**: match CLI and client versions in `package.json`.

````

Place this file at the root of your repository under `.github/`. Copilot Chat automatically applies these rules to every conversation in your project.

## Related pages

- [`Agent Skills`](https://www.prisma.io/docs/ai/tools/skills): Give your AI coding agent up-to-date Prisma knowledge with installable skills
- [`ChatGPT`](https://www.prisma.io/docs/ai/tools/chatgpt): Learn how to add the Prisma MCP server to ChatGPT to manage your databases and Compute deployments.
- [`Codex`](https://www.prisma.io/docs/ai/tools/codex): Learn how to install the Prisma Codex plugin and use Prisma MCP from Codex
- [`Cursor`](https://www.prisma.io/docs/ai/tools/cursor): Learn tips and best practices for using Prisma ORM with the Cursor AI code editor
- [`MCP server`](https://www.prisma.io/docs/ai/tools/mcp-server): Manage Prisma Postgres databases, Prisma Compute deployments, and Object Storage with the Prisma MCP server.

# MCP server (/docs/ai/tools/mcp-server)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Manage Prisma Postgres databases, Prisma Compute deployments, and Object Storage with the Prisma MCP server.

Location: AI > AI Tools > MCP server

## Overview [#overview]

The [Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP) lets AI tools connect to services such as Prisma.

Prisma provides an MCP server that lets AI tools manage [Prisma Postgres databases](https://www.prisma.io/docs/postgres), apps deployed on [Prisma Compute](https://www.prisma.io/docs/compute), and [Object Storage](https://www.prisma.io/docs/storage) buckets and access keys. Sign in with your Prisma account and select a workspace when you connect.

## Usage [#usage]

You need a Prisma account and access to a workspace, which groups your projects. If you don't have one, sign up at [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=ai).

Add `https://mcp.prisma.io/mcp` as the server URL in your AI tool's MCP settings. If it asks for a transport, select **Streamable HTTP**. Follow the [setup instructions for your AI tool](#integrating-in-ai-tools) for its configuration format. Clients that use an `mcpServers` JSON entry accept:

```json title="MCP configuration"
{
  "mcpServers": {
    "Prisma": {
      "url": "https://mcp.prisma.io/mcp"
    }
  }
}
```

Connect and sign in with your Prisma account, then select a workspace and approve access. Ask "List my Prisma databases" to check that the connection works. See [Tools](#tools) for the full list of supported operations.

> [!WARNING]
> Tools that change or delete resources can cause data loss or interrupt live traffic. Check the target workspace and resources before approving an operation in your AI tool.

## Sample prompts [#sample-prompts]

* "Show me a list of all the databases in this workspace."
* "Create a new database in the US region for me."
* "Show me all available backups of my database."
* "Show me all customers and run an analysis over their orders."
* "List my Compute apps and show the latest failed builds."
* "Show the runtime logs for this deployment."
* "Show how this project's Composer services connect, and give me the Console links."
* "Set LOG_LEVEL to debug for this project's preview environment."
* "Search the Prisma docs and explain how to deploy a project to Prisma Compute."

## Integrating in AI tools [#integrating-in-ai-tools]

AI tools have different ways of integrating MCP servers. In most cases, there are dedicated configuration files where you add the JSON configuration from above.

The sections below cover the config formats of common AI tools.

### VS Code [#vs-code]

Install the Prisma MCP server in VS Code with the link below:

<a
  href="vscode:mcp/install?%7B%22name%22%3A%22Prisma%22%2C%22gallery%22%3Atrue%2C%22url%22%3A%22https%3A%2F%2Fmcp.prisma.io%2Fmcp%22%7D"
  aria-label="Install Prisma MCP server in VS Code"
  style="{
  display: &#x22;inline-flex&#x22;,
  alignItems: &#x22;center&#x22;,
  borderRadius: &#x22;6px&#x22;,
  overflow: &#x22;hidden&#x22;,
  textDecoration: &#x22;none&#x22;,
  height: &#x22;2.0rem&#x22;,
}"
>
  <span
    style="{
    backgroundColor: &#x22;#2C2C2C&#x22;,
    color: &#x22;white&#x22;,
    padding: &#x22;0.6rem 0.8rem&#x22;,
  }"
  >
    VS CODE
  </span>

  <span
    style="{
    backgroundColor: &#x22;#0098FF&#x22;,
    color: &#x22;white&#x22;,
    padding: &#x22;0.6rem 1rem&#x22;,
  }"
  >
    INSTALL PRISMA MCP SERVER
  </span>
</a>

This will prompt you to open VS Code. Once opened, you'll be guided to install the Prisma MCP server directly into your VS Code configuration.

If your browser blocks the link, [you can set it up manually](https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_add-an-mcp-server-to-your-workspace) by creating a `.vscode/mcp.json` file in your workspace and adding:

```json title=".vscode/mcp.json"
{
  "servers": {
    "Prisma": {
      "url": "https://mcp.prisma.io/mcp"
    }
  }
}
```

Explore additional Prisma features and workflows for VS Code in [our docs](https://www.prisma.io/docs/guides/postgres/vscode).

### Codex [#codex]

The Prisma Codex plugin includes the remote Prisma MCP server and curated Prisma skills for Prisma ORM, Prisma Client, database setup, Prisma Postgres, and Prisma ORM upgrades.

Add the Prisma plugin marketplace to Codex:

```bash title="Codex"
codex plugin marketplace add prisma/codex-plugin
```

Restart Codex, open its plugin directory in the app, select the Prisma marketplace, and install the `Prisma` plugin. The plugin configures the remote Prisma MCP server at `https://mcp.prisma.io/mcp`; on first use, Codex will authenticate with Prisma Console so it can access the workspace you choose.

Learn more in the [Codex integration guide](https://www.prisma.io/docs/ai/tools/codex).

### Cursor [#cursor]

To learn more about Cursor's MCP integration, check out the [Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol#configuration-locations).

#### Add via one-click installation [#add-via-one-click-installation]

You can add the Prisma MCP server to Cursor using the [one-click installation](https://docs.cursor.com/context/model-context-protocol#one-click-installation) by clicking on the following link:

<a href="https://pris.ly/cursor-deeplink" target="_blank" rel="noopener noreferrer">
  <img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Install MCP Server" />
</a>

This will prompt you to open the Cursor app in your browser. Once opened, you'll be guided to install the Prisma MCP server directly into your Cursor configuration.

#### Add via Cursor Settings UI [#add-via-cursor-settings-ui]

When opening the **Cursor Settings**, you can add the Prisma MCP Server as follows:

1. Select **MCP** in the settings sidenav
2. Click **+ Add new global MCP server**
3. Add the `Prisma` snippet to the `mcpServers` JSON object:
   ```json title="Cursor MCP configuration"
   {
     "mcpServers": {
       "Prisma": {
         "url": "https://mcp.prisma.io/mcp"
       }
     }
   }
   ```

#### Global configuration [#global-configuration]

Adding it via the **Cursor Settings** settings will modify the global `~/.cursor/mcp.json` config file. In this case, the Prisma MCP server will be available in *all* your Cursor projects:

```json title="~/.cursor/mcp.json"
{
  "mcpServers": {
    "Prisma": {
      "url": "https://mcp.prisma.io/mcp"
    }
    // other MCP servers
  }
}
```

#### Project configuration [#project-configuration]

If you want the Prisma MCP server to be available only in specific Cursor projects, add it to the Cursor config of the respective project inside the `.cursor` directory in the project's root:

```json title=".cursor/mcp.json"
{
  "mcpServers": {
    "Prisma": {
      "url": "https://mcp.prisma.io/mcp"
    }
    // other MCP servers
  }
}
```

### Windsurf [#windsurf]

To learn more about Windsurf's MCP integration, check out the [Windsurf MCP docs](https://docs.windsurf.com/windsurf/cascade/mcp).

#### Add via Windsurf MCP Plugin Store (Recommended) [#add-via-windsurf-mcp-plugin-store-recommended]

Use the Prisma MCP plugin from the [Windsurf MCP Plugin Store](https://docs.windsurf.com/windsurf/cascade/mcp#adding-a-new-mcp-plugin). Follow [the steps here](https://www.prisma.io/docs/ai/tools/windsurf#add-prisma-mcp-server-via-windsurf-plugins) to add the Prisma MCP plugin in Windsurf. This is the recommended way to add the Prisma MCP server to Windsurf.

#### Add via Windsurf Settings UI [#add-via-windsurf-settings-ui]

When opening the **Windsurf Settings** (via **Windsurf - Settings** > **Advanced Settings or Command Palette** > **Open Windsurf Settings Page**), you can add the Prisma MCP Server as follows:

1. Select **Cascade** in the settings sidenav
2. Click **Add Server**
3. Add the `Prisma` snippet to the `mcpServers` JSON object:
   ```json title="Windsurf MCP configuration"
   {
     "mcpServers": {
       "Prisma": {
         "url": "https://mcp.prisma.io/mcp"
       }
     }
   }
   ```

#### Global configuration [#global-configuration-1]

Adding it via the **Windsurf Settings** will modify the global `~/.codeium/windsurf/mcp_config.json` config file. Alternatively, you can also manually add it to that file:

```json title="~/.codeium/windsurf/mcp_config.json"
{
  "mcpServers": {
    "Prisma": {
      "url": "https://mcp.prisma.io/mcp"
    }
    // other MCP servers
  }
}
```

### Warp [#warp]

You can add the Prisma MCP to Warp as a globally available tool. First, [visit your MCP settings](https://docs.warp.dev/knowledge-and-collaboration/mcp#how-to-access-mcp-server-settings&#x29; and click **+ Add**. From here, you can configure the Prisma MCP server as JSON:

```json title="Warp MCP configuration"
{
  "Prisma": {
    "url": "https://mcp.prisma.io/mcp"
  }
}
```

Hit **Save** and ensure the MCP server is running from your MCP settings panel. Then, open a new terminal window and ask Warp to manage your Prisma database. It should reach for the Prisma MCP server automatically.

To learn more about Warp's MCP integration, visit the [Warp MCP docs](https://docs.warp.dev/knowledge-and-collaboration/mcp).

### Claude Code [#claude-code]

Claude Code is a terminal-based AI tool where you can add MCP servers using the `claude mcp add` command:

```bash title="Claude Code"
claude mcp add --transport http prisma https://mcp.prisma.io/mcp
```

Learn more in the [Claude Code MCP docs](https://code.claude.com/docs/en/mcp).

### Claude Desktop only [#claude-desktop-only]

Follow the instructions in the [Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user#2-add-the-filesystem-mcp-server) to create the required configuration file:

* macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
* Windows: `%APPDATA%\Claude\claude_desktop_config.json`

Then add the JSON snippet to that configuration file:

```json title="Claude Desktop configuration"
{
  "mcpServers": {
    "Prisma": {
      "url": "https://mcp.prisma.io/mcp"
    }
    // other MCP servers
  }
}
```

### Claude Desktop & Web [#claude-desktop--web]

Alternatively, you can add the Prisma MCP server as an [integration](https://www.anthropic.com/news/integrations):

1. In a new chat, find the **Connect apps** field in the main Claude UI below the input prompt field
2. Click **+ Add integration**
3. Enter the following:

* **Integration name**: `Prisma`
* **Integration URL**: `https://mcp.prisma.io/mcp`

1. Click **Add**

### ChatGPT [#chatgpt]

You can add the Prisma MCP server to ChatGPT to manage your databases and Compute deployments using natural language. Learn more about setting it up in our [ChatGPT integration guide](https://www.prisma.io/docs/ai/tools/chatgpt).

### Gemini CLI [#gemini-cli]

Gemini CLI can add the Prisma MCP server using HTTP transport:

```bash title="Gemini CLI"
gemini mcp add --transport http Prisma https://mcp.prisma.io/mcp --scope user
```

You can also add the standard MCP configuration to your `~/.gemini/settings.json` file:

```json title="~/.gemini/settings.json"
{
  "mcpServers": {
    "Prisma": {
      "url": "https://mcp.prisma.io/mcp"
    }
  }
}
```

### fx [#fx]

[fx](https://fx.sh) is a terminal coding agent by [Vercel Labs](https://github.com/vercel-labs). It reads MCP servers from a single trusted file, `~/.fx/mcp.json`, and never loads MCP configuration from a repository. Remote servers are added by editing that file directly.

Install fx and sign in if you haven't already:

```bash title="fx"
curl -fsSL https://fx.sh/setup.sh | bash
fx login
```

Then add the Prisma MCP server to `~/.fx/mcp.json`. Note that fx uses an `mcp` key rather than `mcpServers`, and remote servers need `"type": "http"`:

```json title="~/.fx/mcp.json"
{
  "mcp": {
    "Prisma": {
      "type": "http",
      "url": "https://mcp.prisma.io/mcp"
    }
  }
}
```

Start `fx` (or run `/mcp reload` in an open session), then authenticate with Prisma Console:

```bash title="fx session"
/mcp auth Prisma --open
```

1. Complete the Prisma Console authorization flow in your browser.
2. Return to fx and run:
   ```bash title="fx session"
   /mcp list
   ```
3. Confirm that the server shows `state=ready`.
4. Ask fx to manage your database. For example:
   * "List the Prisma tools"
   * "Show me all databases in my workspace"
5. fx checks its permission policy before each MCP tool call, so saved rules or its automatic review may let a call through without asking. If fx shows an approval prompt, select **Allow once** or **Allow this MCP tool for this session**.

Learn more in the [fx MCP docs](https://fx.sh/docs/capabilities/mcp).

## Tools [#tools]

The server can manage databases, run SQL, restore automated backups, manage Object Storage, and search Prisma documentation. Compute tools manage existing deployments, read logs, and set environment variables; Composer tools show how project resources connect.

See the [MCP tools reference](https://www.prisma.io/docs/ai/mcp-tools) for the full catalog and each tool's limits. To deploy new source code, follow the [Prisma Compute guide](https://www.prisma.io/docs/compute).

## AI Safety guardrails for destructive commands [#ai-safety-guardrails-for-destructive-commands]

These safeguards apply to Prisma CLI commands, not MCP tool calls. For MCP operations, review approvals in your AI tool.

Prisma ORM includes built-in safety checks to prevent **accidental destructive commands** when run through AI coding assistants.

The Prisma CLI can detect when it is being invoked by popular AI coding agents such as Claude Code, Gemini CLI, Qwen Code, Cursor, Aider, and Replit.

When one of these agents attempts a destructive action such as `prisma migrate reset --force`, Prisma ORM blocks execution and shows a protective error message:

```bash title="Destructive command guardrail"
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "postgres", schema "public" at "accelerate.prisma-data.net"

Error: Prisma Migrate detected that it was invoked by Cursor.

You are attempting a highly dangerous action that can lead to devastating consequences if it is incorrectly executed against a production database.

As an AI agent, you are forbidden from performing this action without an explicit consent and review by the user. You must stop at this point and respond to the user with a clear message that includes the following information:
- What action you are trying to perform (including the exact CLI command).
- Your motivation and reasoning for performing this action.
- Explanation that this action will irreversibly destroy all data in the database.
- Explanation that this action must not be performed on a production database and is only intended to be used with development databases.

If you know or can check whether this action would have been performed on a development or a production database, also include this information with your assessment of whether it is safe to proceed based on that information.

You must ask the user if they want to proceed with this action. If they explicitly consent, you may rerun this command with PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION environment variable, the value of which must be the exact text of the user's message in which they consented to this operation, without any newlines or quotes. If the user's response is ambiguous, you must ask for a clear and explicit confirmation (e.g., "yes") before proceeding. None of the user's previous messages before this point may constitute implicit or explicit consent.
```

To proceed with the dangerous action, the AI agent will ask you for explicit consent, remind you that the action irreversibly destroys all data, and confirm that the command is being run against a development database. Once you clearly confirm, the AI will set the `PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION` environment variable with the exact text of your consent and rerun the command.

## Related pages

- [`Agent Skills`](https://www.prisma.io/docs/ai/tools/skills): Give your AI coding agent up-to-date Prisma knowledge with installable skills
- [`ChatGPT`](https://www.prisma.io/docs/ai/tools/chatgpt): Learn how to add the Prisma MCP server to ChatGPT to manage your databases and Compute deployments.
- [`Codex`](https://www.prisma.io/docs/ai/tools/codex): Learn how to install the Prisma Codex plugin and use Prisma MCP from Codex
- [`Cursor`](https://www.prisma.io/docs/ai/tools/cursor): Learn tips and best practices for using Prisma ORM with the Cursor AI code editor
- [`GitHub Copilot`](https://www.prisma.io/docs/ai/tools/github-copilot): Learn about the features available with GitHub Copilot and Prisma ORM, plus best practices and tips

# Agent Skills (/docs/ai/tools/skills)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Give your AI coding agent up-to-date Prisma knowledge with installable skills

Location: AI > AI Tools > Agent Skills

AI coding agents often struggle with Prisma: they generate outdated v6 patterns, hallucinate APIs, and miss breaking changes like ESM-only support and required driver adapters. **Prisma Skills** fix this by giving your agent accurate, version-specific knowledge it can reference automatically.

Skills are packaged instructions that follow the open [Agent Skills](https://agentskills.io/) format. Once installed, your agent uses them whenever it detects a relevant task, no prompting required.

Prisma ships skills from three places, matched to what you are building:

| You are working with                           | Where the skills come from                                        | Install command                  |
| ---------------------------------------------- | ----------------------------------------------------------------- | -------------------------------- |
| Prisma ORM v7, Prisma Postgres, Prisma Compute | [prisma/skills](https://github.com/prisma/skills)                 | `npx skills add prisma/skills`   |
| [Prisma ORM 8](https://www.prisma.io/docs/orm)                           | ships inside the `@prisma/orm-*` packages                         | `npx prisma@latest init`         |
| [Prisma Composer](https://www.prisma.io/docs/composer)                   | [prisma/composer](https://github.com/prisma/composer) (`skills/`) | `npx skills add prisma/composer` |

## Install [#install]

Add all skills from the main registry to your project:

  

#### bun

```bash
bunx skills add prisma/skills
```

#### pnpm

```bash
pnpm dlx skills add prisma/skills
```

#### yarn

```bash
yarn dlx skills add prisma/skills
```

#### npm

```bash
npx skills add prisma/skills
```

Or install only the ones you need:

  

#### bun

```bash
bunx skills add prisma/skills --skill prisma-client-api
```

#### pnpm

```bash
pnpm dlx skills add prisma/skills --skill prisma-client-api
```

#### yarn

```bash
yarn dlx skills add prisma/skills --skill prisma-client-api
```

#### npm

```bash
npx skills add prisma/skills --skill prisma-client-api
```

The Prisma ORM CLI's [`skills` commands](https://www.prisma.io/docs/cli/skills) do not install from this registry. They sync the skills that ship inside the Prisma ORM packages a project installs, so use `npx skills add prisma/skills` directly for the v7 skills above.

> [!NOTE]
> Skills are compatible with any agent that supports the [Agent Skills](https://agentskills.io/) format, including Claude Code, Cursor, Codex, Windsurf, and others.

## Available skills [#available-skills]

### `prisma-cli` [#prisma-cli]

Complete reference for all Prisma CLI commands in v7.

Covers `init`, `generate`, `dev`, `migrate dev`, `migrate deploy`, `db push`, `db pull`, `db seed`, `studio`, and more. Use this when your agent needs to run Prisma commands, set up projects, or manage migrations.

### `prisma-client-api` [#prisma-client-api]

Comprehensive Prisma Client API reference for v7.

Covers CRUD operations (`findMany`, `create`, `update`, `delete`), query options (`select`, `include`, `omit`, `orderBy`), filter operators, transactions (`$transaction`), raw queries (`$queryRaw`, `$executeRaw`), and client methods (`$connect`, `$disconnect`, `$extends`).

### `prisma-upgrade-v7` [#prisma-upgrade-v7]

Step-by-step migration guide from Prisma v6 to v7.

Covers ESM module configuration, required driver adapters, the new `prisma.config.ts` file, manual environment variable loading, and removed features (middleware, metrics, deprecated CLI flags). Essential for upgrading existing projects.

### `prisma-mongodb-upgrade` [#prisma-mongodb-upgrade]

Helps you move a MongoDB project from Prisma ORM 6 to [Prisma ORM 8](https://www.prisma.io/docs/orm).

Covers the migration mechanics: schema-to-contract mapping, client API changes, the migration lifecycle, and cutover verification. Use this when your agent needs to make that move: it maps your schema and queries across and guides the cutover, following the [MongoDB upgrade guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb).

### `prisma-database-setup` [#prisma-database-setup]

Guides for configuring Prisma with different database providers.

Covers PostgreSQL, Prisma Postgres, MySQL/MariaDB, SQLite, MongoDB, SQL Server, and CockroachDB. Use this when setting up a new project or switching databases.

### `prisma-postgres` [#prisma-postgres]

Prisma Postgres workflows across Console, CLI, REST API, and SDK.

Covers `npx create-db`, Console operations, programmatic provisioning via the REST API, and the `@prisma/management-api-sdk`. Use this when creating or managing Prisma Postgres databases.

### `prisma-postgres-setup` [#prisma-postgres-setup]

Gets a new Prisma Postgres database up and connected to your project.

Covers authenticating with a service token, listing regions, creating a project and database via the REST API, obtaining a connection string, and configuring `prisma.config.ts`, the schema, and the driver adapter. Use this when setting up a database or connecting an app to Prisma Postgres.

### `prisma-compute` [#prisma-compute]

Deploys and hosts your app on [Prisma Compute](https://www.prisma.io/docs/compute).

Covers `prisma.compute.ts` and `defineComputeConfig`, the unified Prisma CLI's `service`, `project`, and `git` commands, auth and workspace selection, runtime host/port binding, and framework readiness for Next.js, Nuxt, Astro, Hono, Nest, TanStack Start, and more. Use this when deploying or hosting a Prisma app.

### `prisma-driver-adapter-implementation` [#prisma-driver-adapter-implementation]

Helps you build a SQL driver adapter for Prisma ORM 7.

Covers `SqlDriverAdapter`, `Transaction`, savepoint hooks, argument and result mapping, `DriverAdapterError` behavior, and shadow-database handling. Use this when building a new database driver adapter or debugging adapter-level transaction and error behavior.

## Available skills for Prisma ORM 8 [#available-skills-for-prisma-8]

[Prisma ORM](https://www.prisma.io/docs/orm) ships one skill, `prisma-8`. It travels inside the `@prisma/orm-postgres`, `@prisma/orm-sqlite`, and `@prisma/orm-mongo` packages, so the copy in your project always describes the version you installed.

Projects scaffolded with `create-prisma` already have it: the scaffold runs `prisma init` for you. [`orm init`](https://www.prisma.io/docs/cli/orm-init) does not install skills; its only skill work is deleting retired skill directories. To install the skill in an existing project, or to refresh it after adding an agent runtime, use the family-level CLI:

  

#### bun

```bash
bunx --bun prisma@latest init
```

#### pnpm

```bash
pnpm dlx prisma@latest init
```

#### yarn

```bash
yarn dlx prisma@latest init
```

#### npm

```bash
npx prisma@latest init
```

That sets up the skill for every agent runtime the installer supports (Claude Code, Cursor, Codex, Windsurf). [`prisma skills sync`](https://www.prisma.io/docs/cli/skills) copies the skill out of the installed package into those directories, and every `prisma` command prints one line on stderr when the copies have drifted from the installed packages.

| Skill      | What your agent uses it for                                                                                                                                                                                                                                                                                                                                                                                                                         |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `prisma-8` | Everything Prisma ORM: contract authoring (PSL and TypeScript builders), picking the right API for a query (the ORM API, the SQL query builder, the MongoDB pipeline builder), migrations and reviews, setting up the client (`db.ts`, middleware, `DATABASE_URL`), build-tool integration, Supabase and RLS, reading `PN-*` structured errors, and upgrading an application or an extension package. Routes each task to a bundled reference file. |

Upgrading is a branch inside `prisma-8`, not a separate skill. The two flows live in its `references/upgrade-app.md` and `references/upgrade-extension.md`, and the per-transition instructions under `prisma-8/upgrading/`; the version you upgrade to carries the instructions for the transitions leading to it.

If you want the skill without installing the packages, `npx skills add prisma/prisma/skills#v<your-version> --skill prisma-8` still reads the repository. That is a fallback: nothing keeps a copy installed that way up to date.

The Prisma ORM docs reference the `prisma-8` skill in each page's "Prompt your coding agent" section, with prompts that map to the page you are reading.

## Available skills for Prisma Composer [#available-skills-for-prisma-composer]

[Prisma Composer](https://www.prisma.io/docs/composer) ships one skill, `prisma-composer`, from the [prisma/composer](https://github.com/prisma/composer) repository:

  

#### bun

```bash
bunx skills add prisma/composer
```

#### pnpm

```bash
pnpm dlx skills add prisma/composer
```

#### yarn

```bash
yarn dlx skills add prisma/composer
```

#### npm

```bash
npx skills add prisma/composer
```

It covers the whole Composer story: the mental model (Modules, `compute()`, `service.load()`), RPC contracts, databases, the first-party Modules for scheduled jobs, object storage, and event streams, config params and secrets, testing, and deploying with stages. Install it before your agent writes Composer code so it works from the current authoring API instead of inventing one.

## Useful commands [#useful-commands]

List available skills before installing:

  

#### bun

```bash
bunx skills add prisma/skills --list
```

#### pnpm

```bash
pnpm dlx skills add prisma/skills --list
```

#### yarn

```bash
yarn dlx skills add prisma/skills --list
```

#### npm

```bash
npx skills add prisma/skills --list
```

List skills currently installed in your project:

  

#### bun

```bash
bunx skills list
```

#### pnpm

```bash
pnpm dlx skills list
```

#### yarn

```bash
yarn dlx skills list
```

#### npm

```bash
npx skills list
```

## Example prompts [#example-prompts]

Once skills are installed, your agent will use them automatically. Try prompts like:

* *"Set up Prisma with PostgreSQL in this project"*
* *"Upgrade this project from Prisma 6 to 7"*
* *"Write a query to find all users with their posts"*
* *"Run migrations for production"*
* *"Create a new Prisma Postgres database"*

## Learn more [#learn-more]

* [Prisma Skills on skills.sh](https://skills.sh/prisma/skills) - browse available skills and install instructions
* [GitHub repository](https://github.com/prisma/skills) - source code, contribution guidelines, and skill structure
* [Agent Skills format](https://agentskills.io/) - the open standard behind skills

## Related pages

- [`ChatGPT`](https://www.prisma.io/docs/ai/tools/chatgpt): Learn how to add the Prisma MCP server to ChatGPT to manage your databases and Compute deployments.
- [`Codex`](https://www.prisma.io/docs/ai/tools/codex): Learn how to install the Prisma Codex plugin and use Prisma MCP from Codex
- [`Cursor`](https://www.prisma.io/docs/ai/tools/cursor): Learn tips and best practices for using Prisma ORM with the Cursor AI code editor
- [`GitHub Copilot`](https://www.prisma.io/docs/ai/tools/github-copilot): Learn about the features available with GitHub Copilot and Prisma ORM, plus best practices and tips
- [`MCP server`](https://www.prisma.io/docs/ai/tools/mcp-server): Manage Prisma Postgres databases, Prisma Compute deployments, and Object Storage with the Prisma MCP server.

# Tabnine (/docs/ai/tools/tabnine)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn tips and best practices for using Prisma ORM with the Tabnine AI code editor

Location: AI > AI Tools > Tabnine

[Tabnine](https://www.tabnine.com/) is an AI software development platform that comes as an [extension](https://www.tabnine.com/install/) for your IDE (e.g. VS Code, WebStorm, IntelliJ, ...).

## Overview [#overview]

It helps developers write code faster by:

* Providing context-aware [code completion](https://docs.tabnine.com/main/getting-started/getting-the-most-from-tabnines-code-completion) suggestions in the editor for small, repetitive coding tasks
* Offering an integrated [chat](https://docs.tabnine.com/main/getting-started/getting-the-most-from-tabnine-chat) for higher-level tasks and detailed instructions

### Where Tabnine helps with Prisma ORM [#where-tabnine-helps-with-prisma-orm]

Tabnine works well with the following Prisma workflows:

* Data modeling and database schema design
* Constructing and optimizing database queries
* Generating CRUD functionality and other boilerplate code
* Generating plain SQL queries that can be used with [TypedSQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql)
* Generating code for unit and integrations tests
* Guiding through major refactorings
* Generating seeding scripts

### Starting from the Prisma schema [#starting-from-the-prisma-schema]

Because Prisma has its own [schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview), Tabnine can understand the basic shape of your data and help you write code for the other parts of your stack.

We therefore recommend that you start out by defining your Prisma schema and then use Tabnine to build the application layer around it (including API calls, DTOs, business logic, 3rd party integrations, ...).

## Data modeling and database schema design [#data-modeling-and-database-schema-design]

### How Tabnine helps [#how-tabnine-helps]

Designing a database schema from scratch involves a lot of boilerplate and can be time-consuming.

Tabnine can help by:

* Generating boilerplate for models, indexes, constraints, and relations.
* Keeping the schema consistent by sticking to naming and other conventions.
* Auto-completing model and field definitions based on common database patterns.
* Suggesting relationships and field types based on naming conventions.

### Example: Defining a Prisma schema [#example-defining-a-prisma-schema]

#### Prompt [#prompt]

*Define a Prisma schema for a SaaS application with User, Organization, and Subscription models. Ensure relationships are properly set up.*

#### Generated code [#generated-code]

```prisma
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider = "postgresql"
}

model User {
  id             Int          @id @default(autoincrement())
  createdAt      DateTime     @default(now())
  updatedAt      DateTime     @updatedAt
  email          String       @unique
  name           String
  organization   Organization @relation(fields: [organizationId], references: [id])
  organizationId Int
}

model Organization {
  id           Int           @id @default(autoincrement())
  name         String
  slug         String        @unique
  subscription Subscription?
  users        User[]
}

model Subscription {
  id             Int          @id @default(autoincrement())
  organization   Organization @relation(fields: [organizationId], references: [id])
  organizationId Int          @unique
  plan           String
  status         Status
}

enum Status {
  Active
  Paused
  Expired
}
```

## Constructing and optimizing database queries [#constructing-and-optimizing-database-queries]

### How Tabnine helps [#how-tabnine-helps-1]

Prisma ORM provides a high-level API for database queries. Queries that combine filters, pagination, and relations can still take work to construct.

Tabnine can help by:

* Auto-completing Prisma queries based on the schema.
* Suggesting `where` clauses for filters and `skip` / `take` options for pagination logic.
* Helping with efficiency and performance optimizations.

### Example: fetching data with relationships [#example-fetching-data-with-relationships]

#### Prompt [#prompt-1]

*Generate a Prisma query to fetch all active users from an organization with an active subscription. Include data about the users' organizations in the query result.*

#### Generated code [#generated-code-1]

```ts
const activeUsers = await prisma.user.findMany({
  where: {
    organization: {
      subscription: {
        status: "ACTIVE",
      },
    },
  },
  include: {
    organization: true,
  },
});
```

## Generating CRUD functionality and other boilerplate code [#generating-crud-functionality-and-other-boilerplate-code]

### How Tabnine helps [#how-tabnine-helps-2]

Most applications require basic CRUD operations or other boilerplate code that's usually derived from the structure of the database schema. For example, an API layer may expose a set of HTTP endpoints that allow to create, read, update or delete records of a certain model. Similarly, a frontend will data fetching and state management logic to interact with these API endpoints and update the UI accordingly.

Instead of writing this code manually, Tabnine can speed up this process by:

* Generating Prisma `create`, `read`, `update`, and `delete` operations for the backend and UI components for the frontend.
* Auto-completing function names and argument types.
* Write boilerplate code while following best practices for using DTOs, error handling, consistent API design, ...

### Example: Generating CRUD functionality with Next.js [#example-generating-crud-functionality-with-nextjs]

#### Prompt [#prompt-2]

*Generate CRUD functionality for a Next.js app based on the User model from the schema above.*

#### Generated code [#generated-code-2]

##### API endpoints [#api-endpoints]

```ts filename=app/api/users/routes.ts
import { NextResponse } from "next/server";
import prisma from "../../../lib/prisma";

export async function GET() {
  const users = await prisma.user.findMany({
    include: { organization: true },
  });
  return NextResponse.json(users);
}

export async function POST(request: Request) {
  const body = await request.json();
  const user = await prisma.user.create({
    data: {
      email: body.email,
      name: body.name,
      organization: {
        connect: { id: body.organizationId },
      },
    },
    include: { organization: true },
  });
  return NextResponse.json(user);
}

export async function PUT(request: Request) {
  const body = await request.json();
  const user = await prisma.user.update({
    where: { id: body.id },
    data: {
      email: body.email,
      name: body.name,
      organizationId: body.organizationId,
    },
    include: { organization: true },
  });
  return NextResponse.json(user);
}

export async function DELETE(request: Request) {
  const { searchParams } = new URL(request.url);
  const id = searchParams.get("id");
  const user = await prisma.user.delete({
    where: { id: Number(id) },
  });
  return NextResponse.json(user);
}
```

##### React components [#react-components]

```ts filename=app/components/User.tsx
import React, { useState, useEffect } from 'react';

interface User {
  id: number;
  email: string;
  name: string;
  organizationId: number;
}

const User: React.FC = () => {
  const [users, setUsers] = useState<User[]>([]);
  const [newUser, setNewUser] = useState({ email: '', name: '', organizationId: 0 });

  useEffect(() => {
    fetchUsers();
  }, []);

  const fetchUsers = async () => {
    const response = await fetch('/api/users');
    const data = await response.json();
    setUsers(data);
  };

  const createUser = async () => {
    await fetch('/api/users', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(newUser),
    });
    fetchUsers();
    setNewUser({ email: '', name: '', organizationId: 0 });
  };

  const deleteUser = async (id: number) => {
    await fetch(`/api/users?id=${id}`, { method: 'DELETE' });
    fetchUsers();
  };

  return (
    <div>
      <h2>Users</h2>
      <ul>
        {users.map((user) => (
          <li key={user.id}>
            {user.name} ({user.email}) - Org ID: {user.organizationId}
            <button onClick={() => deleteUser(user.id)}>Delete</button>
          </li>
        ))}
      </ul>
      <h3>Create New User</h3>
      <input
        type="text"
        placeholder="Name"
        value={newUser.name}
        onChange={(e) => setNewUser({ ...newUser, name: e.target.value })}
      />
      <input
        type="email"
        placeholder="Email"
        value={newUser.email}
        onChange={(e) => setNewUser({ ...newUser, email: e.target.value })}
      />
      <input
        type="number"
        placeholder="Organization ID"
        value={newUser.organizationId}
        onChange={(e) => setNewUser({ ...newUser, organizationId: Number(e.target.value) })}
      />
      <button onClick={createUser}>Create User</button>
    </div>
  );
};

export default User;
```

## Generating plain SQL queries for use with TypedSQL [#generating-plain-sql-queries-for-use-with-typedsql]

### How Tabnine helps [#how-tabnine-helps-3]

While Prisma provides a high-level API for querying, sometimes a developer may need to drop down to raw SQL for more low-level control of a query. In these cases, they can use [TypedSQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql) which provides full type safety for raq SQL queries in Prisma ORM.

One common use case are aggregation queries, such as calculating percentages of different subscription statuses in the schema example above.

Tabnine can assist by:

* Generating SQL queries based on your Prisma schema.
* Structuring complex aggregations without manual trial and error.
* Integrating the queries in your application code.

### Example: Calculating the percentages of active, expired, and paused subscriptions [#example-calculating-the-percentages-of-active-expired-and-paused-subscriptions]

#### Prompt [#prompt-3]

*Generate a SQL query that returns the percentage of subscriptions that are Active, Paused, and Expired.*

#### Generated SQL query [#generated-sql-query]

```sql title="prisma/sql/subscriptionsReport.sql"
SELECT
  status,
  COUNT(*) * 100.0 / (SELECT COUNT(*) FROM "Subscription") AS percentage
FROM "Subscription"
GROUP BY status;
```

#### Application code [#application-code]

```ts
import { PrismaClient } from "../prisma/generated/client";
import { subscriptionsReport } from "../prisma/generated/client/sql";

const prisma = new PrismaClient();

const usersWithPostCounts = await prisma.$queryRawTyped(subscriptionsReport());
console.log(usersWithPostCounts);
```

## Generating code for unit and integration tests [#generating-code-for-unit-and-integration-tests]

### How Tabnine helps [#how-tabnine-helps-4]

Writing tests ensures that Prisma-based applications function correctly and behave according to requirements and expectations. However, writing tests is a time-consuming activity that often follows predictable and repetitive patterns.

Tabnine can help with tests by:

* Generating test boilerplate for both unit and integration tests.
* Suggesting mocks and fixtures for Prisma database interactions.
* Helping structure test cases to follow best practices.
* Providing integration test scaffolding for testing Prisma with a real or in-memory database.

### Example: Writing a unit test for a Prisma service [#example-writing-a-unit-test-for-a-prisma-service]

#### Prompt [#prompt-4]

*Generate a Jest unit test for a Prisma service function that fetches all active users.*

#### Generated code [#generated-code-3]

```ts filename=__tests__/userService.test.ts
import { prismaMock } from "../prisma/singleton";
import { getActiveUsers } from "../services/userService";

test("should return only active users", async () => {
  prismaMock.user.findMany.mockResolvedValue([
    { id: 1, name: "Alice", email: "alice@example.com" },
    { id: 2, name: "Bob", email: "bob@example.com" },
  ]);

  const users = await getActiveUsers();
  expect(users).toHaveLength(2);
  expect(users[0].email).toBe("alice@example.com");
});
```

## Guiding through major refactorings [#guiding-through-major-refactorings]

### How Tabnine helps [#how-tabnine-helps-5]

Prisma ORM's type-safe queries make refactorings safer and more predictable: after making schema changes, the generated Prisma Client code will be updated and the TypeScript compiler will highlight all places that need a change.

However, there may still be more difficult situations during a refactoring, e.g. when business logic or complex queries need to be adjusted.

Tabnine can assist during refactorings by:

* Identifying patterns in your code and suggesting refactorings while maintaining consistency.
* Helping update database queries after schema changes and reducing manual effort.
* Providing function rewrites to simplify and optimize logic.
* Suggesting breaking changes that need to be handled across your codebase.

### Example: Refactoring a Prisma query after a schema change [#example-refactoring-a-prisma-query-after-a-schema-change]

#### Prompt [#prompt-5]

*Refactor this Prisma query to support soft deletion using a `deletedAt` timestamp field in the User model.*

#### Initial code [#initial-code]

```ts
const users = await prisma.user.findMany();
```

#### Refactored code [#refactored-code]

```ts
const users = await prisma.user.findMany({
  where: { deletedAt: null },
});
```

## Generating seeding scripts [#generating-seeding-scripts]

### How Tabnine helps [#how-tabnine-helps-6]

Seeding a database with realistic test data can be cumbersome. Realistic seed data is helpful during development because it gives the developer a better impression of the application when it's used in the real-world. Tabnine can help with database seeding by:

* Generating scripts with structured seed data based on the schema and with specific requirements.
* Creating real-looking placeholder data that can be used to test the app.
* Generate specific data to cover edge cases.

### Example: Creating a seed script [#example-creating-a-seed-script]

#### Prompt [#prompt-6]

*Generate a Prisma seed script for populating User, Organization, and Subscription models.*

#### Generated code [#generated-code-4]

```ts
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient();

async function main() {
  await prisma.organization.create({
    data: {
      name: "Prisma Corp",
      slug: "prisma-corp",
      subscription: {
        create: {
          plan: "PRO",
          status: "ACTIVE",
        },
      },
      users: {
        create: [
          { name: "Alice Doe", email: "alice@prisma.io" },
          { name: "Bob Smith", email: "bob@prisma.io" },
        ],
      },
    },
  });

  console.log("Seed data created successfully");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

## Using the Prisma VS Code extension to manage your database [#using-the-prisma-vs-code-extension-to-manage-your-database]

If you use Tabnine in an editor that can install the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) and you work with [Prisma Postgres](https://www.prisma.io/docs/postgres), install the extension. It provides a UI for managing local and remote Prisma Postgres instances: view, create, and delete instances, push local databases to the cloud, and visualize your schema.

### Database management UI [#database-management-ui]

With its built-in database management interface, the [Prisma VS Code extension](https://www.prisma.io/docs/guides/postgres/vscode) lets you work with local and remote Prisma Postgres instances from inside your editor.

#### Workflows [#workflows]

The UI enables the following workflows:

* Authenticate with the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=ai)
* View, create and delete Prisma Postgres instances (local & remote)
* "Push to cloud": deploy a local Prisma Postgres instance
* View and edit data via an embedded Prisma Studio
* Visualize your database schema

#### Usage [#usage]

To manage Prisma Postgres instances via the UI in the Prisma VS Code extension:

1. Ensure you have the latest version of the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) installed
2. Find the Prisma logo in the **Activity Bar**
3. Click the **Sign in to get started** button
4. Authenticate with the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=ai) using the sign-in prompt, then select a target [workspace](https://www.prisma.io/docs/console/concepts#workspace)

### Prisma Studio built-in [#prisma-studio-built-in]

Beyond managing your database instances, the Prisma VS Code extension embeds Prisma Studio in your editor, so you can create, update, and delete records without leaving it. See the [setup steps](https://www.prisma.io/docs/studio/integrations/vscode-integration).

## Related pages

- [`Agent Skills`](https://www.prisma.io/docs/ai/tools/skills): Give your AI coding agent up-to-date Prisma knowledge with installable skills
- [`ChatGPT`](https://www.prisma.io/docs/ai/tools/chatgpt): Learn how to add the Prisma MCP server to ChatGPT to manage your databases and Compute deployments.
- [`Codex`](https://www.prisma.io/docs/ai/tools/codex): Learn how to install the Prisma Codex plugin and use Prisma MCP from Codex
- [`Cursor`](https://www.prisma.io/docs/ai/tools/cursor): Learn tips and best practices for using Prisma ORM with the Cursor AI code editor
- [`GitHub Copilot`](https://www.prisma.io/docs/ai/tools/github-copilot): Learn about the features available with GitHub Copilot and Prisma ORM, plus best practices and tips

# Windsurf (/docs/ai/tools/windsurf)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn tips and best practices for using Prisma ORM with the Windsurf AI code editor

Location: AI > AI Tools > Windsurf

[Windsurf Editor](https://windsurf.com/editor/) is an AI code editor with an agent (Cascade) and project rules. This guide covers how to use it with Prisma to:

* Define project-specific best practices with `.windsurfrules`.
* Use Windsurf's context-aware capabilities.
* Generate schemas, queries, and seed data tailored to your database.

> [!NOTE]
> While this guide is focused on Windsurf, these patterns should work with any AI editor. [Let us know on X](https://pris.ly/x?utm_source=docs\&utm_medium=inline_text) if you'd like us to create guides for your preferred tool.

## Prisma MCP server [#prisma-mcp-server]

Prisma provides its own [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) server that lets you manage Prisma Postgres databases, inspect schemas, and execute SQL queries.

### Add Prisma MCP server via Windsurf Plugins [#add-prisma-mcp-server-via-windsurf-plugins]

You can add the Prisma MCP server via [Windsurf MCP Plugin Store](https://docs.windsurf.com/windsurf/cascade/mcp#adding-a-new-mcp-plugin).

New MCP plugins can be added from the **Plugin Store**, which you can access by clicking on the **Plugins** icon in the top right menu in the **Cascade** panel, or from the **Windsurf Settings** > **Cascade** > **Plugins** section. Search for **Prisma** in the **Plugin Store** and install the `Prisma` plugin.

> [!NOTE]
> You can also add the Prisma MCP server manually. Learn more about how you can add the MCP server manually to [Windsurf](https://www.prisma.io/docs/ai/tools/mcp-server#windsurf).

## Defining project-specific rules with `.windsurfrules` [#defining-project-specific-rules-with-windsurfrules]

The [`.windsurfrules` file](https://docs.windsurf.com/windsurf/cascade/memories) in Windsurf gives Windsurf persistent instructions for your Prisma project, so generated code follows your conventions without manual adjustments.

Create a `.windsurfrules` file in the root of your project. Below is an example configuration:

**Example <code>.windsurfrules</code> file**

```text title=".windsurfrules"
You are a senior TypeScript/JavaScript programmer with expertise in Prisma, clean code principles, and modern backend development.
Generate code, corrections, and refactorings that comply with the following guidelines:
TypeScript General Guidelines
Basic Principles
- Use English for all code and documentation.
- Always declare explicit types for variables and functions.
  - Avoid using "any".
  - Create precise, descriptive types.
- Use JSDoc to document public classes and methods.
- Maintain a single export per file.
- Write self-documenting, intention-revealing code.
Nomenclature
- Use PascalCase for classes and interfaces.
- Use camelCase for variables, functions, methods.
- Use kebab-case for file and directory names.
- Use UPPERCASE for environment variables and constants.
- Start function names with a verb.
- Use verb-based names for boolean variables:
  - isLoading, hasError, canDelete
- Use complete words, avoiding unnecessary abbreviations.
  - Exceptions: standard abbreviations like API, URL
  - Accepted short forms:
    - i, j for loop indices
    - err for errors
    - ctx for contexts
Functions
- Write concise, single-purpose functions.
  - Aim for less than 20 lines of code.
- Name functions descriptively with a verb.
- Minimize function complexity:
  - Use early returns.
  - Extract complex logic to utility functions.
- Leverage functional programming techniques:
  - Prefer map, filter, reduce.
  - Use arrow functions for simple operations.
  - Use named functions for complex logic.
- Use object parameters for multiple arguments.
- Maintain a single level of abstraction.
Data Handling
- Encapsulate data in composite types.
- Prefer immutability.
  - Use readonly for unchanging data.
  - Use as const for literal values.
- Validate data at the boundaries.
Error Handling
- Use specific, descriptive error types.
- Provide context in error messages.
- Use global error handling where appropriate.
- Log errors with sufficient context.
Prisma-Specific Guidelines
Schema Design
- Use meaningful, domain-driven model names.
- Leverage Prisma schema features:
  - Use @id for primary keys.
  - Use @unique for natural unique identifiers.
  - Utilize @relation for explicit relationship definitions.
- Keep schemas normalized and DRY.
- Use meaningful field names and types.
- Implement soft delete with deletedAt timestamp.
- Use Prisma's native type decorators.
Prisma Client Usage
- Always use type-safe Prisma client operations.
- Prefer transactions for complex, multi-step operations.
- Handle optional relations explicitly.
- Use Prisma's filtering and pagination capabilities.
Database Migrations
- Create migrations for schema changes.
- Use descriptive migration names.
- Review migrations before applying.
- Never modify existing migrations.
- Keep migrations idempotent.
Error Handling with Prisma
- Catch and handle Prisma-specific errors:
  - PrismaClientKnownRequestError
  - PrismaClientUnknownRequestError
  - PrismaClientValidationError
- Provide user-friendly error messages.
- Log detailed error information for debugging.
Testing Prisma Code
- Use in-memory database for unit tests.
- Mock Prisma client for isolated testing.
- Test different scenarios:
  - Successful operations
  - Error cases
  - Edge conditions
- Use factory methods for test data generation.
- Implement integration tests with actual database.
Performance Considerations
- Use select and include judiciously.
- Avoid N+1 query problems.
- Use findMany with take and skip for pagination.
- Leverage Prisma's distinct for unique results.
- Profile and optimize database queries.
Security Best Practices
- Never expose raw Prisma client in APIs.
- Use input validation before database operations.
- Implement row-level security.
- Sanitize and validate all user inputs.
- Use Prisma's built-in protections against SQL injection.
Coding Style
- Keep Prisma-related code in dedicated repositories/modules.
- Separate data access logic from business logic.
- Create repository patterns for complex queries.
- Use dependency injection for Prisma services.
Code Quality
- Follow SOLID principles.
- Prefer composition over inheritance.
- Write clean, readable, and maintainable code.
- Continuously refactor and improve code structure.
Development Workflow
- Use version control (Git).
- Implement comprehensive test coverage.
- Use continuous integration.
- Perform regular code reviews.
- Keep dependencies up to date.
```

## Using Windsurf's context-aware capabilities [#using-windsurfs-context-aware-capabilities]

Windsurf's [context-awareness](https://docs.windsurf.com/context-awareness/overview) features let you add project files and external resources to the context Windsurf works from. Including your Prisma schema and relevant documentation helps Windsurf generate queries, tests, and seed data that match your database schema.

### Including Additional Prisma Resources [#including-additional-prisma-resources]

Windsurf has built-in knowledge of common libraries, but that knowledge can lag behind the current Prisma release. Reference external Prisma resources explicitly when you need current, authoritative context.

For example, you might reference:

* [Prisma Changelog](https://www.prisma.io/changelog)
* [Prisma Blog](https://www.prisma.io/blog)
* [Prisma Documentation](https://www.prisma.io/docs)

#### Reference the resource in your requests: [#reference-the-resource-in-your-requests]

When asking for code, explanations, or reviews, include the link to the relevant Prisma resource and specify that it should be used as a reference.

```bash
Generate a migration script using best practices from prisma.io/docs.
```

#### Request persistent awareness: [#request-persistent-awareness]

Ask Windsurf to always consider a specific resource for all Prisma-related work in your project.

```bash
Always use the Prisma Changelog at prisma.io/changelog for Prisma updates in this project.
```

#### Ask for regular updates: [#ask-for-regular-updates]

If you want Windsurf to check for updates or new features, explicitly request it.

```bash
Before suggesting Prisma code, check the latest changes from prisma.io/changelog.
```

### Using schema as context [#using-schema-as-context]

Out of the box, Windsurf automatically considers the current file, other open files, and indexed portions of your codebase as context. To make sure Cascade uses your Prisma schema, keep your `schema.prisma` file open or pinned in the editor.

## Generating Prisma schema [#generating-prisma-schema]

Windsurf can generate a Prisma schema from a description. The more specific the prompt (models, fields, relations, defaults), the closer the result matches what you need. Here is an example prompt and its result:

> [!NOTE]
> LLMs may produce different results each time, even with the same prompt.

  

#### Prompt to generate Prisma schema

```text copy 
"Create a Prisma schema for a SaaS app using PostgreSQL as a provider with `User`, `Organization`, and `Subscription` models, ensuring all models include `createdAt` and `updatedAt` DateTime fields with defaults, a soft-delete `deletedAt` field, and proper relationships between entities."
```

#### Result

```prisma title="schema.prisma" showLineNumbers 
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
provider = "postgresql"
}

model User {
id Int @id @default(autoincrement())
email String @unique
name String
password String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
organization Organization @relation(fields: [organizationId], references: [id])
organizationId Int
role UserRole @default(MEMBER)
}

model Organization {
id Int @id @default(autoincrement())
name String
slug String @unique
subscription Subscription?
users User[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
}

model Subscription {
id Int @id @default(autoincrement())
organization Organization @relation(fields: [organizationId], references: [id])
organizationId Int @unique
plan SubscriptionPlan
status SubscriptionStatus @default(ACTIVE)
startDate DateTime
endDate DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
}

enum UserRole {
ADMIN
MEMBER
}

enum SubscriptionPlan {
FREE
BASIC
PREMIUM
ENTERPRISE
}

enum SubscriptionStatus {
ACTIVE
CANCELED
EXPIRED
PAST_DUE
}
```

## Generating Prisma queries [#generating-prisma-queries]

Windsurf can write queries against your Prisma schema. State the fields to include, the conditions to apply, and the relations to traverse, and Windsurf generates a query that type-checks against your schema. Here is an example prompt and its resulting query:

  

#### Prompt to generate a database query

```text copy 
"Generate a query to retrieve all User records associated with an Organization that has an `active` Subscription, while excluding any records where the `deletedAt` field is set."
```

#### Result

```ts showLineNumbers 
const activeUsers = await prisma.user.findMany({
  where: {
    deletedAt: null,
    organization: {
      deletedAt: null,
      subscription: {
        deletedAt: null,
        status: "ACTIVE",
      },
    },
  },
  include: {
    organization: {
      include: {
        subscription: true,
      },
    },
  },
  orderBy: {
    createdAt: "desc",
  },
  skip: 0,
  take: 10,
});
```

## Creating seed files with Windsurf [#creating-seed-files-with-windsurf]

Windsurf can generate seed scripts that populate your database with realistic data, including the relations defined in your schema. Here is an example prompt and its resulting seed script:

  

#### Prompt to seed the database

```text copy 
"Generate code to populate the Prisma schema with realistic data for the User, Organization, and Subscription models, ensuring all necessary fields are included."
```

#### Result

```ts title="seed.ts" 
import {
  PrismaClient,
  UserRole,
  SubscriptionPlan,
  SubscriptionStatus,
} from "../prisma/generated/client";

const prisma = new PrismaClient();

async function main() {
  // Clear existing data
  await prisma.user.deleteMany();
  await prisma.subscription.deleteMany();
  await prisma.organization.deleteMany();

  const organizations = [
    {
      name: "Tech Innovators",
      slug: "tech-innovators",
      subscription: {
        plan: SubscriptionPlan.ENTERPRISE,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-01-01"),
      },
      users: [
        {
          name: "Emma Thompson",
          email: "emma@techinnovators.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Michael Chen",
          email: "michael@techinnovators.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Digital Solutions",
      slug: "digital-solutions",
      subscription: {
        plan: SubscriptionPlan.PREMIUM,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-01-15"),
      },
      users: [
        {
          name: "Sarah Wilson",
          email: "sarah@digitalsolutions.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "James Miller",
          email: "james@digitalsolutions.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Cloud Systems",
      slug: "cloud-systems",
      subscription: {
        plan: SubscriptionPlan.BASIC,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-02-01"),
      },
      users: [
        {
          name: "David Garcia",
          email: "david@cloudsystems.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Lisa Wang",
          email: "lisa@cloudsystems.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Data Analytics Co",
      slug: "data-analytics",
      subscription: {
        plan: SubscriptionPlan.PREMIUM,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-01-10"),
      },
      users: [
        {
          name: "Alex Johnson",
          email: "alex@dataanalytics.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Rachel Kim",
          email: "rachel@dataanalytics.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Smart Solutions",
      slug: "smart-solutions",
      subscription: {
        plan: SubscriptionPlan.FREE,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-02-15"),
      },
      users: [
        {
          name: "Daniel Brown",
          email: "daniel@smartsolutions.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Maria Rodriguez",
          email: "maria@smartsolutions.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
  ];

  for (const org of organizations) {
    const createdOrg = await prisma.organization.create({
      data: {
        name: org.name,
        slug: org.slug,
        subscription: {
          create: {
            plan: org.subscription.plan,
            status: org.subscription.status,
            startDate: org.subscription.startDate,
          },
        },
      },
    });

    for (const user of org.users) {
      await prisma.user.create({
        data: {
          name: user.name,
          email: user.email,
          password: user.password,
          role: user.role,
          organizationId: createdOrg.id,
        },
      });
    }
  }

  console.log("Seed data created successfully");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

## Using the Prisma VS Code extension to manage your database [#using-the-prisma-vs-code-extension-to-manage-your-database]

The [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) also works in Windsurf. It provides a UI for managing local and remote [Prisma Postgres](https://www.prisma.io/docs/postgres) instances: view, create, and delete instances, push local databases to the cloud, and visualize your schema.

### Database management UI [#database-management-ui]

With its built-in database management interface, [the Prisma VS Code extension](https://www.prisma.io/docs/guides/postgres/vscode) lets you work with local and remote Prisma Postgres instances from inside your editor.

#### Workflows [#workflows]

The UI enables the following workflows:

* Authenticate with the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=ai)
* View, create and delete Prisma Postgres instances (local & remote)
* "Push to cloud": deploy a local Prisma Postgres instance
* View and edit data via an embedded Prisma Studio
* Visualize your database schema

#### Usage [#usage]

To manage Prisma Postgres instances via the UI in the Prisma VS Code extension:

1. Ensure you have the latest version of the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) installed
2. Find the Prisma logo in the **Activity Bar**
3. Click the **Sign in to get started** button
4. Authenticate with the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=ai) using the sign-in prompt, then select a target [workspace](https://www.prisma.io/docs/console/concepts#workspace)

### Prisma Studio built-in [#prisma-studio-built-in]

Beyond managing your database instances, the Prisma VS Code extension embeds Prisma Studio in your editor, so you can create, update, and delete records without leaving it. See the [setup steps](https://www.prisma.io/docs/studio/integrations/vscode-integration).

## Additional resources [#additional-resources]

To keep learning:

* [Windsurf Documentation](https://docs.windsurf.com/windsurf/getting-started)
* [Prisma Documentation](https://www.prisma.io/docs)

## Related pages

- [`Agent Skills`](https://www.prisma.io/docs/ai/tools/skills): Give your AI coding agent up-to-date Prisma knowledge with installable skills
- [`ChatGPT`](https://www.prisma.io/docs/ai/tools/chatgpt): Learn how to add the Prisma MCP server to ChatGPT to manage your databases and Compute deployments.
- [`Codex`](https://www.prisma.io/docs/ai/tools/codex): Learn how to install the Prisma Codex plugin and use Prisma MCP from Codex
- [`Cursor`](https://www.prisma.io/docs/ai/tools/cursor): Learn tips and best practices for using Prisma ORM with the Cursor AI code editor
- [`GitHub Copilot`](https://www.prisma.io/docs/ai/tools/github-copilot): Learn about the features available with GitHub Copilot and Prisma ORM, plus best practices and tips

# Linktree Clone SaaS (/docs/ai/tutorials/linktree-clone)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A vibe coding tutorial: build a Linktree clone SaaS application from scratch using Next.js, Prisma ORM, Prisma Postgres, and Clerk authentication with AI assistance

Location: AI > Tutorials > Linktree Clone SaaS

## Introduction [#introduction]

In this vibe coding tutorial, you'll build a **Linktree clone SaaS** application from scratch with an AI coding assistant. The stack is:

* **[Next.js](https://nextjs.org/)**: React framework for production
* **[Prisma ORM](https://www.prisma.io/orm)**: Type-safe database access
* **[Prisma Postgres](https://www.prisma.io/postgres)**: Serverless PostgreSQL database
* **[Clerk](https://clerk.com/)**: Authentication and user management

By the end of this tutorial, you'll have a working SaaS application where users can sign up, create their profile, and manage their personal link page, all built with AI-assisted development.

> [!NOTE]
> What is Vibe Coding?
> 
> Vibe coding is a development approach where you collaborate with AI assistants to build applications. You describe what you want to build, and the AI helps generate the code while you guide the direction and make architectural decisions.

## Video tutorial [#video-tutorial]

Watch this step-by-step walkthrough of the entire build process:

[Watch video](https://www.youtube.com/watch?v=R3GJ1eo943k)

## Prerequisites [#prerequisites]

Before starting this tutorial, make sure you have:

* [Node.js 20+](https://nodejs.org) installed
* A [Clerk account](https://clerk.com) (free tier works)
* An AI coding assistant ([Cursor](https://cursor.com), [Windsurf](https://windsurf.com), [GitHub Copilot](https://github.com/features/copilot), etc.)
* Basic familiarity with React and TypeScript

> [!NOTE]
> Recommended AI Models
> 
> Use Claude Sonnet 4, Gemini 2.5 Pro, GPT-4o, or a newer model. Older models generate less accurate code and handle the architecture in this tutorial less reliably.

## 1. Set up your project [#1-set-up-your-project]

Create a new Next.js application:

  

#### bun

```bash
bunx create-next-app@latest app-name
```

#### pnpm

```bash
pnpm dlx create-next-app@latest app-name
```

#### yarn

```bash
yarn dlx create-next-app@latest app-name
```

#### npm

```bash
npx create-next-app@latest app-name
```

Once the setup is complete, add **Prisma** and **Prisma Postgres** to your project with the prepared setup prompt.

👉 &#x2A;*Find the setup prompt here:** [Next.js + Prisma Prompt](https://www.prisma.io/docs/ai/prompts/nextjs)

**How to use it:**

1. Create a new file called `prompt.md` at the root of your project
2. Copy and paste the prompt content into this file
3. Ask your AI assistant to follow the instructions in this file

The AI sets up Prisma ORM, creates your database connection, and configures the project.

### Quick Check [#quick-check]

Verify the setup:

1. Start your development server:
   
     

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```
   
2. Open Prisma Studio to view your seed data:
   
     

#### bun

```bash
bun run db:studio
```

#### pnpm

```bash
pnpm run db:studio
```

#### yarn

```bash
yarn db:studio
```

#### npm

```bash
npm run db:studio
```
   

If both commands run without errors and you can see sample data in Prisma Studio, you're ready to continue.

> [!NOTE]
> Good Practice: Commit Early and Often
> 
> Throughout this tutorial, we'll commit our changes regularly. This makes it easy to track progress and roll back if something goes wrong.
> 
> Start by linking your project to GitHub:
> 
> ```bash
> git init
> git add .
> git commit -m "Initial setup: Next.js app with Prisma"
> ```

## 2. Set Up Authentication with Clerk [#2-set-up-authentication-with-clerk]

Add user authentication with [Clerk](https://clerk.com/), which provides sign-up, sign-in, and session management.

**Steps to follow:**

1. Go to [Clerk](https://clerk.com/) and create an account (if you don't have one)
2. Create a new application in your Clerk dashboard
3. Follow Clerk's official quickstart guide to integrate it with your Next.js app:

👉 &#x2A;*Clerk Next.js Quickstart:** [clerk.com/docs/nextjs/getting-started/quickstart](https://clerk.com/docs/nextjs/getting-started/quickstart)

The guide will walk you through installing the SDK, adding environment variables, and wrapping your app with the `ClerkProvider`.

Once complete, commit your changes:

```bash
git add .
git commit -m "Add Clerk authentication setup"
```

## 3. Update your database schema [#3-update-your-database-schema]

Since we're building a Linktree clone, we need to update the database schema to support our specific data model. This includes:

* A `User` model with a unique `username` (for public profile URLs like `/username`)
* A `Link` model to store each user's links

Replace the contents of your `prisma/schema.prisma` file with the following:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

// Example User model for testing
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  username  String   @unique // Important for the public profile URL
  clerkId   String   @unique // Links to Clerk Auth
  name      String?
  links     Link[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Link {
  id        Int      @id @default(autoincrement())
  title     String
  url       String
  userId    Int
  user      User     @relation(fields: [userId], references: [id])
  createdAt DateTime @default(now())
}
```

Since we're changing the schema structure, we need to reset the database. The existing seed data was just for testing purposes, so it's safe to drop and recreate:

  

#### bun

```bash
bunx prisma db push --force-reset
```

#### pnpm

```bash
pnpm prisma db push --force-reset
```

#### yarn

```bash
yarn prisma db push --force-reset
```

#### npm

```bash
npx prisma db push --force-reset
```

This command:

* **Drops** the existing database tables
* **Creates** new tables based on your updated schema

> [!WARNING]
> Use with Caution
> 
> The `--force-reset` flag deletes all existing data. This is fine during prototyping, but never use it on a production database. Once your schema is stable, switch to `prisma migrate dev` for proper migration tracking.

### Quick Check [#quick-check-1]

Open Prisma Studio to verify the new schema is applied:

  

#### bun

```bash
bun run db:studio
```

#### pnpm

```bash
pnpm run db:studio
```

#### yarn

```bash
yarn db:studio
```

#### npm

```bash
npm run db:studio
```

You should see the updated `User` and `Link` tables (they'll be empty, which is expected).

**Commit your changes:**

```bash
git add .
git commit -m "Update schema for Linktree clone"
```

## 4. Connect Clerk users to your database [#4-connect-clerk-users-to-your-database]

When a user signs in with Clerk, they exist in Clerk's system but **not** in your database. To bridge this gap, create a "Claim Username" flow where users pick their unique username (e.g., `yourapp.com/johndoe`) after signing in for the first time.

> [!NOTE]
> Use ASK Mode First
> 
> When working with AI assistants, we recommend using **ASK mode** by default to review suggested changes before applying them. Only switch to AGENT mode once you're comfortable with the proposed code.

### The Prompt [#the-prompt]

Copy and paste the following prompt into your AI assistant:

```markdown
Connect Clerk authentication to your Prisma database with a "Claim Username" flow.

**Goal:**

When a user signs in via Clerk, they don't automatically exist in YOUR database. Create a flow where:

1. Logged out → Show landing page with "Sign In" button
2. Logged in but no DB profile → Show "Claim Username" form
3. Has DB profile → Show dashboard

**User Model (already in schema):**

model User {
id Int @id @default(autoincrement())
email String @unique
username String @unique
clerkId String @unique
name String?
links Link[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

**Files to create/update:**

1. `app/actions.ts` - Server Action with `claimUsername(formData)`
2. `app/page.tsx` - Three-state UI (logged out / claim username / dashboard)
3. `app/api/users/route.ts` - Update POST to accept `clerkId`, `email`, `username`, `name`

**Requirements:**

- Use `'use server'` directive in `app/actions.ts`
- Use `currentUser()` from `@clerk/nextjs/server` to get auth user
- Store `clerkId`, `email`, `username`, and `name` in User model
- Use `redirect("/")` after successful profile creation
- Handle username uniqueness (Prisma will throw if duplicate)

**Pattern:**

1. Server Action receives FormData, validates username (min 3 chars, alphanumeric + underscore)
2. Creates User in Prisma with Clerk's `user.id` as `clerkId`
3. Page.tsx checks: `currentUser()` → then `prisma.user.findUnique({ where: { clerkId } })`
4. Render different UI based on auth state and DB state

**Keep it simple:**

- No middleware file needed
- No webhook sync (user creates profile manually)
- Basic validation (username length >= 3)
- Errors just throw (no fancy error UI for MVP)
```

After the AI generates the code, you may see TypeScript errors. This is because the Prisma Client needs to be regenerated to reflect the schema changes:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### Quick Check [#quick-check-2]

Test the complete flow:

1. Stop your dev server and restart it
2. Open your app in the browser
3. Sign up as a new user through Clerk
4. You should see the "Claim Username" form
5. Enter a username and submit
6. Verify the user appears in Prisma Studio (`npm run db:studio`)

If everything works, commit your changes.

## 5. Upgrade the UI Design [#5-upgrade-the-ui-design]

Give the app a cleaner, friendlier look inspired by platforms like Buy Me a Coffee.

👉 [Visit Buy Me a Coffee for design inspiration](https://buymeacoffee.com/)

Copy and paste this prompt to your AI assistant:

```markdown
Design a minimal, friendly UI inspired by Buy Me a Coffee.

**Theme:**

- Force light mode only (no dark mode switching)
- Clean white background (#FFFFFF)
- Black text (#000000) for headings
- Gray (#6B7280) for secondary text
- Bright yellow (#FFDD00) for CTA buttons
- Light gray (#F7F7F7) for cards/sections
- Subtle borders (#E5E5E5)

**Typography & Spacing:**

- Large, bold headlines (text-5xl or bigger)
- Generous whitespace and padding
- Rounded corners everywhere (rounded-full for buttons, rounded-xl for cards)

**Buttons:**

- Primary: Yellow background, black text, rounded-full, font-semibold
- Secondary: White background, border, rounded-full

**Overall feel:**

- Friendly, approachable, not corporate
- Minimal — only essential elements
- Mobile-first with good touch targets (py-4, px-8 on buttons)
- One unified canvas — background applies to the entire page (body), with white cards floating on top. No separate section backgrounds.

Use Tailwind CSS. Keep it simple.
```

### Quick Check [#quick-check-3]

After the AI applies the changes:

1. Refresh your app and browse through all pages
2. Verify the design has updated but **no functionality has changed**
3. Test the sign-in flow and username claim process

Once verified, commit the changes:

```bash
git add .
git commit -m "Update UI design"
```

## 6. Build Link Management (Add & Delete) [#6-build-link-management-add--delete]

Add the core functionality, managing links. Users should be able to add new links and delete existing ones from their dashboard.

Copy and paste this prompt:

```markdown
Build a simple dashboard for managing links using Next.js App Router and Server Actions.

**Requirements:**

- Server Component page that fetches user data from database
- "Add Link" form with Title and URL inputs
- List of existing links with Delete button
- Use Server Actions (no API routes) for create/delete operations
- Use `revalidatePath("/")` after mutations to refresh the page

**Pattern:**

1. Create server actions in `actions.ts` with `'use server'` directive
2. Pass actions directly to form `action` prop
3. Keep page.tsx as a Server Component (no 'use client')
4. Use hidden inputs for IDs (e.g., `<input type="hidden" name="linkId" value={id} />`)

**Keep it simple:**

- No loading states
- No client components
- No confirmation dialogs
- Just forms + server actions + revalidation

This is the MVP pattern for CRUD with Next.js App Router.
```

### Quick Check [#quick-check-4]

Test the link management:

1. Add a new link with a title and URL
2. Verify it appears in your dashboard
3. Delete the link
4. Verify it's removed

Both operations should work instantly without page navigation.

## 7. Create Public Profile Pages [#7-create-public-profile-pages]

This is the heart of a Linktree clone: public profile pages that anyone can visit at `/username`.

Copy and paste this prompt:

```markdown
Build a public profile page at /[username] using Next.js App Router dynamic routes.

**Requirements:**

- Create `app/[username]/page.tsx` as a Server Component
- Fetch user + links from database by username (from URL params)
- Return 404 if user not found (use `notFound()` from next/navigation)
- Display: avatar (first letter), username, name, and list of links
- Links open in new tab with `target="_blank"`
- Add a small "Create your own" link at the bottom

**Pattern:**

1. Get params: `const { username } = await params`
2. Query database with `findUnique({ where: { username } })`
3. If no user: call `notFound()`
4. Render profile with links as clickable buttons

**Keep it simple:**

- No auth required (it's a public page)
- Pure Server Component (no 'use client')
- Basic styling with hover effects

This is the core "Linktree" feature — anyone can visit /username to see the links.
```

### Quick Check [#quick-check-5]

Test your public profile:

1. Navigate to `localhost:3000/your-username` (replace with your actual username)
2. Verify your profile and links display correctly
3. Click a link and confirm it opens in a new tab

## 8. Add a "Copy Link" Button [#8-add-a-copy-link-button]

Make it easy for users to share their profile URL with a one-click copy button.

Copy and paste this prompt:

```markdown
**Requirements:**

- Create a Client Component (`'use client'`) for the button
- Use `navigator.clipboard.writeText(url)` to copy
- Show "Copied!" feedback for 2 seconds after clicking
- Use `useState` to toggle the button text

**Pattern:**

1. Create `app/components/copy-button.tsx` with 'use client'
2. Accept `url` as a prop
3. On click: copy to clipboard, set `copied` to true
4. Use `setTimeout` to reset after 2 seconds
5. Import and use in your Server Component page

**Keep it simple:**

- One small client component
- No toast libraries
- Just inline text feedback ("Copy link" → "Copied!")
```

### Quick Check [#quick-check-6]

1. Find the "Copy link" button on your dashboard
2. Click it and verify it shows "Copied!"
3. Paste somewhere to confirm the URL was copied correctly

## 9. Create a Custom 404 Page [#9-create-a-custom-404-page]

When someone visits a non-existent username, they should see a friendly error page instead of a generic 404.

Copy and paste this prompt:

```markdown
Create a custom 404 page for Next.js App Router.

**Requirements:**

- Create `app/not-found.tsx` (Server Component)
- Display: 404 heading, friendly message, "Go home" button
- Match your app's design (colors, fonts, spacing)

**Pattern:**

- Next.js automatically uses `not-found.tsx` when `notFound()` is called
- Or when a route doesn't exist
- No configuration needed — just create the file

**Keep it simple:**

- Static page, no data fetching
- One heading, one message, one link
- Same styling as rest of the app
```

### Quick Check [#quick-check-7]

Test the 404 page by visiting a random URL like `/this-user-does-not-exist`. You should see your custom 404 page with a link back to the homepage.

## 10. Add a Custom Background [#10-add-a-custom-background]

Add a custom background pattern to the app.

**First**, either:

* Download a background SVG pattern you like, or
* Create your own using tools like [SVG Backgrounds](https://www.svgbackgrounds.com/) or [Hero Patterns](https://heropatterns.com/)

**Then**, save it as `background.svg` in your `public/` folder.

Copy and paste this prompt:

````markdown
Add a custom SVG background to my app.

**Requirements:**

- The svg file is in the `public/` folder (e.g., `public/background.svg`)
- Apply it as a fixed, full-cover background on the body

**Pattern:**
In `globals.css`, update the body:

```css
body {
  background: var(--background) url("/background.svg") center/cover no-repeat fixed;
  min-height: 100vh;
}
```

**Key properties:**

- `center/cover` — centers and scales to fill
- `no-repeat` — prevents tiling
- `fixed` — background stays in place when scrolling

Files in `public/` are served at the root URL, so `/background.svg` works.
````

### Quick Check [#quick-check-8]

1. Refresh your app
2. Verify the background appears on **all pages** (homepage, dashboard, profile pages, 404)
3. If the background doesn't appear everywhere, ask your AI to fix it

Commit your changes once it's working correctly.

## 11. Add Glassmorphism Card Containers [#11-add-glassmorphism-card-containers]

Create visual depth by adding semi-transparent card containers that "float" over the background.

Copy and paste this prompt:

````markdown
Add a reusable card container class to create visual separation from the background.

**Requirements:**

- Create a `.card` class in `globals.css`
- Apply glassmorphism: semi-transparent white + blur
- Use on all main content areas (landing, forms, dashboard, profile pages)

**Pattern:**
In `globals.css`, add:

```css
.card {
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(10px);
  border-radius: 1.5rem;
  padding: 2rem;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06);
}
```

**Usage:**
Wrap content sections with `<div className="card">...</div>`

For public profile pages (/[username]):
Wrap the entire profile (avatar, name, username, and links list) in a single .card container
This creates a Linktree-style floating card effect
Footer/attribution links stay outside the card

Hero section:
Add a soft radial glow behind the content (large blurred white circle, blur-3xl, 50% opacity)
No visible container edges — just organic, fading brightness
Content floats freely over the glow

**Result:**

- Content "lifts" off the background
- Subtle blur creates depth
- Consistent UI across all pages
````

## 12. Display Clerk Profile Images [#12-display-clerk-profile-images]

If users sign in with Google or another OAuth provider, Clerk stores their profile photo. Display it on public profiles.

Copy and paste this prompt:

````markdown
On the public profile page (`/[username]`), display the user's Clerk profile image (Google photo, etc.) instead of the initial letter avatar.

**Pattern:**

```typescript
// Fetch Clerk user to get profile image
const client = await clerkClient();
const clerkUser = await client.users.getUser(user.clerkId);
```

**Display:**

- Use a plain `<img>` tag (not Next.js Image component)
- If `clerkUser.imageUrl` exists, show the image
- Otherwise fallback to the yellow initial avatar

**Keep it simple:**

- No try/catch — let errors bubble up
- No next.config changes needed
- No database schema changes needed
````

### Quick Check [#quick-check-9]

Visit your public profile page and verify your profile image (from Google, GitHub, etc.) is displayed instead of the initial letter avatar.

## 13. Add Icons with Lucide [#13-add-icons-with-lucide]

Add icons with Lucide React to make buttons and empty states easier to read.

Copy and paste this prompt:

```markdown
Add Lucide React icons to improve the UI.

First install: npm install lucide-react

Add icons to these elements:

- View button: ExternalLink icon
- Delete button: Trash2 icon (replace text with icon)
- Empty links state: Link icon

Import icons from 'lucide-react' and use with size prop (e.g., size={18}).

Keep buttons minimal — only add icons where they improve clarity.
```

### Quick Check [#quick-check-10]

Browse through your app and verify the icons appear on:

* The view/external link buttons
* The delete buttons
* The empty state when no links exist

## 14. Deploy to Vercel [#14-deploy-to-vercel]

Deploy your app to Vercel.

> [!WARNING]
> Important Steps
> 
> Follow these steps carefully to avoid deployment errors.

### Step 1: Configure Prisma for Production [#step-1-configure-prisma-for-production]

Add a `postinstall` script to ensure Prisma Client is generated during deployment.

Add this to your `package.json` scripts section:

```json title="package.json"
{
  "scripts": {
    "postinstall": "prisma generate"
  }
}
```

📖 &#x2A;*Reference:** [Deploy to Vercel - Build Configuration](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-vercel#build-configuration)

### Step 2: Clean Up Development Files [#step-2-clean-up-development-files]

Delete the `scripts/` folder if it exists. This folder was auto-generated during initial setup for seed data, you don't need it in production.

### Step 3: Deploy to Vercel [#step-3-deploy-to-vercel]

1. Push your code to GitHub (if you haven't already)
2. Go to [vercel.com](https://vercel.com) and import your repository
3. **Important:** Add all your environment variables in Vercel's dashboard:
   * `DATABASE_URL`
   * `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY`
   * `CLERK_SECRET_KEY`

### Step 4: Update the App URL [#step-4-update-the-app-url]

After your first deployment:

1. Copy your production URL from Vercel (e.g., `https://your-app.vercel.app`)
2. Add a new environment variable in Vercel:
   ```text
   NEXT_PUBLIC_APP_URL=https://your-app.vercel.app
   ```
3. Redeploy to apply the change

> [!WARNING]
> Don't Forget This Step
> 
> If you skip setting `NEXT_PUBLIC_APP_URL`, features like the "Copy Link" button will copy `localhost` URLs instead of your production URL.

### Final Check [#final-check]

Test your deployed app thoroughly:

* [ ] Sign up flow works
* [ ] Username claiming works
* [ ] Adding/deleting links works
* [ ] Public profile pages load correctly
* [ ] Copy link copies the correct production URL
* [ ] 404 page displays for non-existent usernames

Your Linktree clone is live.

### Resources [#resources]

* [Prisma Documentation](https://www.prisma.io/docs/orm)
* [Next.js Documentation](https://nextjs.org/docs)
* [Clerk Documentation](https://clerk.com/docs)
* [Tailwind CSS Documentation](https://tailwindcss.com/docs)

## Related pages

- [`Build a Tweet SaaS with Next.js, Prisma Postgres, and Ollama`](https://www.prisma.io/docs/ai/tutorials/typefully-clone): A vibe coding tutorial: build a tweet polishing app from scratch using Next.js, Prisma ORM, Prisma Postgres, UploadThing, and a local LLM with Ollama.

# Build a Tweet SaaS with Next.js, Prisma Postgres, and Ollama (/docs/ai/tutorials/typefully-clone)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A vibe coding tutorial: build a tweet polishing app from scratch using Next.js, Prisma ORM, Prisma Postgres, UploadThing, and a local LLM with Ollama.

Location: AI > Tutorials > Build a Tweet SaaS with Next.js, Prisma Postgres, and Ollama

## Introduction [#introduction]

In this vibe coding tutorial, you'll build **TweetSmith**, a tweet polishing application that rewrites rough draft tweets into well-formatted content using AI. The AI runs locally on your machine, so no API keys are required.

You'll use an AI coding assistant to build a full-stack application with:

* **[Next.js](https://nextjs.org/)**: React framework for production
* **[Prisma ORM](https://www.prisma.io/orm)**: Type-safe database access
* **[Prisma Postgres](https://www.prisma.io/postgres)**: Serverless PostgreSQL database
* **[Ollama](https://ollama.com/)**: Run LLMs locally on your machine
* **[UploadThing](https://uploadthing.com/)**: File uploads for tweet images
* **[Lucide React](https://lucide.dev/)**: Icon library

By the end of this tutorial, you'll have a working application where users can paste draft tweets, transform them with AI, save their favorites, and even attach images, all built with AI-assisted development.

> [!NOTE]
> What is Vibe Coding?
> 
> Vibe coding is a development approach where you collaborate with AI assistants to build applications. You describe what you want to build, and the AI helps generate the code while you guide the direction and make architectural decisions.

## Video tutorial [#video-tutorial]

Watch this step-by-step walkthrough of the entire build process:

[Watch video](https://www.youtube.com/watch?v=QIuR2_pKFXA)

## Prerequisites [#prerequisites]

Before starting this tutorial, make sure you have:

* [Node.js 20+](https://nodejs.org) installed
* [Ollama](https://ollama.com/) installed on your machine
* An AI coding assistant ([Cursor](https://cursor.com), [Windsurf](https://windsurf.com), [GitHub Copilot](https://github.com/features/copilot), etc.)
* Basic familiarity with React and TypeScript

> [!NOTE]
> Recommended AI Models
> 
> Use Claude Sonnet 4, Gemini 2.5 Pro, GPT-4o, or a newer model. Older models generate less accurate code and handle the architecture in this tutorial less reliably.

## 1. Set up your local LLM [#1-set-up-your-local-llm]

Set up Ollama first so the local model is ready to transform tweets. It runs entirely on your machine, with no API keys, usage limits, or internet connection required.

### Pull the Model [#pull-the-model]

Open your terminal and download the Gemma 3 model:

```bash
ollama pull gemma3:4b
```

You should see a progress indicator like "pulling manifest…95%". This downloads approximately 3.3GB.

### Verify It's Working [#verify-its-working]

Test that the model responds:

```bash
ollama run gemma3:4b
```

Type something and confirm it responds. Press `Ctrl+C` to exit.

You can also verify the API is accessible:

```bash
curl http://localhost:11434/api/tags
```

You should see JSON output showing `gemma3:4b` is installed:

```json
{
  "models": [{
    "name": "gemma3:4b",
    "family": "gemma3",
    "parameter_size": "4.3B",
    "quantization_level": "Q4_K_M"
  }]
}
```

> [!NOTE]
> Gemma 3 4B
> 
> This model fits local development:
> 
> * **4.3B parameters**: enough for tweet formatting
> * **Q4_K_M quantization**: memory-efficient (\~3.3GB)
> * **Runs on M-series Macs** with 16GB RAM
> * **No API keys or costs**: free and private

Your local LLM is ready. Ollama runs as a background service, so you don't need to keep a terminal open.

## 2. Create your Next.js project [#2-create-your-nextjs-project]

Create a new Next.js application:

  

#### bun

```bash
bunx create-next-app@latest tweetsmith
```

#### pnpm

```bash
pnpm dlx create-next-app@latest tweetsmith
```

#### yarn

```bash
yarn dlx create-next-app@latest tweetsmith
```

#### npm

```bash
npx create-next-app@latest tweetsmith
```

When prompted, select:

* TypeScript: **Yes**
* ESLint: **Yes**
* Tailwind CSS: **Yes**
* `src/` directory: **No**
* App Router: **Yes**
* Turbopack: **Yes** (optional)
* Import alias: &#x2A;*@/**\* (default)

Navigate into your project:

```bash
cd tweetsmith
```

### Quick Check [#quick-check]

Start your development server to verify everything works:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open `http://localhost:3000`. You should see the default Next.js page.

> [!NOTE]
> Good Practice: Commit Early and Often
> 
> Throughout this tutorial, we'll commit our changes regularly. This makes it easy to track progress and roll back if something goes wrong.
> 
> ```bash
> git init
> git add .
> git commit -m "Initial setup: Next.js app"
> ```

## 3. Build the TweetSmith UI [#3-build-the-tweetsmith-ui]

Create a minimalist, dark-themed UI inspired by tools like [Typefully](https://typefully.com/). Copy and paste this prompt to your AI assistant:

```markdown
I have a fresh Next.js 15 project with Tailwind CSS already set up.

I need you to create a minimalist single-page UI for a TweetSmith app called "TweetSmith". 

**Design requirements:**
- Dark theme only (no light/dark toggle)
- Typefully-inspired aesthetic: sophisticated, clean, minimal
- Color palette:
  - Background: #141414 (soft charcoal)
  - Card/inputs: #1c1c1c
  - Borders: #2a2a2a
  - Muted text: #888888
  - Foreground/text: #fafafa
- Typography: Geist font (already configured), small refined sizes
- Labels should be uppercase with letter-spacing

**What to create:**

1. Update `app/globals.css` with the dark color palette and CSS variables

2. Update `app/layout.tsx` with proper metadata (title: "TweetSmith") and force the dark background

3. Create `app/components/TweetTransformer.tsx` - a client component with:
   - A textarea input for draft tweets
   - A character counter (X / 280)
   - A "Transform" button (disabled when empty)
   - An output section for the result (only visible when there's a result)
   - Loading state ready for future API integration
   - The handleTransform function should just console.log for now

4. Update `app/page.tsx` with:
   - Simple header with app name and tagline
   - The TweetTransformer component
   - Subtle footer saying "powered by ollama"

Keep it minimal, no extra features, just clean functional UI. Maximum width should be max-w-md for a focused feel.
```

### Quick Check [#quick-check-1]

1. Restart your dev server if needed
2. You should see a dark-themed page with a textarea and transform button
3. Type something and verify the character counter updates
4. The button should be disabled when the textarea is empty

Once it looks good, commit your changes:

```bash
git add .
git commit -m "Add TweetSmith UI"
```

## 4. Connect to your local LLM [#4-connect-to-your-local-llm]

Wire the UI to your local Ollama instance with a helper file and an API route.

### Create the Ollama Helper [#create-the-ollama-helper]

Copy and paste this prompt:

```markdown
Create `app/lib/ollama.ts` - a helper file to communicate with a local Ollama LLM.

Requirements:
- Ollama runs at http://localhost:11434
- Model name: "gemma3:4b"
- Use the /api/generate endpoint
- Create TypeScript types for OllamaRequest and OllamaResponse
- Export a function `generateWithOllama(prompt: string)` that:
  - Sends a POST request with the prompt
  - Uses stream: false (no streaming, keep it simple)
  - Returns the response text as a string
  - Throws an error if the request fails

Keep it minimal with clear comments explaining what each part does.
```

### Create the Transform API Route [#create-the-transform-api-route]

Copy and paste this prompt:

```markdown
Create `app/api/transform/route.ts` - a Next.js API route that transforms tweets.

Requirements:
- POST endpoint that accepts { draft: string } in the body
- Validate that draft exists and is a string (return 400 if invalid)
- Use the generateWithOllama function from "@/app/lib/ollama"
- Build a prompt that tells the LLM to:
  - Act as a tweet formatter
  - Make the draft cleaner, more engaging, well-formatted
  - Keep it under 280 characters
  - Return only the improved tweet, nothing else
- Return { transformed: string } on success
- Return { error: string } with status 500 if Ollama fails
- Add a helpful error message asking if Ollama is running

Use NextRequest and NextResponse from next/server.
```

### Connect the Frontend [#connect-the-frontend]

Copy and paste this prompt:

```markdown
Update the TweetTransformer component to call the transform API:

1. Add an "error" state (useState) to handle errors
2. Update handleTransform to:
   - Reset error and result states first
   - Set loading to true
   - Call POST /api/transform with { draft: draftTweet }
   - On success: set the transformed tweet from response
   - On error: set error message from the catch
   - Use finally to always set loading to false
3. Display error message in red below the button when there's an error

Keep the existing UI structure, just wire up the real API call.
```

### Quick Check [#quick-check-2]

1. Make sure Ollama is running in the background
2. Type a draft tweet like "just shipped a new feature, its pretty cool i think"
3. Click Transform
4. You should see a polished version appear after a few seconds

If you get an error, check that:

* Ollama is running (`curl http://localhost:11434/api/tags`)
* The model name matches (`gemma3:4b`)

## 5. Add Temperature for Variety [#5-add-temperature-for-variety]

You might notice the LLM returns the exact same output every time. That's because LLMs are deterministic by default: given the same input, they produce the same output. Adding a "temperature" parameter introduces controlled randomness that makes each response slightly different while keeping it coherent.

```markdown
Update the ollama.ts file to add temperature for response variety:

1. Add an optional "options" field to OllamaRequest type with temperature?: number
2. In the request body, add:
   options: {
     temperature: 0.7
   }
```

> [!NOTE]
> What is Temperature?
> 
> Temperature controls randomness in LLM responses. A value of `0` means deterministic (same output every time), while `1` means maximum creativity. `0.7` gives variety while staying on topic.

Now each transform gives slightly different results.

```bash
git add .
git commit -m "Connect to Ollama LLM for tweet transformation"
```

## 6. Add Filter Options [#6-add-filter-options]

Right now, every tweet gets the same treatment, but users have different needs: some want short tweets while others need the full 280 characters, and some want emojis while others don't. Give users control over the output with a collapsible filter panel for character limits and emoji usage.

First, install Lucide for icons:

  

#### bun

```bash
bun add lucide-react
```

#### pnpm

```bash
pnpm add lucide-react
```

#### yarn

```bash
yarn add lucide-react
```

#### npm

```bash
npm install lucide-react
```

Then copy and paste this prompt:

```markdown
Create `app/components/FilterOptions.tsx` with filters for tweet generation.

Requirements:
- Export a `Filters` type with: maxChars (number) and emojiMode ("none" | "few" | "many")
- Export two components:
  1. `FilterButton` - a toggle button showing current filter values (e.g., "Filters 280 · few")
  2. `FilterPanel` - the expanded controls panel

FilterButton props: isOpen, onToggle, filters
FilterPanel props: filters, onFiltersChange

FilterPanel should include:
- A range slider for maxChars (100-280, step 20)
- Three icon buttons for emoji mode using Lucide icons:
  - Ban icon for "none"
  - Smile icon for "few"  
  - SmilePlus icon for "many"
- Display inline with dividers between sections
- Compact design with small buttons (h-7 w-7)

Use SlidersHorizontal and ChevronDown from lucide-react for the button.
Style: dark theme, rounded-lg, border-border, bg-card.
```

## 7. Add Context Settings [#7-add-context-settings]

Filters control the format, but not the voice. A tech founder tweets differently than a lifestyle blogger, so let users describe their tone, style, and audience, and the AI can generate tweets that sound like them. Add a context panel where users describe their voice; it is saved to localStorage so it persists across sessions.

```markdown
Create `app/components/ContextSettings.tsx` with context management.

Export two components:
1. `ContextButton` - toggle button with User icon from lucide-react
   - Props: isOpen, onToggle, hasContext (boolean)
   - Show a small dot indicator when context is set
2. `ContextPanel` - just the textarea
   - Props: onContextChange
   - Load/save to localStorage with key "TweetSmith-context"

Use User and ChevronDown icons from lucide-react.
Keep the textarea at 2 rows, placeholder about style/tone.
```

### Integrate the Panels [#integrate-the-panels]

```markdown
Update `app/components/TweetTransformer.tsx` to use the new component structure.

Changes:
1. Import ContextButton, ContextPanel from ContextSettings
2. Import FilterButton, FilterPanel, Filters from FilterOptions
3. Add state for which panel is open: type OpenPanel = "none" | "context" | "filters"
4. Track hasContext state (check localStorage on mount)

Layout structure:
- Settings row: flex container with gap-2 containing both buttons INLINE
- Below the row: conditionally render either ContextPanel or FilterPanel (only one at a time)
- Clicking one panel closes the other

This keeps both buttons always on the same line, with expanded content appearing below.
Default filters: maxChars 280, emojiMode "few"
```

### Update the API to Use Filters [#update-the-api-to-use-filters]

```markdown
Update `app/api/transform/route.ts` to use the filter values.

Key changes:
1. Extract filter values directly: maxChars and emojiMode with defaults (280, "few")
2. Build emoji rule as a simple string based on mode
3. Put STRICT LIMITS at the TOP of the prompt (most important):
   - "Maximum {maxChars} characters (THIS IS MANDATORY)"
   - Emoji rule
   - "No hashtags"
4. Add context as "Author style:" if provided
5. Keep GUIDELINES brief: lead with value, sound human, be engaging
6. End with: 'Respond with ONLY the rewritten tweet. No quotes, no explanation.'

Remove any complex buildFilterRules function - inline everything for clarity.
The prompt should be shorter and more direct for better local LLM compliance.
```

### Quick Check [#quick-check-3]

1. Open the Filters panel and adjust the character limit
2. Toggle between emoji modes
3. Add some context like "Tech founder, casual tone"
4. Transform a tweet and verify the output respects your settings

```bash
git add .
git commit -m "Add filter options and context settings"
```

## 8. Create a Tweet Preview Card [#8-create-a-tweet-preview-card]

Plain text output works, but a preview styled like a real Twitter/X post, with profile picture, verified badge, and formatting, makes the result easier to judge and share. Create a tweet preview card with loading skeletons:

```markdown
Create `app/components/TweetPreview.tsx` - a tweet-like preview card with 3 states.

Props: content (string | null), isLoading (boolean)

Structure:
1. Header with profile image, name, verified badge, and handle
2. Content area (changes based on state)
3. Footer with character count or placeholder

Three states:
1. EMPTY (no content, not loading):
   - Show placeholder text styled like a tweet but in text-muted
   - Example: "Follow us on X to stay updated on all the latest features and releases from Prisma! 🚀\n\nYour polished tweet will appear here ✨"
   - Footer shows "prisma.io"

2. LOADING (isLoading true):
   - Show 3 animated skeleton bars with animate-pulse
   - Different widths: 90%, 75%, 60%
   - Footer skeleton bar

3. CONTENT (has content):
   - Show the actual tweet text
   - Copy button in header (using Copy/Check icons from lucide-react)
   - Footer shows "X / 280 characters"

Use Image from next/image for the profile picture.
Add verified badge as inline SVG (Twitter blue checkmark).
```

### Add a Logo [#add-a-logo]

Add a logo image (like `icon-logo.png`) to your `public/` folder, then:

```markdown
Update `app/page.tsx` to use a logo image instead of text for the header.

Changes:
1. Import Image from "next/image"
2. Replace the h1 text with an Image component:
   - src="/icon-logo.png" (or your logo file)
   - width={80} height={80}
   - Add className="mb-3" for spacing
3. Keep the tagline text below: "polish your tweets with AI"
4. Use flex flex-col items-center on the header

The header should now show: Logo image centered, tagline below.
```

```bash
git add .
git commit -m "Add tweet preview card and logo"
```

## 9. Add Prisma Postgres [#9-add-prisma-postgres]

Add a database to save favorite tweets, using Prisma ORM with Prisma Postgres.

### Install Dependencies [#install-dependencies]

  

#### bun

```bash
bun add prisma@prev tsx --dev
bun add @prisma/adapter-pg @prisma/client@7 dotenv
```

#### pnpm

```bash
pnpm add prisma@prev tsx --save-dev
pnpm add @prisma/adapter-pg @prisma/client@7 dotenv
```

#### yarn

```bash
yarn add prisma@prev tsx --dev
yarn add @prisma/adapter-pg @prisma/client@7 dotenv
```

#### npm

```bash
npm install prisma@prev tsx --save-dev
npm install @prisma/adapter-pg @prisma/client@7 dotenv
```

### Initialize Prisma [#initialize-prisma]

> [!WARNING]
> User Action Required
> 
> Run the following commands in your terminal. `prisma init` creates the project files, and `create-db` gives you the `postgres://...` connection string you need for Prisma Postgres.

  

#### bun

```bash
bunx --bun prisma init --output ../app/generated/prisma
bunx create-db
```

#### pnpm

```bash
pnpm prisma init --output ../app/generated/prisma
pnpm dlx create-db
```

#### yarn

```bash
yarn prisma init --output ../app/generated/prisma
yarn dlx create-db
```

#### npm

```bash
npx prisma init --output ../app/generated/prisma
npx create-db
```

Replace the generated `DATABASE_URL` in `.env` with the `postgres://...` connection string from `npx create-db`.

> [!NOTE]
> Important: Check Your DATABASE_URL
> 
> Ensure your `.env` file uses a standard PostgreSQL URL format:
> 
> ```bash
> DATABASE_URL="postgres://..."
> ```
>
> If it still shows `prisma+postgres://...`, replace it with the `postgres://...` connection string from `npx create-db`.

### Update the Schema [#update-the-schema]

Replace the contents of `prisma/schema.prisma` with:

```prisma
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model SavedTweet {
  id          String   @id @default(cuid())
  original    String   // The draft tweet input
  transformed String   // The polished/transformed tweet
  context     String?  // Optional user context/style used
  imageUrl    String?  // Optional image URL
  imageAlt    String?  // Optional alt text for accessibility
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}
```

### Create the Prisma Client [#create-the-prisma-client]

Create `lib/prisma.ts`:

```typescript
import { PrismaClient } from "../app/generated/prisma/client"
import { PrismaPg } from "@prisma/adapter-pg"

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
})

const globalForPrisma = global as unknown as { prisma: PrismaClient }

const prisma = globalForPrisma.prisma || new PrismaClient({
  adapter,
})

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma

export default prisma
```

### Add Database Scripts [#add-database-scripts]

Update your `package.json` scripts:

```json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint",
    "db:test": "tsx scripts/test-database.ts",
    "db:studio": "prisma studio"
  }
}
```

### Create a Test Script [#create-a-test-script]

Create `scripts/test-database.ts`:

```typescript
import "dotenv/config"
import prisma from "../lib/prisma"

async function testDatabase() {
  console.log("🔍 Testing Prisma Postgres connection...\n")

  try {
    console.log("✅ Connected to database!")

    console.log("\n📝 Creating a test saved tweet...")
    const newTweet = await prisma.savedTweet.create({
      data: {
        original: "just shipped a new feature, its pretty cool i think",
        transformed: "Just shipped a new feature! 🚀 Pretty excited about this one ✨",
        context: "Tech founder, casual tone",
      },
    })
    console.log("✅ Created saved tweet:", newTweet)

    console.log("\n📋 Fetching all saved tweets...")
    const allTweets = await prisma.savedTweet.findMany()
    console.log(`✅ Found ${allTweets.length} saved tweet(s)`)

    console.log("\n🎉 All tests passed! Your database is working perfectly.\n")
  } catch (error) {
    console.error("❌ Error:", error)
    process.exit(1)
  }
}

testDatabase()
```

### Push Schema and Test [#push-schema-and-test]

  

#### bun

```bash
bunx prisma db push
bunx prisma generate
bun run db:test
```

#### pnpm

```bash
pnpm prisma db push
pnpm prisma generate
pnpm run db:test
```

#### yarn

```bash
yarn prisma db push
yarn prisma generate
yarn db:test
```

#### npm

```bash
npx prisma db push
npx prisma generate
npm run db:test
```

You should see success messages. Open Prisma Studio to view your data:

  

#### bun

```bash
bun run db:studio
```

#### pnpm

```bash
pnpm run db:studio
```

#### yarn

```bash
yarn db:studio
```

#### npm

```bash
npm run db:studio
```

### Create the Tweets API [#create-the-tweets-api]

Copy and paste this prompt:

```markdown
Create `app/api/tweets/route.ts` with GET, POST, and DELETE handlers.

Requirements:
- GET: Fetch all saved tweets ordered by createdAt desc
- POST: Save a new tweet with { original, transformed, context?, imageUrl?, imageAlt? }
- DELETE: Delete a tweet by id (passed as query param ?id=xxx)

Use try-catch blocks and return appropriate error responses.
Import prisma from "../../../lib/prisma"
```

### Quick Check [#quick-check-4]

Test the API with curl:

```bash
# Save a tweet
curl -X POST http://localhost:3000/api/tweets \
  -H "Content-Type: application/json" \
  -d '{"original":"test draft","transformed":"Test polished! ✨"}'

# Get all tweets
curl http://localhost:3000/api/tweets
```

```bash
git add .
git commit -m "Add Prisma Postgres database"
```

## 10. Add Save Functionality [#10-add-save-functionality]

Users often want to save their best transformed tweets for later, whether they are not ready to post yet or want to build a collection. Add a save button to the tweet preview card with visual feedback:

```markdown
Add a Save button to save transformed tweets to the database.

Requirements:
- Add a Save button next to the Copy button in TweetPreview
- Use POST /api/tweets with { original, transformed, context }
- Pass original (draft) and context from TweetTransformer to TweetPreview

UX States:
- Default: Bookmark icon with hover scale effect
- Saving: Spinning Loader2 icon + "Saving" text
- Saved: Green tinted background (emerald-500/10), checkmark icon with zoom animation

Important: The "Saved" state must persist until a NEW tweet is generated. Use useRef to track previous content and useEffect to reset saved state only when content changes. Do not use setTimeout to reset the saved state.

Match the minimal dark aesthetic of the app (200ms ease-out transitions, subtle hover states).
```

## 11. Build the Tweet Library [#11-build-the-tweet-library]

Saved tweets need a place to live. Build a slide-in library panel where users can browse their saved tweets, copy them for posting, or load them back as drafts to iterate further. This completes the workflow from draft to polish to save to reuse:

```markdown
Add a Library feature to browse and reuse saved tweets.

Components to create:
- LibraryButton.tsx - Fixed top-right button with count badge
- LibraryPanel.tsx - Slide-in panel from right (360px, backdrop blur)
- SavedTweetCard.tsx - Tweet cards that look like published tweets

LibraryButton:
- Fixed position top-right (fixed top-6 right-6)
- Shows saved tweets count as badge
- Toggles panel open/close

LibraryPanel:
- Slides in from right with 300ms ease-out animation
- Backdrop overlay with blur
- Header with title, count, and close button
- Scrollable list of SavedTweetCard components
- Empty state with icon when no tweets saved
- Fetches tweets from GET /api/tweets when opened

SavedTweetCard:
- Looks like a real published tweet (profile image, name, verified badge, handle, date)
- Shows transformed tweet content only (not original)
- Footer: character count on left, Copy/Delete icons on right (subtle, brighten on hover)
- Click anywhere on card → loads transformed text into Draft textarea and closes panel
- Delete shows inline confirmation (Cancel/Delete buttons), not a modal

Integration:
- Add library state to TweetTransformer (isOpen, count)
- Fetch count on mount and after saving
- Pass onUseAsDraft callback to set draft and clear transformed tweet
- Refresh count when panel closes (in case tweets were deleted)

Styling: Match minimal dark aesthetic - subtle borders, muted colors, smooth 200ms transitions.
```

### Quick Check [#quick-check-5]

1. Save a few transformed tweets
2. Click the Library button in the top-right
3. Verify your saved tweets appear in the panel
4. Click a tweet to load it back into the draft
5. Delete a tweet and verify it disappears

```bash
git add .
git commit -m "Add tweet library with save/browse/delete"
```

## 12. Add Theme Switcher [#12-add-theme-switcher]

Add a choice of dark themes so users can pick one that matches their style, from purple twilight to warm desert tones to newspaper grey:

```markdown
Add a theme system to my app with 3 dark themes and a minimal theme switcher.

THEMES:
1. "Disco" - Purple/violet twilight vibes
   - Background: #17171c (deep blue-black)
   - Accent: #a78bfa (soft violet)
   
2. "Dust" - Desert warmth, amber tones
   - Background: #1a1816 (warm charcoal)
   - Accent: #d4a574 (warm amber/sand)
   
3. "Press" - Old newspaper, pure greys
   - Background: #262626 (true grey)
   - Accent: #a3a3a3 (neutral grey)

IMPLEMENTATION:
- Use CSS custom properties (:root and [data-theme="..."]) for all colors
- Add a subtle radial gradient glow at the top of the page using the accent color
- Create a ThemeSwitcher component with small colored dots (one per theme)
- Place the switcher in the footer for minimal UI impact
- Persist theme choice in localStorage
- Add smooth transitions when switching themes (0.3s ease)
- Prevent transition flash on page load with a "no-transitions" class

UX REQUIREMENTS:
- Each dot shows the accent color of that theme
- Selected theme has a subtle ring + slight scale up
- Unselected themes are dimmed (opacity 40%) and brighten on hover
- Theme changes should animate smoothly across all UI elements
```

## 13. Add Smooth Animated Panels [#13-add-smooth-animated-panels]

The filter and context panels currently appear and disappear abruptly. Use the CSS Grid height animation trick to animate expand and collapse without the layout jumps of traditional height transitions:

```markdown
Add smooth animated collapsible panels that expand/collapse without layout jumps.

ANIMATED PANEL COMPONENT:
Create a reusable AnimatedPanel component using the CSS Grid trick for height animation:

- Use display: grid with gridTemplateRows
- Closed state: gridTemplateRows: "0fr" (collapses to 0 height)
- Open state: gridTemplateRows: "1fr" (expands to content height)
- Wrap children in a div with overflow: hidden
- Add opacity fade: 0 when closed, 1 when open
- Transition: "grid-template-rows 0.25s cubic-bezier(0.32, 0.72, 0, 1), opacity 0.2s ease"

COLLAPSE GAP TRICK:
If parent uses gap/space between items, add negative margin when closed to collapse the gap:
- marginTop: isOpen ? undefined : "-12px" (adjust based on your gap size)
- Animate the margin too for smooth effect

PREVENT SCROLLBAR LAYOUT SHIFT:
Add to your global CSS on html element:
- scrollbar-gutter: stable (reserves space for scrollbar)
- overflow-x: hidden (prevents horizontal scroll)

This creates buttery smooth expand/collapse without the jarring height jump or scrollbar layout shift.
```

```bash
git add .
git commit -m "Add themes and smooth animations"
```

## 14. Add Image Uploads [#14-add-image-uploads]

Let users attach an image to their polished tweets. UploadThing handles the file upload, with a pattern that previews locally first and uploads only when saving, so no orphaned files are left if users change their mind:

### Install UploadThing [#install-uploadthing]

  

#### bun

```bash
bun add uploadthing @uploadthing/react
```

#### pnpm

```bash
pnpm add uploadthing @uploadthing/react
```

#### yarn

```bash
yarn add uploadthing @uploadthing/react
```

#### npm

```bash
npm install uploadthing @uploadthing/react
```

### Get your API token [#get-your-api-token]

1. Go to [uploadthing.com](https://uploadthing.com) and create an account
2. Create a new app in the dashboard
3. Copy your `UPLOADTHING_TOKEN` and add it to your `.env`:

```bash
UPLOADTHING_TOKEN=your_token_here
```

### Implement Image Upload [#implement-image-upload]

```markdown
Add image upload to tweets using UploadThing.

Requirements:
1. Users should be able to attach ONE image to their tweet
2. The image should only be uploaded to UploadThing when clicking "Save" (not when selecting the image)
3. While editing, show a local preview using URL.createObjectURL() - this avoids orphaned uploads if the user changes their mind
4. Show upload progress in the Save button ("Uploading..." → "Saving...")
5. Allow removing the selected image before saving (X button on the image preview)
6. Display saved images in the tweet library/cards

Implementation steps:
1. Create UploadThing FileRouter at app/api/uploadthing/core.ts with a "tweetImage" route (4MB max, 1 file)
2. Create the route handler at app/api/uploadthing/route.ts
3. Create typed utilities at app/lib/uploadthing.ts with useUploadThing hook
4. Update TweetPreview component:
   - Add file state (File object) and preview URL state
   - Add hidden file input + "Add image" label/button
   - Show image preview with remove button
   - In handleSave: if file exists, call startUpload() first, then save tweet with the returned URL
5. Update SavedTweetCard to display imageUrl if present

The schema already has imageUrl and imageAlt fields.
Key pattern: Store File locally → preview with createObjectURL → upload only on save → save URL to database
```

### Quick Check [#quick-check-6]

1. Transform a tweet
2. Click "Add image" and select a photo
3. Verify the preview appears with an X button to remove
4. Click Save and watch the button states: "Uploading..." → "Saving..." → "Saved!"
5. Open the Library and verify the image appears with the saved tweet

```bash
git add .
git commit -m "Add image upload with UploadThing"
```

## Summary [#summary]

You've built a tweet polishing application with:

* ✅ Local AI with Ollama (no API keys)
* ✅ Customizable filters and context
* ✅ Three dark themes
* ✅ Cloud database with Prisma Postgres
* ✅ Image uploads with UploadThing
* ✅ Animated panels

### Next steps [#next-steps]

Here are some ideas to extend your app:

* Add user authentication with [Clerk](https://clerk.com)
* Add multiple LLM model options
* Implement tweet scheduling
* Add analytics to track transformations
* Create shareable public links

## Resources [#resources]

* [Prisma Documentation](https://www.prisma.io/docs/orm)
* [Next.js Documentation](https://nextjs.org/docs)
* [Ollama Documentation](https://ollama.com/library)
* [UploadThing Documentation](https://docs.uploadthing.com)
* [Tailwind CSS Documentation](https://tailwindcss.com/docs)
* [Lucide Icons](https://lucide.dev/icons)

## Related pages

- [`Linktree Clone SaaS`](https://www.prisma.io/docs/ai/tutorials/linktree-clone): A vibe coding tutorial: build a Linktree clone SaaS application from scratch using Next.js, Prisma ORM, Prisma Postgres, and Clerk authentication with AI assistance

# Database Metrics (/docs/console/features/metrics)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Monitor your database performance with Console metrics

Location: Console > Features > Database Metrics

You can have a single workspace that hosts several databases. Within each database, you can view detailed reports on how your database is performing, with various metrics like:

* Average response size
* Average query duration
* Total egress
* Total operations
* Cache utilization

## Databases [#databases]

For Prisma Postgres projects, the **Database** tab in the project view lets you configure and manage your databases. This interface provides tools to monitor and maintain your database resources. The **Connections** section displays a table with the following columns:

| Column Name   | Description                                                                      |
| ------------- | -------------------------------------------------------------------------------- |
| **Hint**      | Provides the URL structure for the database in use.                              |
| **Static IP** | Indicates whether static IP is enabled for the database and associated products. |
| **Products**  | Lists the products that are enabled using the database URL.                      |
| **Action**    | Allows you to disable all active products and remove the connection.             |

# Feature Maturity (/docs/console/more/feature-maturity)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Understand Early Access, Preview, and Public Beta feature stages in the Console

Location: Console > More > Feature Maturity

Prisma releases updates to Console multiple times per week, as opposed to the Prisma ORM that we release on a set schedule every few weeks. This is why we consider the lifecycle and process for maturing features in Console differently.

You can [check out the releases and maturity process for the Prisma ORM](https://www.prisma.io/docs/orm/v7/more/releases) for further details.

You can find information about releases across *all* Prisma tools and products in the [changelog](https://www.prisma.io/changelog).

## Early Access [#early-access]

If a feature on the Console is labeled as **Early Access**:

* It is ready to try out and represents the cutting edge of what we are building.
* It can still evolve based on feedback from our users, and its API surface won't change drastically as it matures.
* We reserve ourselves the right to throttle or remove access to a feature in Early Access to preserve the stability of the platform, or enforce its use to stay within the scope defined in our [Terms of Service](https://pris.ly/terms).

Your feedback in our [Discord](https://pris.ly/discord?utm_source=docs\&utm_medium=inline_text) shapes the design of the features. This will help us ensure that they can solve your problems in the best way possible.

## Preview [#preview]

If a feature on the Console is labeled as **Preview**:

* We have refined the software based on the valuable feedback we obtained during the Early Access phase.
* We developed the feature further, bringing it closer to the final version, and it is close to being ready for production usage.
* We have lifted the invite gate, so users no longer need an invitation to access the feature. Users just need to sign up to gain access.
* We have increased the stability of the software compared to the Early Access phase. While there might still be some issues, they should be less frequent and less critical.
* We use the Preview phase as a final stress test to ensure the product is ready for heavy production workloads.

We recommend testing the product in a staging environment and welcome any feedback in our [Discord](https://pris.ly/discord?utm_source=docs\&utm_medium=inline_text). This will assist us in improving the product for its final release.

## Public Beta [#public-beta]

If a product or feature is labeled as **Public Beta**:

* It is open for anyone to try. No invite or waitlist is required.
* The core model is stable, and the documented happy paths work end to end. It is a good fit for evaluation, dogfooding, staging environments, internal tools, and low-risk apps.
* Behavior should stay stable unless the documentation or release notes call out an exception.
* Details can still change before general availability: exact limits, pricing, retention policies, runtime guardrails, supported frameworks and build behavior, some CLI and API details, Console UX, naming, and advanced workflows.
* We don't recommend it yet for mission-critical or heavy production workloads.

Public Beta is the final stress-test phase before general availability. Expect some rough edges, and tell us about them in [Discord](https://pris.ly/discord?utm_source=docs\&utm_medium=inline_text); your feedback directly shapes the release.

## Related pages

- [`Support`](https://www.prisma.io/docs/console/more/support): Find the right support for any Console question

# Support (/docs/console/more/support)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Find the right support for any Console question

Location: Console > More > Support

Share your experiences with us on [Discord](https://pris.ly/discord?utm_source=docs\&utm_medium=intro_text).

## Support [#support]

Your support options are based on your workspace's active plan. For more details, take a look at our [pricing page](https://www.prisma.io/pricing).

### Community support [#community-support]

Reach out to us in our [Discord](https://pris.ly/discord?utm_source=docs\&utm_medium=inline_text).

### Standard support [#standard-support]

* Email support, [support@prisma.io](mailto\:support@prisma.io), or reach out via the Console
* 2 business days, Mon-Fri, 9am-5pm CET

### Premium support [#premium-support]

* Email support, [support@prisma.io](mailto\:support@prisma.io), or reach out via the Console
* 1 business hour, Mon-Fri, 9am-5pm CET

### Dedicated support [#dedicated-support]

Dedicated contact person.

## Deleting your PDP account [#deleting-your-pdp-account]

If you want to delete your PDP account, &#x2A;*email us at [support@prisma.io](mailto\:support@prisma.io)** specifying the email id or GitHub handle with which you signed up.

To ensure that you're not accidentally disabling any infrastructure powering one of your applications, we require that you **disable Accelerate in *all* environments of *all* your projects** that live in the account to be deleted.
Additionally there should be no active subscriptions in the account to be deleted. Please cancel any active subscriptions before requesting account deletion.

## Related pages

- [`Feature Maturity`](https://www.prisma.io/docs/console/more/feature-maturity): Understand Early Access, Preview, and Public Beta feature stages in the Console

# debug (Prisma CLI v7) (/docs/cli/v7/debug)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting

Location: CLI > v7 > debug

The `prisma debug` command prints information helpful for debugging and bug reports.

> [!NOTE]
> Available from version 5.6.0 and newer.

## Usage [#usage]

```bash
prisma debug [options]
```

## Options [#options]

| Option         | Description                            |
| -------------- | -------------------------------------- |
| `-h`, `--help` | Display help message                   |
| `--config`     | Custom path to your Prisma config file |
| `--schema`     | Custom path to your Prisma schema      |

## Examples [#examples]

### Display debug information [#display-debug-information]

  

#### bun

```bash
bunx prisma debug
```

#### pnpm

```bash
pnpm prisma debug
```

#### yarn

```bash
yarn prisma debug
```

#### npm

```bash
npx prisma debug
```

Output:

```text
-- Prisma schema --
Path: /prisma/schema.prisma

-- Local cache directory for engines files --
Path: /.cache/prisma

-- Environment variables --
When not set, the line is dimmed and no value is displayed.
When set, the line is bold and the value is inside the `` backticks.

For general debugging
 - CI:
 - DEBUG:
 - NODE_ENV:
 - RUST_LOG:
 - RUST_BACKTRACE:
 - NO_COLOR:
 - TERM: `xterm-256color`
 - NODE_TLS_REJECT_UNAUTHORIZED:
 - NO_PROXY:
 - http_proxy:
 - HTTP_PROXY:
 - https_proxy:
 - HTTPS_PROXY:

For hiding messages
 - PRISMA_DISABLE_WARNINGS:
 - PRISMA_HIDE_PREVIEW_FLAG_WARNINGS:
 - PRISMA_HIDE_UPDATE_MESSAGE:

For downloading engines
 - PRISMA_ENGINES_MIRROR:
 - PRISMA_BINARIES_MIRROR (deprecated):
 - PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING:
 - BINARY_DOWNLOAD_VERSION:

For custom engines
 - PRISMA_SCHEMA_ENGINE_BINARY:
 - PRISMA_MIGRATION_ENGINE_BINARY:

For Prisma Client
 - PRISMA_SHOW_ALL_TRACES:

For Prisma Migrate
 - PRISMA_SCHEMA_DISABLE_ADVISORY_LOCK:

For Prisma Studio
 - BROWSER:

-- Terminal is interactive? --
true

-- CI detected? --
false
```

### Use with older versions [#use-with-older-versions]

If using an older Prisma version:

  

#### bun

```bash
bunx prisma@prev debug
```

#### pnpm

```bash
pnpm dlx prisma@prev debug
```

#### yarn

```bash
yarn dlx prisma@prev debug
```

#### npm

```bash
npx prisma@prev debug
```

## Related pages

- [`db`](https://www.prisma.io/docs/cli/v7/db): Manage your database schema and lifecycle during development
- [`dev`](https://www.prisma.io/docs/cli/v7/dev): Start a local Prisma Postgres server for development
- [`format`](https://www.prisma.io/docs/cli/v7/format): Format and validate your Prisma schema file with consistent structure
- [`generate`](https://www.prisma.io/docs/cli/v7/generate): Generate artifacts like Prisma Client based on your Prisma schema
- [`init`](https://www.prisma.io/docs/cli/v7/init): Set up a new Prisma project in the current directory

# format (Prisma CLI v7) (/docs/cli/v7/format)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Format and validate your Prisma schema file with consistent structure

Location: CLI > v7 > format

The `prisma format` command formats your Prisma schema file. It validates, formats, and persists the schema.

## Usage [#usage]

```bash
prisma format [options]
```

## Options [#options]

| Option         | Description                            |
| -------------- | -------------------------------------- |
| `-h`, `--help` | Display help message                   |
| `--config`     | Custom path to your Prisma config file |
| `--schema`     | Custom path to your Prisma schema      |

## Examples [#examples]

### Format the default schema [#format-the-default-schema]

  

#### bun

```bash
bunx prisma format
```

#### pnpm

```bash
pnpm prisma format
```

#### yarn

```bash
yarn prisma format
```

#### npm

```bash
npx prisma format
```

Output on success:

```text
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Formatted prisma/schema.prisma in 116ms
```

### Format a specific schema [#format-a-specific-schema]

  

#### bun

```bash
bunx prisma format --schema=./alternative/schema.prisma
```

#### pnpm

```bash
pnpm prisma format --schema=./alternative/schema.prisma
```

#### yarn

```bash
yarn prisma format --schema=./alternative/schema.prisma
```

#### npm

```bash
npx prisma format --schema=./alternative/schema.prisma
```

## Error output [#error-output]

If the schema has validation errors, formatting will fail:

```text
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Error: Schema validation error - Error (query-engine-node-api library)
Error code: P1012
error: The preview feature "unknownFeatureFlag" is not known. Expected one of: [...]
  schema.prisma:3
   |
 2 |     provider        = "prisma-client"
 3 |     previewFeatures = ["unknownFeatureFlag"]
   |

Validation Error Count: 1
```

## Related pages

- [`db`](https://www.prisma.io/docs/cli/v7/db): Manage your database schema and lifecycle during development
- [`debug`](https://www.prisma.io/docs/cli/v7/debug): Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting
- [`dev`](https://www.prisma.io/docs/cli/v7/dev): Start a local Prisma Postgres server for development
- [`generate`](https://www.prisma.io/docs/cli/v7/generate): Generate artifacts like Prisma Client based on your Prisma schema
- [`init`](https://www.prisma.io/docs/cli/v7/init): Set up a new Prisma project in the current directory

# generate (Prisma CLI v7) (/docs/cli/v7/generate)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Generate artifacts like Prisma Client based on your Prisma schema

Location: CLI > v7 > generate

The `prisma generate` command generates assets like Prisma Client based on the [`generator`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators) and [`data model`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models) blocks defined in your `schema.prisma` file.

## Usage [#usage]

```bash
prisma generate [options]
```

## How it works [#how-it-works]

1. Inspects the current directory to find a Prisma schema
2. Generates a customized Prisma Client based on your schema into the output directory specified in the generator block

## Prerequisites [#prerequisites]

Add a generator definition in your `schema.prisma` file:

```prisma
generator client {
  provider = "prisma-client"
  output   = "./generated"
}
```

## Options [#options]

| Option             | Description                                            |
| ------------------ | ------------------------------------------------------ |
| `-h`, `--help`     | Display help message                                   |
| `--config`         | Custom path to your Prisma config file                 |
| `--schema`         | Custom path to your Prisma schema                      |
| `--sql`            | Generate typed SQL module                              |
| `--watch`          | Watch the Prisma schema and regenerate after changes   |
| `--generator`      | Generator to use (can be provided multiple times)      |
| `--no-hints`       | Hide hint messages (still outputs errors and warnings) |
| `--require-models` | Do not allow generating a client without models        |

## Examples [#examples]

### Generate Prisma Client [#generate-prisma-client]

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

Output:

```text
✔ Generated Prisma Client to ./node_modules/.prisma/client in 61ms

You can now start using Prisma Client in your code:

import { PrismaClient } from '../prisma/generated/client'

const prisma = new PrismaClient()
```

### Generate with a custom schema path [#generate-with-a-custom-schema-path]

  

#### bun

```bash
bunx prisma generate --schema=./alternative/schema.prisma
```

#### pnpm

```bash
pnpm prisma generate --schema=./alternative/schema.prisma
```

#### yarn

```bash
yarn prisma generate --schema=./alternative/schema.prisma
```

#### npm

```bash
npx prisma generate --schema=./alternative/schema.prisma
```

### Watch mode [#watch-mode]

Automatically regenerate when the schema changes:

  

#### bun

```bash
bunx prisma generate --watch
```

#### pnpm

```bash
pnpm prisma generate --watch
```

#### yarn

```bash
yarn prisma generate --watch
```

#### npm

```bash
npx prisma generate --watch
```

Output:

```text
Watching... /home/prismauser/prisma/schema.prisma

✔ Generated Prisma Client to ./node_modules/.prisma/client in 45ms
```

### Generate specific generators [#generate-specific-generators]

Run only specific generators:

  

#### bun

```bash
bunx prisma generate --generator client
```

#### pnpm

```bash
pnpm prisma generate --generator client
```

#### yarn

```bash
yarn prisma generate --generator client
```

#### npm

```bash
npx prisma generate --generator client
```

Multiple generators:

  

#### bun

```bash
bunx prisma generate --generator client --generator zod_schemas
```

#### pnpm

```bash
pnpm prisma generate --generator client --generator zod_schemas
```

#### yarn

```bash
yarn prisma generate --generator client --generator zod_schemas
```

#### npm

```bash
npx prisma generate --generator client --generator zod_schemas
```

## Generated assets [#generated-assets]

The `prisma-client` generator creates a customized client for working with your database. You can [customize the output folder](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider) using the `output` field in the generator block.

## Related pages

- [`db`](https://www.prisma.io/docs/cli/v7/db): Manage your database schema and lifecycle during development
- [`debug`](https://www.prisma.io/docs/cli/v7/debug): Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting
- [`dev`](https://www.prisma.io/docs/cli/v7/dev): Start a local Prisma Postgres server for development
- [`format`](https://www.prisma.io/docs/cli/v7/format): Format and validate your Prisma schema file with consistent structure
- [`init`](https://www.prisma.io/docs/cli/v7/init): Set up a new Prisma project in the current directory

# Overview (Prisma CLI v7) (/docs/cli/v7)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The Prisma CLI is the command-line interface for Prisma ORM. Use it to initialize projects, generate Prisma Client, manage databases, run migrations, and browse data with Prisma Studio

Location: CLI > Overview

The Prisma CLI provides commands for:

* **Project setup**: Initialize new Prisma projects
* **Code generation**: Generate Prisma Client and other artifacts
* **Database management**: Pull schemas, push changes, seed data
* **Migrations**: Create, apply, and manage database migrations
* **Development tools**: Local database servers, schema validation, formatting

## Installation [#installation]

The Prisma CLI is available as an npm package. Install it as a development dependency:

  

#### bun

```bash
bun add prisma@prev --dev
```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
```

#### yarn

```bash
yarn add prisma@prev --dev
```

#### npm

```bash
npm install prisma@prev --save-dev
```

> [!NOTE]
> This page documents the Prisma 7 CLI that ships in the `prisma` package. Prisma 8 introduces a new, unified Prisma CLI that also includes commands for [Prisma Composer](https://www.prisma.io/docs/composer) and [Prisma Compute](https://www.prisma.io/docs/compute). Prisma 8 publishes it as `prisma@latest`. See the [Prisma 8 CLI reference](https://www.prisma.io/docs/cli), the [`deploy`](https://www.prisma.io/docs/cli/deploy) and [`dev`](https://www.prisma.io/docs/cli/dev) commands, and the [platform commands](https://www.prisma.io/docs/cli#platform-commands).

## Usage [#usage]

```bash
prisma [command]
```

## Commands [#commands]

| Command                        | Description                                          |
| ------------------------------ | ---------------------------------------------------- |
| [`init`](https://www.prisma.io/docs/cli/v7/init)         | Set up Prisma for your app                           |
| [`dev`](https://www.prisma.io/docs/cli/v7/dev)           | Start a local Prisma Postgres server for development |
| [`generate`](https://www.prisma.io/docs/cli/v7/generate) | Generate artifacts (e.g. Prisma Client)              |
| [`db`](https://www.prisma.io/docs/cli/v7/db)             | Manage your database schema and lifecycle            |
| [`migrate`](https://www.prisma.io/docs/cli/v7/migrate)   | Migrate your database                                |
| [`studio`](https://www.prisma.io/docs/cli/v7/studio)     | Browse your data with Prisma Studio                  |
| [`validate`](https://www.prisma.io/docs/cli/v7/validate) | Validate your Prisma schema                          |
| [`format`](https://www.prisma.io/docs/cli/v7/format)     | Format your Prisma schema                            |
| [`version`](https://www.prisma.io/docs/cli/v7/version)   | Display Prisma version info                          |
| [`debug`](https://www.prisma.io/docs/cli/v7/debug)       | Display Prisma debug info                            |

## Global flags [#global-flags]

These flags are available for all commands:

| Flag                | Description                         |
| ------------------- | ----------------------------------- |
| `--help`, `-h`      | Show help information for a command |
| `--preview-feature` | Run Preview Prisma commands         |

## Using a HTTP proxy [#using-a-http-proxy]

Prisma CLI supports custom HTTP proxies. This is useful when behind a corporate firewall.

Set one of these environment variables:

* `HTTP_PROXY` or `http_proxy`: Proxy URL for HTTP traffic (e.g., `http://localhost:8080`)
* `HTTPS_PROXY` or `https_proxy`: Proxy URL for HTTPS traffic (e.g., `https://localhost:8080`)

## Related pages

- [`auth`](https://www.prisma.io/docs/cli/auth): Sign in to your Prisma account from the CLI, sign out, and manage workspace sessions.
- [`branch`](https://www.prisma.io/docs/cli/branch): List platform branches for a project.
- [`bucket`](https://www.prisma.io/docs/cli/bucket): Create and manage object-store buckets.
- [`Configuration`](https://www.prisma.io/docs/cli/configuration): Configure Prisma ORM CLI commands with prisma.config.ts and global flags.
- [`contract emit`](https://www.prisma.io/docs/cli/contract-emit): Emit Prisma ORM contract artifacts.

# init (Prisma CLI v7) (/docs/cli/v7/init)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up a new Prisma project in the current directory

Location: CLI > v7 > init

The `prisma init` command bootstraps a fresh Prisma project within the current directory.

## Usage [#usage]

```bash
prisma init [options]
```

The command creates a `prisma` directory containing a `schema.prisma` file. By default, the project is configured for [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres), but you can choose a different database using the `--datasource-provider` option.

## Options [#options]

| Option                  | Description                                                                                               |
| ----------------------- | --------------------------------------------------------------------------------------------------------- |
| `-h`, `--help`          | Display help message                                                                                      |
| `--db`                  | Provision a fully managed Prisma Postgres database on the Prisma Data Platform                            |
| `--datasource-provider` | Define the datasource provider: `postgresql`, `mysql`, `sqlite`, `sqlserver`, `mongodb`, or `cockroachdb` |
| `--generator-provider`  | Define the generator provider to use (default: `prisma-client`)                                           |
| `--preview-feature`     | Define a preview feature to use (can be specified multiple times)                                         |
| `--output`              | Define Prisma Client generator output path                                                                |
| `--url`                 | Define a custom datasource URL                                                                            |

## Flags [#flags]

| Flag           | Description                                     |
| -------------- | ----------------------------------------------- |
| `--with-model` | Add an example model to the created schema file |

## Examples [#examples]

### Set up a new Prisma project (default) [#set-up-a-new-prisma-project-default]

Sets up a new project configured for local Prisma Postgres:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

### Specify a datasource provider [#specify-a-datasource-provider]

Set up a new project with MySQL as the datasource provider:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider mysql
```

#### pnpm

```bash
pnpm prisma init --datasource-provider mysql
```

#### yarn

```bash
yarn prisma init --datasource-provider mysql
```

#### npm

```bash
npx prisma init --datasource-provider mysql
```

### Specify a generator provider [#specify-a-generator-provider]

Set up a project with the legacy `prisma-client-js` generator instead of the default `prisma-client` generator:

  

#### bun

```bash
bunx --bun prisma init --generator-provider prisma-client-js
```

#### pnpm

```bash
pnpm prisma init --generator-provider prisma-client-js
```

#### yarn

```bash
yarn prisma init --generator-provider prisma-client-js
```

#### npm

```bash
npx prisma init --generator-provider prisma-client-js
```

### Specify preview features [#specify-preview-features]

Set up a project with specific preview features enabled:

  

#### bun

```bash
bunx --bun prisma init --preview-feature metrics
```

#### pnpm

```bash
pnpm prisma init --preview-feature metrics
```

#### yarn

```bash
yarn prisma init --preview-feature metrics
```

#### npm

```bash
npx prisma init --preview-feature metrics
```

Multiple preview features:

  

#### bun

```bash
bunx --bun prisma init --preview-feature views --preview-feature metrics
```

#### pnpm

```bash
pnpm prisma init --preview-feature views --preview-feature metrics
```

#### yarn

```bash
yarn prisma init --preview-feature views --preview-feature metrics
```

#### npm

```bash
npx prisma init --preview-feature views --preview-feature metrics
```

### Specify a custom output path [#specify-a-custom-output-path]

Set up a project with a custom output path for Prisma Client:

  

#### bun

```bash
bunx --bun prisma init --output ./generated-client
```

#### pnpm

```bash
pnpm prisma init --output ./generated-client
```

#### yarn

```bash
yarn prisma init --output ./generated-client
```

#### npm

```bash
npx prisma init --output ./generated-client
```

### Specify a custom datasource URL [#specify-a-custom-datasource-url]

Set up a project with a specific database URL:

  

#### bun

```bash
bunx --bun prisma init --url mysql://user:password@localhost:3306/mydb
```

#### pnpm

```bash
pnpm prisma init --url mysql://user:password@localhost:3306/mydb
```

#### yarn

```bash
yarn prisma init --url mysql://user:password@localhost:3306/mydb
```

#### npm

```bash
npx prisma init --url mysql://user:password@localhost:3306/mydb
```

### Add an example model [#add-an-example-model]

Set up a project with an example `User` model:

  

#### bun

```bash
bunx --bun prisma init --with-model
```

#### pnpm

```bash
pnpm prisma init --with-model
```

#### yarn

```bash
yarn prisma init --with-model
```

#### npm

```bash
npx prisma init --with-model
```

### Provision a Prisma Postgres database [#provision-a-prisma-postgres-database]

Create a new project with a managed Prisma Postgres database:

  

#### bun

```bash
bunx --bun prisma init --db
```

#### pnpm

```bash
pnpm prisma init --db
```

#### yarn

```bash
yarn prisma init --db
```

#### npm

```bash
npx prisma init --db
```

This requires authentication with the [Prisma Data Platform Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=cli).

## Generated files [#generated-files]

After running `prisma init`, you'll have the following files:

### `prisma/schema.prisma` [#prismaschemaprisma]

The Prisma schema file where you define your data model:

```prisma
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}
```

### `prisma.config.ts` [#prismaconfigts]

A TypeScript configuration file for Prisma:

```typescript
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### `.env` [#env]

Environment variables file for your project:

```bash
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
```

### `.gitignore` [#gitignore]

Git ignore file configured for Prisma projects:

```bash
node_modules
.env
/generated/prisma
```

## Related pages

- [`db`](https://www.prisma.io/docs/cli/v7/db): Manage your database schema and lifecycle during development
- [`debug`](https://www.prisma.io/docs/cli/v7/debug): Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting
- [`dev`](https://www.prisma.io/docs/cli/v7/dev): Start a local Prisma Postgres server for development
- [`format`](https://www.prisma.io/docs/cli/v7/format): Format and validate your Prisma schema file with consistent structure
- [`generate`](https://www.prisma.io/docs/cli/v7/generate): Generate artifacts like Prisma Client based on your Prisma schema

# studio (Prisma CLI v7) (/docs/cli/v7/studio)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Browse and manage your database data with Prisma Studio web interface

Location: CLI > v7 > studio

The `prisma studio` command starts a local web server with a web app to interactively browse and manage your data.

## Usage [#usage]

```bash
prisma studio [options]
```

> [!NOTE]
> Supported databases
> 
> Prisma Studio currently supports PostgreSQL, MySQL, and SQLite. Support for CockroachDB and MongoDB is not available yet but may be added in future releases.

## Prerequisites [#prerequisites]

Configure your database connection in `prisma.config.ts`:

```prisma file=schema.prisma
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

```typescript file=prisma.config.ts
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

## Options [#options]

| Option            | Description                                          | Default        |
| ----------------- | ---------------------------------------------------- | -------------- |
| `-h`, `--help`    | Display help message                                 |                |
| `-p`, `--port`    | Port number to start Studio on                       | `5555`         |
| `-b`, `--browser` | Browser to auto-open Studio in                       | System default |
| `--config`        | Custom path to your Prisma config file               |                |
| `--url`           | Database connection string (overrides Prisma config) |                |

## Examples [#examples]

### Start Studio on the default port [#start-studio-on-the-default-port]

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

### Start Studio on a custom port [#start-studio-on-a-custom-port]

  

#### bun

```bash
bunx prisma studio --port 7777
```

#### pnpm

```bash
pnpm prisma studio --port 7777
```

#### yarn

```bash
yarn prisma studio --port 7777
```

#### npm

```bash
npx prisma studio --port 7777
```

### Start Studio in a specific browser [#start-studio-in-a-specific-browser]

  

#### bun

```bash
bunx prisma studio --browser firefox
```

#### pnpm

```bash
pnpm prisma studio --browser firefox
```

#### yarn

```bash
yarn prisma studio --browser firefox
```

#### npm

```bash
npx prisma studio --browser firefox
```

Or using the `BROWSER` environment variable:

```bash
BROWSER=firefox prisma studio
```

### Start Studio without opening a browser [#start-studio-without-opening-a-browser]

  

#### bun

```bash
bunx prisma studio --browser none
```

#### pnpm

```bash
pnpm prisma studio --browser none
```

#### yarn

```bash
yarn prisma studio --browser none
```

#### npm

```bash
npx prisma studio --browser none
```

### Start Studio with a custom config file [#start-studio-with-a-custom-config-file]

  

#### bun

```bash
bunx prisma studio --config=./prisma.config.ts
```

#### pnpm

```bash
pnpm prisma studio --config=./prisma.config.ts
```

#### yarn

```bash
yarn prisma studio --config=./prisma.config.ts
```

#### npm

```bash
npx prisma studio --config=./prisma.config.ts
```

### Start Studio with a direct database connection string [#start-studio-with-a-direct-database-connection-string]

  

#### bun

```bash
bunx prisma studio --url="postgresql://user:password@localhost:5432/dbname"
```

#### pnpm

```bash
pnpm prisma studio --url="postgresql://user:password@localhost:5432/dbname"
```

#### yarn

```bash
yarn prisma studio --url="postgresql://user:password@localhost:5432/dbname"
```

#### npm

```bash
npx prisma studio --url="postgresql://user:password@localhost:5432/dbname"
```

## Related pages

- [`db`](https://www.prisma.io/docs/cli/v7/db): Manage your database schema and lifecycle during development
- [`debug`](https://www.prisma.io/docs/cli/v7/debug): Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting
- [`dev`](https://www.prisma.io/docs/cli/v7/dev): Start a local Prisma Postgres server for development
- [`format`](https://www.prisma.io/docs/cli/v7/format): Format and validate your Prisma schema file with consistent structure
- [`generate`](https://www.prisma.io/docs/cli/v7/generate): Generate artifacts like Prisma Client based on your Prisma schema

# validate (Prisma CLI v7) (/docs/cli/v7/validate)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Validate your Prisma schema for syntax errors and configuration issues

Location: CLI > v7 > validate

The `prisma validate` command validates the [Prisma Schema Language](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) of your Prisma schema file.

## Usage [#usage]

```bash
prisma validate [options]
```

## Options [#options]

| Option         | Description                            |
| -------------- | -------------------------------------- |
| `-h`, `--help` | Display help message                   |
| `--config`     | Custom path to your Prisma config file |
| `--schema`     | Custom path to your Prisma schema      |

## Examples [#examples]

### Validate the default schema [#validate-the-default-schema]

  

#### bun

```bash
bunx prisma validate
```

#### pnpm

```bash
pnpm prisma validate
```

#### yarn

```bash
yarn prisma validate
```

#### npm

```bash
npx prisma validate
```

Output on success:

```text
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
The schema at /absolute/path/prisma/schema.prisma is valid
```

### Validate a specific schema [#validate-a-specific-schema]

  

#### bun

```bash
bunx prisma validate --schema=./alternative/schema.prisma
```

#### pnpm

```bash
pnpm prisma validate --schema=./alternative/schema.prisma
```

#### yarn

```bash
yarn prisma validate --schema=./alternative/schema.prisma
```

#### npm

```bash
npx prisma validate --schema=./alternative/schema.prisma
```

### Validate with a config file [#validate-with-a-config-file]

  

#### bun

```bash
bunx prisma validate --config=./prisma.config.ts
```

#### pnpm

```bash
pnpm prisma validate --config=./prisma.config.ts
```

#### yarn

```bash
yarn prisma validate --config=./prisma.config.ts
```

#### npm

```bash
npx prisma validate --config=./prisma.config.ts
```

## Error output [#error-output]

If the schema has validation errors:

```text
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Error: Schema validation error - Error (query-engine-node-api library)
Error code: P1012
error: The preview feature "unknownFeatureFlag" is not known. Expected one of: [...]
  schema.prisma:3
   |
 2 |     provider        = "prisma-client"
 3 |     previewFeatures = ["unknownFeatureFlag"]
   |

Validation Error Count: 1
```

## Related pages

- [`db`](https://www.prisma.io/docs/cli/v7/db): Manage your database schema and lifecycle during development
- [`debug`](https://www.prisma.io/docs/cli/v7/debug): Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting
- [`dev`](https://www.prisma.io/docs/cli/v7/dev): Start a local Prisma Postgres server for development
- [`format`](https://www.prisma.io/docs/cli/v7/format): Format and validate your Prisma schema file with consistent structure
- [`generate`](https://www.prisma.io/docs/cli/v7/generate): Generate artifacts like Prisma Client based on your Prisma schema

# version (Prisma CLI v7) (/docs/cli/v7/version)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Display Prisma version information for CLI, Client, and engine binaries

Location: CLI > v7 > version

The `prisma version` command outputs information about your current Prisma version, platform, and engine binaries.

## Usage [#usage]

```bash
prisma version [options]
```

Or use the shorthand:

```bash
prisma -v [options]
```

## Options [#options]

| Option         | Description                               |
| -------------- | ----------------------------------------- |
| `-h`, `--help` | Display help message                      |
| `--json`       | Output version information in JSON format |

## Examples [#examples]

### Display version information [#display-version-information]

  

#### bun

```bash
bunx prisma version
```

#### pnpm

```bash
pnpm prisma version
```

#### yarn

```bash
yarn prisma version
```

#### npm

```bash
npx prisma version
```

Output:

```text
Environment variables loaded from .env
prisma               : 2.21.0-dev.4
@prisma/client       : 2.21.0-dev.4
Current platform     : windows
Query Engine         : query-engine 2fb8f444d9cdf7c0beee7b041194b42d7a9ce1e6
Migration Engine     : migration-engine-cli 2fb8f444d9cdf7c0beee7b041194b42d7a9ce1e6
Format Binary        : prisma-fmt 60ba6551f29b17d7d6ce479e5733c70d9c00860e
Default Engines Hash : 60ba6551f29b17d7d6ce479e5733c70d9c00860e
Studio               : 0.365.0
```

### Display version using shorthand [#display-version-using-shorthand]

  

#### bun

```bash
bunx prisma -v
```

#### pnpm

```bash
pnpm prisma -v
```

#### yarn

```bash
yarn prisma -v
```

#### npm

```bash
npx prisma -v
```

### Display version as JSON [#display-version-as-json]

  

#### bun

```bash
bunx prisma version --json
```

#### pnpm

```bash
pnpm prisma version --json
```

#### yarn

```bash
yarn prisma version --json
```

#### npm

```bash
npx prisma version --json
```

Output:

```json
{
  "prisma": "2.21.0-dev.4",
  "@prisma/client": "2.21.0-dev.4",
  "current-platform": "windows",
  "query-engine": "query-engine 60ba6551f29b17d7d6ce479e5733c70d9c00860e",
  "migration-engine": "migration-engine-cli 60ba6551f29b17d7d6ce479e5733c70d9c00860e",
  "format-binary": "prisma-fmt 60ba6551f29b17d7d6ce479e5733c70d9c00860e",
  "default-engines-hash": "60ba6551f29b17d7d6ce479e5733c70d9c00860e",
  "studio": "0.365.0"
}
```

## Related pages

- [`db`](https://www.prisma.io/docs/cli/v7/db): Manage your database schema and lifecycle during development
- [`debug`](https://www.prisma.io/docs/cli/v7/debug): Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting
- [`dev`](https://www.prisma.io/docs/cli/v7/dev): Start a local Prisma Postgres server for development
- [`format`](https://www.prisma.io/docs/cli/v7/format): Format and validate your Prisma schema file with consistent structure
- [`generate`](https://www.prisma.io/docs/cli/v7/generate): Generate artifacts like Prisma Client based on your Prisma schema

# Expand-and-contract migrations (/docs/guides/database/data-migration)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Replace a column without downtime using the expand and contract pattern, with the data backfill inside a Prisma ORM migration.

Location: Guides > Database > Expand-and-contract migrations

## Introduction [#introduction]

When you change a production schema, you want the data to stay consistent and the app to keep running. The expand and contract pattern gets you there in two reviewable steps: first add the new column and copy the data across (expand), then remove the old column once nothing reads it (contract). In this guide you replace a `published` boolean on a `Post` model with a `status` enum.

In Prisma ORM the data move is not a separate script. A migration is a TypeScript file, and the backfill is one more operation in it, a `dataTransform` that runs in the same transaction as the schema change. Every command and output below was run against a local PostgreSQL database.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/database/data-migration](https://www.prisma.io/docs/guides/v7/database/data-migration).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* A PostgreSQL connection string for a development database, and one for the database you deploy to
* Git, for the branch-per-migration workflow

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Perform an expand-and-contract migration with Prisma ORM, following https://www.prisma.io/docs/guides/database/data-migration.md.

1. In a project with a `Post` model that has a `published Boolean @default(false)` field, make sure Prisma ORM is set up (`npx prisma@latest orm init --yes --target postgres --authoring psl` if it is not), `DATABASE_URL` is in `.env`, and the current contract is applied as a migration (`npx prisma contract emit`, `npx prisma migration plan --name init`, `npx prisma db migrate --advance-ref db`). Run `npx prisma@latest init` so the Prisma agent skills are installed, and use them.
2. Expand: add `enum Status { @@type("pg/text@1") Draft = "Draft" InProgress = "InProgress" InReview = "InReview" Published = "Published" }` and `status Status @default(Draft)` to `Post`. Keep `published`. Run `contract emit` and `migration plan --name add_status`.
3. Open the planned `migration.ts` and append a `this.dataTransform(endContract, 'backfill-post-status', { check, run })` operation built with the typed SQL builder against the migration's own end contract: `check` selects `id` from `Post` where `published = true AND status != 'Published'` with `limit(1)`, `run` updates those rows to `status = 'Published'`. Recompile with `node <migration-dir>/migration.ts`, confirm `ops.json` contains a `data` operation, then apply with `npx prisma db migrate --advance-ref db`. Verify with a query that every row with `published = true` now has `status = 'Published'`.
4. Update application code to read and write `status` instead of `published`.
5. Contract: remove `published` from the contract, run `contract emit`, `migration plan --name drop_published`, review the destructive warning, and apply with `npx prisma db migrate --advance-ref db`.
6. For the production database, run `npx prisma db migrate --db "$PRODUCTION_DATABASE_URL"`, adding `--show` first if you want to preview the route. Do not use `db update` against production.
```

## 1. Set up the project [#1-set-up-the-project]

If you already have a Prisma ORM project whose contract is applied through migrations, skip to [step 2](#2-expand-the-contract). This step builds the starting point: a `Post` model with a `published` boolean, an `init` migration, and three rows of data.

Create a project and add Prisma ORM to it:

```bash
mkdir expand-contract && cd expand-contract
```

  

#### bun

```bash
bun init
bunx prisma@latest orm init --yes --target postgres --authoring psl
```

#### pnpm

```bash
pnpm init
pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### yarn

```bash
yarn init
yarn dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### npm

```bash
npm init
npx prisma@latest orm init --yes --target postgres --authoring psl
```

`orm init` writes `prisma.config.ts`, `src/prisma/contract.prisma`, `src/prisma/db.ts`, and `.env.example`, installs `@prisma/orm-postgres` and the `prisma` CLI, and emits the contract once. There is nothing to generate afterwards: the runtime reads the emitted `contract.json` directly, so there is no `prisma generate` step and no client package to install.

`npm init -y` sets `"type": "commonjs"`, and `orm init` warns that the generated `db.ts` needs ES modules. Change it to `"type": "module"` in `package.json`.

Put your development connection string in `.env`. Both `prisma.config.ts` and `db.ts` load it:

```bash title=".env"
DATABASE_URL="postgres://user:password@localhost:5432/expand_contract"
```

Replace the generated contract with the starting model:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
}
```

Emit the contract, plan the first migration, and apply it. `--advance-ref db` records where your development database is, so the next `migration plan` knows what to diff against:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name init
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name init
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name init
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name init
npx prisma db migrate --advance-ref db
```

```text no-copy
✔ Applied 1 migration(s) (2 operation(s)) across 1 contract space(s)

App space
├─ Create schema "public"
├─ Create table "Post"
└─ marker e8804d8e27d8737475c7be0c538afd9665907df8b82c605bd5cd50926dd73fde

✔ Advanced ref "db" → e8804d8e27d8737475c7be0c538afd9665907df8b82c605bd5cd50926dd73fde
```

Seed a few posts so the migration has data to move. Node.js 24 runs TypeScript directly:

```typescript title="src/seed.ts"
import { db } from "./prisma/db.ts";

await db.orm.public.Post.create({ title: "Hello World", content: "First post", published: true });
await db.orm.public.Post.create({ title: "Draft ideas", content: null, published: false });
await db.orm.public.Post.create({ title: "Release notes", content: "v1.0", published: true });

const posts = await db.orm.public.Post.select("id", "title", "published").all();
console.log(posts);

await db.close();
```

```bash
node src/seed.ts
```

```text no-copy
[
  { id: 1, title: 'Hello World', published: true },
  { id: 2, title: 'Draft ideas', published: false },
  { id: 3, title: 'Release notes', published: true }
]
```

## 2. Expand the contract [#2-expand-the-contract]

Create a branch for the expand step:

```bash
git checkout -b expand-post-status
```

Add the `Status` enum and a `status` field. Leave `published` in place; the app keeps working against it until the contract step. Prisma ORM stores an enum as `text` with a `CHECK` constraint, and the `@@type` line says so:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  status    Status  @default(Draft) // [!code ++]
}

enum Status { // [!code ++]
  @@type("pg/text@1") // [!code ++]
  Draft      = "Draft" // [!code ++]
  InProgress = "InProgress" // [!code ++]
  InReview   = "InReview" // [!code ++]
  Published  = "Published" // [!code ++]
} // [!code ++]
```

Emit the contract and plan the migration. Planning is offline; it diffs the emitted contract against the `db` ref and writes a migration directory:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_status
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_status
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_status
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_status
```

```text no-copy
✔ Planned 2 operation(s)

migrations/app/20260910T1552_add_status
├─ Add column "status" to "Post"
└─ Add check constraint "Post_status_check_eaa35e2a" on "Post"

from:       e8804d8e27d8737475c7be0c538afd9665907df8b82c605bd5cd50926dd73fde
to:         0e9486dcd7f4216d673cbe0ec503edb638520dec9b0a8a22f48bb88edd1442c4
app space:  migrations/app/20260910T1552_add_status

ℹ DDL preview

ALTER TABLE "public"."Post" ADD COLUMN "status" text DEFAULT 'Draft' NOT NULL;
ALTER TABLE "public"."Post" ADD CONSTRAINT "Post_status_check_eaa35e2a" CHECK ("status" IN ('Draft', 'InProgress', 'InReview', 'Published'));
```

Your directory name carries your own timestamp. The planner did not ask for a backfill because the column has a default, so every existing row would become `Draft`. That is wrong for posts that are already published. The next step fixes it.

## 3. Add the data migration [#3-add-the-data-migration]

Open `migrations/app/<timestamp>_add_status/migration.ts`. It is the file the planner wrote, and you edit it like any other TypeScript. Add the imports that wire up a typed SQL builder against this migration's own end contract, then append a `dataTransform` operation after the two schema operations:

```typescript title="migrations/app/20260910T1552_add_status/migration.ts"
#!/usr/bin/env -S node
import type { Contract as End } from '../../snapshots/0e9486dcd7f4216d673cbe0ec503edb638520dec9b0a8a22f48bb88edd1442c4/contract';
import endContractJson from '../../snapshots/0e9486dcd7f4216d673cbe0ec503edb638520dec9b0a8a22f48bb88edd1442c4/contract.json' with { type: 'json' };
import type { Contract as Start } from '../../snapshots/e8804d8e27d8737475c7be0c538afd9665907df8b82c605bd5cd50926dd73fde/contract';
import startContract from '../../snapshots/e8804d8e27d8737475c7be0c538afd9665907df8b82c605bd5cd50926dd73fde/contract.json' with { type: 'json' };
import { Migration, MigrationCLI, col, lit } from '@prisma/orm-postgres/migration';
import postgresAdapter from '@prisma/orm-postgres/adapter/runtime'; // [!code ++]
import { sql } from '@prisma/orm-postgres/builder/runtime'; // [!code ++]
import { createExecutionContext, createSqlExecutionStack } from '@prisma/orm-postgres/family-runtime'; // [!code ++]
import postgresTarget, { PostgresContractSerializer } from '@prisma/orm-postgres/target/runtime'; // [!code ++]

const endContract = new PostgresContractSerializer().deserializeContract(endContractJson) as End; // [!code ++]

const db = sql<End>({ // [!code ++]
  context: createExecutionContext({ // [!code ++]
    contract: endContract, // [!code ++]
    stack: createSqlExecutionStack({ target: postgresTarget, adapter: postgresAdapter }), // [!code ++]
  }), // [!code ++]
  rawCodecInferer: postgresAdapter.rawCodecInferer, // [!code ++]
}); // [!code ++]

export default class M extends Migration<Start, End> {
  override readonly startContractJson = startContract;
  override readonly endContractJson = endContractJson;

  override get operations() {
    return [
      this.addColumn({
        schema: 'public',
        table: 'Post',
        column: col('status', 'text', {
          notNull: true,
          default: lit('Draft'),
          codecRef: { codecId: 'pg/text@1' },
        }),
      }),
      this.addCheckConstraint({
        schema: 'public',
        table: 'Post',
        constraint: 'Post_status_check_eaa35e2a',
        expression: "\"status\" IN ('Draft', 'InProgress', 'InReview', 'Published')",
      }),
      this.dataTransform(endContract, 'backfill-post-status', { // [!code ++]
        check: () => // [!code ++]
          db.public.Post // [!code ++]
            .select('id') // [!code ++]
            .where((f, fns) => fns.and(fns.eq(f.published, true), fns.ne(f.status, 'Published'))) // [!code ++]
            .limit(1), // [!code ++]
        run: () => // [!code ++]
          db.public.Post // [!code ++]
            .update({ status: 'Published' }) // [!code ++]
            .where((f, fns) => fns.and(fns.eq(f.published, true), fns.ne(f.status, 'Published'))), // [!code ++]
      }), // [!code ++]
    ];
  }
}

MigrationCLI.run(import.meta.url, M);
```

The snapshot paths in your file carry your own contract hashes; keep the ones the planner wrote. The planner writes the JSON import as `endContract`. Rename that import to `endContractJson`, as the version above does, and bind `endContract` to the deserialized contract, because the builder and `dataTransform` both need the deserialized form.

Three things to notice:

* `check` is a query that returns a row while work remains. Prisma compiles it twice: as an `EXISTS` precheck that decides whether the step runs, and as a `NOT EXISTS` postcheck that proves the step finished.
* `run` is the update. Both closures are typed against the migration's own contract snapshot, which is why `f.status` type-checks even though the column does not exist in the database yet.
* There is no `published: false` branch. Those rows take the column default, `Draft`, when `ADD COLUMN` runs.

Recompile the migration. Running the file regenerates `ops.json`, the file `db migrate` actually executes, and re-signs `migration.json`:

```bash
node migrations/app/20260910T1552_add_status/migration.ts
```

```text no-copy
Wrote ops.json + migration.json to /Users/you/expand-contract/migrations/app/20260910T1552_add_status
```

Review what the backfill compiled to. `migration show` lists the operation, and `ops.json` holds the exact SQL:

  

#### bun

```bash
bunx prisma migration show 20260910T1552_add_status
```

#### pnpm

```bash
pnpm prisma migration show 20260910T1552_add_status
```

#### yarn

```bash
yarn prisma migration show 20260910T1552_add_status
```

#### npm

```bash
npx prisma migration show 20260910T1552_add_status
```

```text no-copy
✔ 20260910T1552_add_status

3 operation(s)
├─ Add column "status" to "Post"
├─ Add check constraint "Post_status_check_eaa35e2a" on "Post"
└─ Data transform: backfill-post-status
```

```json title="migrations/app/20260910T1552_add_status/ops.json (the data operation)" no-copy
{
  "id": "data_migration.backfill-post-status",
  "operationClass": "data",
  "precheck": [{ "sql": "SELECT EXISTS (SELECT \"id\" AS \"id\" FROM \"public\".\"Post\" WHERE (\"published\" = $1 AND \"status\" != $2) LIMIT 1) AS ok", "params": [true, "Published"] }],
  "execute": [{ "sql": "UPDATE \"public\".\"Post\" SET \"status\" = $1 WHERE (\"published\" = $2 AND \"status\" != $3)", "params": ["Published", true, "Published"] }],
  "postcheck": [{ "sql": "SELECT NOT EXISTS (SELECT \"id\" AS \"id\" FROM \"public\".\"Post\" WHERE (\"published\" = $1 AND \"status\" != $2) LIMIT 1) AS ok", "params": [true, "Published"] }]
}
```

Commit `migration.ts`, `ops.json`, and `migration.json` together. Recompiling stores a hash of `ops.json` and `migration.json` inside `migration.json`. If either file changes after that, `db migrate` refuses to run the migration, and `npx prisma migration check` reports the same problem before you commit.

## 4. Apply the expand migration [#4-apply-the-expand-migration]

Apply it to your development database. On PostgreSQL the whole run is one transaction, so the column, the constraint, and the backfill land together or not at all:

  

#### bun

```bash
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma db migrate --advance-ref db
```

```text no-copy
✔ Applied 1 migration(s) (3 operation(s)) across 1 contract space(s)

App space
├─ Add column "status" to "Post"
├─ Add check constraint "Post_status_check_eaa35e2a" on "Post"
├─ Data transform: backfill-post-status
└─ marker 0e9486dcd7f4216d673cbe0ec503edb638520dec9b0a8a22f48bb88edd1442c4

✔ Advanced ref "db" → 0e9486dcd7f4216d673cbe0ec503edb638520dec9b0a8a22f48bb88edd1442c4
```

Check the rows. The published posts moved to `Published`, and the draft kept the default:

```typescript title="src/posts.ts"
import { db } from "./prisma/db.ts";

const posts = await db.orm.public.Post
  .select("id", "title", "published", "status")
  .orderBy((p) => p.id.asc())
  .all();
console.log(posts);

await db.close();
```

```bash
node src/posts.ts
```

```text no-copy
[
  { id: 1, title: 'Hello World', published: true, status: 'Published' },
  { id: 2, title: 'Draft ideas', published: false, status: 'Draft' },
  { id: 3, title: 'Release notes', published: true, status: 'Published' }
]
```

Both columns exist now, so this is the moment to move application code from `published` to `status`. The new field is typed as `'Draft' | 'InProgress' | 'InReview' | 'Published'` in the emitted contract:

```typescript
const published = await db.orm.public.Post
  .select("id", "title", "status")
  .where((p) => p.status.eq("Published"))
  .orderBy((p) => p.id.asc())
  .all();
```

```text no-copy
[
  { id: 1, title: 'Hello World', status: 'Published' },
  { id: 3, title: 'Release notes', status: 'Published' }
]
```

Merge the branch and deploy it. Wait until nothing reads or writes `published` before you continue.

## 5. Contract the schema [#5-contract-the-schema]

Create a branch for the cleanup:

```bash
git checkout -b drop-published-column
```

Remove the old field:

```prisma title="src/prisma/contract.prisma"
model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false) // [!code --]
  status    Status  @default(Draft)
}
```

Emit and plan. The planner flags the drop as destructive, which is the review signal for this step:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name drop_published
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name drop_published
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name drop_published
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name drop_published
```

```text no-copy
✔ Planned 1 operation(s)

migrations/app/20260910T1554_drop_published
└─ ⚠ Drop column "published" from "Post"

⚠ This migration contains destructive operations that may cause data loss.

ℹ DDL preview

ALTER TABLE "public"."Post" DROP COLUMN "published";
```

Nothing to edit this time. Apply it:

  

#### bun

```bash
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma db migrate --advance-ref db
```

```text no-copy
✔ Applied 1 migration(s) (1 operation(s)) across 1 contract space(s)

App space
├─ ⚠ Drop column "published" from "Post"
└─ marker 79567c619bcb9790bf476efc358730a10317c94fc352e908e19424fc6441350a
```

The data survived the round trip. Drop `published` from the select in `src/posts.ts` and run it again:

```text no-copy
[
  { id: 1, title: 'Hello World', status: 'Published' },
  { id: 2, title: 'Draft ideas', status: 'Draft' },
  { id: 3, title: 'Release notes', status: 'Published' }
]
```

`migration log` reads the database's own ledger of what ran:

  

#### bun

```bash
bunx prisma migration log
```

#### pnpm

```bash
pnpm prisma migration log
```

#### yarn

```bash
yarn prisma migration log
```

#### npm

```bash
npx prisma migration log
```

```text no-copy
Applied at                  Migration                     Change             Ops
2026-09-10 17:51:19 +02:00  20260910T1551_init            ∅ → e8804d8        2 ops
2026-09-10 17:53:46 +02:00  20260910T1552_add_status      e8804d8 → 0e9486d  3 ops
2026-09-10 17:55:39 +02:00  20260910T1554_drop_published  0e9486d → 79567c6  1 ops
```

## 6. Deploy to production [#6-deploy-to-production]

Production runs the same migrations from the same files; only the connection string changes. `db migrate` reads the database's marker, finds the path through the [migration graph](https://www.prisma.io/docs/orm/migrations/the-migration-graph), and applies whatever is pending, backfill included. Your deploy pipeline needs one command:

  

#### bun

```bash
bunx prisma db migrate --db "$PRODUCTION_DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db migrate --db "$PRODUCTION_DATABASE_URL"
```

#### yarn

```bash
yarn prisma db migrate --db "$PRODUCTION_DATABASE_URL"
```

#### npm

```bash
npx prisma db migrate --db "$PRODUCTION_DATABASE_URL"
```

It refuses to run a migration whose `ops.json` or `migration.json` changed after it was compiled. If your pipeline deploys each environment to a ref, as [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration) shows, add `--to <ref>` to that command. To see the route before it runs, add `--show`, which previews it without changing anything. Here is that preview against a production database that shipped the `init` migration and holds live rows, followed by the apply:

```text no-copy
ℹ The following 2 migrations will run:

  20260910T1552_add_status    e8804d8 → 0e9486d
  20260910T1554_drop_published  0e9486d → 79567c6
```

```text no-copy
✔ Applied 2 migration(s) (4 operation(s)) across 1 contract space(s)

App space
├─ Add column "status" to "Post"
├─ Add check constraint "Post_status_check_eaa35e2a" on "Post"
├─ Data transform: backfill-post-status
├─ ⚠ Drop column "published" from "Post"
└─ marker 79567c619bcb9790bf476efc358730a10317c94fc352e908e19424fc6441350a
```

In practice the two migrations reach production in separate deploys, one per branch, and the app moves from `published` to `status` between them. The commands are the same either way. Production never runs your TypeScript: the runner executes `ops.json`, which is plain data, so no application code runs with production credentials.

## Common gotchas [#common-gotchas]

> [!WARNING]
> Do not use `db update` for this change. It reconciles the database with the contract directly and does not carry data operations, so the backfill would not run. Use `migration plan` and `db migrate`, which is also what production needs: a reviewed, checked-in migration.

> [!NOTE]
> If `migration plan` stops with `MIGRATION.PLAN_ORIGIN_UNKNOWN`, the `db` ref is missing. That happens when you applied a migration with plain `db migrate`. Either re-run `npx prisma db migrate --advance-ref db`, or pass `--from <migration-dir>` to the plan.

> [!NOTE]
> If `db migrate` reports `MIGRATION.HASH_MISMATCH`, the migration's `ops.json` or `migration.json` changed after it was compiled, for example by a hand edit. Restore both files from Git, or move the edit into `migration.ts` and recompile with `node <migration-dir>/migration.ts`, then apply again. Never edit `ops.json` by hand.

> [!NOTE]
> The `check` query must return rows, not a count. Prisma wraps it in `EXISTS` and `NOT EXISTS`; an aggregate always returns one row, so the step would never be skipped and the postcheck would always fail.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add a `dataTransform` to the latest migration that backfills `status` from `published`, recompile it, and show me the compiled SQL in ops.json."
* "Plan a migration that drops the `published` column and explain the destructive warning."
* "Preview what `db migrate` would run against staging and summarize the operations."

## Next steps [#next-steps]

* [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration): placeholders, `rawSql`, and the recompile loop in depth.
* [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration): targets, refs, and what happens when a run fails.
* [Rollbacks and recovery](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery): a rollback is one more planned migration, and a failed run is safe to retry.
* [The migration graph](https://www.prisma.io/docs/orm/migrations/the-migration-graph): why two branches with migrations merge cleanly.

## Related pages

- [`Multiple databases`](https://www.prisma.io/docs/guides/database/multiple-databases): Connect one Next.js app to two PostgreSQL databases with Prisma ORM: one contract, config, and client per database, selected with the --config flag.
- [`Schema management in teams`](https://www.prisma.io/docs/guides/database/schema-changes): Plan, merge, and apply Prisma ORM migrations when several developers change the schema at the same time.

# Multiple databases (/docs/guides/database/multiple-databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Connect one Next.js app to two PostgreSQL databases with Prisma ORM: one contract, config, and client per database, selected with the --config flag.

Location: Guides > Database > Multiple databases

## Introduction [#introduction]

This guide shows you how to use two databases from one [Next.js](https://nextjs.org/) app with Prisma ORM. You give each database its own data contract, its own `prisma.config.ts`, and its own Prisma ORM client, then render data from both on one page. The same layout works for any number of databases and is a good fit for multi-tenant apps or for keeping unrelated data in separate databases.

Every command and code block below was run against two local PostgreSQL databases, `users` and `posts`.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/database/multiple-databases](https://www.prisma.io/docs/guides/v7/database/multiple-databases).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* Two PostgreSQL connection strings, or nothing at all: `npx create-db@latest` can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you, run it twice for two
* A [Vercel](https://vercel.com/) account if you want to deploy at the end

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a Next.js app that reads from two PostgreSQL databases with Prisma ORM, following https://www.prisma.io/docs/guides/database/multiple-databases.md.

1. Scaffold with `npx create-next-app@latest my-multi-db-app --yes`, then in the project run `npx prisma@latest orm init --yes --target postgres --authoring psl --schema-path ./prisma/users/contract.prisma`. Run `npx prisma@latest init` so the Prisma agent skills are installed, and use them.
2. Rename `prisma.config.ts` to `prisma.users.config.ts`, point it at `USERS_DATABASE_URL` and `./prisma/users/migrations`, and reduce `prisma/users/contract.prisma` to a `User` model. Create the same three files for the posts database: `prisma.posts.config.ts` reading `POSTS_DATABASE_URL`, `prisma/posts/contract.prisma` with a `Post` model that stores `authorId Int` (no relation across databases), and `prisma/posts/db.ts`. Export `usersDb` and `postsDb` from the two `db.ts` files.
3. Put both connection strings in `.env` (use the ones I give you, or create two Prisma Postgres databases with `npx create-db@latest` and show me the claim URLs). Add package scripts that run `prisma contract emit`, `prisma db init`, and `prisma db verify` once per config with `--config`, then run them.
4. Write a seed script that inserts two users and two posts, run it with `node prisma/seed.ts`, and rewrite `app/page.tsx` as a server component that lists users from `usersDb` and posts from `postsDb`, joining authors in application code.
5. Start `npm run dev` in the background, verify http://localhost:3000 renders both lists, stop the server, and confirm `npm run build` passes.
```

## 1. Set up a Next.js project [#1-set-up-a-nextjs-project]

Create a new Next.js app and accept the defaults (TypeScript, Tailwind CSS, App Router, no `src` directory):

  

#### bun

```bash
bunx create-next-app@latest my-multi-db-app
cd my-multi-db-app
```

#### pnpm

```bash
pnpm dlx create-next-app@latest my-multi-db-app
cd my-multi-db-app
```

#### yarn

```bash
yarn dlx create-next-app@latest my-multi-db-app
cd my-multi-db-app
```

#### npm

```bash
npx create-next-app@latest my-multi-db-app
cd my-multi-db-app
```

This guide starts from `create-next-app` and adds Prisma ORM with `orm init` instead of using the `next` template of `create-prisma`. That template wires a single database and declares it for Prisma Compute; here you want exactly the Prisma files, once per database, and nothing else.

## 2. Add Prisma ORM for the users database [#2-add-prisma-orm-for-the-users-database]

Run `orm init` from the project root. The `--schema-path` flag puts the contract in a folder named after the database, and `orm init` places the client file next to it:

  

#### bun

```bash
bunx prisma@latest orm init --yes --target postgres --authoring psl --schema-path ./prisma/users/contract.prisma
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl --schema-path ./prisma/users/contract.prisma
```

#### yarn

```bash
yarn dlx prisma@latest orm init --yes --target postgres --authoring psl --schema-path ./prisma/users/contract.prisma
```

#### npm

```bash
npx prisma@latest orm init --yes --target postgres --authoring psl --schema-path ./prisma/users/contract.prisma
```

The command installs `@prisma/orm-postgres` and `dotenv`, adds `prisma` as a dev dependency, sets `"type": "module"` in `package.json`, updates `tsconfig.json`, and writes these files:

```text no-copy
prisma/users/contract.prisma
prisma/users/db.ts
prisma.config.ts
prisma-8.md
.env.example
```

There is no `prisma generate` and no generated client package. The emitted `contract.json` and `contract.d.ts` next to the contract are what the runtime and the type checker read.

### 2.1. Give the config a database-specific name [#21-give-the-config-a-database-specific-name]

Prisma ORM commands read `./prisma.config.ts` by default and take a different file with the global [`--config`](https://www.prisma.io/docs/cli/global-flags) flag. Rename the generated config so each database has one:

```bash
mv prisma.config.ts prisma.users.config.ts
```

Point it at the users contract, a users-only migrations folder, and a `USERS_DATABASE_URL` variable:

```typescript title="prisma.users.config.ts"
import 'dotenv/config';
import { definePrismaConfig } from '@prisma/cli-engine';
import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./prisma/users/contract.prisma",
    migrations: { // [!code ++]
      dir: "./prisma/users/migrations", // [!code ++]
    }, // [!code ++]
    db: {
      connection: process.env.USERS_DATABASE_URL!, // [!code ++]
    },
  }),
});
```

`migrations.dir` matters once you use checked-in migrations: without it both configs would write to the same `./migrations` folder.

### 2.2. Define the users contract [#22-define-the-users-contract]

Replace the starter contract with a single `User` model:

```prisma title="prisma/users/contract.prisma"
// use prisma-8

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

### 2.3. Name the client after the database [#23-name-the-client-after-the-database]

Change `prisma/users/db.ts` to read `USERS_DATABASE_URL` and export a name you can tell apart from the second client:

```typescript title="prisma/users/db.ts"
import 'dotenv/config';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const usersDb = postgres<Contract>({ // [!code ++]
  contractJson,
  url: process.env.USERS_DATABASE_URL!, // [!code ++]
});
```

`contract.d.ts` and `contract.json` do not exist yet; you emit them in step 4.

## 3. Add the posts database [#3-add-the-posts-database]

The second database needs the same three files. Create them by hand; running `orm init` again would replace the files from step 2.

```bash
mkdir -p prisma/posts
```

```typescript title="prisma.posts.config.ts"
import 'dotenv/config';
import { definePrismaConfig } from '@prisma/cli-engine';
import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./prisma/posts/contract.prisma",
    migrations: {
      dir: "./prisma/posts/migrations",
    },
    db: {
      connection: process.env.POSTS_DATABASE_URL!,
    },
  }),
});
```

```prisma title="prisma/posts/contract.prisma"
// use prisma-8

model Post {
  id        Int               @id @default(autoincrement())
  title     String
  content   String?
  authorId  Int
  createdAt TimestamptzString @default(now())
}
```

`authorId` is a plain integer, not a relation. A contract describes one database, and PostgreSQL cannot enforce a foreign key into another database, so the link between a post and its author is resolved in application code in step 5.

```typescript title="prisma/posts/db.ts"
import 'dotenv/config';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const postsDb = postgres<Contract>({
  contractJson,
  url: process.env.POSTS_DATABASE_URL!,
});
```

Now set both connection strings. Both config files and both clients load `.env` through `dotenv/config`, and Next.js loads it as well:

```bash title=".env"
USERS_DATABASE_URL="postgres://user:password@localhost:5432/users"
POSTS_DATABASE_URL="postgres://user:password@localhost:5432/posts"
```

`orm init` already added `.env` to `.gitignore`. Update `.env.example` with the two variable names so collaborators know what to set.

## 4. Emit the contracts and initialize both databases [#4-emit-the-contracts-and-initialize-both-databases]

Each Prisma ORM command works on one config. Add scripts that run every command once per database so you do not have to type `--config` twice:

```json title="package.json"
"scripts": {
  "dev": "next dev",
  "build": "next build",
  "start": "next start",
  "contract:emit": "prisma contract emit --config ./prisma.users.config.ts && prisma contract emit --config ./prisma.posts.config.ts", // [!code ++]
  "db:init": "prisma db init --config ./prisma.users.config.ts && prisma db init --config ./prisma.posts.config.ts", // [!code ++]
  "db:verify": "prisma db verify --config ./prisma.users.config.ts && prisma db verify --config ./prisma.posts.config.ts", // [!code ++]
  "db:update": "prisma db update --config ./prisma.users.config.ts && prisma db update --config ./prisma.posts.config.ts", // [!code ++]
  "db:seed": "node prisma/seed.ts", // [!code ++]
  "prebuild": "npm run contract:emit" // [!code ++]
}
```

`prebuild` re-emits both contracts before every `next build`, locally and on Vercel, so the build never runs against stale artifacts.

Emit the contract artifacts for both databases. This step is offline:

  

#### bun

```bash
bun run contract:emit
```

#### pnpm

```bash
pnpm run contract:emit
```

#### yarn

```bash
yarn contract:emit
```

#### npm

```bash
npm run contract:emit
```

```text no-copy
✔ Emitted contract.json and contract.d.ts
│  contract:  prisma/users/contract.json
│  types:     prisma/users/contract.d.ts

✔ Emitted contract.json and contract.d.ts
│  contract:  prisma/posts/contract.json
│  types:     prisma/posts/contract.d.ts
```

Create the tables in both databases and sign each one with its contract:

  

#### bun

```bash
bun run db:init
```

#### pnpm

```bash
pnpm run db:init
```

#### yarn

```bash
yarn db:init
```

#### npm

```bash
npm run db:init
```

```text no-copy
│  contract:  prisma/users/contract.json
│  database:  postgres://****@localhost:5432/users

✔ Applied 2 operation(s) across 1 contract space

App space
├─ Create table "User"
├─ Add unique constraint on "User" (email)
└─ marker f340195186d0acf8e9914097e58af0375650e7251358382aa9ad3ed5b724daf7

│  contract:  prisma/posts/contract.json
│  database:  postgres://****@localhost:5432/posts

✔ Applied 1 operation(s) across 1 contract space

App space
├─ Create table "Post"
└─ marker a0c012793cc392569087d82d7ea41686c8e60586b63c7a131391b99717157804
```

Each database now carries a marker with the hash of the contract it was initialized from. Confirm both match:

  

#### bun

```bash
bun run db:verify
```

#### pnpm

```bash
pnpm run db:verify
```

#### yarn

```bash
yarn db:verify
```

#### npm

```bash
npm run db:verify
```

```text no-copy
│  contract:  prisma/users/contract.json
│  database:  postgres://****@localhost:5432/users

✔ Database marker and schema match contract

│  contract:  prisma/posts/contract.json
│  database:  postgres://****@localhost:5432/posts

✔ Database marker and schema match contract
```

The marker is also what protects you from crossing the wires. Verifying the users contract against the posts database stops immediately:

  

#### bun

```bash
bunx prisma db verify --config ./prisma.users.config.ts --db "$POSTS_DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db verify --config ./prisma.users.config.ts --db "$POSTS_DATABASE_URL"
```

#### yarn

```bash
yarn prisma db verify --config ./prisma.users.config.ts --db "$POSTS_DATABASE_URL"
```

#### npm

```bash
npx prisma db verify --config ./prisma.users.config.ts --db "$POSTS_DATABASE_URL"
```

```text no-copy
✘ [CONTRACT.MARKER_MISMATCH] Hash mismatch
  why: Contract storageHash does not match database marker
```

## 5. Query both databases from the app [#5-query-both-databases-from-the-app]

### 5.1. Seed both databases [#51-seed-both-databases]

Create a script that writes through both clients. Node.js 24 runs TypeScript directly, so no extra tooling is needed:

```typescript title="prisma/seed.ts"
import { usersDb } from "./users/db.ts";
import { postsDb } from "./posts/db.ts";

async function main() {
  const alice = await usersDb.orm.public.User.create({
    email: "alice@prisma.io",
    name: "Alice",
  });
  const bob = await usersDb.orm.public.User.create({
    email: "bob@prisma.io",
    name: "Bob",
  });

  await postsDb.orm.public.Post.create({
    title: "Hello from the posts database",
    content: "This row lives in the posts database.",
    authorId: alice.id,
  });
  await postsDb.orm.public.Post.create({
    title: "Two databases, one app",
    content: null,
    authorId: bob.id,
  });

  console.log("Seeded", alice.email, "and", bob.email, "with one post each.");
  await usersDb.close();
  await postsDb.close();
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
```

The `.ts` extensions in the imports are what Node.js needs to resolve the files. Allow them in `tsconfig.json`, otherwise `next build` fails its type check with `TS5097`:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "allowImportingTsExtensions": true // [!code ++]
  }
}
```

Run the seed:

  

#### bun

```bash
bun run db:seed
```

#### pnpm

```bash
pnpm run db:seed
```

#### yarn

```bash
yarn db:seed
```

#### npm

```bash
npm run db:seed
```

```text no-copy
Seeded alice@prisma.io and bob@prisma.io with one post each.
```

Both clients open their connection pool on the first query. The script closes them at the end so the process can exit.

### 5.2. Render data from both databases [#52-render-data-from-both-databases]

Replace `app/page.tsx` with a server component that queries each client and joins posts to their authors in memory:

```tsx title="app/page.tsx"
import { usersDb } from "@/prisma/users/db";
import { postsDb } from "@/prisma/posts/db";

export const dynamic = "force-dynamic";

export default async function Home() {
  const users = await usersDb.orm.public.User.select("id", "email", "name").all();
  const posts = await postsDb.orm.public.Post
    .select("id", "title", "authorId")
    .orderBy((p) => p.id.asc())
    .all();

  const authorById = new Map(users.map((u) => [u.id, u]));

  return (
    <main className="mx-auto max-w-2xl p-8 font-sans">
      <h1 className="text-3xl font-bold">Multi-database showcase</h1>
      <p className="mt-2 text-zinc-600">
        Users come from one PostgreSQL database, posts from another.
      </p>

      <h2 className="mt-8 text-xl font-semibold">Users</h2>
      <ul className="mt-2 list-disc pl-6">
        {users.map((user) => (
          <li key={user.id}>
            {user.name} ({user.email})
          </li>
        ))}
      </ul>

      <h2 className="mt-8 text-xl font-semibold">Posts</h2>
      <ul className="mt-2 list-disc pl-6">
        {posts.map((post) => (
          <li key={post.id}>
            {post.title}, by {authorById.get(post.authorId)?.name ?? "unknown"}
          </li>
        ))}
      </ul>
    </main>
  );
}
```

Each client is typed by its own `contract.d.ts`: `usersDb.orm.public` only knows `User`, `postsDb.orm.public` only knows `Post`, and mixing them up is a type error. `force-dynamic` keeps Next.js from trying to render the page at build time, when no database is reachable.

### 5.3. Run the development server [#53-run-the-development-server]

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

```text no-copy
▲ Next.js 16.3.4 (Turbopack)
- Local:         http://localhost:3000
- Environments: .env
✓ Ready in 894ms
```

Open [http://localhost:3000](http://localhost:3000). The page lists Alice and Bob under **Users** and the two posts under **Posts**, each attributed to its author. One request, two databases, no adapter or extra client package in between.

Finally, confirm the production build passes. `prebuild` emits both contracts first:

  

#### bun

```bash
bun run build
```

#### pnpm

```bash
pnpm run build
```

#### yarn

```bash
yarn build
```

#### npm

```bash
npm run build
```

```text no-copy
> prisma contract emit --config ./prisma.users.config.ts && prisma contract emit --config ./prisma.posts.config.ts
...
✓ Compiled successfully
```

## 6. Deploy to Vercel [#6-deploy-to-vercel]

The app needs two environment variables in production and nothing else that is Prisma-specific: `prebuild` runs on Vercel, and there is no client to generate and no engine binary to ship.

1. Push the project to a GitHub repository. If you do not have one yet, [create one on GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository), then run:
   ```bash
   git add .
   git commit -m "Next.js app with two Prisma 8 databases"
   git branch -M main
   git remote add origin https://github.com/<your-username>/<repository-name>.git
   git push -u origin main
   ```
2. In the [Vercel dashboard](https://vercel.com/), follow [Import an existing project](https://vercel.com/docs/getting-started-with-vercel/import) and stop at the step where you configure the project, before clicking **Deploy**.
3. Expand **Environment variables** and add both connection strings:
   * **Key**: `USERS_DATABASE_URL`, **Value**: the users database connection string from your `.env`
   * **Key**: `POSTS_DATABASE_URL`, **Value**: the posts database connection string from your `.env`
4. Click **Deploy**. Vercel runs `npm run build`, which emits both contracts and builds the app.

> [!WARNING]
> Set both variables before the first deploy. Each config file reads its variable with a non-null assertion, and a missing one fails the first request to the page.

Open the live URL. The page renders the same two lists from the same two databases. The Vercel deploy was not run while validating this guide; the `npm run build` it executes is the one from step 5.

## Common gotchas [#common-gotchas]

> [!WARNING]
> Commands without `--config` fail once the default config is gone. Running `npx prisma contract emit` with no `./prisma.config.ts` (or with one that has no `orm` section) stops with `[CONFIG.FILE_NOT_FOUND]` and a hint that the `orm` config section is absent. Use the package scripts from step 4, or pass `--config` explicitly.

* **No relations across databases.** A contract covers one database. Keep a plain id column such as `authorId` on the side that references the other database, and join in application code.
* **`npx prisma@latest init` writes a third config.** It creates a `prisma.config.ts` that holds only the `skills` section for agent skills. That is expected; the database commands keep using `--config` with the two database configs.
* **Do not close a client per request.** In `page.tsx` and route handlers, never call `usersDb.close()`. The pools are shared across requests and close when the process exits. Only scripts such as `prisma/seed.ts` close them.
* **`orm init` picks the package manager from your lockfile.** Run it after `create-next-app` has written `package-lock.json`, `pnpm-lock.yaml`, or `bun.lock`, or it may install with a different package manager than the one you use.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add a `Comment` model to `prisma/posts/contract.prisma`, emit with `--config ./prisma.posts.config.ts`, and update the posts database."
* "Add a third database for billing following the same layout: `prisma.billing.config.ts`, `prisma/billing/contract.prisma`, `prisma/billing/db.ts`, and extend the package scripts."
* "Write a route handler that creates a post for the signed-in user, validating that the `authorId` exists in the users database first."

## Next steps [#next-steps]

* Change a contract, then run `npm run contract:emit` and `npm run db:update` to apply the change to both databases in development. For checked-in migrations, run [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) and [`db migrate`](https://www.prisma.io/docs/cli/db-migrate) with the `--config` of the database you changed; each writes to its own `migrations.dir`.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [CLI configuration](https://www.prisma.io/docs/cli/configuration) covers everything `prisma.config.ts` can hold.
* Splitting the app itself into packages? See [pnpm workspaces](https://www.prisma.io/docs/guides/deployment/pnpm-workspaces) and [Turborepo](https://www.prisma.io/docs/guides/deployment/turborepo).

## Related pages

- [`Expand-and-contract migrations`](https://www.prisma.io/docs/guides/database/data-migration): Replace a column without downtime using the expand and contract pattern, with the data backfill inside a Prisma ORM migration.
- [`Schema management in teams`](https://www.prisma.io/docs/guides/database/schema-changes): Plan, merge, and apply Prisma ORM migrations when several developers change the schema at the same time.

# Schema management in teams (/docs/guides/database/schema-changes)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Plan, merge, and apply Prisma ORM migrations when several developers change the schema at the same time.

Location: Guides > Database > Schema management in teams

## Introduction [#introduction]

When a team works on one schema, two people change it at the same time. In Prisma ORM, migrations form a graph rather than a numbered list, so parallel changes do not force anyone to rename files or rebuild history. This guide shows how that works day to day: what to commit, how to incorporate a teammate's migration, and how to resolve the case where two branches planned a migration from the same starting point and both merged.

Every command and every output below was run against a Git repository with three checkouts (two teammates and you), each with its own local PostgreSQL database.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/database/schema-changes](https://www.prisma.io/docs/guides/v7/database/schema-changes).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* A Prisma ORM project with a contract and at least one migration (the [PostgreSQL quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql) gives you one)
* A PostgreSQL database per developer, reachable as `DATABASE_URL`
* Basic familiarity with Git branches and merges
* The [migration loop](https://www.prisma.io/docs/orm/migrations/how-migrations-work): `contract emit`, `migration plan`, `db migrate`

## Use with your agent [#use-with-your-agent]

To delegate the pull-and-apply part of this guide to your coding agent, copy the prompt below and hand it over:

```text
Bring my local database up to date with the migrations on this branch using Prisma ORM, following https://www.prisma.io/docs/guides/database/schema-changes.md.

1. Run `npx prisma migration status` and tell me what is pending. If it reports "Up to date", stop.
2. If it warns that there is no migration path from the database state to the contract, the graph has two branch tips. Run `npx prisma migration graph`, then plan one merge migration from each tip with `npx prisma migration plan --from <migration-dir> --name merge_<other-change>`, and show me both DDL previews before continuing.
3. Apply with `npx prisma db migrate --advance-ref db`, then run `npx prisma migration check` and `npx prisma db verify`.
4. If `migration plan` fails with MIGRATION.PLAN_ORIGIN_UNKNOWN, do not delete any migration directory. Find the contract state the database is on in the `npx prisma migration status` output, pass that hash with `--from`, and show me the error text. If you cannot tell which state the database is on, stop and ask me.
```

## 1. Understand migration basics [#1-understand-migration-basics]

### 1.1. Migrations form a graph [#11-migrations-form-a-graph]

Each migration directory records the contract state it starts `from` and the state it ends at, `to`, as hashes in its `migration.json`. Those links are the migration history. The timestamp in the directory name is for humans; nothing depends on it. That is why two developers can plan migrations from the same state on separate branches and merge without renaming anything. [The migration graph](https://www.prisma.io/docs/orm/migrations/the-migration-graph) explains the model in full.

Three commands answer the questions a team asks most:

| Question                                             | Command                       | Needs a database? |
| ---------------------------------------------------- | ----------------------------- | ----------------- |
| What does the history look like?                     | `npx prisma migration graph`  | No                |
| Where is my database, and what is pending?           | `npx prisma migration status` | Yes               |
| Do the migration files on this branch hold together? | `npx prisma migration check`  | No                |

### 1.2. Commit these files [#12-commit-these-files]

Commit everything Prisma ORM needs to rebuild a database from scratch:

* `src/prisma/contract.prisma`, the schema you author
* `src/prisma/contract.json` and `src/prisma/contract.d.ts`, the emitted contract (generated, but committed; `orm init` marks them `linguist-generated` in `.gitattributes`)
* `migrations/app/`, every migration directory: `migration.ts`, `ops.json`, and `migration.json` together
* `migrations/snapshots/`, the contract snapshots migrations are typed against
* `migrations/app/refs/`, named refs, including the `db` ref described next
* `prisma.config.ts`

Do not commit `.env`. `orm init` already lists it in `.gitignore`.

### 1.3. Where a plan starts [#13-where-a-plan-starts]

`migration plan` is offline. It never asks the database which contract state it matches, so you have to tell it which state to plan from. It resolves the origin in this order: an explicit `--from`, otherwise the ref named `db` in `migrations/app/refs/db.json`, otherwise the empty database. Keep the `db` ref pointing at the state your local database matches by applying with `--advance-ref db`:

  

#### bun

```bash
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma db migrate --advance-ref db
```

Do that every time you apply, and every plan chains from the right place without flags. Section 3 shows what happens when it cannot.

### 1.4. The project this guide starts from [#14-the-project-this-guide-starts-from]

The project was created with `npx prisma@latest orm init --yes --target postgres --authoring psl` and has this contract:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  username  String?
  name      String?
  posts     Post[]
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}
```

Its first migration was planned and applied on `main` with:

  

#### bun

```bash
bunx prisma migration plan --name init
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma migration plan --name init
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma migration plan --name init
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma migration plan --name init
npx prisma db migrate --advance-ref db
```

```text no-copy
✔ Applied 1 migration(s) (6 operation(s)) across 1 contract space(s)

App space
├─ Create schema "public"
├─ Create table "Post"
├─ Create table "User"
├─ Add unique constraint on "User" (email)
├─ Create index "Post_authorId_idx_e47547ed" on "Post"
├─ Add foreign key "Post_authorId_fkey" on "Post"
└─ marker 91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e

✔ Advanced ref "db" → 91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
→ Check every space against the database: {bin} migration status
```

The `{bin}` in the hint is the CLI's placeholder for however you invoked it. Read it as `npx prisma migration status`. Every developer clones this repository, points `DATABASE_URL` in their `.env` at their own database, and runs `npx prisma db migrate` once to bring it to the same state.

## 2. Incorporate team changes [#2-incorporate-team-changes]

### 2.1. Pull, check, apply [#21-pull-check-apply]

When a teammate merges a schema change, it arrives as three things: an edited `contract.prisma`, the re-emitted `contract.json` and `contract.d.ts`, and a new migration directory. Pull them, then ask Prisma which contract state your database matches:

```bash
git pull
```

  

#### bun

```bash
bunx prisma migration status
```

#### pnpm

```bash
pnpm prisma migration status
```

#### yarn

```bash
yarn prisma migration status
```

#### npm

```bash
npx prisma migration status
```

If nothing changed, you see the whole history marked applied:

```text no-copy
○   91e7f9f  @contract @db (db)
│↑  20260910T1543_init         ∅ → 91e7f9f  6 ops  ✓ applied
○   ∅

✔ Up to date
```

`@db` marks the contract state your database matches, `@contract` the emitted contract, and `(db)` the state the `db` ref names. When migrations are pending, the tree flags each one with `⧗ pending` and a summary line tells you how many. Apply them and update the `db` ref in one step:

  

#### bun

```bash
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma db migrate --advance-ref db
```

There is no generate step after applying: your typed client reads `contract.json`, which you just pulled.

### 2.2. Example scenario [#22-example-scenario]

The rest of this guide follows three developers changing the same contract. Ania adds a `favoriteColor` field, Javier adds a `Tag` model, and you add a `bestPacmanScore` field:

  

#### Before

```prisma title="src/prisma/contract.prisma" 
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  username  String?
  name      String?
  posts     Post[]
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}
```

#### After

```prisma title="src/prisma/contract.prisma" 
model User {
  id              Int      @id @default(autoincrement())
  email           String   @unique
  username        String?
  name            String?
  favoriteColor   String? // Added by Ania // [!code ++]
  bestPacmanScore Int?    // Added by you // [!code ++]
  posts           Post[]
  createdAt       TimestamptzString @default(now())
  updatedAt       temporal.updatedAtString()
}

// Added by Javier // [!code ++]
model Tag { // [!code ++]
  tagName     String @id // [!code ++]
  tagCategory String // [!code ++]
} // [!code ++]
```

## 3. Handle concurrent changes [#3-handle-concurrent-changes]

Ania and Javier both branch from the same commit on `main`, where the `db` ref points at the `init` state.

### 3.1. Ania adds a field [#31-ania-adds-a-field]

On her branch, Ania adds the field:

```prisma title="src/prisma/contract.prisma"
model User {
  /* ... */
  favoriteColor String?
}
```

Then she emits, plans, and applies to her own database:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_favorite_color
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_favorite_color
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_favorite_color
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_favorite_color
```

```text no-copy
✔ Planned 1 operation(s)

migrations/app/20260910T1546_add_favorite_color
└─ Add column "favoriteColor" to "User"

from:       91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
to:         b29af3990b528c7a67809a2ac609305c59aa9c0af1ed0e4591cc0a727b38b1d1
app space:  migrations/app/20260910T1546_add_favorite_color

ℹ DDL preview

ALTER TABLE "public"."User" ADD COLUMN "favoriteColor" text;
```

The `from:` line is the `init` state, taken from the `db` ref. She applies and commits:

  

#### bun

```bash
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma db migrate --advance-ref db
```

```text no-copy
✔ Applied 1 migration(s) (1 operation(s)) across 1 contract space(s)

App space
├─ Add column "favoriteColor" to "User"
└─ marker b29af3990b528c7a67809a2ac609305c59aa9c0af1ed0e4591cc0a727b38b1d1

✔ Advanced ref "db" → b29af3990b528c7a67809a2ac609305c59aa9c0af1ed0e4591cc0a727b38b1d1
```

```bash
git add -A
git commit -m "Add User.favoriteColor"
```

### 3.2. Javier adds a model [#32-javier-adds-a-model]

On his branch, from the same starting commit, Javier adds a model:

```prisma title="src/prisma/contract.prisma"
model Tag {
  tagName     String @id
  tagCategory String
}
```

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_tag_model
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_tag_model
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_tag_model
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_tag_model
```

```text no-copy
✔ Planned 1 operation(s)

migrations/app/20260910T1547_add_tag_model
└─ Create table "Tag"

from:       91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
to:         18b24e59a8b291a37b50e0d82c7afb58b314a2b64920d530627c73bd6e2d9768
app space:  migrations/app/20260910T1547_add_tag_model

ℹ DDL preview

CREATE TABLE "public"."Tag" (
  "tagCategory" text NOT NULL,
  "tagName" text NOT NULL,
  PRIMARY KEY ("tagName")
);
```

His plan also starts `from:` the `init` state. He applies with `db migrate --advance-ref db` and commits. Both migrations now leave the same node and arrive at different ones. Neither developer knows about the other yet, and neither needs to.

### 3.3. Merge both branches [#33-merge-both-branches]

Ania's branch merges into `main` first, as a fast-forward. Javier's merge conflicts:

```bash
git merge javier/tag-model
```

```text no-copy
Auto-merging migrations/app/refs/db.json
CONFLICT (content): Merge conflict in migrations/app/refs/db.json
Auto-merging src/prisma/contract.d.ts
CONFLICT (content): Merge conflict in src/prisma/contract.d.ts
Auto-merging src/prisma/contract.json
CONFLICT (content): Merge conflict in src/prisma/contract.json
Auto-merging src/prisma/contract.prisma
Automatic merge failed; fix conflicts and then commit the result.
```

Read the list carefully. `contract.prisma`, the file you author, merged cleanly: the two edits touch different parts of the schema. The three conflicts are all in files Prisma writes for you, and none of them needs hand editing:

* `contract.json` and `contract.d.ts` are emitted from `contract.prisma`. Re-emit and they are regenerated from the merged source, conflict markers and all:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

```text no-copy
✔ Emitted contract.json and contract.d.ts

storageHash:    1e5059c1976c2439863eae8ac13211916ca411614c917394c413346f0d00f60b
```

* `migrations/app/refs/db.json` records the contract state a local database last matched. Each branch pointed it at its own state, and neither is the state your database matches now. Take either side; you will set it correctly when you apply in section 3.5.

```bash
git checkout --ours migrations/app/refs/db.json
```

Do not commit yet. The graph is not finished.

### 3.4. What Prisma reports after the merge [#34-what-prisma-reports-after-the-merge]

Draw the graph:

  

#### bun

```bash
bunx prisma migration graph
```

#### pnpm

```bash
pnpm prisma migration graph
```

#### yarn

```bash
yarn prisma migration graph
```

#### npm

```bash
npx prisma migration graph
```

```text no-copy
○     1e5059c  @contract

○     b29af39  (db)
│↑    20260910T1546_add_favorite_color  91e7f9f → b29af39  1 ops
│ ○   18b24e5
│ │↑  20260910T1547_add_tag_model       91e7f9f → 18b24e5  1 ops
│─╯
○     91e7f9f
│↑    20260910T1543_init                      ∅ → 91e7f9f  6 ops
○     ∅

1 space(s), 4 contract(s), 3 migration(s)
```

Read it bottom-up. From `init` (`91e7f9f`) two branches leave: Ania's ends at `b29af39`, Javier's at `18b24e5`. The merged contract you just emitted, `1e5059c`, sits at the top with no edge arriving at it. No database can reach it yet. `migration status` draws the same graph and marks where your database is, which is still on `init` (`@db`):

  

#### bun

```bash
bunx prisma migration status
```

#### pnpm

```bash
pnpm prisma migration status
```

#### yarn

```bash
yarn prisma migration status
```

#### npm

```bash
npx prisma migration status
```

```text no-copy
○     1e5059c  @contract

○     b29af39  (db)
│↑    20260910T1546_add_favorite_color  91e7f9f → b29af39  1 ops
│ ○   18b24e5
│ │↑  20260910T1547_add_tag_model       91e7f9f → 18b24e5  1 ops
│─╯
○     91e7f9f  @db
│↑    20260910T1543_init                      ∅ → 91e7f9f  6 ops  ✓ applied
○     ∅

⚠ No migration path from the database state (91e7f9f03580) to the application's contract (1e5059c1976c). Run `{bin} migration plan --name <name>` to author one.
```

Do not follow that hint literally. Without `--from`, the planner takes the `db` ref as its origin, and after `git checkout --ours` that ref is Ania's tip, so `migration plan --name merge_schema` writes only the half of the merge her branch is missing. Javier's database would still have no path to the top. Had the ref still pointed at `init`, the planner would have started a third branch from the divergence point instead, with a warning that it forks the graph. Neither is the merge. Do not delete either branch's migration directory to get out of this: Ania's and Javier's databases have already applied those migrations. Name the origin yourself, once per tip.

### 3.5. Close the diamond [#35-close-the-diamond]

Plan one merge migration from each tip. Each one carries the change its branch is missing, and both arrive at the merged contract:

  

#### bun

```bash
bunx prisma migration plan --from 20260910T1546_add_favorite_color --name merge_add_tag_model
```

#### pnpm

```bash
pnpm prisma migration plan --from 20260910T1546_add_favorite_color --name merge_add_tag_model
```

#### yarn

```bash
yarn prisma migration plan --from 20260910T1546_add_favorite_color --name merge_add_tag_model
```

#### npm

```bash
npx prisma migration plan --from 20260910T1546_add_favorite_color --name merge_add_tag_model
```

```text no-copy
✔ Planned 1 operation(s)

migrations/app/20260910T1550_merge_add_tag_model
└─ Create table "Tag"

from:       b29af3990b528c7a67809a2ac609305c59aa9c0af1ed0e4591cc0a727b38b1d1
to:         1e5059c1976c2439863eae8ac13211916ca411614c917394c413346f0d00f60b
```

  

#### bun

```bash
bunx prisma migration plan --from 20260910T1547_add_tag_model --name merge_add_favorite_color
```

#### pnpm

```bash
pnpm prisma migration plan --from 20260910T1547_add_tag_model --name merge_add_favorite_color
```

#### yarn

```bash
yarn prisma migration plan --from 20260910T1547_add_tag_model --name merge_add_favorite_color
```

#### npm

```bash
npx prisma migration plan --from 20260910T1547_add_tag_model --name merge_add_favorite_color
```

```text no-copy
✔ Planned 1 operation(s)

migrations/app/20260910T1550_merge_add_favorite_color
└─ Add column "favoriteColor" to "User"

from:       18b24e59a8b291a37b50e0d82c7afb58b314a2b64920d530627c73bd6e2d9768
to:         1e5059c1976c2439863eae8ac13211916ca411614c917394c413346f0d00f60b
```

`--from` accepts a migration directory name, as here, or a contract hash from the graph. The planner diffs the two contract snapshots and writes exactly the operations that are missing on that side. Review both DDL previews the way you would review any migration. The graph is now a diamond, and every database on either branch has a path to the top:

  

#### bun

```bash
bunx prisma migration graph
```

#### pnpm

```bash
pnpm prisma migration graph
```

#### yarn

```bash
yarn prisma migration graph
```

#### npm

```bash
npx prisma migration graph
```

```text no-copy
○     1e5059c  @contract
│─╮
│↑│   20260910T1550_merge_add_tag_model       b29af39 → 1e5059c  1 ops
│ │↑  20260910T1550_merge_add_favorite_color  18b24e5 → 1e5059c  1 ops
○ │   b29af39  (db)
│↑│   20260910T1546_add_favorite_color        91e7f9f → b29af39  1 ops
│ ○   18b24e5
│ │↑  20260910T1547_add_tag_model             91e7f9f → 18b24e5  1 ops
│─╯
○     91e7f9f
│↑    20260910T1543_init                            ∅ → 91e7f9f  6 ops
○     ∅

1 space(s), 5 contract(s), 5 migration(s)
```

Your own database is still on `init`, so two migrations are pending for it. Apply them and let `--advance-ref db` set the `db` ref to where the database actually ends up, which also settles the `db.json` conflict from section 3.3:

  

#### bun

```bash
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma db migrate --advance-ref db
```

```text no-copy
✔ Applied 2 migration(s) (2 operation(s)) across 1 contract space(s)

App space
├─ Add column "favoriteColor" to "User"
├─ Create table "Tag"
└─ marker 1e5059c1976c2439863eae8ac13211916ca411614c917394c413346f0d00f60b

✔ Advanced ref "db" → 1e5059c1976c2439863eae8ac13211916ca411614c917394c413346f0d00f60b
```

The runner walked `init → add_favorite_color → merge_add_tag_model`. It could equally have walked the other side; both paths end at the same contract. Now commit the merge, the re-emitted contract, both merge migrations, and the `db` ref together:

```bash
git add -A
git commit -m "Merge javier/tag-model and plan merge migrations"
```

### 3.6. Every database runs only the migrations it needs [#36-every-database-catches-up-on-its-own-path]

Ania pulls `main`. Her database matches `b29af39`, so only the migration that adds Javier's table is pending for her:

  

#### bun

```bash
bunx prisma migration status
```

#### pnpm

```bash
pnpm prisma migration status
```

#### yarn

```bash
yarn prisma migration status
```

#### npm

```bash
npx prisma migration status
```

```text no-copy
○     1e5059c  @contract (db)
│─╮
│↑│   20260910T1550_merge_add_tag_model       b29af39 → 1e5059c  1 ops  ⧗ pending
│ │↑  20260910T1550_merge_add_favorite_color  18b24e5 → 1e5059c  1 ops
○ │   b29af39  @db
│↑│   20260910T1546_add_favorite_color        91e7f9f → b29af39  1 ops  ✓ applied
│ ○   18b24e5
│ │↑  20260910T1547_add_tag_model             91e7f9f → 18b24e5  1 ops
│─╯
○     91e7f9f
│↑    20260910T1543_init                            ∅ → 91e7f9f  6 ops  ✓ applied
○     ∅

⚠ 1 pending: run `{bin} db migrate --to 1e5059c1976c`
```

  

#### bun

```bash
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma db migrate --advance-ref db
```

```text no-copy
✔ Applied 1 migration(s) (1 operation(s)) across 1 contract space(s)

App space
├─ Create table "Tag"
└─ marker 1e5059c1976c2439863eae8ac13211916ca411614c917394c413346f0d00f60b
```

Javier does the same, and for him the pending migration is `merge_add_favorite_color`, which adds Ania's column. Nobody re-created anything, and the database's own ledger shows the route each one took:

  

#### bun

```bash
bunx prisma migration log
```

#### pnpm

```bash
pnpm prisma migration log
```

#### yarn

```bash
yarn prisma migration log
```

#### npm

```bash
npx prisma migration log
```

```text no-copy
Applied at                  Migration                          Change             Ops
2026-09-10 17:45:41 +02:00  20260910T1543_init                 ∅ → 91e7f9f        6 ops
2026-09-10 17:46:17 +02:00  20260910T1546_add_favorite_color   91e7f9f → b29af39  1 ops
2026-09-10 17:52:47 +02:00  20260910T1550_merge_add_tag_model  b29af39 → 1e5059c  1 ops
```

## 4. Integrate your changes [#4-integrate-your-changes]

### 4.1. Pull first [#41-pull-first]

With `main` merged and your database on the merged state, add your own field. Always pull and apply before you plan, so your plan chains from the state everyone shares:

```bash
git pull
```

  

#### bun

```bash
bunx prisma migration status
```

#### pnpm

```bash
pnpm prisma migration status
```

#### yarn

```bash
yarn prisma migration status
```

#### npm

```bash
npx prisma migration status
```

### 4.2. Edit, emit, plan [#42-edit-emit-plan]

```prisma title="src/prisma/contract.prisma"
model User {
  /* ... */
  favoriteColor   String?
  bestPacmanScore Int?
}
```

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_best_pacman_score
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_best_pacman_score
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_best_pacman_score
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_best_pacman_score
```

```text no-copy
✔ Planned 1 operation(s)

migrations/app/20260910T1554_add_best_pacman_score
└─ Add column "bestPacmanScore" to "User"

from:       1e5059c1976c2439863eae8ac13211916ca411614c917394c413346f0d00f60b
to:         4961e5b3ceb00cb24a60245343f288095c5a00fc2344d02db1b68509a8b91440
app space:  migrations/app/20260910T1554_add_best_pacman_score

ℹ DDL preview

ALTER TABLE "public"."User" ADD COLUMN "bestPacmanScore" int4;
```

No `--from` was needed: the `db` ref points at the merged state because the last apply advanced it. Check the `from:` line anyway. If it does not name the state you expect, stop and read [Common gotchas](#common-gotchas).

### 4.3. Apply and check [#43-apply-and-check]

  

#### bun

```bash
bunx prisma db migrate --advance-ref db
bunx prisma migration check
```

#### pnpm

```bash
pnpm prisma db migrate --advance-ref db
pnpm prisma migration check
```

#### yarn

```bash
yarn prisma db migrate --advance-ref db
yarn prisma migration check
```

#### npm

```bash
npx prisma db migrate --advance-ref db
npx prisma migration check
```

```text no-copy
✔ Applied 1 migration(s) (1 operation(s)) across 1 contract space(s)

App space
├─ Add column "bestPacmanScore" to "User"
└─ marker 4961e5b3ceb00cb24a60245343f288095c5a00fc2344d02db1b68509a8b91440

✔ Advanced ref "db" → 4961e5b3ceb00cb24a60245343f288095c5a00fc2344d02db1b68509a8b91440
```

```text no-copy
✔ All checks passed
```

`migration check` is offline and verifies every migration's hash and the graph's integrity. Run it after you edit a migration by hand, so an `ops.json` or `migration.json` that no longer matches its hash shows up before you commit. A pipeline does not need it, because `db migrate` refuses such a migration too.

`migration check` reads only the files, so it cannot tell you whether a database matches them. `db verify` does. Run `npx prisma db verify --db "$DATABASE_URL"` after `db migrate`, and it fails if the database's marker or its tables differ from the contract you emitted. A pipeline that migrates a shared database runs `db migrate` alone; it refuses a database whose marker is outside your history with `MIGRATION.MARKER_MISMATCH` before it runs anything. [Migrate a shared database from a workflow](https://www.prisma.io/docs/guides/integrations/github-actions#migrate-a-shared-database) shows the job.

### 4.4. Commit [#44-commit]

Commit the same set of files your teammates did:

```bash
git add src/prisma/contract.prisma src/prisma/contract.json src/prisma/contract.d.ts migrations
git commit -m "Add User.bestPacmanScore"
```

The final graph on `main` is a diamond with one more step on top, and your application code can use all three changes right away:

```ts title="script.ts"
const user = await db.orm.public.User.create({
  email: "pacman@prisma.io",
  favoriteColor: "yellow",
  bestPacmanScore: 3333360,
});
const tag = await db.orm.public.Tag.create({ tagName: "arcade", tagCategory: "games" });
```

## Common gotchas [#common-gotchas]

> [!WARNING]
> `migration plan` fails with `MIGRATION.PLAN_ORIGIN_UNKNOWN` when the project has migrations but no `db` ref and you passed no `--from`. This happens in a fresh clone that has never run `db migrate --advance-ref db`, or after a merge dropped `refs/db.json`. The error lists the three exits:
> 
> ```text no-copy
> ✘ [MIGRATION.PLAN_ORIGIN_UNKNOWN] Cannot determine the plan origin: migrations exist but no origin is named
>   why: Migrations exist on disk, but there is no `db` ref and no --from was given, so the plan origin would silently fall back to an empty database and the resulting migration would recreate everything the existing migrations already create.
> → Point the db ref at the origin contract: {bin} migration ref set db <contract>
> → Plan from an explicit origin: {bin} migration plan --from <contract>
> → Plan from an empty database deliberately: {bin} migration plan --from @empty
> ```
>
> Pick the first or second. `--from @empty` over an existing history is only right for a deliberate rebuild.

> [!WARNING]
> Never run `db update` against a database another developer, CI, or production shares. It reconciles the database to your contract directly and leaves no migration behind, so the next `db migrate` from a teammate finds a marker the graph does not know. Use `db update` only on your own throwaway database, and switch to `migration plan` before you open a pull request.

> [!NOTE]
> The merge conflict in `migrations/app/refs/db.json` is expected whenever two branches both applied with `--advance-ref db`. The file records where one developer's database was, so no merged value is "correct" for everyone. Resolve it with either side and let your next `db migrate --advance-ref db` write the truth.

> [!NOTE]
> Renaming a field plans as a destructive drop column plus add column, because the planner has no rename hint yet. Before a rename reaches a shared database, [edit the migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) to replace the pair with a `rawSql` `ALTER TABLE ... RENAME COLUMN`, then recompile it with `node migration.ts`.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, check whether my database is behind the migrations on this branch and apply what is pending."
* "Two branches both added migrations from the same state. Draw the migration graph and plan the merge migrations from each tip."
* "Run `migration check` and explain any integrity failure before I open this pull request."

## Next steps [#next-steps]

* [The migration graph](https://www.prisma.io/docs/orm/migrations/the-migration-graph): refs, markers, and how `db migrate` finds a path
* [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration): the status, preview, apply rhythm for staging and production
* [Rollbacks and recovery](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery): planning a backwards edge when a merged change has to come out
* [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration): backfills and raw SQL when a schema change needs a data step

## Related pages

- [`Expand-and-contract migrations`](https://www.prisma.io/docs/guides/database/data-migration): Replace a column without downtime using the expand and contract pattern, with the data backfill inside a Prisma ORM migration.
- [`Multiple databases`](https://www.prisma.io/docs/guides/database/multiple-databases): Connect one Next.js app to two PostgreSQL databases with Prisma ORM: one contract, config, and client per database, selected with the --config flag.

# Bun workspaces (/docs/guides/deployment/bun-workspaces)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up Prisma ORM in a Bun workspaces monorepo through a shared database package, seed it with Bun, and query it from a Next.js app in the same workspace.

Location: Guides > Deployment > Bun workspaces

## Introduction [#introduction]

This guide shows you how to use Prisma ORM in a [Bun workspaces](https://bun.sh/docs/install/workspaces) monorepo. You create a shared `database` package that owns the schema, the database client, and a seed script, then import that client from a Next.js app in the same workspace. Every workspace member shares one lockfile and one `bun install`, so the database package is wired into the app like any other dependency.

Every command, file, and output below was run end to end against a live PostgreSQL database.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/deployment/bun-workspaces](https://www.prisma.io/docs/guides/v7/deployment/bun-workspaces).

## Prerequisites [#prerequisites]

* [Bun](https://bun.sh/docs/installation) 1.1 or later (`bun --version`)
* [Node.js](https://nodejs.org) 24 or later: Bun runs the scripts, and Next.js runs on Node.js
* A PostgreSQL connection string, or nothing at all: `bunx create-db@latest` can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a Bun workspaces monorepo with a shared Prisma ORM database package and a Next.js app that queries it.

1. Create `my-monorepo` with a root `package.json` that sets `"workspaces": ["apps/*", "packages/*"]`, then create `apps/` and `packages/database/`. Give `packages/database` a `package.json` with `"name": "database"`, `"private": true`, `"type": "module"` and `"main": "index.ts"`.
2. In `packages/database`, run `bunx prisma@latest orm init --yes --target postgres --authoring psl`. Then run `bunx prisma@latest init` there so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `bunx create-db@latest` and show me the claim URL it prints. Write it as `DATABASE_URL` into `packages/database/.env`.
3. Add package scripts to `packages/database`: `db:init` (`prisma db init`), `db:update` (`prisma db update`), `db:seed` (`bun src/prisma/seed.ts`). Run `bun run db:init` there.
4. Create `packages/database/index.ts` that re-exports `db` from `./src/prisma/db`, and `packages/database/src/prisma/seed.ts` that upserts three users with `db.orm.public.User.upsert({ create, update: {}, conflictOn: { email } })` and ends with `await db.close()`, following https://www.prisma.io/docs/guides/deployment/bun-workspaces.md. Run `bun run db:seed`.
5. Add root scripts `dev`, `build`, `start`, `db:init`, `db:update` and `seed` that use `bun run --filter <package> <script>`.
6. In `apps/`, run `bun create next-app@latest web --yes`, delete `apps/web/.git`, add `"database": "workspace:*"` to its dependencies, copy `packages/database/.env` to `apps/web/.env`, and run `bun install` from the root.
7. Replace `apps/web/app/page.tsx` with a server component that exports `dynamic = "force-dynamic"` and lists users from `db.orm.public.User.select("id", "name", "email").all()`.
8. Start `bun run dev` from the root in the background, wait until it reports ready, verify `curl http://localhost:3000` returns the seeded users, then stop the dev server.

Use the installed Prisma ORM skills.
```

## 1. Set up the workspace [#1-set-up-the-workspace]

Create a directory for the monorepo and a root `package.json` that declares where the apps and shared packages live:

```bash
mkdir my-monorepo
cd my-monorepo
```

```json title="package.json"
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": ["apps/*", "packages/*"]
}
```

Create the directories for the app and the shared database package:

```bash
mkdir apps
mkdir -p packages/database
```

## 2. Set up the database package [#2-set-up-the-database-package]

The `database` package owns the schema, the emitted contract, the Prisma ORM client, and the seed script. Every app in the workspace imports the client from it.

### 2.1. Initialize Prisma ORM [#21-initialize-prisma-orm]

Give the package a `package.json`. `"main": "index.ts"` lets other workspace members import the TypeScript source directly, so there is no build step for the package:

```json title="packages/database/package.json"
{
  "name": "database",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "main": "index.ts"
}
```

Then add Prisma ORM to the package:

```bash
cd packages/database
bunx prisma@latest orm init --target postgres
```

Choose `PSL` as the authoring style and keep the default schema path. The command detects Bun as the package manager, installs `@prisma/orm-postgres` and `dotenv` plus the dev dependencies `prisma`, `@types/node`, and `@prisma/cli-engine`, and writes:

* `src/prisma/contract.prisma`: the schema, with starter `User` and `Post` models
* `src/prisma/db.ts`: the client the rest of the workspace imports
* `prisma.config.ts`: loads `.env` and points the CLI at the contract and `DATABASE_URL`
* `.env.example`, `tsconfig.json`, `.gitignore`, and `prisma-8.md`
* a `contract:emit` script in `package.json`

It also runs the first `contract emit`, which compiles the schema into `src/prisma/contract.json` and `src/prisma/contract.d.ts`. Those two files are what your queries are type-checked against, so there is no `prisma generate` step and no generated client folder to export from the package.

Bun installs the workspace's dependencies into the root `node_modules` and writes a single `bun.lock` at the root, even though you ran the command inside `packages/database`.

The generated client reads `DATABASE_URL` from the environment and loads `.env` first:

```ts title="packages/database/src/prisma/db.ts"
import 'dotenv/config';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});
```

There is no driver adapter and no engine to configure: the runtime talks to PostgreSQL directly.

### 2.2. Set the connection string and add scripts [#22-set-the-connection-string-and-add-scripts]

Create `.env` in the database package. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `bunx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database.

```bash title="packages/database/.env"
DATABASE_URL="postgres://user:password@localhost:5432/mydb"
```

Add the database scripts next to the `contract:emit` script that `orm init` created. The seed script runs with `bun`, which executes TypeScript directly:

```json title="packages/database/package.json"
{
  "scripts": {
    "contract:emit": "prisma contract emit",
    "db:init": "prisma db init", // [!code ++]
    "db:update": "prisma db update", // [!code ++]
    "db:verify": "prisma db verify", // [!code ++]
    "db:seed": "bun src/prisma/seed.ts" // [!code ++]
  }
}
```

### 2.3. Initialize the database [#23-initialize-the-database]

Apply the schema to the database and sign it:

```bash
bun run db:init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Applied 0 operation(s)` when there is nothing left to do.

### 2.4. Export the client [#24-export-the-client]

Create `index.ts` at the package root. It re-exports the client and the `Contract` type so apps import from `database` and never reach into the package's internals:

```ts title="packages/database/index.ts"
export { db } from "./src/prisma/db";
export type { Contract } from "./src/prisma/contract.d";
```

### 2.5. Seed the database [#25-seed-the-database]

Create the seed script. `upsert` with `conflictOn` makes it safe to run more than once, and `await db.close()` at the end lets the process exit instead of waiting on the connection pool:

```ts title="packages/database/src/prisma/seed.ts"
import { db } from "./db";

const users = [
  { email: "alice@example.com", name: "Alice" },
  { email: "bob@example.com", name: "Bob" },
  { email: "charlie@example.com", name: "Charlie" },
];

for (const user of users) {
  await db.orm.public.User.upsert({
    create: user,
    update: {},
    conflictOn: { email: user.email },
  });
}

console.log(`Seeded ${users.length} users.`);
await db.close();
```

Model access is namespace-qualified on PostgreSQL: `db.orm.public.User`, where `public` is the default schema.

Run it:

```bash
bun run db:seed
```

```text no-copy
$ bun src/prisma/seed.ts
Seeded 3 users.
```

The shared database package is now complete.

## 3. Add root scripts [#3-add-root-scripts]

Go back to the workspace root and add scripts that fan out to the packages with `bun run --filter`:

```bash
cd ../..
```

```json title="package.json"
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": ["apps/*", "packages/*"],
  "scripts": { // [!code ++]
    "dev": "bun run --filter web dev", // [!code ++]
    "build": "bun run --filter database contract:emit && bun run --filter web build", // [!code ++]
    "start": "bun run --filter web start", // [!code ++]
    "db:init": "bun run --filter database db:init", // [!code ++]
    "db:update": "bun run --filter database db:update", // [!code ++]
    "seed": "bun run --filter database db:seed" // [!code ++]
  } // [!code ++]
}
```

`build` emits the contract before building the app, so a schema edit is never stale in a production build. There is no generate step to run before `dev`: the emitted `contract.json` and `contract.d.ts` are plain files that the app imports.

Check that the seed works from the root:

```bash
bun run seed
```

```text no-copy
$ bun run --filter database db:seed
database db:seed: Seeded 3 users.
database db:seed: Exited with code 0
```

## 4. Set up the Next.js app [#4-set-up-the-nextjs-app]

### 4.1. Create the app [#41-create-the-app]

Create a Next.js app named `web` inside `apps/`:

```bash
cd apps
bun create next-app@latest web --yes
```

```text no-copy
Initializing project with template: app-tw

Installing dependencies:
- next
- react
- react-dom
...
Success! Created web at /path/to/my-monorepo/apps/web
```

`--yes` accepts the defaults (App Router, TypeScript, Tailwind, no `src/` directory) and uses Bun as the package manager because you ran it with `bun create`. Bun recognizes that `apps/web` is inside a workspace and records its dependencies in the root `bun.lock`.

The scaffold also initializes a Git repository inside `apps/web`. Remove it, because the monorepo root should be the only repository:

```bash
cd web
rm -rf .git
```

### 4.2. Add the database package [#42-add-the-database-package]

Add the shared package as a workspace dependency:

```json title="apps/web/package.json"
{
  "dependencies": {
    "database": "workspace:*", // [!code ++]
    "next": "16.3.4",
    "react": "19.2.8",
    "react-dom": "19.2.8"
  }
}
```

The client in the database package reads `DATABASE_URL` from `.env` in the current working directory, and Next.js loads `.env` from the app directory. Copy the file so both find it:

```bash
cp ../../packages/database/.env .
```

The Next.js `.gitignore` already excludes `.env*`, so the copy stays out of Git.

Then link the package by installing from the root:

```bash
cd ../..
bun install
```

```text no-copy
bun install v1.3.3 (274e01c7)
Saved lockfile

Checked 478 installs across 616 packages (no changes) [440.00ms]
```

`apps/web/node_modules/database` is now a symlink to `packages/database`.

### 4.3. Query the database from a server component [#43-query-the-database-from-a-server-component]

Replace `apps/web/app/page.tsx` with a server component that lists the users. `dynamic = "force-dynamic"` makes the page query the database on every request instead of once at build time:

```tsx title="apps/web/app/page.tsx"
import { db } from "database";

export const dynamic = "force-dynamic";

export default async function Home() {
  const users = await db.orm.public.User.select("id", "name", "email").all();

  return (
    <main>
      <h1>Users</h1>
      {users.length === 0 && <p>No users have been added to the database yet.</p>}
      <ul>
        {users.map((user) => (
          <li key={user.id}>{`${user.name} (${user.email})`}</li>
        ))}
      </ul>
    </main>
  );
}
```

`users` is typed from the contract, so `user.name` and `user.email` autocomplete in the app even though the schema lives in another package. Turbopack compiles the package's TypeScript source through the workspace symlink; no `transpilePackages` setting is needed.

### 4.4. Run the app [#44-run-the-app]

Start the dev server from the workspace root:

```bash
bun run dev
```

```text no-copy
$ bun run --filter web dev
web dev: ▲ Next.js 16.3.4 (Turbopack)
web dev: - Local:         http://localhost:3000
web dev: - Network:       http://192.168.1.16:3000
web dev: - Environments: .env
web dev: ✓ Ready in 4.0s
```

Open [http://localhost:3000](http://localhost:3000), or check it from another terminal:

```bash
curl -s http://localhost:3000 | grep -o '<h1>.*</ul>'
```

```html no-copy
<h1>Users</h1><ul><li>Alice (alice@example.com)</li><li>Bob (bob@example.com)</li><li>Charlie (charlie@example.com)</li></ul>
```

The production build works the same way. `bun run build` emits the contract and then runs `next build`; `bun run start` serves the result:

```bash
bun run build
```

```text no-copy
$ bun run --filter database contract:emit && bun run --filter web build
database contract:emit: Exited with code 0
web build: ▲ Next.js 16.3.4 (Turbopack)
web build:   Creating an optimized production build ...
web build: ✓ Compiled successfully in 26.2s
web build:   Running TypeScript ...
web build:   Finished TypeScript in 15.8s ...
web build:
web build: Route (app)
web build: ┌ ƒ /
web build: └ ○ /_not-found
web build:
web build: ƒ  (Dynamic)  server-rendered on demand
web build: Exited with code 0
```

## 5. Change the schema [#5-change-the-schema]

Schema changes happen in one place. Edit `packages/database/src/prisma/contract.prisma`, for example to add a field to `User`:

```prisma title="packages/database/src/prisma/contract.prisma"
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  username  String?
  name      String?
  bio       String? // [!code ++]
  posts     Post[]
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}
```

Then, from the root, emit the contract and update the database:

```bash
bun run --filter database contract:emit
bun run db:update
```

```text no-copy
"summary": "Applied 1 operation(s) across 1 space(s), signature updated"
```

The Next.js app picks up the new field on its next request because it imports the package's emitted `contract.d.ts` directly. For a checked-in migration instead of a direct update, use [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) and [`db migrate`](https://www.prisma.io/docs/cli/db-migrate).

## Common gotchas [#common-gotchas]

> [!WARNING]
> If the app fails with `CONTRACT.MARKER_READ_FAILED` and `Postgres driver not connected`, `DATABASE_URL` is not set in the app's environment. The client is constructed in `packages/database`, but the environment it reads comes from the process that imports it. Make sure `apps/web/.env` exists, or export `DATABASE_URL` in the shell that runs `bun run dev`.

> [!WARNING]
> `db update` refuses to apply an operation that destroys data, such as dropping a column, without consent. Interactively it asks you to type the database name; in a script or CI job, pass `--confirm <database name>`.

> [!NOTE]
> Without `export const dynamic = "force-dynamic"`, Next.js prerenders the page at build time and the users list is frozen at whatever the database held during `bun run build`.

Do not call `db.close()` in a server component or route handler. The client in `packages/database` is a module-level singleton whose connection pool is shared across requests; close it only in short-lived scripts such as the seed.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`bunx prisma@latest init`](https://www.prisma.io/docs/cli/init) once inside `packages/database` to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. It adds a `postinstall` script that re-syncs the skills after every `bun install`. Prompts that map to this guide:

* "Using the prisma-8 skill, add a `packages/database/src/prisma/reset.ts` script that deletes all posts and users."
* "Add a `/users/[id]` page in `apps/web` that loads one user with their posts from the shared `database` package."
* "Add an `apps/api` Bun server to the workspace that exposes `GET /users` from the shared `database` package."

## Next steps [#next-steps]

You now have a Bun workspaces monorepo with a shared Prisma ORM database package integrated into a Next.js app.

* To add task orchestration and caching on top of this setup, see the [Turborepo](https://www.prisma.io/docs/guides/deployment/turborepo) guide.
* To serve the same package from a plain Bun server instead of Next.js, see the [Bun](https://www.prisma.io/docs/guides/runtimes/bun) guide.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Cloudflare Workers`](https://www.prisma.io/docs/guides/deployment/cloudflare-workers): Add Prisma ORM to a Cloudflare Worker, query PostgreSQL from the fetch handler with the nodejs_compat flag, and deploy it with Wrangler.
- [`Docker`](https://www.prisma.io/docs/guides/deployment/docker): Build an Express app on Prisma ORM, run PostgreSQL from Docker Compose, then run the app and the database together in containers.
- [`pnpm workspaces`](https://www.prisma.io/docs/guides/deployment/pnpm-workspaces): Set up Prisma 8 in a shared database package inside a pnpm workspaces monorepo and query it from a Next.js app.
- [`Turborepo`](https://www.prisma.io/docs/guides/deployment/turborepo): Share one Prisma 8 database package across the apps in a Turborepo monorepo, with contract emit and migrations wired into turbo tasks.

# Cloudflare Workers (/docs/guides/deployment/cloudflare-workers)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to a Cloudflare Worker, query PostgreSQL from the fetch handler with the nodejs_compat flag, and deploy it with Wrangler.

Location: Guides > Deployment > Cloudflare Workers

## Introduction [#introduction]

In this guide, you add Prisma ORM to a Cloudflare Worker, create tables in a PostgreSQL database, insert and count rows from the Worker's `fetch` handler, and deploy the Worker with Wrangler.

Cloudflare Workers do not expose raw TCP sockets by default, which is why most PostgreSQL drivers cannot run in them. With the `nodejs_compat` compatibility flag enabled, the `pg` driver that `@prisma/orm-postgres` uses connects through Cloudflare's Node.js socket API, so Prisma ORM runs inside the Worker without a special build. This works with [Prisma Postgres](https://www.prisma.io/docs/postgres), which pools connections for you, with any PostgreSQL server reachable over TCP and TLS, and with [Hyperdrive](https://developers.cloudflare.com/hyperdrive/) in front of your own database.

Every command, code block, and output below was run with `wrangler dev` against a local PostgreSQL 17 database, and the same Worker was also run against a Prisma Postgres database over TLS.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/deployment/cloudflare-workers](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-workers).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* A [Cloudflare account](https://dash.cloudflare.com/sign-up/workers-and-pages) for the deploy step
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Add Prisma ORM to a new Cloudflare Worker, query PostgreSQL from it, and prepare it for deployment.

1. Scaffold: `npm create cloudflare@latest prisma-cloudflare-worker -- --type=hello-world --lang=ts --git --no-deploy --no-agents`. In `prisma-cloudflare-worker`, run `npx prisma@latest orm init --yes --target postgres --authoring psl`, then `npx prisma@latest init` so the Prisma agent skills are installed and stay current, and use them.
2. Add `"compatibility_flags": ["nodejs_compat"]` to `wrangler.jsonc`. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Write it to `.env` as `DATABASE_URL`; both the Prisma CLI and `wrangler dev` read that file.
3. Run `npx prisma db init` to create the tables from `src/prisma/contract.prisma`.
4. Replace `src/index.ts` following https://www.prisma.io/docs/guides/deployment/cloudflare-workers.md: create one `postgres<Contract>({ contractJson, url: env.DATABASE_URL })` client per request inside `fetch`, run the queries, and close it with `ctx.waitUntil(db.close())`. Do not import the module-level client from `src/prisma/db.ts` in the Worker; a connection shared across requests hangs the second request. Run `npx wrangler types` so `Env` includes `DATABASE_URL`.
5. Start `npm run dev` in the background, wait until it reports ready, verify `curl http://localhost:8787` twice returns a created user and a growing count, then stop the dev server.
6. Deploy: check `npx wrangler whoami`; if I am not logged in, stop and ask me to run `npx wrangler login`. Then run `npx wrangler secret put DATABASE_URL` with the production connection string and `npm run deploy`, and verify the live URL.
```

## 1. Create a Worker [#1-create-a-worker]

Scaffold a TypeScript "Hello World" Worker:

  

#### bun

```bash
bunx create-cloudflare prisma-cloudflare-worker --type hello-world --lang=ts --git --no-deploy --no-agents
```

#### pnpm

```bash
pnpm create cloudflare prisma-cloudflare-worker --type=hello-world --lang=ts --git --no-deploy --no-agents
```

#### yarn

```bash
yarn create cloudflare prisma-cloudflare-worker --type=hello-world --lang=ts --git --no-deploy --no-agents
```

#### npm

```bash
npm create cloudflare@latest prisma-cloudflare-worker -- --type=hello-world --lang=ts --git --no-deploy --no-agents
```

```text no-copy
╭ Create an application with Cloudflare Step 1 of 3
│
├ In which directory do you want to create your application?
│ dir ./prisma-cloudflare-worker
│
├ What would you like to start with?
│ category Hello World example
│
├ Which template would you like to use?
│ type Worker only
│
├ Which language do you want to use?
│ lang TypeScript
│
╰ Application configured

🎉  SUCCESS  Application created successfully!
```

The flags skip the interactive prompts. Drop them if you prefer to answer the questions yourself. Then enter the project:

```bash
cd prisma-cloudflare-worker
```

## 2. Add Prisma ORM [#2-add-prisma-orm]

### 2.1. Initialize Prisma ORM in the project [#21-initialize-prisma-orm-in-the-project]

Prisma ORM has no Prisma Client to generate, no driver adapter package, and no query engine binary. `orm init` adds everything the Worker needs:

  

#### bun

```bash
bunx prisma@latest orm init --yes --target postgres --authoring psl
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### yarn

```bash
yarn dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### npm

```bash
npx prisma@latest orm init --yes --target postgres --authoring psl
```

Without `--yes`, the command asks for the contract authoring style and the schema path instead; the values above are the defaults. It installs the packages and emits the contract:

```json no-copy
{"kind":"step-finished","step":"npm add @prisma/orm-postgres dotenv","outcome":"ok"}
{"kind":"step-finished","step":"npm add -D prisma@latest","outcome":"ok"}
{"kind":"step-finished","step":"npm add -D @prisma/cli-engine@0.6.1","outcome":"ok"}
{"kind":"step-finished","step":"Emit the contract","outcome":"ok"}
{"kind":"result","envelope":{"ok":true,"result":{"target":"postgres","authoring":"psl","schemaPath":"src/prisma/contract.prisma","filesWritten":["src/prisma/contract.prisma","prisma.config.ts","src/prisma/db.ts","prisma-8.md",".env.example","tsconfig.json",".gitignore",".gitattributes","package.json","README.md"]}}}
```

The important files:

* `src/prisma/contract.prisma`: your schema. It starts with a `User` and a `Post` model.
* `src/prisma/contract.json` and `src/prisma/contract.d.ts`: emitted from the contract. The Worker imports both; there is no `prisma generate` step.
* `prisma.config.ts`: tells the CLI where the contract is and reads `DATABASE_URL` from `.env`.
* `src/prisma/db.ts`: a module-level client for Node.js scripts. The Worker does not import it; step 3 explains why.

`orm init` also sets `"type": "module"` in `package.json` and adds a `contract:emit` script. Whenever you edit `src/prisma/contract.prisma`, run `npm run contract:emit` to refresh the emitted files.

### 2.2. Enable Node.js compatibility [#22-enable-nodejs-compatibility]

Add the `nodejs_compat` flag to `wrangler.jsonc`. It gives the `pg` driver inside `@prisma/orm-postgres` the `node:net` and `node:tls` modules it needs to open a PostgreSQL connection from the Worker:

```json title="wrangler.jsonc"
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "prisma-cloudflare-worker",
  "main": "src/index.ts",
  "compatibility_date": "2026-09-07",
  "compatibility_flags": ["nodejs_compat"], // [!code ++]
  "observability": {
    "enabled": true
  },
  "upload_source_maps": true
}
```

### 2.3. Set your database connection string [#23-set-your-database-connection-string]

Create a `.env` file with your PostgreSQL connection string. If you do not have a database, `npx create-db@latest` creates a Prisma Postgres database and prints a connection string and a claim URL you can open to keep it.

```bash title=".env"
DATABASE_URL="postgres://user:password@localhost:5432/mydb"
```

Both tools read this one file: the Prisma CLI through `prisma.config.ts`, and `wrangler dev` directly, which exposes the value to the Worker as `env.DATABASE_URL`.

### 2.4. Create the tables [#24-create-the-tables]

  

#### bun

```bash
bunx prisma db init
```

#### pnpm

```bash
pnpm prisma db init
```

#### yarn

```bash
yarn prisma db init
```

#### npm

```bash
npx prisma db init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

`db init` creates the `user` and `post` tables from the contract and signs the database, which records that it matches the emitted contract. There is no `prisma migrate dev` in Prisma ORM; use [`db update`](https://www.prisma.io/docs/cli/db-update) for later schema changes during development and [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) when you want a checked-in migration.

## 3. Query the database from the Worker [#3-query-the-database-from-the-worker]

Replace `src/index.ts` with a handler that creates a user and counts all users:

```typescript title="src/index.ts"
import postgres from "@prisma/orm-postgres/runtime";
import type { Contract } from "./prisma/contract.d";
import contractJson from "./prisma/contract.json" with { type: "json" };

export default {
	async fetch(request, env, ctx): Promise<Response> {
		const path = new URL(request.url).pathname;
		if (path === "/favicon.ico") return new Response("Not found", { status: 404 });

		const db = postgres<Contract>({ contractJson, url: env.DATABASE_URL });
		try {
			const user = await db.orm.public.User.create({
				email: `user-${Math.ceil(Math.random() * 1000)}@prisma.io`,
				name: "Jon Doe",
			});
			const { total } = await db.orm.public.User.aggregate((a) => ({ total: a.count() }));

			return new Response(
				`Created new user: ${user.name} (${user.email}).\nNumber of users in the database: ${total}.\n`,
			);
		} finally {
			ctx.waitUntil(db.close());
		}
	},
} satisfies ExportedHandler<Env>;
```

Three things to notice:

* The client is created inside `fetch`, with the connection string from `env`, and closed after the response with `ctx.waitUntil(db.close())`. This is the opposite of a Node.js server, where you keep one client for the life of the process. Workers do not let a socket opened during one request be used by another, so a module-level client works for the first request and hangs the next one. That is why the Worker does not import `src/prisma/db.ts`.
* Models are namespace-qualified on PostgreSQL: `db.orm.public.User`. `.create(...)` returns the inserted row, database defaults included.
* `contract.json` is imported with `with { type: "json" }`. Wrangler bundles it into the Worker.

### 3.1. Generate the Env types [#31-generate-the-env-types]

`wrangler dev` reads `DATABASE_URL` from `.env`. Regenerate the Worker types so `Env` declares it:

  

#### bun

```bash
bunx wrangler types
```

#### pnpm

```bash
pnpm dlx wrangler types
```

#### yarn

```bash
yarn dlx wrangler types
```

#### npm

```bash
npx wrangler types
```

```text no-copy
✨ Types written to worker-configuration.d.ts
```

`worker-configuration.d.ts` now contains `DATABASE_URL: string` on `Env`, and `npx tsc --noEmit` passes.

### 3.2. Run the Worker locally [#32-run-the-worker-locally]

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

```text no-copy
Using secrets defined in .env
Your Worker has access to the following bindings:
Binding                            Resource                  Mode
env.DATABASE_URL ("(hidden)")      Environment Variable      local
⎔ Starting local server...
[wrangler:info] Ready on http://localhost:8787
```

Open [http://localhost:8787](http://localhost:8787) or call it from another terminal. Each request creates a user:

```bash
curl http://localhost:8787
```

```text no-copy
Created new user: Jon Doe (user-241@prisma.io).
Number of users in the database: 16.
```

Call it again and the count goes up by one. The queries run inside `workerd`, the same runtime Cloudflare uses in production.

## 4. Deploy to Cloudflare [#4-deploy-to-cloudflare]

### 4.1. Store the connection string as a secret [#41-store-the-connection-string-as-a-secret]

Wrangler does not upload `.env`. Store the production connection string as a Worker secret instead. Log in first if you have not (`npx wrangler login` opens a browser), then run:

  

#### bun

```bash
bunx wrangler secret put DATABASE_URL
```

#### pnpm

```bash
pnpm dlx wrangler secret put DATABASE_URL
```

#### yarn

```bash
yarn dlx wrangler secret put DATABASE_URL
```

#### npm

```bash
npx wrangler secret put DATABASE_URL
```

Paste the connection string when prompted. In production, the database must accept TCP connections with TLS from Cloudflare's network. A Prisma Postgres direct connection string (`postgres://...@db.prisma.io:5432/postgres?sslmode=require`) works as is and pools connections on the database side, so a Worker creating one client per request stays within the connection limit.

### 4.2. Deploy the Worker [#42-deploy-the-worker]

  

#### bun

```bash
bun run deploy
```

#### pnpm

```bash
pnpm run deploy
```

#### yarn

```bash
yarn deploy
```

#### npm

```bash
npm run deploy
```

Wrangler bundles the Worker (about 1.4 MB, 300 KB gzipped, with Prisma ORM included) and prints the live URL, `https://prisma-cloudflare-worker.<your-subdomain>.workers.dev`. Open it: the Worker creates a user in your production database on every request, exactly as it did locally. The upload itself was not run while validating this guide; the bundle size comes from `wrangler deploy --dry-run`, and the production path (TLS to Prisma Postgres from inside `workerd`) was verified with `wrangler dev`.

### 4.3. Optional: connect through Hyperdrive [#43-optional-connect-through-hyperdrive]

If your database is not Prisma Postgres, [Hyperdrive](https://developers.cloudflare.com/hyperdrive/) keeps a warm connection pool close to your database so each request does not pay for a new TCP and TLS handshake. Create a Hyperdrive config from your connection string:

  

#### bun

```bash
bunx wrangler hyperdrive create prisma-cloudflare-worker --connection-string="postgres://user:password@host:5432/database"
```

#### pnpm

```bash
pnpm dlx wrangler hyperdrive create prisma-cloudflare-worker --connection-string="postgres://user:password@host:5432/database"
```

#### yarn

```bash
yarn dlx wrangler hyperdrive create prisma-cloudflare-worker --connection-string="postgres://user:password@host:5432/database"
```

#### npm

```bash
npx wrangler hyperdrive create prisma-cloudflare-worker --connection-string="postgres://user:password@host:5432/database"
```

Add the binding it prints to `wrangler.jsonc`. The `localConnectionString` is what `wrangler dev` uses instead of Hyperdrive. The `hyperdrive create` command was not run while validating this guide; the local binding below was:

```json title="wrangler.jsonc"
{
  "compatibility_flags": ["nodejs_compat"],
  "hyperdrive": [ // [!code ++]
    { // [!code ++]
      "binding": "HYPERDRIVE", // [!code ++]
      "id": "<id printed by hyperdrive create>", // [!code ++]
      "localConnectionString": "postgres://user:password@localhost:5432/mydb" // [!code ++]
    } // [!code ++]
  ] // [!code ++]
}
```

Run `npx wrangler types` again, then pass the Hyperdrive connection string to the client instead of `env.DATABASE_URL`:

```typescript title="src/index.ts"
const db = postgres<Contract>({ contractJson, url: env.HYPERDRIVE.connectionString });
```

Everything else in the handler stays the same. The `localConnectionString` must include a password, even for a local server that does not check one; otherwise `wrangler dev` refuses to start with `You must provide a password`.

## Common gotchas [#common-gotchas]

> [!WARNING]
> Do not share a Prisma ORM client across requests in a Worker. The module-level `db` in `src/prisma/db.ts` keeps a connection pool alive between requests, and the second request that reuses a pooled socket never completes. `wrangler dev` reports:
> 
> ```text no-copy
> ✘ [ERROR] Uncaught Error: The Workers runtime canceled this request because it detected that your Worker's code had hung and would never generate a response.
> ```
>
> Create the client inside `fetch` and close it with `ctx.waitUntil(db.close())`, as the handler above does.

> [!NOTE]
> `@prisma/orm-postgres/serverless` exports `postgresServerless`, a per-request client built for serverless runtimes. It opens one `pg` connection per `await db.connect({ url })` call and disposes it when the request scope ends (`await using`). It runs in Workers with `nodejs_compat`, but it exposes only the SQL builder (`db.sql`), not `db.orm`, so this guide uses the regular runtime client per request instead. Reach for it when you only need [SQL builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries) queries.

> [!NOTE]
> `wrangler dev` reads `.env` for local values, but `wrangler deploy` never uploads it. Production values come from `wrangler secret put` or from bindings such as Hyperdrive.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add a `GET /users` route to the Worker that returns all users as JSON."
* "Add a `POST /users` route that creates a user from the request body and returns 201."
* "Add a `published Boolean @default(false)` field to `Post` in `src/prisma/contract.prisma`, emit the contract, and update the database with `db update`."

## Next steps [#next-steps]

* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* Change the schema in `src/prisma/contract.prisma`, then run `npm run contract:emit` and [`npx prisma db update`](https://www.prisma.io/docs/cli/db-update).
* Use [Hono](https://hono.dev/) for routing on Workers; the [Hono guide](https://www.prisma.io/docs/guides/frameworks/hono) shows the same per-route query pattern.
* [Cloudflare Workers documentation](https://developers.cloudflare.com/workers/) and the [Node.js compatibility reference](https://developers.cloudflare.com/workers/runtime-apis/nodejs/).
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Bun workspaces`](https://www.prisma.io/docs/guides/deployment/bun-workspaces): Set up Prisma ORM in a Bun workspaces monorepo through a shared database package, seed it with Bun, and query it from a Next.js app in the same workspace.
- [`Docker`](https://www.prisma.io/docs/guides/deployment/docker): Build an Express app on Prisma ORM, run PostgreSQL from Docker Compose, then run the app and the database together in containers.
- [`pnpm workspaces`](https://www.prisma.io/docs/guides/deployment/pnpm-workspaces): Set up Prisma 8 in a shared database package inside a pnpm workspaces monorepo and query it from a Next.js app.
- [`Turborepo`](https://www.prisma.io/docs/guides/deployment/turborepo): Share one Prisma 8 database package across the apps in a Turborepo monorepo, with contract emit and migrations wired into turbo tasks.

# Docker (/docs/guides/deployment/docker)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Build an Express app on Prisma ORM, run PostgreSQL from Docker Compose, then run the app and the database together in containers.

Location: Guides > Deployment > Docker

## Introduction [#introduction]

This guide walks you through running a Prisma ORM application in Docker. You build a small Node.js app with [Express](https://expressjs.com/), add Prisma ORM to it with `orm init`, run PostgreSQL from Docker Compose to apply the first migration, and then containerize the app so the app and the database start together with one command.

Prisma ORM has no query engines, no `prisma generate` step, and no `schema.prisma`. That makes the container story short: the image needs Node.js, your dependencies, the committed contract artifacts, and the migrations directory. The container applies pending migrations at start and then runs the server.

Every command and output below was run end to end with Docker Desktop.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/deployment/docker](https://www.prisma.io/docs/guides/v7/deployment/docker).

## Prerequisites [#prerequisites]

* [Docker](https://docs.docker.com/) and [Docker Compose](https://docs.docker.com/compose/) installed
* [Node.js](https://nodejs.org) 24 or later

Before starting, make sure no PostgreSQL service is running locally and that ports `5432` (PostgreSQL), `3000` (application server), and `5555` (Prisma Studio) are free.

To stop an existing PostgreSQL service, use:

```bash
sudo systemctl stop postgresql  # Linux
brew services stop postgresql   # macOS
net stop postgresql             # Windows (Run as Administrator)
```

To stop all running Docker containers and free up ports:

```bash
docker ps -q | xargs docker stop
```

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Containerize a new Express app on Prisma ORM with Docker Compose, following https://www.prisma.io/docs/guides/deployment/docker.md.

1. Create `docker-test`, run `npm init -y` and `npm install express`, then run `npx prisma@latest orm init --yes --target postgres --authoring psl`. Set `"type": "module"` in package.json and add the scripts `start` (`node src/index.ts`), `contract:emit` (`prisma contract emit`), and `db:migrate` (`prisma db migrate`). Run `npx prisma@latest init` so the Prisma agent skills are installed, and use them.
2. Replace `src/prisma/contract.prisma` with a single `User` model (id, createdAt, email, name), run `npx prisma contract emit`, and write `src/index.ts`: an Express server whose `GET /` counts users with `db.orm.public.User.aggregate((a) => ({ total: a.count() }))` and reports whether any exist. Read the port from `PORT` with a default of 3000.
3. Write `docker-compose.postgres.yml` with a `postgres:17` service on port 5432 (user postgres, password prisma, database postgres, with a pg_isready healthcheck). Start it with `docker compose -f docker-compose.postgres.yml up -d`, set `DATABASE_URL="postgresql://postgres:prisma@localhost:5432/postgres"` in `.env`, run `npx prisma migration plan --name init` then `npx prisma db migrate`, start `npm start` in the background, verify `curl http://localhost:3000` returns "No users have been added yet.", stop the server, and run `docker compose -f docker-compose.postgres.yml down`.
4. Regenerate the lockfile with `rm -rf node_modules package-lock.json && npm install` so `npm ci` succeeds on Linux. Write a `.dockerignore` (node_modules, .env, .env.prod), a `Dockerfile` based on `node:24-alpine` that runs `npm ci`, copies the project, and uses `CMD ["sh", "-c", "npm run db:migrate && npm start"]`, a `docker-compose.yml` with a `postgres_db` service and a `server` service that builds the Dockerfile, publishes port 3000, waits for the database healthcheck, and loads `.env.prod`, and `.env.prod` with `DATABASE_URL="postgresql://postgres:prisma@postgres_db:5432/postgres"`.
5. Run `docker compose up --build -d`, verify `curl http://localhost:3000` returns "No users have been added yet.", show me the `server` logs, then run `docker compose down -v`.
```

## 1. Set up your Node.js and Prisma ORM application [#1-set-up-your-nodejs-and-prisma-orm-application]

Start by creating a small Node.js application with Express and Prisma ORM.

### 1.1. Initialize your project [#11-initialize-your-project]

Create a new project directory, initialize a Node.js project, and install Express:

  

#### bun

```bash
mkdir docker-test
cd docker-test
bun init
bun add express
```

#### pnpm

```bash
mkdir docker-test
cd docker-test
pnpm init
pnpm add express
```

#### yarn

```bash
mkdir docker-test
cd docker-test
yarn init
yarn add express
```

#### npm

```bash
mkdir docker-test
cd docker-test
npm init
npm install express
```

Installing Express first also creates `package-lock.json`, which is how the next command detects that you use npm.

### 1.2. Add Prisma ORM [#12-add-prisma-orm]

Run `orm init` in the project. It preselects PostgreSQL and the PSL authoring style, installs the runtime and the CLI, and emits the contract artifacts:

  

#### bun

```bash
bunx prisma@latest orm init --yes --target postgres --authoring psl
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### yarn

```bash
yarn dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### npm

```bash
npx prisma@latest orm init --yes --target postgres --authoring psl
```

```text no-copy
package.json declares "type": "commonjs" ... the scaffolded prisma/db.ts uses an ESM-only import attribute (`with { type: 'json' }`) and will not load under that module type.
If you want the default, set "type": "module" in package.json.
✔ npm add @prisma/orm-postgres dotenv
✔ npm add -D prisma@latest @types/node
✔ npm add -D @prisma/cli-engine@0.6.1
✔ Emit the contract
│  target:     postgres
│  authoring:  psl
│  schema:     src/prisma/contract.prisma
written
├─ src/prisma/contract.prisma
├─ prisma.config.ts
├─ src/prisma/db.ts
├─ prisma-8.md
├─ .env.example
├─ tsconfig.json
├─ .gitignore
├─ .gitattributes
└─ package.json
✔ Done. Open prisma-8.md to get started.
```

The command creates:

* `prisma.config.ts`, which tells the CLI where the contract lives and loads `.env` through `dotenv/config`.
* `src/prisma/contract.prisma`, your data model.
* `src/prisma/contract.json` and `src/prisma/contract.d.ts`, the emitted artifacts the runtime and the CLI read. Commit both.
* `src/prisma/db.ts`, the client your app imports. It reads `DATABASE_URL` from the environment.

The warning at the top matters: `npm init -y` writes `"type": "commonjs"`, and the scaffolded `db.ts` is an ES module. Open `package.json`, switch the module type, and replace the scripts with the ones this guide uses:

```json title="package.json"
{
  "name": "docker-test",
  "version": "1.0.0",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1", // [!code --]
    "start": "node src/index.ts", // [!code ++]
    "contract:emit": "prisma contract emit",
    "db:migrate": "prisma db migrate" // [!code ++]
  },
  "type": "commonjs", // [!code --]
  "type": "module", // [!code ++]
  "dependencies": {
    "@prisma/orm-postgres": "...",
    "dotenv": "...",
    "express": "..."
  },
  "devDependencies": {
    "@prisma/cli-engine": "...",
    "@types/node": "...",
    "prisma": "..."
  }
}
```

There is no `prisma generate` and no `postinstall` hook to add. Node.js 24 runs `src/index.ts` directly, so the `start` script needs no build step either.

### 1.3. Define the data model [#13-define-the-data-model]

Replace the starter contract with a single `User` model:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

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

Emit the contract again so `contract.json` and `contract.d.ts` match the new model:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

```text no-copy
✔ Emitted contract.json and contract.d.ts
storageHash:  f340195186d0acf8e9914097e58af0375650e7251358382aa9ad3ed5b724daf7
```

`contract emit` is offline; it needs no database.

### 1.4. Create an Express server [#14-create-an-express-server]

Create `src/index.ts` next to the `src/prisma/` folder:

```typescript title="src/index.ts"
import express from "express";
import { db } from "./prisma/db.ts";

const app = express();
app.use(express.json());

// Report whether any users exist
app.get("/", async (req, res) => {
  const { total } = await db.orm.public.User.aggregate((a) => ({
    total: a.count(),
  }));
  res.json(
    total === 0
      ? "No users have been added yet."
      : "Some users have been added to the database.",
  );
});

const PORT = Number(process.env.PORT) || 3000;

app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});
```

Model access is namespace-qualified on PostgreSQL (`db.orm.public.User`), and [counting](https://www.prisma.io/docs/orm/fundamentals/reading-data#count-records) goes through `.aggregate(...)`. There is no `PrismaClient`, no driver adapter, and nothing to instantiate: `db.ts` already exports the client.

With the application in place, the next step is a PostgreSQL database to migrate against.

## 2. Set up a PostgreSQL database with Docker Compose [#2-set-up-a-postgresql-database-with-docker-compose]

To create the first migration, start a standalone PostgreSQL database with Docker Compose.

### 2.1. Create a Docker Compose file for PostgreSQL [#21-create-a-docker-compose-file-for-postgresql]

Create `docker-compose.postgres.yml` in the project root:

```yml title="docker-compose.postgres.yml"
services:
  postgres:
    image: postgres:17
    restart: always
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=prisma
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
      interval: 5s
      timeout: 2s
      retries: 20
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
```

### 2.2. Start the PostgreSQL container [#22-start-the-postgresql-container]

```bash
docker compose -f docker-compose.postgres.yml up -d
```

```text no-copy
 Container docker-test-postgres-1  Started
```

### 2.3. Create and apply the first migration [#23-create-and-apply-the-first-migration]

Point the project at the database. `orm init` wrote `.env.example`; create `.env` with the connection string of the container you just started:

```bash title=".env"
DATABASE_URL="postgresql://postgres:prisma@localhost:5432/postgres" # [!code highlight]
```

Plan the first migration from the emitted contract. This is offline and writes a migration package under `migrations/app/`:

  

#### bun

```bash
bunx prisma migration plan --name init
```

#### pnpm

```bash
pnpm prisma migration plan --name init
```

#### yarn

```bash
yarn prisma migration plan --name init
```

#### npm

```bash
npx prisma migration plan --name init
```

```text no-copy
✔ Planned 3 operation(s)

migrations/app/20260910T1532_init
├─ Create schema "public"
├─ Create table "User"
└─ Add unique constraint on "User" (email)

from:       (baseline)
to:         f340195186d0acf8e9914097e58af0375650e7251358382aa9ad3ed5b724daf7
```

Apply it to the running database:

  

#### bun

```bash
bunx prisma db migrate
```

#### pnpm

```bash
pnpm prisma db migrate
```

#### yarn

```bash
yarn prisma db migrate
```

#### npm

```bash
npx prisma db migrate
```

```text no-copy
│  migrations:  migrations
│  database:    postgresql://****:****@localhost:5432/postgres
✔ Applied 1 migration(s) (3 operation(s)) across 1 contract space(s)
App space
├─ Create schema "public"
├─ Create table "User"
├─ Add unique constraint on "User" (email)
└─ marker f340195186d0acf8e9914097e58af0375650e7251358382aa9ad3ed5b724daf7
```

`db migrate` applies the migration packages in `migrations/` and records the resulting contract hash in the database. Running it again is safe; it reports `Already up to date`. This is the same command the container runs at start in step 3, which replaces `prisma migrate deploy` from Prisma ORM 7. There is no generate step afterwards: the runtime reads `contract.json`, which you already emitted.

Confirm the database and the contract agree:

  

#### bun

```bash
bunx prisma migration status
```

#### pnpm

```bash
pnpm prisma migration status
```

#### yarn

```bash
yarn prisma migration status
```

#### npm

```bash
npx prisma migration status
```

```text no-copy
○   f340195  @contract @db
│↑  20260910T1532_init         ∅ → f340195  3 ops  ✓ applied
○   ∅
✔ Up to date
```

### 2.4. Test the application [#24-test-the-application]

Start the server:

  

#### bun

```bash
bun start
```

#### pnpm

```bash
pnpm start
```

#### yarn

```bash
yarn start
```

#### npm

```bash
npm start
```

```text no-copy
Server is running on http://localhost:3000
```

Open [`http://localhost:3000`](http://localhost:3000) or query it with curl:

```bash
curl http://localhost:3000
```

```json no-copy
"No users have been added yet."
```

Stop the server with `Ctrl+C`.

### 2.5. Clean up the standalone database [#25-clean-up-the-standalone-database]

Remove the standalone PostgreSQL container:

```bash
docker compose -f docker-compose.postgres.yml down --remove-orphans
```

This stops and removes the container and the default network. The named `postgres_data` volume stays; add `-v` to remove it too.

With the application tested locally, the next step is to containerize it.

## 3. Run the app and database together with Docker Compose [#3-run-the-app-and-database-together-with-docker-compose]

Containerizing the application means it runs the same way on any host that has Docker installed.

### 3.1. Regenerate the lockfile [#31-regenerate-the-lockfile]

`orm init` installs its packages in three steps, and on macOS and Windows the resulting `package-lock.json` misses two Linux-only optional packages that the Prisma CLI depends on. `npm ci` inside the Linux image then refuses to install:

```text no-copy
npm error `npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file with `npm install` before continuing.
npm error Missing: @emnapi/runtime@1.11.3 from lock file
```

Regenerate the lockfile once from a clean install before you build the image:

  

#### bun

```bash
rm -rf node_modules package-lock.json
bun install
```

#### pnpm

```bash
rm -rf node_modules package-lock.json
pnpm install
```

#### yarn

```bash
rm -rf node_modules package-lock.json
yarn install
```

#### npm

```bash
rm -rf node_modules package-lock.json
npm install
```

The new lockfile records every platform's optional packages, so the same `npm ci` works on your machine and in the container.

### 3.2. Create the Dockerfile [#32-create-the-dockerfile]

Prisma ORM ships no native query engine, so the choice between Alpine and Debian base images is only about image size and your other dependencies. Both `node:24-alpine` and `node:24-slim` were tested with this guide and behave the same; no `openssl` or `libc6-compat` package is needed.

First, keep the host's `node_modules` and local environment files out of the image:

```text title=".dockerignore"
node_modules
.env
.env.prod
```

Then create the `Dockerfile`:

```shell title="Dockerfile"
FROM node:24-alpine

WORKDIR /usr/src/app

COPY package.json package-lock.json ./

RUN npm ci

COPY . .

CMD ["sh", "-c", "npm run db:migrate && npm start"]
```

What the image needs, and why:

* `npm ci` installs dev dependencies too. The container runs the Prisma CLI at start to apply migrations, so `prisma` has to be in the image.
* `COPY . .` brings in `src/prisma/contract.json`, `src/prisma/contract.d.ts`, and `migrations/`. Because those are committed, the build has no Prisma step. If you prefer not to commit the emitted artifacts, add `RUN npx prisma contract emit` after the copy; it runs offline.
* `CMD` applies pending migrations with `db migrate` and then starts the server. On a fresh database this creates the schema; on an existing one it reports `Already up to date` and moves on.
* `DATABASE_URL` is not baked in. The CLI reads it through `prisma.config.ts` and the runtime through `src/prisma/db.ts`, both from the container's environment, which Compose sets in the next step.

### 3.3. Create and configure a Docker Compose file [#33-create-and-configure-a-docker-compose-file]

With the `Dockerfile` ready, use Docker Compose to manage the app and the database together.

Create `docker-compose.yml` in the project root:

```yml title="docker-compose.yml"
services:
  postgres_db:
    image: postgres:17
    hostname: postgres_db
    container_name: postgres_db
    restart: always
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: prisma
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
      interval: 5s
      timeout: 2s
      retries: 20

  server:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    depends_on:
      postgres_db:
        condition: service_healthy
    env_file:
      - .env.prod
```

The `server` service waits for the database healthcheck before it starts, so `db migrate` never runs against a database that is still booting.

### 3.4. Configure the environment variable for the container [#34-configure-the-environment-variable-for-the-container]

Inside the Compose network the database is reachable by its service name, not `localhost`. Create `.env.prod` with that hostname:

```bash title=".env.prod"
DATABASE_URL="postgresql://postgres:prisma@postgres_db:5432/postgres" # [!code highlight]
```

Compose strips the quotes when it loads the file. `.env` (with the `localhost` URL) stays on your machine for local commands; `.dockerignore` keeps it out of the image.

### 3.5. Build and run the application [#35-build-and-run-the-application]

Build the image and start both services:

```bash
docker compose up --build -d
```

```text no-copy
[+] up 4/4
 ✔ Image docker-test-server       Built                                     1.4s
 ✔ Network docker-test_default    Created                                   0.0s
 ✔ Container postgres_db          Healthy                                   5.7s
 ✔ Container docker-test-server-1 Started                                   5.7s
```

Check the app:

```bash
curl http://localhost:3000
```

```json no-copy
"No users have been added yet."
```

The server logs show the migration running before the server starts:

```bash
docker compose logs server
```

```text no-copy
server-1  | > docker-test@1.0.0 db:migrate
server-1  | > prisma db migrate
server-1  | {"kind":"result","envelope":{"ok":true,"commandId":"db.migrate","result":{"ok":true,"migrationsApplied":1,"migrationsTotal":1,...,"summary":"Applied 1 migration(s) (3 operation(s)) across 1 contract space(s)",...}}}
server-1  | > docker-test@1.0.0 start
server-1  | > node src/index.ts
server-1  | Server is running on http://localhost:3000
```

The CLI prints JSON lines when it has no terminal attached, which is what you see in container logs. Restart the server and the migration step becomes a no-op:

```bash
docker compose restart server
docker compose logs --since 30s server
```

```text no-copy
server-1  | ...,"summary":"Already up to date",...
server-1  | Server is running on http://localhost:3000
```

Your Prisma ORM app and database now run together under Docker Compose. To stop everything and remove the containers, network, and volumes:

```bash
docker compose down -v
```

### 3.6. Bonus: browse the database with Prisma Studio [#36-bonus-browse-the-database-with-prisma-studio]

[Prisma Studio](https://www.prisma.io/docs/studio) lets you view and edit your data in the browser. With the Compose stack running, the database is published on port `5432`, so run Studio on your machine against it. Studio ships with the Prisma ORM 7 CLI and takes the connection string directly; run it from a directory outside the project, because that CLI cannot read the Prisma ORM 8 `prisma.config.ts`:

```bash
cd .. && npx prisma@prev studio --url "postgresql://postgres:prisma@localhost:5432/postgres"
```

```text no-copy
Prisma Studio is running at: http://localhost:5555
```

Open [`http://localhost:5555`](http://localhost:5555) to browse the `User` table. Once the database has an applied migration, Studio also shows a **Migrations** view with the history `db migrate` recorded; see [Studio with Prisma ORM](https://www.prisma.io/docs/studio/prisma-next).

Running Studio as a Compose service, as the Prisma ORM 7 guide did, does not work from the host: the Studio server binds to `127.0.0.1` inside its container, so a published port never reaches it.

## Common gotchas [#common-gotchas]

> [!WARNING]
> Do not call `db.close()` in a route handler. The client's connection pool is shared across requests; close it only on process shutdown.

* **`npm ci` fails in the image with `Missing: @emnapi/runtime ... from lock file`.** The lockfile `orm init` leaves behind on macOS or Windows lacks Linux-only optional packages. Regenerate it as in [step 3.1](#31-regenerate-the-lockfile).
* **`db.ts` will not load.** If `orm init` warned about `"type": "commonjs"`, set `"type": "module"` in `package.json`. The scaffolded `db.ts` imports `contract.json` with an ES module import attribute.
* **The image is large.** The built image measured 2.12 GB on disk on `node:24-alpine` and 2.23 GB on `node:24-slim` (the `DISK USAGE` column of `docker image ls`), almost all of it the `prisma` dev dependency, which bundles the Composer and deploy toolchain. The image needs the CLI because it runs `db migrate` at start.
* **`docker run --env-file` keeps the quotes.** Compose strips the quotes around `DATABASE_URL` in `.env.prod`; plain `docker run --env-file` does not, and the Prisma CLI then rejects the URL. Pass `-e DATABASE_URL=...` without quotes when you run the image by hand.
* **Port 3000 or 5432 is already in use.** Change the host side of the port mapping (`"3100:3000"`) or stop the service that holds the port; the container side stays the same.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add a POST /users route that creates a user from the request body."
* "Add a `Post` model with an author relation to the contract, plan a migration named add_posts, and apply it with db migrate."
* "Add a healthcheck to the server service in docker-compose.yml that hits GET / once the migration has run."

## Next steps [#next-steps]

* Change the schema in `src/prisma/contract.prisma`, run `npm run contract:emit`, then `npx prisma migration plan --name <change>`; the next `docker compose up --build` applies it. See [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration) and [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration).
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Bun workspaces`](https://www.prisma.io/docs/guides/deployment/bun-workspaces): Set up Prisma ORM in a Bun workspaces monorepo through a shared database package, seed it with Bun, and query it from a Next.js app in the same workspace.
- [`Cloudflare Workers`](https://www.prisma.io/docs/guides/deployment/cloudflare-workers): Add Prisma ORM to a Cloudflare Worker, query PostgreSQL from the fetch handler with the nodejs_compat flag, and deploy it with Wrangler.
- [`pnpm workspaces`](https://www.prisma.io/docs/guides/deployment/pnpm-workspaces): Set up Prisma 8 in a shared database package inside a pnpm workspaces monorepo and query it from a Next.js app.
- [`Turborepo`](https://www.prisma.io/docs/guides/deployment/turborepo): Share one Prisma 8 database package across the apps in a Turborepo monorepo, with contract emit and migrations wired into turbo tasks.

# pnpm workspaces (/docs/guides/deployment/pnpm-workspaces)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up Prisma 8 in a shared database package inside a pnpm workspaces monorepo and query it from a Next.js app.

Location: Guides > Deployment > pnpm workspaces

## Introduction [#introduction]

This guide shows you how to set up Prisma 8 in its own package inside a [pnpm workspaces](https://pnpm.io/workspaces) monorepo. The `database` package owns the contract, the emitted types, and the client. A Next.js app in the same workspace imports that client and renders users from the database.

Every command and output below was run end to end with pnpm 12 against a PostgreSQL database.

> [!NOTE]
> Using Prisma 7?
> 
> Prisma 8 is the current release of Prisma ORM. Prisma 7 remains fully supported; the Prisma 7 version of this guide is at [/guides/v7/deployment/pnpm-workspaces](https://www.prisma.io/docs/guides/v7/deployment/pnpm-workspaces).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* [pnpm](https://pnpm.io/installation) 10.26 or later, but not 12.0 to 12.4.0, which have a defect that breaks step 2.1 (this guide uses pnpm 12.7.0)
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Set up a pnpm workspaces monorepo with a shared Prisma 8 database package and a Next.js app that renders users from it.

1. Create `my-monorepo` with `pnpm init`, a `pnpm-workspace.yaml` listing `apps/*` and `packages/*` with `allowBuilds` for `esbuild`, `msgpackr-extract`, and `workerd`, and the directories `apps` and `packages/database`.
2. In `packages/database`, run `pnpm init`, then `npx prisma@latest orm init --yes --target postgres --authoring psl`. Then run `pnpm prisma init` in the same directory so the Prisma agent skills are installed, and use them.
3. Write `packages/database/.env` with `DATABASE_URL` (use the connection string I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints). Run `pnpm prisma db init` in `packages/database`.
4. Add `src/index.ts` exporting `db` from `./prisma/db`, set `"exports": { ".": "./src/index.ts" }` in the package's package.json, add a `src/seed.ts` that upserts two users with `db.orm.public.User.upsert(...)` and closes with `await db.close()`, and run it with `node src/seed.ts`.
5. In `apps`, run `pnpm create next-app@latest web --yes --skip-install`, delete `apps/web/.git` and `apps/web/pnpm-workspace.yaml`, add `sharp: false` and `unrs-resolver: false` to `allowBuilds` in the root `pnpm-workspace.yaml`, add `"database": "workspace:*"` to `apps/web/package.json`, copy `packages/database/.env` to `apps/web/.env`, and run `pnpm install` from the workspace root.
6. Replace `apps/web/app/page.tsx` with a server component that imports `{ db } from "database"`, exports `dynamic = "force-dynamic"`, queries `db.orm.public.User.select("id", "email", "name").all()`, and renders the list.
7. Add root scripts `dev`, `build`, `start`, `db:init`, `db:update`, and `seed` that filter to the right package, start `pnpm dev` in the background, verify http://localhost:3000 renders the seeded users, then stop it. Finally run `pnpm build` and confirm it completes.
```

## 1. Create the workspace [#1-create-the-workspace]

Create the monorepo directory and initialize it:

```bash
mkdir my-monorepo
cd my-monorepo
pnpm init
```

pnpm 12 writes a root `package.json` with `"type": "module"` and a pinned `packageManager` field. Next, create `pnpm-workspace.yaml`:

```yaml title="pnpm-workspace.yaml"
packages:
  - "apps/*"
  - "packages/*"

allowBuilds:
  esbuild: true
  msgpackr-extract: true
  workerd: true
```

The `allowBuilds` block matters. pnpm does not run dependency install scripts unless you approve them. Since pnpm 11 an unapproved script fails the install (`strictDepBuilds` is on by default); pnpm 10 only warns and skips the script, which leaves the package half-installed, unless you set `strictDepBuilds: true`. The Prisma ORM 8 CLI's toolchain pulls in three packages with install scripts, so approve them up front. The `allowBuilds` key exists since pnpm 10.26, so use that version or later; without the key, the first `pnpm add` that `orm init` runs fails with `ERR_PNPM_IGNORED_BUILDS` on pnpm 11 (on pnpm 10 with the default settings it installs the three packages without running their scripts).

Create the directories for apps and shared packages:

```bash
mkdir -p apps packages/database
```

## 2. Set up the shared database package [#2-set-up-the-shared-database-package]

The `database` package holds the contract (your schema), the emitted `contract.json` and `contract.d.ts`, and the `db` client every app imports. Prisma 8 has no `prisma generate` step and no generated client directory: `contract emit` writes the two artifacts next to the contract, and the runtime reads them.

### 2.1. Initialize Prisma 8 in the package [#21-initialize-prisma-8-in-the-package]

```bash
cd packages/database
pnpm init
npx prisma@latest orm init --target postgres
```

Answer the prompts: choose `PSL` for the authoring style and keep the other defaults, including the schema path `src/prisma/contract.prisma`. `orm init` detects pnpm from the workspace, adds the dependencies to this package, and writes the Prisma 8 files:

```text no-copy
▸ pnpm add @prisma/orm-postgres dotenv
✔ pnpm add @prisma/orm-postgres dotenv
▸ pnpm add -D prisma@latest @types/node
✔ pnpm add -D prisma@latest @types/node
▸ pnpm add -D @prisma/cli-engine@0.6.1
✔ pnpm add -D @prisma/cli-engine@0.6.1
▸ Emit the contract
✔ Emit the contract
│  target:     postgres
│  authoring:  psl
│  schema:     src/prisma/contract.prisma
written
├─ src/prisma/contract.prisma
├─ prisma.config.ts
├─ src/prisma/db.ts
├─ prisma-8.md
├─ .env.example
├─ tsconfig.json
├─ .gitignore
├─ .gitattributes
└─ package.json
```

On pnpm 12.0 to 12.4.0, `orm init` writes all the files and then fails at `Emit the contract` with `CLI.INIT_EMIT_FAILED`. If you hit it, apply the `pnpm dedupe` fix from [Common gotchas](#common-gotchas) and continue.

The `@prisma/cli-engine` version comes from the `prisma` package the previous step installed, so the two always match. `orm init` emits the contract itself, so `src/prisma/contract.json` and `src/prisma/contract.d.ts` exist as soon as it finishes. After every schema edit, re-emit with the package's own CLI:

```bash
pnpm prisma contract emit
```

`orm init` wrote a starter contract with `User` and `Post` models in `src/prisma/contract.prisma`, and a client in `src/prisma/db.ts`:

```typescript title="packages/database/src/prisma/db.ts"
import 'dotenv/config';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});
```

There is no driver adapter and no engine to configure. The `with { type: 'json' }` import attribute is required by Node's ESM loader; pnpm's `pnpm init` already set `"type": "module"` on the package, which is what the generated files expect. If your package declares `"type": "commonjs"`, `orm init` leaves it alone and prints a warning; change it to `"module"`.

### 2.2. Connect the database [#22-connect-the-database]

`prisma.config.ts` loads `.env` through `dotenv/config` and reads `DATABASE_URL`. Create `.env` in the package with your connection string, or the one `npx create-db@latest` prints:

```bash title="packages/database/.env"
DATABASE_URL="postgres://user:password@localhost:5432/mydb"
```

Apply the contract to the database and sign it:

```bash
pnpm prisma db init
```

```text no-copy
✔ Initialising database across spaces
│  contract:  src/prisma/contract.json
│  database:  postgres://****@localhost:5432/mydb
✔ Applied 5 operation(s) across 1 contract space
App space
├─ Create table "Post"
├─ Create table "User"
├─ Add unique constraint on "User" (email)
├─ Create index "Post_authorId_idx_e47547ed" on "Post"
├─ Add foreign key "Post_authorId_fkey" on "Post"
└─ marker 91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
✔ Advanced ref "db" → 91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
```

If `db init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Database already matches contract` when there is nothing left to do.

### 2.3. Export the client and add a seed script [#23-export-the-client-and-add-a-seed-script]

Create the package entry point that apps will import:

```typescript title="packages/database/src/index.ts"
export { db } from "./prisma/db";
```

Add a seed script so the app has rows to render. Node.js 24 runs TypeScript directly, but it needs the `.ts` extension on relative imports, so this file names it:

```typescript title="packages/database/src/seed.ts"
import { db } from "./prisma/db.ts";

const users = [
  { email: "alice@prisma.io", name: "Alice" },
  { email: "bob@prisma.io", name: "Bob" },
];

for (const user of users) {
  await db.orm.public.User.upsert({
    create: user,
    update: {},
    conflictOn: { email: user.email },
  });
}

console.log(await db.orm.public.User.select("id", "email", "name").all());

await db.close();
```

Point the package at the entry point and add scripts for the database steps. Replace the `main` field `pnpm init` wrote with an `exports` map, and drop the placeholder `test` script:

```json title="packages/database/package.json"
{
  "name": "database",
  "version": "1.0.0",
  "type": "module",
  "exports": {
    ".": "./src/index.ts"
  },
  "scripts": {
    "contract:emit": "prisma contract emit",
    "db:init": "prisma db init",
    "db:update": "prisma db update",
    "seed": "node src/seed.ts"
  }
}
```

Keep the `dependencies` and `devDependencies` that `orm init` added. Run the seed:

```bash
pnpm seed
```

```text no-copy
$ node src/seed.ts
[
  { id: 1, email: 'alice@prisma.io', name: 'Alice' },
  { id: 2, email: 'bob@prisma.io', name: 'Bob' }
]
```

The script resolves `@prisma/orm-postgres` through pnpm's isolated `node_modules` without any hoisting configuration, because the package declares it as a direct dependency. That is the rule to keep in mind for the rest of the workspace: the `database` package depends on `@prisma/orm-postgres`, and apps depend on `database`.

## 3. Set up the Next.js app [#3-set-up-the-nextjs-app]

### 3.1. Scaffold the app into the workspace [#31-scaffold-the-app-into-the-workspace]

```bash
cd ../../apps
pnpm create next-app@latest web --yes --skip-install
```

`--yes` accepts the defaults (App Router, TypeScript, Tailwind CSS, no `src/` directory). `--skip-install` keeps `create-next-app` from installing into a nested `node_modules`; the workspace root installs for every package. The scaffold still writes two files that belong to the root, so remove them:

```bash
rm -rf web/.git web/pnpm-workspace.yaml
```

The `pnpm-workspace.yaml` you removed told pnpm not to run the install scripts of two of the app's dependencies. Move that decision to the root file, or the `pnpm install` below fails with `ERR_PNPM_IGNORED_BUILDS`:

```yaml title="pnpm-workspace.yaml"
packages:
  - "apps/*"
  - "packages/*"

allowBuilds:
  esbuild: true
  msgpackr-extract: true
  sharp: false # [!code ++]
  unrs-resolver: false # [!code ++]
  workerd: true
```

Add the shared package as a dependency of the app:

```json title="apps/web/package.json"
"dependencies": {
  "database": "workspace:*", // [!code ++]
  "next": "16.3.6",
  "react": "19.2.8",
  "react-dom": "19.2.8"
}
```

Next.js reads `.env` from the app directory, and `db.ts` reads it from the working directory of the dev server, which is the same place. Copy the file from the database package:

```bash
cp ../packages/database/.env web/.env
```

Install from the workspace root so pnpm links `database` into the app:

```bash
cd ..
pnpm install
```

```text no-copy
Scope: all 3 workspace projects
Progress: resolved 700, reused 700, downloaded 0, added 700, done
Done in 1.9s using pnpm v12.7.0
```

### 3.2. Render users from the shared package [#32-render-users-from-the-shared-package]

Replace `apps/web/app/page.tsx` with a server component that queries through the shared client:

```tsx title="apps/web/app/page.tsx"
import { db } from "database";

export const dynamic = "force-dynamic";

export default async function Home() {
  const users = await db.orm.public.User.select("id", "email", "name").all();

  return (
    <main className="p-8">
      <h1 className="text-2xl font-semibold">Users</h1>
      {users.length === 0 ? (
        <p>No users in the database yet.</p>
      ) : (
        <ul>
          {users.map((user) => (
            <li key={user.id}>
              {user.name ?? "Anonymous"} ({user.email})
            </li>
          ))}
        </ul>
      )}
    </main>
  );
}
```

Model access is namespace-qualified on PostgreSQL: `db.orm.public.User`. `force-dynamic` makes Next.js query on each request instead of at build time, so `pnpm build` does not need a reachable database. Next.js compiles the package's TypeScript source through the `exports` map; no `transpilePackages` entry is needed.

### 3.3. Add root scripts [#33-add-root-scripts]

Add scripts to the root `package.json` that run each step in the right package. `build` re-emits the contract before the app builds, so the types the app compiles against always match `contract.prisma`:

```json title="package.json"
"scripts": {
  "dev": "pnpm --filter web dev",
  "build": "pnpm --filter database contract:emit && pnpm --filter web build",
  "start": "pnpm --filter web start",
  "db:init": "pnpm --filter database db:init",
  "db:update": "pnpm --filter database db:update",
  "seed": "pnpm --filter database seed"
}
```

### 3.4. Run the app [#34-run-the-app]

From the workspace root:

```bash
pnpm dev
```

```text no-copy
$ next dev
▲ Next.js 16.3.6 (Turbopack)
- Local:         http://localhost:3000
- Environments: .env
✓ Ready in 479ms
```

Open [http://localhost:3000](http://localhost:3000) (set `PORT` to change it). The page lists Alice and Bob, rendered by a server component calling Prisma 8 through the `database` package.

## 4. Build for production [#4-build-for-production]

```bash
pnpm build
```

```text no-copy
$ prisma contract emit
$ next build
▲ Next.js 16.3.6 (Turbopack)
✓ Compiled successfully in 1026ms
  Running TypeScript ...
  Finished TypeScript in 2.2s ...
✓ Generating static pages using 5 workers (3/3) in 519ms

Route (app)
┌ ƒ /
└ ○ /_not-found
```

The type check runs across the package boundary: `next build` type-checks `packages/database/src/index.ts` along with the app. Then serve the build:

```bash
pnpm start
```

The page renders the same users from the production server.

## 5. (Optional) Browse your data in Prisma Studio [#5-optional-browse-your-data-in-prisma-studio]

[Prisma Studio](https://www.prisma.io/docs/studio) ships with the Prisma 7 CLI and connects to a Prisma 8 database through `--url`. Run it from the workspace root, which has no `prisma.config.ts` for the Prisma 7 CLI to trip over:

```bash
pnpm dlx prisma@prev studio --url "postgres://user:password@localhost:5432/mydb"
```

```text no-copy
Prisma Studio is running at: http://localhost:51212
```

Open the URL Studio prints. The `User` and `Post` tables appear under **Tables**, with the seeded rows ready to edit. See [Studio with Prisma 8](https://www.prisma.io/docs/studio/prisma-next) for the migration history view.

## Common gotchas [#common-gotchas]

> [!WARNING]
> `pnpm dlx prisma@latest` stops at an interactive **Choose which packages to build** prompt, because `dlx` runs outside the workspace and ignores its `allowBuilds`. Either answer the prompt, or run `npx prisma@latest` from a package directory as this guide does. At the workspace root, `npx` itself fails with `EBADDEVENGINES`: pnpm 12's `pnpm init` writes a `devEngines.packageManager` field that npm enforces. Use the package's own CLI (`pnpm prisma ...`) or `pnpm dlx` there.

* If `orm init` ends with `CLI.INIT_EMIT_FAILED`, or `pnpm prisma contract emit` reports `CLI.CONFIG_UNREADABLE`, and the message says `Cannot find module '@prisma/cli-engine'` or `No "exports" main defined`, the `@prisma/cli-engine` link in `packages/database/node_modules` points at a directory that does not exist. This is a defect in pnpm 12.0 to 12.4.0, and pnpm 12.4.1 or later fixes it. In a project that already hit it, run `pnpm dedupe` to rebuild the link, then `pnpm prisma contract emit`. You do not need to run `orm init` again, because it wrote all its files before it tried to emit. `pnpm install`, `pnpm install --force`, and adding the packages again do not repair the link.
* Every Prisma command reads `DATABASE_URL` from `packages/database/.env` through `prisma.config.ts`, and the app reads `apps/web/.env`. Keep the two files in sync, or export the variable in your shell and drop both files.
* Do not call `db.close()` in a page or route handler. The client is a module-level singleton whose connection pool is shared across requests; close it only in scripts that exit, like `seed.ts`.
* After you change `src/prisma/contract.prisma`, run `pnpm --filter database contract:emit` so the app sees the new types, then `pnpm db:update` to apply the change. The root `build` script emits for you before every build.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`pnpm prisma init`](https://www.prisma.io/docs/cli/init) once inside `packages/database` to install the [Prisma 8 skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. It adds a `postinstall` script that keeps the skills matching your installed packages, and it installs them into `.claude/skills`, `.cursor/skills`, `.agents/skills`, and `.devin/skills` under the package. Prompts that map to this guide:

* "Using the prisma-8 skill, add a `Post` list under each user on the home page with `.include('posts')`."
* "Add a `packages/database` script that creates a post for a given user email."
* "Add a `role` enum to the `User` model in `contract.prisma`, emit the contract, and update the database."

## Next steps [#next-steps]

You now have a pnpm workspace where one package owns the Prisma 8 contract and client, and a Next.js app that renders through it.

* To add task orchestration and caching on top of this setup, see the [Turborepo](https://www.prisma.io/docs/guides/deployment/turborepo) guide.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma 8 overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.
* Use [migration plan](https://www.prisma.io/docs/cli/migration-plan) and [db migrate](https://www.prisma.io/docs/cli/db-migrate) when you want checked-in migrations instead of `db update`.

## Related pages

- [`Bun workspaces`](https://www.prisma.io/docs/guides/deployment/bun-workspaces): Set up Prisma ORM in a Bun workspaces monorepo through a shared database package, seed it with Bun, and query it from a Next.js app in the same workspace.
- [`Cloudflare Workers`](https://www.prisma.io/docs/guides/deployment/cloudflare-workers): Add Prisma ORM to a Cloudflare Worker, query PostgreSQL from the fetch handler with the nodejs_compat flag, and deploy it with Wrangler.
- [`Docker`](https://www.prisma.io/docs/guides/deployment/docker): Build an Express app on Prisma ORM, run PostgreSQL from Docker Compose, then run the app and the database together in containers.
- [`Turborepo`](https://www.prisma.io/docs/guides/deployment/turborepo): Share one Prisma 8 database package across the apps in a Turborepo monorepo, with contract emit and migrations wired into turbo tasks.

# Turborepo (/docs/guides/deployment/turborepo)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Share one Prisma 8 database package across the apps in a Turborepo monorepo, with contract emit and migrations wired into turbo tasks.

Location: Guides > Deployment > Turborepo

## Introduction [#introduction]

This guide shows you how to set up Prisma 8 as a standalone package in a [Turborepo](https://turborepo.dev/docs) monorepo, so that every app shares one database client, one contract, and one migration workflow. You scaffold a monorepo, add a `packages/database` package that owns the Prisma 8 setup, wire its tasks into `turbo.json`, and render users from the `web` Next.js app.

Every command and output below was run end to end against a local PostgreSQL database.

> [!NOTE]
> Using Prisma 7?
> 
> Prisma 8 is the current release of Prisma ORM. Prisma 7 remains fully supported; the Prisma 7 version of this guide is at [/guides/v7/deployment/turborepo](https://www.prisma.io/docs/guides/v7/deployment/turborepo).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* [pnpm](https://pnpm.io) (this guide uses pnpm; the Turborepo scaffold also supports npm, yarn, and Bun)
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Set up Prisma 8 as a shared database package in a new Turborepo monorepo and render users from the web app.

1. Scaffold: `npx create-turbo@latest turborepo-prisma` with pnpm. Then run `npx prisma@latest init` at the monorepo root so the Prisma agent skills are installed and stay current, and use them.
2. Create `packages/database` with `{ "name": "@repo/db", "version": "0.0.0", "private": true }` as its package.json. Because pnpm refuses to run dependency build scripts until they are allowed, add `allowBuilds: { esbuild: true, msgpackr-extract: true, workerd: true }` to `pnpm-workspace.yaml` first. Then run `npx prisma@latest orm init --yes --target postgres --authoring psl` inside `packages/database`, and move the package to the current CLI with `pnpm add -D prisma@latest --filter @repo/db`.
3. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Write it as `DATABASE_URL` into `packages/database/.env`.
4. In `packages/database/package.json`, add `"exports": { ".": "./src/index.ts" }` and the scripts `contract:emit` (`prisma contract emit`), `migration:plan` (`prisma migration plan`), `db:migrate` (`prisma db migrate --advance-ref db`), `migration:status` (`prisma migration status`), and `check-types` (`tsc --noEmit`). Create `src/index.ts` that re-exports `db` from `./prisma/db` and the `Contract` type from `./prisma/contract.d`.
5. In `turbo.json`, add `"globalEnv": ["DATABASE_URL"]`, a cached `contract:emit` task with inputs `src/prisma/contract.prisma` and `prisma.config.ts` and outputs `src/prisma/contract.json` and `src/prisma/contract.d.ts`, make `build`, `dev`, and `check-types` depend on `^contract:emit`, add `migration:plan` (dependsOn `contract:emit`, cache false) and `db:migrate` (cache false).
6. Run `pnpm turbo run migration:plan --filter=@repo/db -- --name init`, review the DDL preview, then `pnpm turbo run db:migrate --filter=@repo/db`.
7. Add `"@repo/db": "workspace:*"` to `apps/web/package.json`, run `pnpm install`, copy `packages/database/.env` to `apps/web/.env`, and replace `apps/web/app/page.tsx` with a server component that exports `const dynamic = "force-dynamic"` and renders `await db.orm.public.User.select("id", "email", "name").all()` as a list, following https://www.prisma.io/docs/guides/deployment/turborepo.md.
8. Start `pnpm turbo run dev --filter=web` in the background, wait until it reports ready, verify http://localhost:3000 renders, then stop the dev server.
```

## 1. Scaffold the monorepo [#1-scaffold-the-monorepo]

Create a Turborepo monorepo named `turborepo-prisma`:

  

#### bun

```bash
bunx create-turbo@latest turborepo-prisma
```

#### pnpm

```bash
pnpm dlx create-turbo@latest turborepo-prisma
```

#### yarn

```bash
yarn dlx create-turbo@latest turborepo-prisma
```

#### npm

```bash
npx create-turbo@latest turborepo-prisma
```

When asked which package manager to use, pick `pnpm`. The scaffold creates two Next.js apps and three shared packages, then installs dependencies:

```text no-copy
>>> Creating a new Turborepo with:

Application packages
 - apps/docs
 - apps/web
Library packages
 - packages/eslint-config
 - packages/typescript-config
 - packages/ui

>>> Success! Created your Turborepo at turborepo-prisma
```

Move into the project root:

```bash
cd turborepo-prisma
```

## 2. Create the `database` package [#2-create-the-database-package]

### 2.1. Create the package [#21-create-the-package]

Create a `database` directory inside `packages` with a minimal `package.json`:

```bash
mkdir -p packages/database
```

```json title="packages/database/package.json"
{
  "name": "@repo/db",
  "version": "0.0.0",
  "private": true
}
```

### 2.2. Allow the build scripts Prisma needs [#22-allow-the-build-scripts-prisma-needs]

pnpm does not run dependency build scripts until you allow them. Since pnpm 11 it fails the install when it finds scripts it was not told about; pnpm 10 only warns and skips them unless you set `strictDepBuilds: true`. The `allowBuilds` key exists since pnpm 10.26, so use that version or later. Prisma ORM 8's toolchain ships three packages with build scripts, so declare them in `pnpm-workspace.yaml` before you install anything:

```yaml title="pnpm-workspace.yaml"
packages:
  - "apps/*"
  - "packages/*"
allowBuilds: # [!code ++]
  esbuild: true # [!code ++]
  msgpackr-extract: true # [!code ++]
  workerd: true # [!code ++]
```

Skip this step on npm, yarn, or Bun. If you forget it, `orm init` in the next step stops with `CLI.INIT_INSTALL_FAILED`; run `pnpm approve-builds`, then re-run the `pnpm add` commands it printed and `pnpm contract:emit`.

### 2.3. Initialize Prisma 8 [#23-initialize-prisma-8]

Run `orm init` inside the package. It is the existing-project path: it adds Prisma 8 to the package you just created instead of scaffolding a new app.

```bash
cd packages/database
```

  

#### bun

```bash
bunx prisma@latest orm init --yes --target postgres --authoring psl
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### yarn

```bash
yarn dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### npm

```bash
npx prisma@latest orm init --yes --target postgres --authoring psl
```

`--yes` accepts the defaults for the remaining prompts (the Prisma schema language for the contract, and `src/prisma/contract.prisma` as its path); drop it to answer them yourself.

```text no-copy
✔ pnpm add @prisma/orm-postgres dotenv
✔ pnpm add -D prisma@latest @types/node
✔ pnpm add -D @prisma/cli-engine
✔ Emit the contract
│  target:     postgres
│  authoring:  psl
│  schema:     src/prisma/contract.prisma

written
├─ src/prisma/contract.prisma
├─ prisma.config.ts
├─ src/prisma/db.ts
├─ prisma-8.md
├─ .env.example
├─ tsconfig.json
├─ .gitignore
├─ .gitattributes
└─ package.json

✔ Done. Open prisma-8.md to get started.
```

`orm init` detects pnpm from the workspace, adds the packages to `@repo/db`, sets `"type": "module"`, and writes four files that matter for the rest of this guide:

* `src/prisma/contract.prisma`: your schema. It starts with `User` and `Post` models.
* `src/prisma/contract.json` and `src/prisma/contract.d.ts`: the emitted contract the runtime and the CLI read. They replace Prisma 7's generated client: there is no `prisma generate` step and no generated directory to ignore. Commit both files; `.gitattributes` already marks them as generated so they collapse in diffs.
* `src/prisma/db.ts`: the client instance, typed by the contract.
* `prisma.config.ts`: where the CLI finds the contract and the database connection.

The generated `db.ts` reads `DATABASE_URL` from the environment and is the module every app will import:

```typescript title="packages/database/src/prisma/db.ts"
import 'dotenv/config';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});
```

### 2.4. Set the database connection [#24-set-the-database-connection]

Create `packages/database/.env` with your PostgreSQL connection string. Use your own, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database.

```bash title="packages/database/.env"
DATABASE_URL="postgres://user:password@localhost:5432/turborepo_prisma"
```

`prisma.config.ts` and `db.ts` both load this file through `dotenv/config`, so every CLI command in this package and every query at runtime picks it up. The root `.gitignore` from the scaffold already ignores `.env` files.

### 2.5. Review the contract [#25-review-the-contract]

Open `src/prisma/contract.prisma`. The starter contract already has the two models this guide renders, so leave it as it is for now; you will change it in step 7.

```prisma title="packages/database/src/prisma/contract.prisma"
// use prisma-8

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  username  String?
  name      String?
  posts     Post[]
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}
```

### 2.6. Add scripts and export the client [#26-add-scripts-and-export-the-client]

Add the database scripts and a package entrypoint to `packages/database/package.json`. `orm init` already added `contract:emit`; the rest map to the Prisma 8 migration loop:

```json title="packages/database/package.json"
{
  "name": "@repo/db",
  "type": "module",
  "version": "0.0.0",
  "private": true,
  "exports": { // [!code ++]
    ".": "./src/index.ts" // [!code ++]
  }, // [!code ++]
  "scripts": {
    "contract:emit": "prisma contract emit",
    "migration:plan": "prisma migration plan", // [!code ++]
    "migration:status": "prisma migration status", // [!code ++]
    "db:migrate": "prisma db migrate --advance-ref db", // [!code ++]
    "db:verify": "prisma db verify", // [!code ++]
    "check-types": "tsc --noEmit" // [!code ++]
  },
  "dependencies": {
    "@prisma/orm-postgres": "8.0.0",
    "dotenv": "^17.4.2"
  },
  "devDependencies": {
    "@prisma/cli-engine": "0.6.1",
    "@types/node": "26.4.1",
    "prisma": "8.0.0"
  }
}
```

Keep the versions `orm init` and the upgrade wrote for you; the ones shown are placeholders. The scripts replace the Prisma 7 trio of `db:generate`, `db:migrate`, and `db:deploy`:

* `contract:emit` compiles `contract.prisma` into `contract.json` and `contract.d.ts`. It is offline and deterministic, which is what makes it cacheable in Turborepo.
* `migration:plan` diffs the emitted contract against your migration history and writes a reviewable migration directory. Also offline.
* `db:migrate` applies pending migrations to `DATABASE_URL`, in development and in CI alike. `--advance-ref db` records the applied state in `migrations/app/refs/db.json`, so the next `migration:plan` knows where to start from and plans only the delta.

Then create the package entrypoint. It re-exports the client and the contract type so apps import one module:

```typescript title="packages/database/src/index.ts"
export { db } from "./prisma/db";
export type { Contract } from "./prisma/contract.d";
```

This follows Turborepo's [Just-in-Time packaging](https://turborepo.dev/docs/core-concepts/internal-packages#just-in-time-packages) pattern: the package exports TypeScript source and the consuming app's bundler compiles it. Next.js handles this for workspace packages without extra configuration.

> [!WARNING]
> If a consumer is not using a bundler, use the [Compiled Packages](https://turborepo.dev/docs/core-concepts/internal-packages#compiled-packages) strategy instead, and add `src/prisma/contract.json` to the files you ship.

## 3. Configure tasks in `turbo.json` [#3-configure-tasks-in-turbojson]

Go back to the project root and wire the database tasks into `turbo.json`:

```bash
cd ../..
```

```json title="turbo.json"
{
  "$schema": "https://turborepo.dev/schema.json",
  "ui": "tui",
  "globalEnv": ["DATABASE_URL"], // [!code ++]
  "tasks": {
    "build": {
      "dependsOn": ["^build", "^contract:emit"], // [!code highlight]
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": [".next/**", "!.next/cache/**", "!.next/dev/**"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "check-types": {
      "dependsOn": ["^check-types", "^contract:emit"] // [!code highlight]
    },
    "dev": {
      "dependsOn": ["^contract:emit"], // [!code ++]
      "cache": false,
      "persistent": true
    },
    "contract:emit": { // [!code ++]
      "inputs": ["src/prisma/contract.prisma", "prisma.config.ts"], // [!code ++]
      "outputs": ["src/prisma/contract.json", "src/prisma/contract.d.ts"] // [!code ++]
    }, // [!code ++]
    "migration:plan": { // [!code ++]
      "dependsOn": ["contract:emit"], // [!code ++]
      "cache": false // [!code ++]
    }, // [!code ++]
    "db:migrate": { // [!code ++]
      "cache": false // [!code ++]
    } // [!code ++]
  }
}
```

What each entry does:

* `contract:emit` is a normal cached task. Its inputs are the contract source and the Prisma config, and its outputs are the two emitted files. When nothing changed, Turborepo replays the cache hit; when the contract changed, it re-emits before anything depends on it.
* `build`, `dev`, and `check-types` depend on `^contract:emit`, so any app that depends on `@repo/db` gets a fresh contract before it compiles. In Prisma 7 this slot held `db:generate`; here the artifacts are committed, and the dependency keeps them from going stale when someone edits the contract and forgets to emit.
* `migration:plan` depends on the package's own `contract:emit`, so a plan always diffs the current contract. Planning and migrating are never cached because they change files on disk and the database.
* `globalEnv` lets `DATABASE_URL` from your shell reach every task and makes it part of the task hash. The `.env*` input on `build` does the same for the per-app `.env` files.

## 4. Plan and apply the first migration [#4-plan-and-apply-the-first-migration]

Plan the first migration from the project root. Turborepo runs `contract:emit` first, then passes `--name init` through to `migration plan`:

```bash
pnpm turbo run migration:plan --filter=@repo/db -- --name init
```

```text no-copy
┌─ @repo/db#contract:emit > cache miss, executing b7a2c51b5beafae3
$ prisma contract emit
✔ Emitted contract.json and contract.d.ts
└─ @repo/db#contract:emit ──
┌─ @repo/db#migration:plan > cache bypass, force executing 6cfc90ea54b2156b
$ prisma migration plan --name init
✔ Planned 6 operation(s)
migrations/app/20260910T1601_init
├─ Create schema "public"
├─ Create table "Post"
├─ Create table "User"
├─ Add unique constraint on "User" (email)
├─ Create index "Post_authorId_idx_e47547ed" on "Post"
└─ Add foreign key "Post_authorId_fkey" on "Post"
from:       (baseline)
to:         91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
ℹ DDL preview
CREATE SCHEMA IF NOT EXISTS "public";
CREATE TABLE "public"."Post" (
...
```

Turborepo shows the tasks in a terminal UI while they run and leaves each task's log in your terminal when it exits. Without a terminal, for example in CI, the Prisma CLI prints JSON instead; add `--format human` to the script to keep the human-readable output. See [Global flags](https://www.prisma.io/docs/cli/global-flags).

The command is offline: it writes `packages/database/migrations/app/<timestamp>_init/` with the migration as TypeScript (`migration.ts`), the compiled operations (`ops.json`), and the history marker (`migration.json`), and prints the exact DDL it will run. Review it, then apply it:

```bash
pnpm turbo run db:migrate --filter=@repo/db
```

```text no-copy
┌─ @repo/db#db:migrate > cache bypass, force executing d71a24f43fe14f8b
$ prisma db migrate --advance-ref db
✔ Applied 1 migration(s) (6 operation(s)) across 1 contract space(s)
App space
├─ Create schema "public"
├─ Create table "Post"
├─ Create table "User"
├─ Add unique constraint on "User" (email)
├─ Create index "Post_authorId_idx_e47547ed" on "Post"
├─ Add foreign key "Post_authorId_fkey" on "Post"
└─ marker 91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
✔ Advanced ref "db" → 91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
└─ @repo/db#db:migrate ──
```

Commit the `migrations/` directory with the rest of the package. The same `db:migrate` task is what CI or a deploy hook runs against staging and production; there is no separate `migrate deploy` command in Prisma 8.

## 5. Use the `database` package in the web app [#5-use-the-database-package-in-the-web-app]

### 5.1. Add the dependency [#51-add-the-dependency]

Add `@repo/db` to `apps/web/package.json`:

```json title="apps/web/package.json"
{
  // ...
  "dependencies": {
    "@repo/db": "workspace:*", // [!code ++]
    "@repo/ui": "workspace:*",
    // ...
  }
  // ...
}
```

Link it from the project root:

```bash
pnpm install
```

### 5.2. Render users in a server component [#52-render-users-in-a-server-component]

Replace `apps/web/app/page.tsx` with a server component that queries the database through the shared client:

```tsx title="apps/web/app/page.tsx"
import { db } from "@repo/db";
import styles from "./page.module.css";

export const dynamic = "force-dynamic";

export default async function Home() {
  const users = await db.orm.public.User.select("id", "email", "name").all();

  return (
    <div className={styles.page}>
      <main className={styles.main}>
        <h1>Users</h1>
        {users.length === 0 ? (
          <p>No users added yet</p>
        ) : (
          <ul>
            {users.map((user) => (
              <li key={user.id}>
                {user.name ?? "Anonymous"} ({user.email})
              </li>
            ))}
          </ul>
        )}
      </main>
    </div>
  );
}
```

Model access is namespace-qualified on PostgreSQL, so the `User` model lives at `db.orm.public.User`, and `select(...)` narrows both the query and the row type. `dynamic = "force-dynamic"` tells Next.js to run the query per request; without it, `next build` prerenders the page once and freezes the user list at build time.

### 5.3. Give the app its connection string [#53-give-the-app-its-connection-string]

Each app reads its own `.env`, so copy the one from the database package:

```bash
cp packages/database/.env apps/web/.env
```

If you would rather keep a single value, export `DATABASE_URL` in your shell instead; the `globalEnv` entry from step 3 passes it into every task. Turborepo [recommends per-package `.env` files](https://turborepo.dev/docs/crafting-your-repository/using-environment-variables#use-env-files-in-packages); for one shared file across the monorepo, see the [`dotenvx` guide for Turborepo](https://dotenvx.com/docs/monorepos/turborepo).

### 5.4. Seed a couple of users [#54-seed-a-couple-of-users]

The page will render "No users added yet" against an empty database. Add a small seed script to the database package so there is something to see. It runs with `tsx`, because Node.js needs file extensions on imports and the package uses extensionless, bundler-style imports:

```bash
pnpm add -D tsx --filter @repo/db
```

```typescript title="packages/database/src/seed.ts"
import { db } from "./index";

const existing = await db.orm.public.User.select("id").all();
if (existing.length === 0) {
  await db.orm.public.User.create({ email: "alice@prisma.io", name: "Alice" });
  await db.orm.public.User.create({ email: "bob@prisma.io", name: "Bob" });
}
console.log(await db.orm.public.User.select("id", "email", "name").all());
await db.close();
```

Add it as a script and run it:

```json title="packages/database/package.json"
{
  "scripts": {
    // ...
    "seed": "tsx src/seed.ts" // [!code ++]
  }
}
```

```bash
pnpm --filter @repo/db seed
```

```text no-copy
[
  { id: 1, email: 'alice@prisma.io', name: 'Alice' },
  { id: 2, email: 'bob@prisma.io', name: 'Bob' }
]
```

The script closes the client at the end because it is a one-off process; the web app never does, since its connection pool lives for the life of the server.

## 6. Run the project [#6-run-the-project]

Start the web app from the project root:

```bash
pnpm turbo run dev --filter=web
```

```text no-copy
▲ Next.js 16.3.4 (Turbopack)
- Local:         http://localhost:3000
- Environments: .env
✓ Ready in 1005ms
```

Turborepo runs `contract:emit` for `@repo/db`, then starts Next.js. Its terminal UI lists both tasks; select `web#dev` to see the Next.js log. Open [http://localhost:3000](http://localhost:3000): the page lists the seeded users.

```text no-copy
Users
Alice (alice@prisma.io)
Bob (bob@prisma.io)
```

`pnpm turbo run build --filter=web` and `pnpm turbo run check-types` go through the same `^contract:emit` dependency, so a production build or a type check never sees a stale contract.

## 7. Change the schema [#7-change-the-schema]

The loop for every later change is: edit the contract, plan, review, apply. Add a `bio` field to `User`:

```prisma title="packages/database/src/prisma/contract.prisma"
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  username  String?
  name      String?
  bio       String? // [!code ++]
  posts     Post[]
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}
```

Plan it. `contract:emit` sees the changed input and re-emits, and because `db:migrate` advanced the `db` ref, the planner starts from the applied state and plans only the delta:

```bash
pnpm turbo run migration:plan --filter=@repo/db -- --name add-user-bio
```

```text no-copy
┌─ @repo/db#contract:emit > cache miss, executing 654198244cf388ef
$ prisma contract emit
✔ Emitted contract.json and contract.d.ts
└─ @repo/db#contract:emit ──
┌─ @repo/db#migration:plan > cache bypass, force executing 83824ab92bdf22eb
$ prisma migration plan --name add-user-bio
✔ Planned 1 operation(s)
migrations/app/20260910T1601_add_user_bio
└─ Add column "bio" to "User"
from:       91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
to:         1cb334c8d48b39d9b29d14f8f8ad799c8d566dc9af2ba6c46a6d02dbb232d425
ℹ DDL preview
ALTER TABLE "public"."User" ADD COLUMN "bio" text;
└─ @repo/db#migration:plan ──
```

Apply it, then check where the database stands:

```bash
pnpm turbo run db:migrate --filter=@repo/db
pnpm --filter @repo/db migration:status
```

```text no-copy
○   1cb334c  @contract @db (db)
│↑  20260910T1601_add_user_bio  91e7f9f → 1cb334c  1 ops  ✓ applied
○   91e7f9f
│↑  20260910T1601_init                ∅ → 91e7f9f  6 ops  ✓ applied
○   ∅
✔ Up to date
```

The next `pnpm turbo run dev --filter=web` re-emits the contract before Next.js starts, and `user.bio` is available in the page's types. For a local change you do not want to keep as a migration, `npx prisma db update` reconciles the database with the contract directly; see [db update](https://www.prisma.io/docs/cli/db-update).

## Common gotchas [#common-gotchas]

> [!WARNING]
> Without a `db` ref or `--from`, `migration plan` has no origin and refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN` once migrations exist, because a plan from an empty database would recreate every table. The `--advance-ref db` flag on `db:migrate` keeps the ref current. If you applied a migration without it, point the ref at that migration once: `npx prisma migration ref set db <migration directory name>`.

> [!WARNING]
> In the web app, never call `db.close()` in a page or route handler; the client's connection pool is shared across requests. Close it only in one-off scripts like the seed.

> [!NOTE]
> `orm init` picks the package manager from the workspace. Run it after `create-turbo` has installed dependencies, so it finds `pnpm-lock.yaml` and adds packages with `pnpm add` instead of guessing.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once at the monorepo root to install the [Prisma 8 skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. It adds a root `prisma.config.ts` that only configures the skills, a `prisma` dev dependency, and a `postinstall` hook that re-syncs them. Prompts that map to this guide:

* "Using the prisma-8 skill, add a `apps/docs` page that lists posts with their authors through `@repo/db`."
* "Add a `published Boolean @default(false)` field to Post, plan the migration, and show me the DDL before applying it."
* "Add a `db:verify` task to turbo.json and run it in CI after `db:migrate`."

## Next steps [#next-steps]

* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work): the plan, review, apply loop your `turbo.json` tasks now run.
* [Read the Prisma 8 overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.
* [Turborepo docs](https://turborepo.dev/docs) and [Next.js docs](https://nextjs.org/docs) for the rest of the monorepo.

## Related pages

- [`Bun workspaces`](https://www.prisma.io/docs/guides/deployment/bun-workspaces): Set up Prisma ORM in a Bun workspaces monorepo through a shared database package, seed it with Bun, and query it from a Next.js app in the same workspace.
- [`Cloudflare Workers`](https://www.prisma.io/docs/guides/deployment/cloudflare-workers): Add Prisma ORM to a Cloudflare Worker, query PostgreSQL from the fetch handler with the nodejs_compat flag, and deploy it with Wrangler.
- [`Docker`](https://www.prisma.io/docs/guides/deployment/docker): Build an Express app on Prisma ORM, run PostgreSQL from Docker Compose, then run the app and the database together in containers.
- [`pnpm workspaces`](https://www.prisma.io/docs/guides/deployment/pnpm-workspaces): Set up Prisma 8 in a shared database package inside a pnpm workspaces monorepo and query it from a Next.js app.

# Astro (/docs/guides/frameworks/astro)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up Prisma ORM in an Astro app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

Location: Guides > Frameworks > Astro

## Introduction [#introduction]

This guide shows you how to use Prisma ORM in an Astro site. You scaffold a project that queries users during server rendering and exposes a JSON API route, initialize the schema, see your data render, and deploy the site to [Prisma Compute](https://www.prisma.io/docs/compute).

Every command below was run end to end against a live [Prisma Postgres](https://www.prisma.io/docs/postgres) database.

## Quick start [#quick-start]

One command scaffolds the project with Prisma ORM wired in:

  

#### bun

```bash
bun create prisma@latest my-astro-app --template astro --provider postgres --no-deploy
```

#### pnpm

```bash
pnpm create prisma@latest my-astro-app --template astro --provider postgres --no-deploy
```

#### yarn

```bash
yarn create prisma@latest my-astro-app --template astro --provider postgres --no-deploy
```

#### npm

```bash
npm create prisma@latest -- my-astro-app --template astro --provider postgres --no-deploy
```

Answer the prompts, then export `DATABASE_URL` in your shell before running the database scripts. If you do not have a database yet, `npx create-db@latest` prints a Prisma Postgres connection string.

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 22.18 or newer (on the 24 line, 24.11 or newer; 24 recommended)
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a Prisma Postgres database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a new Astro app with Prisma ORM, seed it, and deploy it to Prisma Compute.

1. Scaffold: `npm create prisma@latest -- my-astro-app --template astro --provider postgres --yes`. Then run `npx prisma@latest init` in `my-astro-app` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
2. In `my-astro-app`, run `npm run db:init` with `DATABASE_URL` exported. Sample users are seeded automatically on the app's first query; there is no separate seed script.
3. Start `npm run dev` in the background, wait until it reports ready, verify http://localhost:4321 lists the seeded users and `curl http://localhost:4321/api/users` returns them as JSON, then stop the dev server.
4. Confirm `astro.config.mjs` still sets `output: "server"` and `adapter: node({ mode: "standalone" })` (the template sets both).
5. Deploy: check `npx prisma auth whoami`; if I am not signed in, stop and ask me to run `npx prisma auth login`. Then run `npm run build` followed by `npx prisma deploy module.ts` and verify the live URL's /api/users endpoint with curl. The deployed app provisions and seeds its own Prisma Postgres database; do not pass the local DATABASE_URL. If the deploy fails with `HostedStateBootstrapError`, a project with the module's name exists in my workspace but its hosted state cannot be verified; re-run the deploy with `--name <a unique name>`.

Use the installed Prisma ORM skills.
```

## 1. Scaffold and enter the project [#1-scaffold-and-enter-the-project]

  

#### bun

```bash
bun create prisma@latest my-astro-app --template astro --provider postgres --no-deploy
cd my-astro-app
```

#### pnpm

```bash
pnpm create prisma@latest my-astro-app --template astro --provider postgres --no-deploy
cd my-astro-app
```

#### yarn

```bash
yarn create prisma@latest my-astro-app --template astro --provider postgres --no-deploy
cd my-astro-app
```

#### npm

```bash
npm create prisma@latest -- my-astro-app --template astro --provider postgres --no-deploy
cd my-astro-app
```

The scaffold generates the Astro app with Prisma ORM wired in, installs dependencies, and emits the contract your queries are type-checked against.

Next, set the database connection for the local steps. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the generated scripts read the environment variable, not `.env`:

```bash
export DATABASE_URL="<your connection string>"
```

## 2. Initialize the database [#2-initialize-the-database]

  

#### bun

```bash
bun run db:init
```

#### pnpm

```bash
pnpm run db:init
```

#### yarn

```bash
yarn db:init
```

#### npm

```bash
npm run db:init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Applied 0 operation(s)` when there is nothing left to do.

`db:init` applies your schema (`src/prisma/contract.prisma`) to the database and signs it. With TypeScript authoring (`--authoring typescript`) the schema is `src/prisma/contract.ts` and the emitted files land in `src/prisma/generated/`. Sample users are seeded automatically the first time the app queries the database.

## 3. Run and verify [#3-run-and-verify]

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open [http://localhost:4321](http://localhost:4321). The page lists the seeded users; `GET /api/users` returns them as JSON.

## Where things live [#where-things-live]

* `src/pages/index.astro`: queries users in the frontmatter and renders them
* `src/pages/api/users.ts`: a JSON API route backed by the same query
* `src/prisma/db.ts`: the Prisma ORM client both import

Model access is namespace-qualified on PostgreSQL: `db.orm.public.User`. The [Prisma ORM overview](https://www.prisma.io/docs/orm) covers the contract-first model behind it.

## 4. Deploy to Prisma Compute [#4-deploy-to-prisma-compute]

Astro is supported on [Prisma Compute](https://www.prisma.io/docs/compute), which runs the site as a Node server. The scaffold configures that already: `astro.config.mjs` sets `output: "server"` with `adapter: node({ mode: "standalone" })`, and `module.ts` with `service.ts` declare the app for [Prisma Composer](https://www.prisma.io/docs/composer), pointing at the built `dist/server/entry.mjs`. Keep those settings: `output: "server"` renders the page and the API route per request, so the live site reads current data instead of freezing the build-time snapshot into static files, and without the standalone adapter there is no server entrypoint to deploy.

Sign in once (it opens a browser):

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

Then build and deploy from the project directory:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

```text no-copy
my-astro-app
├─ database   postgres-database db_abc123
└─ app        compute-service cps_abc123
              https://xyz.ewr.prisma.build
```

The deploy creates a project named after your module in your workspace, and re-running the deploy reuses it: the CLI finds the hosted state it stored on the first run and converges the project to your module. If a project with that name exists but the CLI cannot identify or verify its stored state (one left behind by a different checkout, for example), the deploy stops with `HostedStateBootstrapError`; deploy under another name with `--name <unique-name>`, or rename the module in `module.ts`. The deploy also provisions its own Prisma Postgres database on the platform, declared in `module.ts`; the `DATABASE_URL` from your local steps is not involved, and the deployed database seeds on the app's first query. Verify the live API route returns the seeded users:

```bash
curl https://xyz.ewr.prisma.build/api/users
```

The live URL's root page renders the same users server-side. For previews per Git branch and deploy on push, see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

## Next steps [#next-steps]

* Change the schema in `src/prisma/contract.prisma`, then run `npm run contract:emit` and `npm run db:update`.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Elysia`](https://www.prisma.io/docs/guides/frameworks/elysia): Build an Elysia API on Prisma ORM with the elysia template and deploy it to Prisma Compute.
- [`Hono`](https://www.prisma.io/docs/guides/frameworks/hono): Build a Hono API on Prisma ORM with the hono template, add your own routes, and deploy it to Prisma Compute.
- [`NestJS`](https://www.prisma.io/docs/guides/frameworks/nestjs): Set up Prisma ORM in a NestJS app with create-prisma, from scaffold to seeded API to a live deploy on Prisma Compute.
- [`Next.js`](https://www.prisma.io/docs/guides/frameworks/nextjs): Set up Prisma ORM in a Next.js app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Nuxt`](https://www.prisma.io/docs/guides/frameworks/nuxt): Set up Prisma ORM in a Nuxt app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

# Elysia (/docs/guides/frameworks/elysia)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Build an Elysia API on Prisma ORM with the elysia template and deploy it to Prisma Compute.

Location: Guides > Frameworks > Elysia

## Introduction [#introduction]

In this guide, you scaffold an Elysia API backed by Prisma ORM, initialize and seed a PostgreSQL database, serve data over HTTP, and deploy the API to [Prisma Compute](https://www.prisma.io/docs/compute) as a Bun app. The `elysia` template generates the server, so most of the work is understanding the pieces.

Every command and response below was run end to end against a live Prisma Postgres database.

## Prerequisites [#prerequisites]

* [Bun](https://bun.sh/) 1.1 or later (Elysia is Bun-first)
* A PostgreSQL connection string, or nothing at all: the scaffold can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Verify `bun --version` first; if Bun is missing, stop and ask. Create a new Elysia API with Prisma ORM, seed it, and deploy it to Prisma Compute.

1. Scaffold: `bun create prisma@latest my-elysia-api --template elysia --provider postgres --yes`. Then run `bunx prisma@latest init` in `my-elysia-api` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
2. In `my-elysia-api`, run `bun run db:init` with `DATABASE_URL` exported. Sample users are seeded automatically on the app's first query; there is no separate seed script.
3. Start `bun run dev` in the background, wait until it reports ready, verify `curl http://localhost:3000/users` returns the seeded users, then stop the dev server.
4. Deploy: check `bunx prisma@latest auth whoami`; if I am not signed in, stop and ask me to run `bunx prisma@latest auth login`. Then run `bun run build` followed by `bunx prisma@latest deploy module.ts` and verify the live URL's /users endpoint. The deployed app provisions and seeds its own Prisma Postgres database; do not pass the local DATABASE_URL. If the deploy fails with `HostedStateBootstrapError`, a project with the module's name exists in my workspace but its hosted state cannot be verified; re-run the deploy with `--name <a unique name>`.

Use the installed Prisma ORM skills.
```

## 1. Scaffold the project [#1-scaffold-the-project]

```bash
bun create prisma@latest my-elysia-api --template elysia --provider postgres --no-deploy
```

Answer the prompts for contract authoring style, package manager, and agent skills. The template generates an Elysia server in `src/index.ts` with `GET /` and `GET /users` routes, the Prisma ORM setup in `src/prisma/`, and package scripts for the database steps.

Next, set the database connection for the local steps. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the generated scripts read the environment variable, not `.env`:

```bash
export DATABASE_URL="<your connection string>"
```

```bash
cd my-elysia-api
```

## 2. Initialize the database [#2-initialize-the-database]

```bash
bun run db:init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Applied 0 operation(s)` when there is nothing left to do.

## 3. Run the server [#3-run-the-server]

```bash
bun run dev
```

The server starts on port 3000 (set `PORT` to change it):

```bash
curl http://localhost:3000/users
```

```json no-copy
[
  { "id": "1", "email": "alice@prisma.io", "username": "alice", "name": "Alice", "createdAt": "2026-07-24T11:43:41.450Z" },
  { "id": "2", "email": "bob@prisma.io", "username": "bob", "name": "Bob", "createdAt": "2026-07-24T11:43:41.490Z" },
  { "id": "3", "email": "carol@prisma.io", "username": "carol", "name": "Carol", "createdAt": "2026-07-24T11:43:41.533Z" }
]
```

The route handler is ordinary Elysia code calling an ordinary Prisma ORM query; there is no framework adapter in between. To add write routes, follow the same pattern as the [Hono guide's POST route](https://www.prisma.io/docs/guides/frameworks/hono#4-add-a-post-route); the query code is identical.

## 4. Deploy to Prisma Compute [#4-deploy-to-prisma-compute]

Elysia is supported on [Prisma Compute](https://www.prisma.io/docs/compute). The scaffold declares the app for [Prisma Composer](https://www.prisma.io/docs/composer) in `module.ts` and `service.ts`, pointing at the bundled server the `build` script produces, so no framework flags are needed. Sign in once (it opens a browser):

```bash
bunx prisma@latest auth login
```

Then build and deploy from the project directory:

```bash
bun run build
bunx prisma@latest deploy module.ts
```

```text no-copy
my-elysia-api
├─ database   postgres-database db_abc123
└─ app        compute-service cps_abc123
              https://xyz.ewr.prisma.build
```

The deploy creates a project named after your module in your workspace, and re-running the deploy reuses it: the CLI finds the hosted state it stored on the first run and converges the project to your module. If a project with that name exists but the CLI cannot identify or verify its stored state (one left behind by a different checkout, for example), the deploy stops with `HostedStateBootstrapError`; deploy under another name with `--name <unique-name>`, or rename the module in `module.ts`. The deploy also provisions its own Prisma Postgres database on the platform, declared in `module.ts`; the `DATABASE_URL` from your local steps is not involved, and the deployed database seeds on the app's first query. Verify the live endpoint returns the seeded users:

```bash
curl https://xyz.ewr.prisma.build/users
```

For previews per Git branch and deploy on push, see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

## Common gotchas [#common-gotchas]

> [!WARNING]
> In a long-running server, don't call `db.close()` in route handlers; the client's connection pool is shared across requests. Close it only on process shutdown.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`bunx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add GET /users/:id that returns one user or a 404."
* "Add a POST /users route that creates a user from the request body."

## Next steps [#next-steps]

* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.
* [Use the Hono guide](https://www.prisma.io/docs/guides/frameworks/hono) for the tested POST route pattern.

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/frameworks/astro): Set up Prisma ORM in an Astro app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Hono`](https://www.prisma.io/docs/guides/frameworks/hono): Build a Hono API on Prisma ORM with the hono template, add your own routes, and deploy it to Prisma Compute.
- [`NestJS`](https://www.prisma.io/docs/guides/frameworks/nestjs): Set up Prisma ORM in a NestJS app with create-prisma, from scaffold to seeded API to a live deploy on Prisma Compute.
- [`Next.js`](https://www.prisma.io/docs/guides/frameworks/nextjs): Set up Prisma ORM in a Next.js app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Nuxt`](https://www.prisma.io/docs/guides/frameworks/nuxt): Set up Prisma ORM in a Nuxt app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

# Hono (/docs/guides/frameworks/hono)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Build a Hono API on Prisma ORM with the hono template, add your own routes, and deploy it to Prisma Compute.

Location: Guides > Frameworks > Hono

## Introduction [#introduction]

In this guide, you scaffold a Hono API backed by Prisma ORM, initialize and seed a PostgreSQL database, serve data over HTTP, add your own POST route, and deploy the API to [Prisma Compute](https://www.prisma.io/docs/compute). The `hono` template generates the server for you, so most of the work is understanding the pieces and extending them.

Every command, route, and response below was run end to end against a live Prisma Postgres database.

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 22.18 or newer (on the 24 line, 24.11 or newer; 24 recommended), or [Bun](https://bun.sh/) (this guide uses Bun for speed; npm works the same)
* A PostgreSQL connection string, or nothing at all: the scaffold can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a new Hono API with Prisma ORM, seed it, and deploy it to Prisma Compute.

1. Scaffold: `npm create prisma@latest -- my-hono-api --template hono --provider postgres --yes`. Then run `npx prisma@latest init` in `my-hono-api` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
2. In `my-hono-api`, run `npm run db:init` with `DATABASE_URL` exported. Sample users are seeded automatically on the app's first query; there is no separate seed script.
3. Start `npm run dev` in the background, wait until it reports ready, verify `curl http://localhost:3000/users` returns the seeded users, then stop the dev server.
4. Add a POST /users route that creates a user from the request body, following https://www.prisma.io/docs/guides/frameworks/hono.md, restart the dev server, and verify it with curl.
5. Deploy: check `npx prisma auth whoami`; if I am not signed in, stop and ask me to run `npx prisma auth login`. Then run `npm run build` followed by `npx prisma deploy module.ts` and verify the live URL's /users endpoint. The deployed app provisions and seeds its own Prisma Postgres database; do not pass the local DATABASE_URL. If the deploy fails with `HostedStateBootstrapError`, a project with the module's name exists in my workspace but its hosted state cannot be verified; re-run the deploy with `--name <a unique name>`.
```

## 1. Scaffold the project [#1-scaffold-the-project]

```bash
bun create prisma@latest my-hono-api --template hono --provider postgres --no-deploy
```

Answer the prompts for contract authoring style, package manager, and agent skills. The template generates a Hono server in `src/index.ts` with two routes (`GET /` and `GET /users`), the Prisma ORM setup in `src/prisma/`, and package scripts for the database steps.

```bash
cd my-hono-api
```

Next, set the database connection for the local steps. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the generated scripts read the environment variable, not `.env`:

```bash
export DATABASE_URL="<your connection string>"
```

## 2. Initialize the database [#2-initialize-the-database]

```bash
bun run db:init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Applied 0 operation(s)` when there is nothing left to do.

## 3. Run the server [#3-run-the-server]

```bash
bun run dev
```

The server starts on port 3000 (set `PORT` to change it). Check both routes:

```bash
curl http://localhost:3000/users
```

```json no-copy
[
  { "id": "1", "email": "alice@prisma.io", "username": "alice", "name": "Alice", "createdAt": "2026-07-06T23:37:32.440Z" },
  { "id": "2", "email": "bob@prisma.io", "username": "bob", "name": "Bob", "createdAt": "2026-07-06T23:37:32.474Z" },
  { "id": "3", "email": "carol@prisma.io", "username": "carol", "name": "Carol", "createdAt": "2026-07-06T23:37:32.507Z" }
]
```

The route handler is ordinary Hono code calling an ordinary Prisma ORM query; there is no framework adapter in between.

## 4. Add a POST route [#4-add-a-post-route]

Add a route that creates a user from the request body. Add this to `src/index.ts` above the `serve(...)` call:

```ts title="src/index.ts"
app.post("/users", async (c) => {
  const body = await c.req.json<{ email: string; name?: string }>();
  const { db } = await import("./prisma/db");
  const user = await db.orm.public.User.create({
    email: body.email,
    name: body.name ?? null,
  });
  return c.json(user, 201);
});
```

Restart the server and create a user:

```bash
curl -X POST http://localhost:3000/users \
  -H "content-type: application/json" \
  -d '{"email":"dev@prisma.io","name":"Dev"}'
```

```json no-copy
{ "createdAt": "2026-07-06T23:37:56.184Z", "email": "dev@prisma.io", "id": 4, "name": "Dev", "username": null }
```

`.create(...)` returns the full inserted record, database defaults included, so the response needs no second query.

## 5. Deploy to Prisma Compute [#5-deploy-to-prisma-compute]

Hono is supported on [Prisma Compute](https://www.prisma.io/docs/compute). The scaffold already declares the app for [Prisma Composer](https://www.prisma.io/docs/composer) in `module.ts` and `service.ts`, so deploying is building and handing that declaration to the CLI. Sign in once (it opens a browser):

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

Then build and deploy from the project directory:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

```text no-copy
my-hono-api
├─ database   postgres-database db_abc123
└─ app        compute-service cps_abc123
              https://xyz.ewr.prisma.build
```

The deploy creates a project named after your module in your workspace, and re-running the deploy reuses it: the CLI finds the hosted state it stored on the first run and converges the project to your module. If a project with that name exists but the CLI cannot identify or verify its stored state (one left behind by a different checkout, for example), the deploy stops with `HostedStateBootstrapError`; deploy under another name with `--name <unique-name>`, or rename the module in `module.ts`. The deploy also provisions its own Prisma Postgres database on the platform, declared in `module.ts`; the `DATABASE_URL` from your local steps is not involved. Verify the live endpoint returns the seeded users (the deployed database seeds on its first query):

```bash
curl https://xyz.ewr.prisma.build/users
```

For previews per Git branch and deploy on push, see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

## Common gotchas [#common-gotchas]

> [!WARNING]
> In a long-running server, don't call `db.close()` in route handlers; the client's connection pool is shared across requests. Close it only on process shutdown.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add GET /users/:id that returns one user or a 404."
* "Expose GET /users/:id/posts using the Post model that ships with the starter contract."
* "Wrap the signup route's writes in a [transaction](https://www.prisma.io/docs/orm/fundamentals/transactions)."

## Next steps [#next-steps]

* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/frameworks/astro): Set up Prisma ORM in an Astro app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Elysia`](https://www.prisma.io/docs/guides/frameworks/elysia): Build an Elysia API on Prisma ORM with the elysia template and deploy it to Prisma Compute.
- [`NestJS`](https://www.prisma.io/docs/guides/frameworks/nestjs): Set up Prisma ORM in a NestJS app with create-prisma, from scaffold to seeded API to a live deploy on Prisma Compute.
- [`Next.js`](https://www.prisma.io/docs/guides/frameworks/nextjs): Set up Prisma ORM in a Next.js app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Nuxt`](https://www.prisma.io/docs/guides/frameworks/nuxt): Set up Prisma ORM in a Nuxt app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

# NestJS (/docs/guides/frameworks/nestjs)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up Prisma ORM in a NestJS app with create-prisma, from scaffold to seeded API to a live deploy on Prisma Compute.

Location: Guides > Frameworks > NestJS

## Introduction [#introduction]

This guide shows you how to use Prisma ORM in a NestJS API. You scaffold a project with a users controller backed by Prisma ORM, initialize the schema, query it over HTTP, and deploy the API to [Prisma Compute](https://www.prisma.io/docs/compute).

Every command below was run end to end against a live [Prisma Postgres](https://www.prisma.io/docs/postgres) database.

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 22.18 or newer (on the 24 line, 24.11 or newer; 24 recommended)
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a Prisma Postgres database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a new NestJS API with Prisma ORM, seed it, and deploy it to Prisma Compute.

1. Scaffold: `npm create prisma@latest -- my-nest-api --template nest --provider postgres --yes`. Then run `npx prisma@latest init` in `my-nest-api` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
2. In `my-nest-api`, run `npm run db:init` with `DATABASE_URL` exported. Sample users are seeded automatically on the app's first query; there is no separate seed script.
3. Start `npm run dev` in the background, wait until it reports ready, and verify `curl http://localhost:3000/users` returns the seeded users; stop the dev server once verified.
4. Deploy: check `npx prisma auth whoami`; if I am not signed in, stop and ask me to run `npx prisma auth login`. Then run `npm run build` followed by `npx prisma deploy module.ts` and verify the live URL's /users endpoint. The deployed app provisions and seeds its own Prisma Postgres database; do not pass the local DATABASE_URL. If the deploy fails with `HostedStateBootstrapError`, a project with the module's name exists in my workspace but its hosted state cannot be verified; re-run the deploy with `--name <a unique name>`.

Use the installed Prisma ORM skills.
```

## 1. Scaffold and enter the project [#1-scaffold-and-enter-the-project]

  

#### bun

```bash
bun create prisma@latest my-nest-api --template nest --provider postgres --no-deploy
cd my-nest-api
```

#### pnpm

```bash
pnpm create prisma@latest my-nest-api --template nest --provider postgres --no-deploy
cd my-nest-api
```

#### yarn

```bash
yarn create prisma@latest my-nest-api --template nest --provider postgres --no-deploy
cd my-nest-api
```

#### npm

```bash
npm create prisma@latest -- my-nest-api --template nest --provider postgres --no-deploy
cd my-nest-api
```

Answer the prompts for contract authoring style, package manager, and agent skills. The scaffold generates the NestJS app with Prisma ORM wired in, installs dependencies, and emits the contract your queries are type-checked against.

Next, set the database connection for the local steps. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the generated scripts read the environment variable, not `.env`:

```bash
export DATABASE_URL="<your connection string>"
```

## 2. Initialize the database [#2-initialize-the-database]

  

#### bun

```bash
bun run db:init
```

#### pnpm

```bash
pnpm run db:init
```

#### yarn

```bash
yarn db:init
```

#### npm

```bash
npm run db:init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Applied 0 operation(s)` when there is nothing left to do.

`db:init` applies your schema (`src/prisma/contract.prisma`) to the database and signs it. With TypeScript authoring (`--authoring typescript`) the schema is `src/prisma/contract.ts` and the emitted files land in `src/prisma/generated/`. Sample users are seeded automatically the first time the app queries the database.

## 3. Run and verify [#3-run-and-verify]

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

The server starts on port 3000 (set `PORT` to change it). Query the API:

```bash
curl http://localhost:3000/users
```

```json no-copy
[
  { "id": "1", "email": "alice@prisma.io", "username": "alice", "name": "Alice", "createdAt": "2026-07-24T10:55:54.156Z" },
  { "id": "2", "email": "bob@prisma.io", "username": "bob", "name": "Bob", "createdAt": "2026-07-24T10:55:54.192Z" },
  { "id": "3", "email": "carol@prisma.io", "username": "carol", "name": "Carol", "createdAt": "2026-07-24T10:55:54.228Z" }
]
```

## Where things live [#where-things-live]

* `src/users.controller.ts`: the `GET /users` route
* `src/users.service.ts`: the service the controller calls
* `src/prisma.service.ts`: the injectable that exposes the Prisma ORM client and query helpers
* `src/prisma/users.ts`: the `listUsers` query the service runs
* `src/prisma/db.ts`: the Prisma ORM client itself

Model access is namespace-qualified on PostgreSQL: `db.orm.public.User`. The [Prisma ORM overview](https://www.prisma.io/docs/orm) covers the contract-first model behind it.

## 4. Deploy to Prisma Compute [#4-deploy-to-prisma-compute]

NestJS is supported on [Prisma Compute](https://www.prisma.io/docs/compute). The scaffold declares the app for [Prisma Composer](https://www.prisma.io/docs/composer) in `module.ts` and `service.ts`, so deploying is building and handing that declaration to the CLI. Sign in once (it opens a browser):

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

Then build and deploy from the project directory:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

```text no-copy
my-nest-api
├─ database   postgres-database db_abc123
└─ app        compute-service cps_abc123
              https://xyz.ewr.prisma.build
```

The deploy creates a project named after your module in your workspace, and re-running the deploy reuses it: the CLI finds the hosted state it stored on the first run and converges the project to your module. If a project with that name exists but the CLI cannot identify or verify its stored state (one left behind by a different checkout, for example), the deploy stops with `HostedStateBootstrapError`; deploy under another name with `--name <unique-name>`, or rename the module in `module.ts`. The deploy also provisions its own Prisma Postgres database on the platform, declared in `module.ts`; the `DATABASE_URL` from your local steps is not involved, and the deployed database seeds on the app's first query. Verify the live endpoint returns the seeded users:

```bash
curl https://xyz.ewr.prisma.build/users
```

For previews per Git branch and deploy on push, see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

## Common gotchas [#common-gotchas]

> [!WARNING]
> In a long-running server, don't call `db.close()` in request handlers; the client's connection pool is shared across requests. Close it only on process shutdown.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add GET /users/:id to the users controller that returns one user or a 404."
* "Expose GET /users/:id/posts using the Post model that ships with the starter contract."
* "Add a POST /users route that creates a user from the request body and returns it with a 201."

## Next steps [#next-steps]

* Change the schema in `src/prisma/contract.prisma`, then run `npm run contract:emit` and `npm run db:update`.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/frameworks/astro): Set up Prisma ORM in an Astro app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Elysia`](https://www.prisma.io/docs/guides/frameworks/elysia): Build an Elysia API on Prisma ORM with the elysia template and deploy it to Prisma Compute.
- [`Hono`](https://www.prisma.io/docs/guides/frameworks/hono): Build a Hono API on Prisma ORM with the hono template, add your own routes, and deploy it to Prisma Compute.
- [`Next.js`](https://www.prisma.io/docs/guides/frameworks/nextjs): Set up Prisma ORM in a Next.js app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Nuxt`](https://www.prisma.io/docs/guides/frameworks/nuxt): Set up Prisma ORM in a Nuxt app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

# Next.js (/docs/guides/frameworks/nextjs)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up Prisma ORM in a Next.js app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

Location: Guides > Frameworks > Next.js

## Introduction [#introduction]

This guide shows you how to use Prisma ORM in a Next.js app. You scaffold a project where a server component queries your database, initialize the schema, see your data render, and deploy the app to [Prisma Compute](https://www.prisma.io/docs/compute).

Every command below was run end to end against a live [Prisma Postgres](https://www.prisma.io/docs/postgres) database.

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 22.18 or newer (on the 24 line, 24.11 or newer; 24 recommended)
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a Prisma Postgres database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a new Next.js app with Prisma ORM, seed it, and deploy it to Prisma Compute.

1. Scaffold: `npm create prisma@latest -- my-app --template next --provider postgres --yes`. Then run `npx prisma@latest init` in `my-app` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
2. In `my-app`, run `npm run db:init` with `DATABASE_URL` exported. Sample users are seeded automatically on the app's first query; there is no separate seed script.
3. Start `npm run dev` in the background, wait until it reports ready, verify http://localhost:3000 renders the seeded users, then stop the dev server.
4. Confirm `next.config.ts` still sets `output: "standalone"` (the template sets it); Prisma Compute deploys the standalone server that `next build` emits.
5. Deploy: check `npx prisma auth whoami`; if I am not signed in, stop and ask me to run `npx prisma auth login`. Then run `npm run build` followed by `npx prisma deploy module.ts` and verify the live URL renders the seeded users. The deployed app provisions and seeds its own Prisma Postgres database; do not pass the local DATABASE_URL. If the deploy fails with `HostedStateBootstrapError`, a project with the module's name exists in my workspace but its hosted state cannot be verified; re-run the deploy with `--name <a unique name>`.
```

## 1. Scaffold and enter the project [#1-scaffold-and-enter-the-project]

  

#### bun

```bash
bun create prisma@latest my-app --template next --provider postgres --no-deploy
cd my-app
```

#### pnpm

```bash
pnpm create prisma@latest my-app --template next --provider postgres --no-deploy
cd my-app
```

#### yarn

```bash
yarn create prisma@latest my-app --template next --provider postgres --no-deploy
cd my-app
```

#### npm

```bash
npm create prisma@latest -- my-app --template next --provider postgres --no-deploy
cd my-app
```

Answer the prompts for contract authoring style, package manager, and agent skills. The scaffold generates the Next.js app with Prisma ORM wired in, installs dependencies, and emits the contract your queries are type-checked against.

Next, set the database connection for the local steps. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the generated scripts read the environment variable, not `.env`:

```bash
export DATABASE_URL="<your connection string>"
```

## 2. Initialize the database [#2-initialize-the-database]

  

#### bun

```bash
bun run db:init
```

#### pnpm

```bash
pnpm run db:init
```

#### yarn

```bash
yarn db:init
```

#### npm

```bash
npm run db:init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Applied 0 operation(s)` when there is nothing left to do.

`db:init` applies your schema (`src/prisma/contract.prisma`) to the database and signs it. With TypeScript authoring (`--authoring typescript`) the schema is `src/prisma/contract.ts` and the emitted files land in `src/prisma/generated/`. Sample users are seeded automatically the first time the app queries the database.

## 3. Run and verify [#3-run-and-verify]

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open [http://localhost:3000](http://localhost:3000) (set `PORT` to change it). The page lists the seeded users, rendered by a server component that calls Prisma ORM directly.

## 4. Deploy to Prisma Compute [#4-deploy-to-prisma-compute]

Next.js is supported on [Prisma Compute](https://www.prisma.io/docs/compute). The scaffold declares the app for [Prisma Composer](https://www.prisma.io/docs/composer) in `module.ts` and `service.ts`, using the `nextjs` build adapter, and sets `output: "standalone"` in `next.config.ts`. Keep that setting: Compute runs the standalone server that `next build` emits.

> [!WARNING]
> Without `output: "standalone"` the deploy still completes, but the uploaded build contains no server to start and the live URL returns a 504. With it, the build drops from roughly 170 MB to 14 MB and boots normally.

Sign in once (it opens a browser):

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

Then build and deploy from the project directory:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

```text no-copy
my-app
├─ database   postgres-database db_abc123
└─ app        compute-service cps_abc123
              https://xyz.ewr.prisma.build
```

Open the live URL: the page renders the seeded users. The deploy creates a project named after your module in your workspace, and re-running the deploy reuses it: the CLI finds the hosted state it stored on the first run and converges the project to your module. If a project with that name exists but the CLI cannot identify or verify its stored state (one left behind by a different checkout, for example), the deploy stops with `HostedStateBootstrapError`; deploy under another name with `--name <unique-name>`, or rename the module in `module.ts`. The deploy also provisions its own Prisma Postgres database on the platform, declared in `module.ts`; the `DATABASE_URL` from your local steps is not involved, and the deployed database seeds on the app's first query. For previews per Git branch and deploy on push, see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

## Where things live [#where-things-live]

* `src/app/page.tsx`: a server component that queries users and renders them
* `src/prisma/db.ts`: the Prisma ORM client your components import
* `src/prisma/contract.prisma`: your schema

Model access is namespace-qualified on PostgreSQL: `db.orm.public.User`. The [Prisma ORM overview](https://www.prisma.io/docs/orm) covers the contract-first model behind it.

## Next steps [#next-steps]

* Change the schema in `src/prisma/contract.prisma`, then run `npm run contract:emit` and `npm run db:update`.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/frameworks/astro): Set up Prisma ORM in an Astro app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Elysia`](https://www.prisma.io/docs/guides/frameworks/elysia): Build an Elysia API on Prisma ORM with the elysia template and deploy it to Prisma Compute.
- [`Hono`](https://www.prisma.io/docs/guides/frameworks/hono): Build a Hono API on Prisma ORM with the hono template, add your own routes, and deploy it to Prisma Compute.
- [`NestJS`](https://www.prisma.io/docs/guides/frameworks/nestjs): Set up Prisma ORM in a NestJS app with create-prisma, from scaffold to seeded API to a live deploy on Prisma Compute.
- [`Nuxt`](https://www.prisma.io/docs/guides/frameworks/nuxt): Set up Prisma ORM in a Nuxt app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

# Nuxt (/docs/guides/frameworks/nuxt)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up Prisma ORM in a Nuxt app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

Location: Guides > Frameworks > Nuxt

## Introduction [#introduction]

This guide shows you how to use Prisma ORM in a Nuxt app. You scaffold a project where a server API route queries your database and the page renders it, initialize the schema, see your data, and deploy the app to [Prisma Compute](https://www.prisma.io/docs/compute).

Every command below was run end to end against a live [Prisma Postgres](https://www.prisma.io/docs/postgres) database.

## Quick start [#quick-start]

One command scaffolds the project with Prisma ORM wired in:

  

#### bun

```bash
bun create prisma@latest my-app --template nuxt --provider postgres --no-deploy
```

#### pnpm

```bash
pnpm create prisma@latest my-app --template nuxt --provider postgres --no-deploy
```

#### yarn

```bash
yarn create prisma@latest my-app --template nuxt --provider postgres --no-deploy
```

#### npm

```bash
npm create prisma@latest -- my-app --template nuxt --provider postgres --no-deploy
```

Answer the prompts, then export `DATABASE_URL` in your shell before running the database scripts. If you do not have a database yet, `npx create-db@latest` prints a Prisma Postgres connection string.

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 22.18 or newer (on the 24 line, 24.11 or newer; 24 recommended)
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a Prisma Postgres database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a new Nuxt app with Prisma ORM, seed it, and deploy it to Prisma Compute.

1. Scaffold: `npm create prisma@latest -- my-app --template nuxt --provider postgres --yes`. Then run `npx prisma@latest init` in `my-app` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
2. In `my-app`, run `npm run db:init` with `DATABASE_URL` exported. Sample users are seeded automatically on the app's first query; there is no separate seed script.
3. Start `npm run dev` in the background, wait until it reports ready, verify that http://localhost:3000 lists the seeded users and `curl http://localhost:3000/api/users` returns them, then stop the dev server.
4. Deploy: check `npx prisma auth whoami`; if I am not signed in, stop and ask me to run `npx prisma auth login`. Then run `npm run build` followed by `npx prisma deploy module.ts` and verify the live URL's /api/users endpoint. The deployed app provisions and seeds its own Prisma Postgres database; do not pass the local DATABASE_URL. If the deploy fails with `HostedStateBootstrapError`, a project with the module's name exists in my workspace but its hosted state cannot be verified; re-run the deploy with `--name <a unique name>`.

Use the installed Prisma ORM skills.
```

## 1. Scaffold and enter the project [#1-scaffold-and-enter-the-project]

  

#### bun

```bash
bun create prisma@latest my-app --template nuxt --provider postgres --no-deploy
cd my-app
```

#### pnpm

```bash
pnpm create prisma@latest my-app --template nuxt --provider postgres --no-deploy
cd my-app
```

#### yarn

```bash
yarn create prisma@latest my-app --template nuxt --provider postgres --no-deploy
cd my-app
```

#### npm

```bash
npm create prisma@latest -- my-app --template nuxt --provider postgres --no-deploy
cd my-app
```

The scaffold generates the Nuxt app with Prisma ORM wired in, installs dependencies, and emits the contract your queries are type-checked against.

Next, set the database connection for the local steps. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the generated scripts read the environment variable, not `.env`:

```bash
export DATABASE_URL="<your connection string>"
```

## 2. Initialize the database [#2-initialize-the-database]

  

#### bun

```bash
bun run db:init
```

#### pnpm

```bash
pnpm run db:init
```

#### yarn

```bash
yarn db:init
```

#### npm

```bash
npm run db:init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Applied 0 operation(s)` when there is nothing left to do.

`db:init` applies your schema (`src/prisma/contract.prisma`) to the database and signs it. With TypeScript authoring (`--authoring typescript`) the schema is `src/prisma/contract.ts` and the emitted files land in `src/prisma/generated/`. Sample users are seeded automatically the first time the app queries the database.

## 3. Run and verify [#3-run-and-verify]

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open [http://localhost:3000](http://localhost:3000). The page lists the seeded users, fetched from the `/api/users` server route. You can hit that route directly:

```bash
curl http://localhost:3000/api/users
```

```json no-copy
{
  "users": [
    { "id": "1", "email": "alice@prisma.io", "username": "alice", "name": "Alice", "createdAt": "2026-07-24T11:43:58.001Z" },
    { "id": "2", "email": "bob@prisma.io", "username": "bob", "name": "Bob", "createdAt": "2026-07-24T11:43:58.035Z" },
    { "id": "3", "email": "carol@prisma.io", "username": "carol", "name": "Carol", "createdAt": "2026-07-24T11:43:58.068Z" }
  ]
}
```

## Where things live [#where-things-live]

* `server/api/users.get.ts`: the server route that queries users
* `app/pages/index.vue`: the page that fetches and renders them
* `src/prisma/db.ts`: the Prisma ORM client the server route imports

Model access is namespace-qualified on PostgreSQL: `db.orm.public.User`. The [Prisma ORM overview](https://www.prisma.io/docs/orm) covers the contract-first model behind it.

## 4. Deploy to Prisma Compute [#4-deploy-to-prisma-compute]

Nuxt is supported on [Prisma Compute](https://www.prisma.io/docs/compute). The scaffold declares the app for [Prisma Composer](https://www.prisma.io/docs/composer) in `module.ts` and `service.ts`, pointing at Nuxt's `.output` build directory, so deploying is building and handing that declaration to the CLI. Sign in once (it opens a browser):

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

Then build and deploy from the project directory:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

```text no-copy
my-app
├─ database   postgres-database db_abc123
└─ app        compute-service cps_abc123
              https://xyz.ewr.prisma.build
```

The deploy creates a project named after your module in your workspace, and re-running the deploy reuses it: the CLI finds the hosted state it stored on the first run and converges the project to your module. If a project with that name exists but the CLI cannot identify or verify its stored state (one left behind by a different checkout, for example), the deploy stops with `HostedStateBootstrapError`; deploy under another name with `--name <unique-name>`, or rename the module in `module.ts`. The deploy also provisions its own Prisma Postgres database on the platform, declared in `module.ts`; the `DATABASE_URL` from your local steps is not involved, and the deployed database seeds on the app's first query. Verify the live app: open the URL to see the rendered user list, or hit the API route:

```bash
curl https://xyz.ewr.prisma.build/api/users
```

For previews per Git branch and deploy on push, see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

## Next steps [#next-steps]

* Change the schema in `src/prisma/contract.prisma`, then run `npm run contract:emit` and `npm run db:update`.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/frameworks/astro): Set up Prisma ORM in an Astro app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Elysia`](https://www.prisma.io/docs/guides/frameworks/elysia): Build an Elysia API on Prisma ORM with the elysia template and deploy it to Prisma Compute.
- [`Hono`](https://www.prisma.io/docs/guides/frameworks/hono): Build a Hono API on Prisma ORM with the hono template, add your own routes, and deploy it to Prisma Compute.
- [`NestJS`](https://www.prisma.io/docs/guides/frameworks/nestjs): Set up Prisma ORM in a NestJS app with create-prisma, from scaffold to seeded API to a live deploy on Prisma Compute.
- [`Next.js`](https://www.prisma.io/docs/guides/frameworks/nextjs): Set up Prisma ORM in a Next.js app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

# React Router (/docs/guides/frameworks/react-router-7)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to a React Router app in framework mode with orm init, then build user and post pages with loaders and a form action.

Location: Guides > Frameworks > React Router

## Introduction [#introduction]

This guide shows you how to use Prisma ORM in a [React Router](https://reactrouter.com/) app running in framework mode. There is no `create-prisma` template for React Router, so you start from `create-react-router` and add Prisma ORM to the existing project with `orm init`. You then define a contract for users and posts, seed the database, read it from route loaders, and write to it from a form action.

`create-react-router@latest` scaffolds React Router 8. The route APIs this guide uses (`loader`, `action`, `routes.ts`, and the generated `Route` types) are the same in React Router 7, and the finished app was run on both majors.

Every command, page, and response below was run end to end against a local PostgreSQL database.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/frameworks/react-router-7](https://www.prisma.io/docs/guides/v7/frameworks/react-router-7).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a new React Router app in framework mode, add Prisma ORM to it, and build a small blog on top.

1. Scaffold: `npx create-react-router@latest my-app --yes`, then `cd my-app`. Run `npx prisma@latest orm init --yes --target postgres --authoring psl` so Prisma ORM is added to the existing project, then `npx prisma@latest init` so the Prisma agent skills are installed and stay current, and use them.
2. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Write it to `.env` as `DATABASE_URL`; the scaffolded `src/prisma/db.ts` and `prisma.config.ts` both load `.env`.
3. Edit `src/prisma/contract.prisma` so `User` has `id`, `email`, `name`, `posts`, `createdAt`, `updatedAt` and `Post` has `id`, `title`, `content`, `published`, `author`, `authorId`, `createdAt`, `updatedAt`, following https://www.prisma.io/docs/guides/frameworks/react-router-7.md. Run `npx prisma contract emit` and `npx prisma db init`.
4. Add `allowImportingTsExtensions: true` to `tsconfig.json`, write `src/prisma/seed.ts` that creates two users with posts and closes the client, and run it with `node src/prisma/seed.ts`.
5. Create `app/lib/db.server.ts` that re-exports `db` from `src/prisma/db.ts`. Build these routes in `app/routes.ts`: `/` lists users, `/posts` lists posts with their author, `/posts/new` has a form whose action creates a post and redirects to it, `/posts/:postId` shows one post or a 404.
6. Start `npm run dev` in the background, wait until it reports ready, verify every route with curl including a POST to `/posts/new`, then stop the dev server. Run `npm run typecheck` and fix anything it reports.
```

## 1. Set up your project [#1-set-up-your-project]

Create a new React Router app in framework mode:

  

#### bun

```bash
bunx create-react-router@latest my-app
```

#### pnpm

```bash
pnpm dlx create-react-router@latest my-app
```

#### yarn

```bash
yarn dlx create-react-router@latest my-app
```

#### npm

```bash
npx create-react-router@latest my-app
```

Accept the defaults at the prompts: initialize a git repository and install dependencies with npm.

```text no-copy
         create-react-router v8.3.1

      ◼  Directory: Using my-app as project directory
      ◼  Using default template See https://github.com/remix-run/react-router-templates for more
      ✔  Template copied
      ✔  Dependencies installed
      ✔  Git initialized

  done   That's it!
```

Move into the project:

```bash
cd my-app
```

## 2. Add Prisma ORM to the project [#2-add-prisma-orm-to-the-project]

### 2.1. Run `orm init` [#21-run-orm-init]

`orm init` adds Prisma ORM to a project that already exists. Run it after the scaffold has installed dependencies so it picks up npm from the lockfile:

  

#### bun

```bash
bunx prisma@latest orm init --yes --target postgres --authoring psl
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### yarn

```bash
yarn dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### npm

```bash
npx prisma@latest orm init --yes --target postgres --authoring psl
```

`--target postgres` selects PostgreSQL, `--authoring psl` keeps the schema in Prisma Schema Language, and `--yes` accepts the default contract path. Run [`orm init`](https://www.prisma.io/docs/cli/orm-init) without flags for the guided version that asks the same questions.

```text no-copy
Updated tsconfig.json with required compiler options.
npm add @prisma/orm-postgres dotenv
npm add -D prisma@latest
npm add -D @prisma/cli-engine@0.6.1
Emit the contract

filesWritten: src/prisma/contract.prisma, prisma.config.ts, src/prisma/db.ts,
              prisma-8.md, .env.example, tsconfig.json, .gitignore,
              .gitattributes, package.json
contractEmitted: true
```

The command installs `@prisma/orm-postgres` (the Postgres runtime) and `dotenv`, adds the `prisma` CLI as a dev dependency, and writes:

* `prisma.config.ts`: the CLI configuration. It loads `.env` and points at your contract.
* `src/prisma/contract.prisma`: your schema, with starter `User` and `Post` models.
* `src/prisma/db.ts`: the Prisma ORM client your loaders import.
* `src/prisma/contract.json` and `src/prisma/contract.d.ts`: emitted from the contract; the runtime validates against the first and your queries are typed by the second.
* A `contract:emit` script in `package.json`, and `"module": "preserve"` in `tsconfig.json`.

There is no `prisma generate` step and no driver adapter package. The emitted contract is what `@prisma/client` and the adapter used to provide.

### 2.2. Set your database connection string [#22-set-your-database-connection-string]

Create a `.env` file at the project root. Use your own PostgreSQL connection string, or run `npx create-db@latest` to get a Prisma Postgres one:

```bash title=".env"
DATABASE_URL="postgres://user:password@localhost:5432/mydb"
```

Both `prisma.config.ts` and `src/prisma/db.ts` import `dotenv/config`, so the CLI, the seed script, and the dev server all read this file.

### 2.3. Define your contract [#23-define-your-contract]

Replace the starter models in `src/prisma/contract.prisma` with the blog schema this guide builds. `User` loses the `username` column and `Post` gains a `published` flag:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}
```

`TimestamptzString` and `temporal.updatedAtString()` are the Prisma ORM idioms for a `timestamptz` column that reaches your code as an ISO string, which is what a React Router loader can hand to the browser without extra serialization.

Emit the contract again so `contract.json` and `contract.d.ts` match:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

```text no-copy
"files": {
  "json": "src/prisma/contract.json",
  "dts": "src/prisma/contract.d.ts"
}
```

### 2.4. Initialize the database [#24-initialize-the-database]

`db init` creates the tables from the contract and signs the database, so later commands can tell whether it still matches:

  

#### bun

```bash
bunx prisma db init
```

#### pnpm

```bash
pnpm prisma db init
```

#### yarn

```bash
yarn prisma db init
```

#### npm

```bash
npx prisma db init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

The five operations are the `user` and `post` tables, the unique constraint on `email`, the index on `authorId`, and the foreign key. If you change the contract later, run `npx prisma contract emit` followed by `npx prisma db update`, or plan a checked-in migration with [`migration plan`](https://www.prisma.io/docs/cli/migration-plan). There is no `prisma migrate dev`.

### 2.5. Seed the database [#25-seed-the-database]

The seed is a plain script that Node.js 24 runs directly, so it imports the client with its `.ts` extension. Tell TypeScript to allow that:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "resolveJsonModule": true,
    "allowImportingTsExtensions": true, // [!code ++]
    "skipLibCheck": true,
    "strict": true
  }
}
```

Create `src/prisma/seed.ts`:

```typescript title="src/prisma/seed.ts"
import { db } from "./db.ts";

const users = [
  {
    email: "alice@prisma.io",
    name: "Alice",
    posts: [
      { title: "Join the Prisma Discord", content: "https://pris.ly/discord", published: true },
      { title: "Prisma on YouTube", content: "https://pris.ly/youtube" },
    ],
  },
  {
    email: "bob@prisma.io",
    name: "Bob",
    posts: [
      { title: "Follow Prisma on Twitter", content: "https://www.twitter.com/prisma", published: true },
    ],
  },
];

for (const { posts, ...data } of users) {
  const user = await db.orm.public.User.create(data);
  for (const post of posts) {
    await db.orm.public.Post.create({ ...post, authorId: user.id });
  }
  console.log(`Created ${user.name} with ${posts.length} post(s)`);
}

await db.close();
```

`create` returns the inserted row, so the user's generated `id` is available for the posts without a second query. The script closes the client at the end; without that call the connection pool keeps the process alive.

Run it:

```bash
node src/prisma/seed.ts
```

```text no-copy
Created Alice with 2 post(s)
Created Bob with 1 post(s)
```

## 3. Integrate Prisma into React Router [#3-integrate-prisma-into-react-router]

### 3.1. Create a server-only `db` helper [#31-create-a-server-only-db-helper]

React Router bundles route modules for the browser as well as the server. Loaders and actions are stripped from the browser build, but the safest way to keep the database client out of it is a module with a `.server` suffix, which React Router refuses to include in client code. Create `app/lib/db.server.ts` and re-export the scaffolded client from it:

```typescript title="app/lib/db.server.ts"
export { db } from "../../src/prisma/db";
```

Routes import it as `~/lib/db.server` through the `~` alias the template configures. The client is created once per process and shared by every request; never close it in a loader or action.

### 3.2. Query your database from a loader [#32-query-your-database-from-a-loader]

Replace `app/routes/home.tsx` so the home page lists users from the database:

```tsx title="app/routes/home.tsx"
import type { Route } from "./+types/home";
import { Link } from "react-router";
import { db } from "~/lib/db.server";

export function meta({}: Route.MetaArgs) {
  return [
    { title: "Superblog" },
    { name: "description", content: "A React Router app on Prisma 8" },
  ];
}

export async function loader() {
  const users = await db.orm.public.User.select("id", "name", "email").all();
  return { users };
}

export default function Home({ loaderData }: Route.ComponentProps) {
  const { users } = loaderData;
  return (
    <div className="min-h-screen flex flex-col items-center justify-center -mt-16">
      <h1 className="text-4xl font-bold mb-8">Superblog</h1>
      <ol className="list-decimal list-inside">
        {users.map((user) => (
          <li key={user.id} className="mb-2">
            {user.name} ({user.email})
          </li>
        ))}
      </ol>
      <Link to="/posts" className="mt-8 underline">
        View posts
      </Link>
    </div>
  );
}
```

Model access is namespace-qualified on PostgreSQL: `db.orm.public.User`. `select` narrows the columns and `all()` runs the query. The `Route.ComponentProps` type carries the loader's return type into the component, so `users` is typed without any annotation.

The template's `app/welcome` directory is no longer imported; delete it.

Start the dev server:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

```text no-copy
  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
```

Open [http://localhost:5173](http://localhost:5173). The page lists Alice and Bob.

> [!NOTE]
> If your editor reports an error on `import type { Route } from "./+types/home"`, run `npm run dev` or `npm run typecheck` once so React Router generates the route types.

## 4. Add a posts list page [#4-add-a-posts-list-page]

Create `app/routes/posts/home.tsx`. The loader includes each post's author so the page can show the name:

```tsx title="app/routes/posts/home.tsx"
import type { Route } from "./+types/home";
import { Link } from "react-router";
import { db } from "~/lib/db.server";

export async function loader() {
  const posts = await db.orm.public.Post.include("author").orderBy((p) => p.id.asc()).all();
  return { posts };
}

export default function Posts({ loaderData }: Route.ComponentProps) {
  const { posts } = loaderData;
  return (
    <div className="min-h-screen flex flex-col items-center justify-center -mt-16">
      <h1 className="text-4xl font-bold mb-8">Posts</h1>
      <ul className="max-w-2xl space-y-4">
        {posts.map((post) => (
          <li key={post.id}>
            <Link to={`/posts/${post.id}`} className="font-semibold underline">
              {post.title}
            </Link>
            <span className="text-sm text-gray-600 ml-2">by {post.author.name}</span>
          </li>
        ))}
      </ul>
      <Link to="/posts/new" className="mt-8 underline">
        Create a post
      </Link>
    </div>
  );
}
```

Register the route in `app/routes.ts`:

```tsx title="app/routes.ts"
import { type RouteConfig, index, route } from "@react-router/dev/routes"; // [!code highlight]

export default [
  index("routes/home.tsx"),
  route("posts", "routes/posts/home.tsx"), // [!code ++]
] satisfies RouteConfig;
```

Open [http://localhost:5173/posts](http://localhost:5173/posts): three posts, each with its author. `include("author")` fetches the relation in the same query, and the result type gains an `author` object, so `post.author.name` type-checks.

## 5. Add a post detail page [#5-add-a-post-detail-page]

Create `app/routes/posts/post.tsx`. The loader reads the post by primary key and throws a 404 when there is none:

```tsx title="app/routes/posts/post.tsx"
import type { Route } from "./+types/post";
import { data } from "react-router";
import { db } from "~/lib/db.server";

export async function loader({ params }: Route.LoaderArgs) {
  const id = Number(params.postId);
  const post = Number.isInteger(id)
    ? await db.orm.public.Post.include("author").first({ id })
    : null;

  if (!post) {
    throw data("Post Not Found", { status: 404 });
  }
  return { post };
}

export default function Post({ loaderData }: Route.ComponentProps) {
  const { post } = loaderData;
  return (
    <div className="min-h-screen flex flex-col items-center justify-center -mt-16">
      <article className="max-w-2xl space-y-4">
        <h1 className="text-4xl font-bold mb-8">{post.title}</h1>
        <p className="text-gray-600 text-center">by {post.author.name}</p>
        <div className="prose prose-gray mt-8">{post.content || "No content available."}</div>
      </article>
    </div>
  );
}
```

`first({ id })` is the primary-key lookup; it returns the row or `null`. Route params are strings, so the loader converts `postId` and refuses anything that is not an integer before it queries.

Add the route:

```tsx title="app/routes.ts"
export default [
  index("routes/home.tsx"),
  route("posts", "routes/posts/home.tsx"),
  route("posts/:postId", "routes/posts/post.tsx"), // [!code ++]
] satisfies RouteConfig;
```

Open [http://localhost:5173/posts/1](http://localhost:5173/posts/1) and [http://localhost:5173/posts/2](http://localhost:5173/posts/2). Then try [http://localhost:5173/posts/999](http://localhost:5173/posts/999): the template's root `ErrorBoundary` renders the 404.

## 6. Add a create page with an action [#6-add-a-create-page-with-an-action]

Create `app/routes/posts/new.tsx`. The `action` receives the form submission, inserts the post, and redirects to its detail page:

```tsx title="app/routes/posts/new.tsx"
import type { Route } from "./+types/new";
import { Form, redirect } from "react-router";
import { db } from "~/lib/db.server";

export async function action({ request }: Route.ActionArgs) {
  const formData = await request.formData();
  const title = String(formData.get("title") ?? "").trim();
  const content = String(formData.get("content") ?? "").trim();

  if (!title) {
    return { error: "Title is required" };
  }

  const post = await db.orm.public.Post.create({
    title,
    content: content || null,
    authorId: 1,
  });

  return redirect(`/posts/${post.id}`);
}

export default function NewPost({ actionData }: Route.ComponentProps) {
  return (
    <div className="max-w-2xl mx-auto p-4">
      <h1 className="text-2xl font-bold mb-6">Create New Post</h1>
      {actionData?.error && <p className="text-red-600 mb-4">{actionData.error}</p>}
      <Form method="post" className="space-y-6">
        <div>
          <label htmlFor="title" className="block text-lg mb-2">
            Title
          </label>
          <input
            type="text"
            id="title"
            name="title"
            placeholder="Enter your post title"
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
        <div>
          <label htmlFor="content" className="block text-lg mb-2">
            Content
          </label>
          <textarea
            id="content"
            name="content"
            placeholder="Write your post content here..."
            rows={6}
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
        <button type="submit" className="w-full bg-blue-500 text-white py-3 rounded-lg hover:bg-blue-600">
          Create Post
        </button>
      </Form>
    </div>
  );
}
```

`create` returns the inserted row with its generated `id`, `published: false` default, and timestamps, so the redirect target is known without another query. The post is attributed to user `1` (Alice from the seed) to keep the example short; a real app takes the author from the session.

Register the route. React Router ranks static segments above dynamic ones, so `/posts/new` reaches this route and not `posts/:postId`, whichever order you list them in:

```tsx title="app/routes.ts"
export default [
  index("routes/home.tsx"),
  route("posts", "routes/posts/home.tsx"),
  route("posts/:postId", "routes/posts/post.tsx"),
  route("posts/new", "routes/posts/new.tsx"), // [!code ++]
] satisfies RouteConfig;
```

Open [http://localhost:5173/posts/new](http://localhost:5173/posts/new) and submit the form, or post to it from the terminal:

```bash
curl -i -X POST http://localhost:5173/posts/new \
  --data-urlencode "title=Hello from curl" \
  --data-urlencode "content=Posted with a form action"
```

```text no-copy
HTTP/1.1 302
location: /posts/4
```

Follow the redirect and the new post renders with Alice as its author. Submitting without a title returns the page with the `Title is required` message instead.

## 7. Type-check and build [#7-type-check-and-build]

React Router's `typecheck` script generates the route types and runs `tsc` across the app, the seed script, and the Prisma files:

  

#### bun

```bash
bun run typecheck
```

#### pnpm

```bash
pnpm run typecheck
```

#### yarn

```bash
yarn typecheck
```

#### npm

```bash
npm run typecheck
```

A production build works the same way as before Prisma was added. `react-router build` bundles the server, and `react-router-serve` runs it on port 3000 (set `PORT` to change it):

  

#### bun

```bash
bun run build
bun run start
```

#### pnpm

```bash
pnpm run build
pnpm run start
```

#### yarn

```bash
yarn build
yarn run start
```

#### npm

```bash
npm run build
npm run start
```

```text no-copy
[react-router-serve] http://localhost:3000 (http://192.168.1.16:3000)
GET /posts 200 - - 7.514 ms
```

The server reads `DATABASE_URL` the same way the dev server does, through the `dotenv/config` import in `src/prisma/db.ts`, so a `.env` file next to the build is enough locally. On a host, set the variable in the environment instead.

## Common gotchas [#common-gotchas]

> [!WARNING]
> Keep the client out of the browser bundle. Import `db` from `~/lib/db.server` only in `loader`, `action`, or other server code. If a component or a shared module reaches it, the build stops with `Error: Server-only module referenced by client` from the `react-router:dot-server` plugin, naming the offending import. That is the `.server` suffix doing its job.

> [!WARNING]
> Do not call `db.close()` in a loader or action. The client in `src/prisma/db.ts` is a module-level singleton whose pool serves every request; closing it after one request breaks the next. Close it only in short scripts such as the seed.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add an edit page at `/posts/:postId/edit` whose action updates the post with `db.orm.public.Post.where({ id }).update(...)`."
* "Add a delete button to the post page that removes the post in an action and redirects to `/posts`."
* "Only list published posts on `/posts`, using a `where` predicate on `published`."
* "Add a `Comment` model to `src/prisma/contract.prisma`, emit the contract, plan a migration, and render comments under each post."

## Next steps [#next-steps]

* Change the schema in `src/prisma/contract.prisma`, then run `npx prisma contract emit` and `npx prisma db update`, or plan a checked-in migration with [`migration plan`](https://www.prisma.io/docs/cli/migration-plan). React Router builds on Vite, so the [Vite plugin](https://www.prisma.io/docs/cli/contract-emit#run-it-automatically) can run `contract emit` for you whenever the contract changes while the dev server runs.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins) covers `include` in depth.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.
* [React Router documentation](https://reactrouter.com/home) for loaders, actions, and routing.

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/frameworks/astro): Set up Prisma ORM in an Astro app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Elysia`](https://www.prisma.io/docs/guides/frameworks/elysia): Build an Elysia API on Prisma ORM with the elysia template and deploy it to Prisma Compute.
- [`Hono`](https://www.prisma.io/docs/guides/frameworks/hono): Build a Hono API on Prisma ORM with the hono template, add your own routes, and deploy it to Prisma Compute.
- [`NestJS`](https://www.prisma.io/docs/guides/frameworks/nestjs): Set up Prisma ORM in a NestJS app with create-prisma, from scaffold to seeded API to a live deploy on Prisma Compute.
- [`Next.js`](https://www.prisma.io/docs/guides/frameworks/nextjs): Set up Prisma ORM in a Next.js app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

# SolidStart (/docs/guides/frameworks/solid-start)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to a SolidStart app with orm init, seed a PostgreSQL database, serve users from an API route, and render them in a page.

Location: Guides > Frameworks > SolidStart

## Introduction [#introduction]

SolidStart is a full-stack framework for building reactive web apps with SolidJS. Its API routes and server functions run on the server, which is where you call Prisma ORM to read from a PostgreSQL database.

In this guide, you scaffold a SolidStart project, add Prisma ORM to it with `orm init`, initialize and seed a PostgreSQL database, serve users from an API route, and render them in a page with loading and error states. There is no `create-prisma` template for SolidStart, so this guide follows the add-to-an-existing-project path.

Every command, file, and response below was run end to end against a local PostgreSQL database.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/frameworks/solid-start](https://www.prisma.io/docs/guides/v7/frameworks/solid-start).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later (the SolidStart 2 template requires it)
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a new SolidStart app with Prisma ORM, seed it, and serve users from an API route and a page.

1. Scaffold: `npm init solid@latest my-solid-prisma-app -- -s --v2 -t basic --ts`. Delete the `pnpm-lock.yaml` the template ships (otherwise Prisma picks pnpm), then `cd my-solid-prisma-app` and run `npm install`.
2. Add Prisma ORM: `npx prisma@latest orm init --yes --target postgres --authoring psl`. Then run `npx prisma@latest init` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Write it to `.env` as `DATABASE_URL`.
3. Run `npx prisma db init` to create the tables from `src/prisma/contract.prisma`.
4. Add `src/prisma/seed.ts` that creates two users with posts through `db.orm.public.User.create` and `db.orm.public.Post.create`, closes with `await db.close()`, and run it once with `node src/prisma/seed.ts`.
5. Add `src/routes/api/users.ts` with a `GET` handler that returns `db.orm.public.User.include("posts").all()` as JSON, and replace `src/routes/index.tsx` with a page that loads the same query through a `"use server"` function wrapped in `query` and `createAsync`, with `<Suspense>` for loading and `<ErrorBoundary>` for errors, following https://www.prisma.io/docs/guides/frameworks/solid-start.md. Catch Prisma errors inside the server function and rethrow a plain `Error`.
6. Start `npm run dev` in the background, wait until it reports ready, verify `curl http://localhost:3000/api/users` returns the seeded users and `curl http://localhost:3000/` includes their names, then stop the dev server.
```

## 1. Scaffold the SolidStart project [#1-scaffold-the-solidstart-project]

Create a new SolidStart 2 project from the `basic` TypeScript template:

  

#### bun

```bash
bunx create-solid my-solid-prisma-app -s --v2 -t basic --ts
```

#### pnpm

```bash
pnpm create solid my-solid-prisma-app -s --v2 -t basic --ts
```

#### yarn

```bash
yarn create solid my-solid-prisma-app -s --v2 -t basic --ts
```

#### npm

```bash
npm init solid@latest my-solid-prisma-app -- -s --v2 -t basic --ts
```

```text no-copy
◇  Project created 🎉
◇  To get started, run: ───╮
│  cd my-solid-prisma-app  │
│  npm install             │
│  npm run dev             │
```

The flags skip the prompts: `-s` picks SolidStart, `--v2` picks the stable SolidStart 2 line, `-t basic` picks the template, and `--ts` picks TypeScript. Without them, the CLI asks the same questions interactively.

The template ships a `pnpm-lock.yaml`. Delete it before you continue if you use npm; otherwise `orm init` reads the lockfile and installs Prisma with pnpm:

```bash
cd my-solid-prisma-app
rm pnpm-lock.yaml
```

Install the dependencies:

  

#### bun

```bash
bun install
```

#### pnpm

```bash
pnpm install
```

#### yarn

```bash
yarn install
```

#### npm

```bash
npm install
```

This writes `package-lock.json`, so the next step picks npm.

## 2. Add Prisma ORM [#2-add-prisma-orm]

Run `orm init` from the project root. The flags preselect PostgreSQL and the Prisma Schema Language; drop `--yes` and `--authoring` to answer those questions interactively:

  

#### bun

```bash
bunx prisma@latest orm init --yes --target postgres --authoring psl
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### yarn

```bash
yarn dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### npm

```bash
npx prisma@latest orm init --yes --target postgres --authoring psl
```

```text no-copy
Updated tsconfig.json with required compiler options.
✔ npm add @prisma/orm-postgres dotenv
✔ npm add -D prisma@latest @types/node
✔ npm add -D @prisma/cli-engine@0.6.1
✔ Emit the contract
│  target:     postgres
│  authoring:  psl
│  schema:     src/prisma/contract.prisma
written
├─ src/prisma/contract.prisma
├─ prisma.config.ts
├─ src/prisma/db.ts
├─ prisma-8.md
├─ .env.example
├─ tsconfig.json
├─ .gitignore
├─ .gitattributes
└─ package.json
✔ Done. Open prisma-8.md to get started.
```

The command installs the runtime, writes the Prisma ORM files into the SolidStart project, and emits `src/prisma/contract.json` and `src/prisma/contract.d.ts`, the artifacts your queries are type-checked against. Three files matter for the rest of this guide:

* `src/prisma/contract.prisma`: a starter contract with `User` and `Post` models and a one-to-many relation between them
* `src/prisma/db.ts`: the Prisma ORM client, constructed once and imported by your routes
* `prisma.config.ts`: tells the CLI where the contract lives and reads `DATABASE_URL` from `.env`

The starter contract is the same shape the Prisma ORM 7 guide asked you to write by hand:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  username  String?
  name      String?
  posts     Post[]
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}
```

And the scaffolded client is all the wiring the app needs. There is no `prisma generate`, no generated client directory, and no driver adapter; the emitted contract and the runtime package replace all three:

```typescript title="src/prisma/db.ts"
import 'dotenv/config';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});
```

`orm init` also adds `"node"` to the `types` array and `resolveJsonModule` to `tsconfig.json` so the JSON contract import type-checks, and leaves the SolidStart settings (`jsx`, `jsxImportSource`, the `~/*` path alias) alone.

Now set the database connection. Copy `.env.example` to `.env` and replace the placeholder with your own PostgreSQL connection string, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database:

```bash title=".env"
DATABASE_URL="postgres://user:password@localhost:5432/mydb"
```

Both `prisma.config.ts` and `db.ts` import `dotenv/config`, so the CLI and the dev server read the same file.

## 3. Initialize the database [#3-initialize-the-database]

Create the tables the contract declares and sign the database:

  

#### bun

```bash
bunx prisma db init
```

#### pnpm

```bash
pnpm prisma db init
```

#### yarn

```bash
yarn prisma db init
```

#### npm

```bash
npx prisma db init
```

```text no-copy
✔ Introspecting database schema
✔ Planning migration
✔ Initialising database across spaces
│  contract:  src/prisma/contract.json
│  database:  postgres://****@localhost:5432/mydb

✔ Applied 5 operation(s) across 1 contract space

App space
├─ Create table "Post"
├─ Create table "User"
├─ Add unique constraint on "User" (email)
├─ Create index "Post_authorId_idx_e47547ed" on "Post"
├─ Add foreign key "Post_authorId_fkey" on "Post"
└─ marker 91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
```

`db init` replaces `prisma migrate dev` from Prisma ORM 7 for the first apply: it creates what is missing and records the contract hash in the database. Later schema changes go through [`db update`](https://www.prisma.io/docs/cli/db-update) for a direct development update or [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) for a checked-in migration. To confirm the database matches the contract at any time, run `npx prisma db verify`.

## 4. Seed the database [#4-seed-the-database]

Create `src/prisma/seed.ts`. It creates two users and their posts through the ORM API. `create()` returns the inserted row, so the user's `id` is available for the posts without a second query:

```typescript title="src/prisma/seed.ts"
import { db } from "./db.ts";

const users = [
  {
    name: "Alice",
    email: "alice@prisma.io",
    posts: [
      { title: "Join the Prisma Discord", content: "https://pris.ly/discord" },
      { title: "Prisma on YouTube", content: "https://pris.ly/youtube" },
    ],
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
    posts: [{ title: "Follow Prisma on Twitter", content: "https://www.twitter.com/prisma" }],
  },
];

async function main() {
  for (const { posts, ...user } of users) {
    const created = await db.orm.public.User.create(user);
    for (const post of posts) {
      await db.orm.public.Post.create({ ...post, authorId: created.id });
    }
    console.log(`Seeded ${created.email} with ${posts.length} post(s)`);
  }
  await db.close();
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
```

Node.js 24 runs TypeScript directly, so no extra tooling is needed. Run the script once:

```bash
node src/prisma/seed.ts
```

```text no-copy
Seeded alice@prisma.io with 2 post(s)
Seeded bob@prisma.io with 1 post(s)
```

Running it a second time fails on the unique `email` constraint, which is expected. The script closes the connection pool at the end because a one-off script would otherwise keep the process alive; the app's routes never do this.

## 5. Serve users from an API route [#5-serve-users-from-an-api-route]

SolidStart maps files under `src/routes/api/` to HTTP endpoints. Create `src/routes/api/users.ts`:

```typescript title="src/routes/api/users.ts"
import { db } from "~/prisma/db";

export async function GET() {
  const users = await db.orm.public.User.include("posts").all();
  return Response.json(users);
}
```

Model access is namespace-qualified on PostgreSQL, so the `User` model is `db.orm.public.User`. `.include("posts")` eager-loads the relation and `.all()` returns the rows as an array.

Start the dev server:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

```text no-copy
  VITE v8.3.1  ready in 5509 ms

  ➜  Local:   http://localhost:3000/
  ➜  Network: use --host to expose
```

Then request the route:

```bash
curl http://localhost:3000/api/users
```

```json no-copy
[
  {
    "createdAt": "2026-09-10 21:45:05.701722+06",
    "email": "alice@prisma.io",
    "id": 1,
    "name": "Alice",
    "updatedAt": "2026-09-10 21:45:04.523+06",
    "username": null,
    "posts": [
      { "authorId": 1, "content": "https://pris.ly/discord", "createdAt": "2026-09-10 21:45:05.875837+06", "id": 1, "title": "Join the Prisma Discord", "updatedAt": "2026-09-10 21:45:05.874+06" },
      { "authorId": 1, "content": "https://pris.ly/youtube", "createdAt": "2026-09-10 21:45:05.975729+06", "id": 2, "title": "Prisma on YouTube", "updatedAt": "2026-09-10 21:45:05.975+06" }
    ]
  },
  {
    "createdAt": "2026-09-10 21:45:05.980593+06",
    "email": "bob@prisma.io",
    "id": 2,
    "name": "Bob",
    "updatedAt": "2026-09-10 21:45:05.979+06",
    "username": null,
    "posts": [
      { "authorId": 2, "content": "https://www.twitter.com/prisma", "createdAt": "2026-09-10 21:45:05.984988+06", "id": 3, "title": "Follow Prisma on Twitter", "updatedAt": "2026-09-10 21:45:05.983+06" }
    ]
  }
]
```

The route handler is ordinary SolidStart code calling an ordinary Prisma ORM query; there is no framework adapter in between.

## 6. Render the users in a page [#6-render-the-users-in-a-page]

Replace `src/routes/index.tsx` with a page that loads the same query. The Prisma ORM 7 guide fetched the API route from the component with `fetch("http://localhost:3000/api/users")`. SolidStart renders pages on the server first, where a relative `fetch("/api/users")` fails with `Invalid URL` and an absolute one hard-codes your host, so the page calls the query through a server function instead. `query` from `@solidjs/router` caches and deduplicates it, and `createAsync` exposes the result to the component:

```typescript title="src/routes/index.tsx"
import { Title } from "@solidjs/meta";
import { createAsync, query } from "@solidjs/router";
import { ErrorBoundary, For, Suspense } from "solid-js";
import { db } from "~/prisma/db";

const getUsers = query(async () => {
  "use server";
  try {
    return await db.orm.public.User.include("posts").all();
  } catch (error) {
    console.error(error);
    throw new Error("Could not load users");
  }
}, "users");

export default function Home() {
  const users = createAsync(() => getUsers());

  return (
    <main>
      <Title>SolidStart + Prisma</Title>
      <h1>SolidStart + Prisma</h1>
      <ErrorBoundary fallback={<p>Error loading data</p>}>
        <Suspense fallback={<p>Loading...</p>}>
          <For each={users()}>
            {(user) => (
              <div>
                <h3>{user.name}</h3>
                <For each={user.posts}>{(post) => <p>{post.title}</p>}</For>
              </div>
            )}
          </For>
        </Suspense>
      </ErrorBoundary>
    </main>
  );
}
```

Three things to notice:

* `"use server"` keeps the Prisma query and the database connection on the server. The browser only receives the rows.
* The rows are typed by the contract: `user.name` and `user.posts` autocomplete without importing any generated types. The `User` and `Post` type imports from the Prisma ORM 7 guide are gone because `createAsync` infers the shape from the query.
* `<Suspense>` renders the loading state while the query runs and `<ErrorBoundary>` renders the error state if it throws. The `catch` block logs the real Prisma error on the server and throws a plain `Error` for the client; see the gotchas below for why.

Open [http://localhost:3000](http://localhost:3000) or request the page from the terminal:

```bash
curl http://localhost:3000/
```

The server-rendered HTML contains `<h3>Alice</h3>` and `<h3>Bob</h3>` with their post titles, streamed in after the `Loading...` fallback. Your SolidStart app now reads users and their posts from PostgreSQL through Prisma ORM, over both an API route and a server-rendered page.

## Common gotchas [#common-gotchas]

> [!WARNING]
> Don't call `db.close()` in API routes or server functions. The client in `src/prisma/db.ts` is constructed once and its connection pool is shared across requests; close it only in one-off scripts like the seed.

* **`orm init` installs with pnpm.** The SolidStart template ships a `pnpm-lock.yaml`, and `orm init` picks its package manager from the lockfile it finds. Delete that file before `npm install` (step 1), or use pnpm throughout.
* **`fetch("/api/users")` fails during server rendering.** Node.js has no origin to resolve a relative URL against, so the render throws `TypeError: Failed to parse URL from /api/users`. Load data through a `"use server"` function as in step 6; keep the API route for HTTP clients.
* **Rethrow a plain `Error` from server functions.** Prisma ORM throws structured errors that carry the SQL state, the failing statement, and a nested cause. When one of those crosses the server-to-browser boundary during server rendering, the page hangs on hydration instead of showing the `<ErrorBoundary>` fallback. Catching it and throwing `new Error("Could not load users")` keeps the fallback working and keeps database details out of the browser.
* **The first request after `npm run dev` can return a 503.** While Vite is still creating its server environment, a request may answer `Vite environment "ssr" is unavailable`. Wait a second and retry; every request after that succeeds.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages:

  

#### bun

```bash
bunx --bun prisma@latest init
```

#### pnpm

```bash
pnpm dlx prisma@latest init
```

#### yarn

```bash
yarn dlx prisma@latest init
```

#### npm

```bash
npx prisma@latest init
```

```text no-copy
✔ Added "postinstall": "prisma skills sync || exit 0" to package.json.
⚠ prisma.config.ts already exists; left untouched.
✔ Synced 3 skills.

project:  ~/my-solid-prisma-app
check:    enabled

Skill                          Package               Version      Installed into
prisma-8                       @prisma/orm-postgres  8.0.0-rc.13  .claude/skills, .cursor/skills, .agents/skills, .devin/skills
prisma-composer-core-concepts  @prisma/composer      0.23.0       .claude/skills, .cursor/skills, .agents/skills, .devin/skills
prisma-platform-core-concepts  prisma                8.0.0-rc.17  .claude/skills, .cursor/skills, .agents/skills, .devin/skills

⚠ [INIT.CONFIG_KEPT] prisma.config.ts already exists, so init left it alone instead of writing the skills section.
→ Add skills: { agents: ["claude", "cursor", "agents", "devin"] } to the object passed to definePrismaConfig in prisma.config.ts.
```

Prompts that map to this guide:

* "Using the prisma-8 skill, add `GET /api/users/:id` that returns one user with posts or a 404."
* "Add a `POST /api/users` route that creates a user from the request body with `db.orm.public.User.create`."
* "Turn the user list into a form that creates a post through a SolidStart `action` and revalidates the `users` query."

## Next steps [#next-steps]

* Change the schema in `src/prisma/contract.prisma`, then run `npx prisma contract emit` and `npx prisma db update`. SolidStart builds on Vite, so the [Vite plugin](https://www.prisma.io/docs/cli/contract-emit#run-it-automatically) can run `contract emit` for you whenever the contract changes while the dev server runs.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.
* [SolidStart documentation](https://start.solidjs.com/) for routing, server functions, and deployment presets.

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/frameworks/astro): Set up Prisma ORM in an Astro app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Elysia`](https://www.prisma.io/docs/guides/frameworks/elysia): Build an Elysia API on Prisma ORM with the elysia template and deploy it to Prisma Compute.
- [`Hono`](https://www.prisma.io/docs/guides/frameworks/hono): Build a Hono API on Prisma ORM with the hono template, add your own routes, and deploy it to Prisma Compute.
- [`NestJS`](https://www.prisma.io/docs/guides/frameworks/nestjs): Set up Prisma ORM in a NestJS app with create-prisma, from scaffold to seeded API to a live deploy on Prisma Compute.
- [`Next.js`](https://www.prisma.io/docs/guides/frameworks/nextjs): Set up Prisma ORM in a Next.js app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

# SvelteKit (/docs/guides/frameworks/sveltekit)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up Prisma ORM in a SvelteKit app with create-prisma, from scaffold to rendered data.

Location: Guides > Frameworks > SvelteKit

## Introduction [#introduction]

This guide shows you how to use Prisma ORM in a SvelteKit app. You scaffold a project where a server load function queries your database, initialize the schema, and see your data render.

Every command below was run end to end against a live [Prisma Postgres](https://www.prisma.io/docs/postgres) database.

## Quick start [#quick-start]

One command scaffolds the project with Prisma ORM wired in:

  

#### bun

```bash
bun create prisma@latest my-app --template svelte --provider postgres --no-deploy
```

#### pnpm

```bash
pnpm create prisma@latest my-app --template svelte --provider postgres --no-deploy
```

#### yarn

```bash
yarn create prisma@latest my-app --template svelte --provider postgres --no-deploy
```

#### npm

```bash
npm create prisma@latest -- my-app --template svelte --provider postgres --no-deploy
```

Answer the prompts, then export `DATABASE_URL` in your shell before running the database scripts. If you do not have a database yet, `npx create-db@latest` prints a Prisma Postgres connection string.

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 22.18 or newer (on the 24 line, 24.11 or newer; 24 recommended)
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a Prisma Postgres database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a new SvelteKit app with Prisma ORM, seed it, and verify the page renders.

1. Scaffold: `npm create prisma@latest -- my-app --template svelte --provider postgres --yes`. Then run `npx prisma@latest init` in `my-app` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
2. In `my-app`, run `npm run db:init` with `DATABASE_URL` exported. Sample users are seeded automatically on the app's first query; there is no separate seed script.
3. Do not deploy to Prisma Compute; it does not support SvelteKit yet. Start `npm run dev` in the background, wait until it reports ready, verify http://localhost:5173 lists the three seeded users, then stop the dev server, following https://www.prisma.io/docs/guides/frameworks/sveltekit.md.

Use the installed Prisma ORM skills.
```

## 1. Scaffold and enter the project [#1-scaffold-and-enter-the-project]

  

#### bun

```bash
bun create prisma@latest my-app --template svelte --provider postgres --no-deploy
cd my-app
```

#### pnpm

```bash
pnpm create prisma@latest my-app --template svelte --provider postgres --no-deploy
cd my-app
```

#### yarn

```bash
yarn create prisma@latest my-app --template svelte --provider postgres --no-deploy
cd my-app
```

#### npm

```bash
npm create prisma@latest -- my-app --template svelte --provider postgres --no-deploy
cd my-app
```

The scaffold generates the SvelteKit app with Prisma ORM wired in, installs dependencies, and emits the contract your queries are type-checked against.

Next, set the database connection. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the generated scripts read the environment variable, not `.env`:

```bash
export DATABASE_URL="<your connection string>"
```

## 2. Initialize the database [#2-initialize-the-database]

  

#### bun

```bash
bun run db:init
```

#### pnpm

```bash
pnpm run db:init
```

#### yarn

```bash
yarn db:init
```

#### npm

```bash
npm run db:init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Applied 0 operation(s)` when there is nothing left to do.

`db:init` applies your schema (`src/prisma/contract.prisma`) to the database and signs it. With TypeScript authoring (`--authoring typescript`) the schema is `src/prisma/contract.ts` and the emitted files land in `src/prisma/generated/`. Sample users are seeded automatically the first time the app queries the database.

## 3. Run and verify [#3-run-and-verify]

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open [http://localhost:5173](http://localhost:5173). The page lists the seeded users, loaded on the server by the `+page.server.ts` load function.

## Where things live [#where-things-live]

* `src/routes/+page.server.ts`: the server `load` function that fetches users
* `src/routes/+page.svelte`: the page that renders them
* `src/prisma/users.ts`: the `listUsers` query helper the load function imports
* `src/prisma/db.ts`: the Prisma ORM client behind that helper

Model access is namespace-qualified on PostgreSQL: `db.orm.public.User`. The [Prisma ORM overview](https://www.prisma.io/docs/orm) covers the contract-first model behind it.

[Prisma Compute](https://www.prisma.io/docs/compute) does not support SvelteKit deployments yet; see [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy) for what is currently supported. In the meantime, the app deploys to SvelteKit's usual hosts through its standard adapters.

## Next steps [#next-steps]

* Change the schema in `src/prisma/contract.prisma`, then run `npm run contract:emit` and `npm run db:update`.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/frameworks/astro): Set up Prisma ORM in an Astro app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Elysia`](https://www.prisma.io/docs/guides/frameworks/elysia): Build an Elysia API on Prisma ORM with the elysia template and deploy it to Prisma Compute.
- [`Hono`](https://www.prisma.io/docs/guides/frameworks/hono): Build a Hono API on Prisma ORM with the hono template, add your own routes, and deploy it to Prisma Compute.
- [`NestJS`](https://www.prisma.io/docs/guides/frameworks/nestjs): Set up Prisma ORM in a NestJS app with create-prisma, from scaffold to seeded API to a live deploy on Prisma Compute.
- [`Next.js`](https://www.prisma.io/docs/guides/frameworks/nextjs): Set up Prisma ORM in a Next.js app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

# TanStack Start (/docs/guides/frameworks/tanstack-start)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up Prisma ORM in a TanStack Start app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

Location: Guides > Frameworks > TanStack Start

## Introduction [#introduction]

This guide shows you how to use Prisma ORM in a TanStack Start app. You scaffold a project where a server function queries your database and a route loader feeds it to the page, initialize the schema, see your data, and deploy the app to [Prisma Compute](https://www.prisma.io/docs/compute).

Every command below was run end to end against a live [Prisma Postgres](https://www.prisma.io/docs/postgres) database.

## Quick start [#quick-start]

One command scaffolds the project with Prisma ORM wired in:

  

#### bun

```bash
bun create prisma@latest my-app --template tanstack-start --provider postgres --no-deploy
```

#### pnpm

```bash
pnpm create prisma@latest my-app --template tanstack-start --provider postgres --no-deploy
```

#### yarn

```bash
yarn create prisma@latest my-app --template tanstack-start --provider postgres --no-deploy
```

#### npm

```bash
npm create prisma@latest -- my-app --template tanstack-start --provider postgres --no-deploy
```

Answer the prompts, then export `DATABASE_URL` in your shell before running the database scripts. If you do not have a database yet, `npx create-db@latest` prints a Prisma Postgres connection string.

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 22.18 or newer (on the 24 line, 24.11 or newer; 24 recommended)
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a Prisma Postgres database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a new TanStack Start app with Prisma ORM, seed it, and deploy it to Prisma Compute.

1. Scaffold: `npm create prisma@latest -- my-app --template tanstack-start --provider postgres --yes`. Then run `npx prisma@latest init` in `my-app` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
2. In `my-app`, run `npm run db:init` with `DATABASE_URL` exported. Sample users are seeded automatically on the app's first query; there is no separate seed script.
3. Start `npm run dev` in the background, wait until it reports ready, verify http://localhost:3000 renders the three seeded users, then stop the dev server.
4. Deploy: check `npx prisma auth whoami`; if I am not signed in, stop and ask me to run `npx prisma auth login`. Then run `npm run build` followed by `npx prisma deploy module.ts` and verify the live URL renders the seeded users. The deployed app provisions and seeds its own Prisma Postgres database; do not pass the local DATABASE_URL. If the deploy fails with `HostedStateBootstrapError`, a project with the module's name exists in my workspace but its hosted state cannot be verified; re-run the deploy with `--name <a unique name>`.
```

## 1. Scaffold and enter the project [#1-scaffold-and-enter-the-project]

  

#### bun

```bash
bun create prisma@latest my-app --template tanstack-start --provider postgres --no-deploy
cd my-app
```

#### pnpm

```bash
pnpm create prisma@latest my-app --template tanstack-start --provider postgres --no-deploy
cd my-app
```

#### yarn

```bash
yarn create prisma@latest my-app --template tanstack-start --provider postgres --no-deploy
cd my-app
```

#### npm

```bash
npm create prisma@latest -- my-app --template tanstack-start --provider postgres --no-deploy
cd my-app
```

The scaffold generates the TanStack Start app with Prisma ORM wired in, installs dependencies, and emits the contract your queries are type-checked against.

Next, set the database connection for the local steps. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the generated scripts read the environment variable, not `.env`:

```bash
export DATABASE_URL="<your connection string>"
```

## 2. Initialize the database [#2-initialize-the-database]

  

#### bun

```bash
bun run db:init
```

#### pnpm

```bash
pnpm run db:init
```

#### yarn

```bash
yarn db:init
```

#### npm

```bash
npm run db:init
```

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Applied 0 operation(s)` when there is nothing left to do.

`db:init` applies your schema (`src/prisma/contract.prisma`) to the database and signs it. With TypeScript authoring (`--authoring typescript`) the schema is `src/prisma/contract.ts` and the emitted files land in `src/prisma/generated/`. Sample users are seeded automatically the first time the app queries the database.

## 3. Run and verify [#3-run-and-verify]

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open [http://localhost:3000](http://localhost:3000). The page lists the seeded users, provided by the route loader's server function.

## 4. Deploy to Prisma Compute [#4-deploy-to-prisma-compute]

TanStack Start is supported on [Prisma Compute](https://www.prisma.io/docs/compute). The scaffold builds with Nitro (the `nitro()` Vite plugin ships in `vite.config.ts`) and declares the app for [Prisma Composer](https://www.prisma.io/docs/composer) in `module.ts` and `service.ts`, pointing at Nitro's `.output` directory. Deploying is building and handing that declaration to the CLI. Sign in once (it opens a browser):

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

Then build and deploy from the project directory:

  

#### bun

```bash
bun run build
bunx prisma deploy module.ts
```

#### pnpm

```bash
pnpm run build
pnpm prisma deploy module.ts
```

#### yarn

```bash
yarn build
yarn prisma deploy module.ts
```

#### npm

```bash
npm run build
npx prisma deploy module.ts
```

```text no-copy
my-app
├─ database   postgres-database db_abc123
└─ app        compute-service cps_abc123
              https://xyz.ewr.prisma.build
```

Open the live URL: the page renders the seeded users. The deploy creates a project named after your module in your workspace, and re-running the deploy reuses it: the CLI finds the hosted state it stored on the first run and converges the project to your module. If a project with that name exists but the CLI cannot identify or verify its stored state (one left behind by a different checkout, for example), the deploy stops with `HostedStateBootstrapError`; deploy under another name with `--name <unique-name>`, or rename the module in `module.ts`. The deploy also provisions its own Prisma Postgres database on the platform, declared in `module.ts`; the `DATABASE_URL` from your local steps is not involved, and the deployed database seeds on the app's first query. For previews per Git branch and deploy on push, see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

## Where things live [#where-things-live]

* `src/routes/index.tsx`: the route: a `createServerFn` queries users, the loader passes them to the page
* `src/prisma/users.ts`: the query helper the server function calls
* `src/prisma/db.ts`: the Prisma ORM client behind it

Model access is namespace-qualified on PostgreSQL: `db.orm.public.User`. The [Prisma ORM overview](https://www.prisma.io/docs/orm) covers the contract-first model behind it.

## Next steps [#next-steps]

* Change the schema in `src/prisma/contract.prisma`, then run `npm run contract:emit` and `npm run db:update`. TanStack Start builds on Vite, so the [Vite plugin](https://www.prisma.io/docs/cli/contract-emit#run-it-automatically) can run `contract emit` for you whenever the contract changes while the dev server runs.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/frameworks/astro): Set up Prisma ORM in an Astro app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.
- [`Elysia`](https://www.prisma.io/docs/guides/frameworks/elysia): Build an Elysia API on Prisma ORM with the elysia template and deploy it to Prisma Compute.
- [`Hono`](https://www.prisma.io/docs/guides/frameworks/hono): Build a Hono API on Prisma ORM with the hono template, add your own routes, and deploy it to Prisma Compute.
- [`NestJS`](https://www.prisma.io/docs/guides/frameworks/nestjs): Set up Prisma ORM in a NestJS app with create-prisma, from scaffold to seeded API to a live deploy on Prisma Compute.
- [`Next.js`](https://www.prisma.io/docs/guides/frameworks/nextjs): Set up Prisma ORM in a Next.js app with create-prisma, from scaffold to rendered data, and deploy it to Prisma Compute.

# AI SDK (with Next.js) (/docs/guides/integrations/ai-sdk)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Build a chat application with AI SDK, Prisma ORM, and Next.js that stores chat sessions and messages in Prisma Postgres.

Location: Guides > Integrations > AI SDK (with Next.js)

## Introduction [#introduction]

[AI SDK](https://ai-sdk.dev/) streams model responses to the browser, and a [Next.js](https://nextjs.org/) route handler gives you a place to persist each exchange with Prisma ORM, so a conversation survives page reloads.

In this guide, you scaffold a Next.js app with Prisma ORM, define a contract for chat sessions and messages, save every completed exchange from the AI SDK route handler, and load a session back into the UI when the page opens.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/integrations/ai-sdk](https://www.prisma.io/docs/guides/v7/integrations/ai-sdk).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* An [OpenAI API key](https://platform.openai.com/api-keys)
* A PostgreSQL connection string, or nothing at all: `npx create-db@latest` can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Build a Next.js chat app with AI SDK that stores chat sessions and messages with Prisma ORM, following https://www.prisma.io/docs/guides/integrations/ai-sdk.md.

1. Scaffold: `npx create-prisma@latest create ai-sdk-prisma --template next --provider postgres --yes`. Then run `npx prisma@latest init` in `ai-sdk-prisma` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `npx create-db@latest` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the Prisma CLI reads the environment variable, not `.env`.
2. Replace `src/prisma/contract.prisma` with the `Session` and `Message` models from the guide (a `MessageRole` enum, `parts` stored as `Json`, `position` for ordering, `onDelete: Cascade` on the relation). Delete the starter files the template generated for its own schema: `src/prisma/users.ts`, `src/prisma/seed.ts`, and the `migrations/` directory. Run `npm run contract:emit` and then `npm run db:init` with `DATABASE_URL` exported.
3. Install `ai`, `@ai-sdk/react`, and `@ai-sdk/openai`. Put `OPENAI_API_KEY` and `DATABASE_URL` in `.env`.
4. Create `src/prisma/chat.ts` with `saveChat(id, messages)` (upsert the session, then upsert each message by id inside `db.transaction`) and `loadChat(id)` (messages for a session ordered by `position`), `src/app/api/chat/route.ts` (streamText with `openai("gpt-5.1")`, `toUIMessageStream` with `originalMessages`, `generateMessageId`, and an `onEnd` that calls `saveChat`), `src/app/api/messages/route.ts` (GET, `?chat=<id>`), a server `src/app/page.tsx` that redirects to `/?chat=<generateId()>` when the id is missing, and a client `src/app/chat.tsx` built on `useChat({ id })` that fetches `/api/messages` on mount.
5. Run `npx tsc --noEmit` and `npm run build`. Start `npm run dev` in the background, open http://localhost:3000, send a message, reload the page, and confirm the conversation is still there. Stop the dev server when done.
```

## 1. Scaffold the project [#1-scaffold-the-project]

The `next` template generates a Next.js app with Prisma ORM already wired in: the contract, the client in `src/prisma/db.ts`, and package scripts for the database steps. That replaces the `create-next-app`, `prisma init`, driver adapter, and `prisma generate` steps of the Prisma ORM 7 guide.

  

#### bun

```bash
bunx create-prisma@latest create ai-sdk-prisma --template next --provider postgres --no-deploy
cd ai-sdk-prisma
```

#### pnpm

```bash
pnpm dlx create-prisma@latest create ai-sdk-prisma --template next --provider postgres --no-deploy
cd ai-sdk-prisma
```

#### yarn

```bash
yarn dlx create-prisma@latest create ai-sdk-prisma --template next --provider postgres --no-deploy
cd ai-sdk-prisma
```

#### npm

```bash
npx create-prisma@latest create ai-sdk-prisma --template next --provider postgres --no-deploy
cd ai-sdk-prisma
```

Answer the prompts for contract authoring style (this guide uses PSL), package manager, and agent skills. The scaffold installs dependencies and emits the contract your queries are type-checked against.

Next, set the database connection for the CLI steps. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `npx create-db@latest`; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the Prisma CLI reads the environment variable, not `.env`:

```bash
export DATABASE_URL="<your connection string>"
```

## 2. Define the data contract [#2-define-the-data-contract]

The template ships a `User` and `Post` starter schema. Replace the whole of `src/prisma/contract.prisma` with the chat models:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

enum MessageRole {
  @@type("pg/text@1")
  user      = "user"
  assistant = "assistant"
}

model Session {
  id        String            @id
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
  messages  Message[]
}

model Message {
  id        String            @id
  role      MessageRole
  parts     Json
  position  Int
  createdAt TimestamptzString @default(now())
  sessionId String
  session   Session           @relation(fields: [sessionId], references: [id], onDelete: Cascade)
}
```

A few things to note:

* `Session.id` and `Message.id` have no default. AI SDK generates a chat id on the client and stable message ids on the server, and you store those.
* `MessageRole` is a Prisma ORM enum: it is stored as `text` and enforced with a `CHECK` constraint. The values match AI SDK's `role` strings, so you can save `message.role` as is.
* `parts` is `Json`. AI SDK messages carry an array of parts (text, reasoning, tool calls), and storing it verbatim means the UI can render a saved message exactly like a live one.
* `position` records where a message sits in the conversation, so `loadChat` can return messages in order.

The template also generated a seed helper and an initial migration for the starter schema. Remove them so nothing references models that no longer exist:

```bash
rm src/prisma/users.ts src/prisma/seed.ts
rm -r migrations
```

Emit the contract and initialize the database:

  

#### bun

```bash
bun run contract:emit
bun run db:init
```

#### pnpm

```bash
pnpm run contract:emit
pnpm run db:init
```

#### yarn

```bash
yarn contract:emit
yarn db:init
```

#### npm

```bash
npm run contract:emit
npm run db:init
```

```text no-copy
"summary": "Applied 4 operation(s) across 1 space(s), database signed"
```

`contract:emit` regenerates `src/prisma/contract.json` and `src/prisma/contract.d.ts`, which is where your query types come from. `db:init` creates the `session` and `message` tables, the index on `sessionId`, and the cascading foreign key, then signs the database. There is no separate `generate` step and no client to instantiate: `src/prisma/db.ts` already exports `db`, and its types follow the contract you just emitted.

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again.

## 3. Install AI SDK and set your API key [#3-install-ai-sdk-and-set-your-api-key]

  

#### bun

```bash
bun add ai @ai-sdk/react @ai-sdk/openai
```

#### pnpm

```bash
pnpm add ai @ai-sdk/react @ai-sdk/openai
```

#### yarn

```bash
yarn add ai @ai-sdk/react @ai-sdk/openai
```

#### npm

```bash
npm install ai @ai-sdk/react @ai-sdk/openai
```

Add your OpenAI API key to `.env`. Put `DATABASE_URL` there too: `next dev` and `next build` load `.env`, so the app finds both values without the shell export. The Prisma CLI does not read `.env`, which is why you still export `DATABASE_URL` for `db:init` and the other `prisma` commands.

```bash title=".env"
DATABASE_URL="<your connection string>"
OPENAI_API_KEY="<your OpenAI API key>"
```

## 4. Save and load chats with Prisma ORM [#4-save-and-load-chats-with-prisma-orm]

Create `src/prisma/chat.ts` with two functions: `saveChat` persists a session and its messages, and `loadChat` reads them back in order.

```typescript title="src/prisma/chat.ts"
import type { JsonValue } from "@prisma/orm-postgres/target/codec-types";
import type { UIMessage } from "ai";

import { db } from "./db.ts";

export async function saveChat(id: string, messages: UIMessage[]) {
  await db.transaction(async (tx) => {
    await tx.orm.public.Session.upsert({
      create: { id },
      update: {},
      conflictOn: { id },
    });

    for (const [position, message] of messages.entries()) {
      if (message.role !== "user" && message.role !== "assistant") continue;

      await tx.orm.public.Message.upsert({
        create: {
          id: message.id,
          sessionId: id,
          role: message.role,
          parts: message.parts as JsonValue,
          position,
        },
        update: { parts: message.parts as JsonValue, position },
        conflictOn: { id: message.id },
      });
    }
  });
}

export async function loadChat(id: string): Promise<UIMessage[]> {
  const rows = await db.orm.public.Message.select("id", "role", "parts")
    .where({ sessionId: id })
    .orderBy((m) => m.position.asc())
    .all();

  return rows.map((row) => ({
    id: row.id,
    role: row.role,
    parts: row.parts as UIMessage["parts"],
  }));
}
```

How it works:

* Model access is namespace-qualified on PostgreSQL: `db.orm.public.Session`, not `db.session`. `db.transaction` hands you a `tx` with the same `orm` surface, and everything inside it commits together or not at all.
* `upsert` takes `create`, `update`, and `conflictOn`. AI SDK sends the whole conversation with every request, so upserting each message by its id keeps saves idempotent: messages that already exist are left alone, and the new user and assistant messages are inserted.
* `message.parts` is typed by AI SDK as an array of part objects. The `as JsonValue` cast tells Prisma ORM to store it in the `Json` column; the reverse cast in `loadChat` hands it back to AI SDK as `UIMessage["parts"]`.
* `.select("id", "role", "parts")` narrows the returned row type to the fields the UI needs, and `.orderBy((m) => m.position.asc())` restores conversation order.

## 5. Create the chat route handler [#5-create-the-chat-route-handler]

The route handler streams the model response to the browser and, once the stream ends, saves the full conversation:

```bash
mkdir -p src/app/api/chat
```

```typescript title="src/app/api/chat/route.ts"
import { openai } from "@ai-sdk/openai";
import {
  convertToModelMessages,
  createIdGenerator,
  createUIMessageStreamResponse,
  streamText,
  toUIMessageStream,
  type UIMessage,
} from "ai";

import { saveChat } from "../../../prisma/chat";

export const maxDuration = 300;

export async function POST(req: Request) {
  const { messages, id }: { messages: UIMessage[]; id: string } = await req.json();

  const result = streamText({
    model: openai("gpt-5.1"),
    messages: await convertToModelMessages(messages),
  });

  return createUIMessageStreamResponse({
    stream: toUIMessageStream({
      stream: result.stream,
      originalMessages: messages,
      generateMessageId: createIdGenerator({ prefix: "msg", size: 16 }),
      onEnd: async ({ messages }) => {
        await saveChat(id, messages);
      },
    }),
  });
}
```

This handler:

1. Reads the conversation and the chat `id` that `useChat` sends in the request body.
2. Converts the UI messages to model messages and streams the response.
3. Passes `originalMessages` so `onEnd` receives the whole conversation, including the new assistant message, and saves it with `saveChat`.

`generateMessageId` gives the assistant message a stable id on the server before it is stored. Without it the id is empty, and every assistant message in a session would collide on the primary key.

## 6. Create the messages API route [#6-create-the-messages-api-route]

The UI calls this route on load to restore a session:

```bash
mkdir -p src/app/api/messages
```

```typescript title="src/app/api/messages/route.ts"
import { NextResponse } from "next/server";

import { loadChat } from "../../../prisma/chat";

export async function GET(req: Request) {
  const id = new URL(req.url).searchParams.get("chat");
  if (!id) {
    return NextResponse.json({ error: "Missing chat id" }, { status: 400 });
  }

  const messages = await loadChat(id);
  return NextResponse.json({ messages });
}
```

## 7. Build the UI [#7-build-the-ui]

The page is a server component. It reads the chat id from the URL, creates one when it is missing, and renders the chat component. Replace `src/app/page.tsx`:

```tsx title="src/app/page.tsx"
import { generateId } from "ai";
import { redirect } from "next/navigation";

import Chat from "./chat";

export default async function Page({
  searchParams,
}: {
  searchParams: Promise<{ chat?: string }>;
}) {
  const { chat } = await searchParams;
  if (!chat) redirect(`/?chat=${generateId()}`);

  return <Chat id={chat} />;
}
```

Keeping the id in the URL is what makes a session survive a reload: the same URL loads the same session.

The chat component is a client component. `useChat({ id })` sends that id with every request, and the `useEffect` loads any saved messages into the hook when the component mounts. Create `src/app/chat.tsx`:

```tsx title="src/app/chat.tsx"
"use client";

import { useChat } from "@ai-sdk/react";
import type { UIMessage } from "ai";
import { useEffect, useState } from "react";

export default function Chat({ id }: { id: string }) {
  const [input, setInput] = useState("");
  const [loading, setLoading] = useState(true);
  const { messages, sendMessage, setMessages } = useChat({ id });

  useEffect(() => {
    fetch(`/api/messages?chat=${id}`)
      .then((res) => res.json())
      .then((data: { messages: UIMessage[] }) => {
        if (data.messages.length > 0) setMessages(data.messages);
        setLoading(false);
      })
      .catch(() => setLoading(false));
  }, [id, setMessages]);

  if (loading) return <p className="empty">Loading...</p>;

  return (
    <main className="shell chat">
      {messages.map((message) => (
        <div key={message.id} className={`bubble ${message.role}`}>
          <p className="eyebrow">{message.role === "user" ? "You" : "AI"}</p>
          {message.parts.map((part, i) =>
            part.type === "text" ? <div key={`${message.id}-${i}`}>{part.text}</div> : null,
          )}
        </div>
      ))}

      <form
        onSubmit={(e) => {
          e.preventDefault();
          if (!input.trim()) return;
          sendMessage({ text: input });
          setInput("");
        }}
      >
        <input
          className="composer"
          value={input}
          placeholder="Say something..."
          onChange={(e) => setInput(e.currentTarget.value)}
        />
      </form>
    </main>
  );
}
```

The template does not include Tailwind, so add a few rules to the end of `src/app/globals.css` for the bubbles and the input:

```css title="src/app/globals.css"
.chat {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding-bottom: 6rem;
}

.bubble {
  max-width: 80%;
  border-radius: 0.5rem;
  padding: 0.75rem 1rem;
  white-space: pre-wrap;
  background: #f0f0f0;
  align-self: flex-start;
}

.bubble.user {
  background: #111;
  color: #fff;
  align-self: flex-end;
}

.bubble .eyebrow {
  color: inherit;
  opacity: 0.6;
}

.composer {
  position: fixed;
  bottom: 2rem;
  left: 50%;
  width: min(40rem, calc(100% - 3rem));
  transform: translateX(-50%);
  padding: 0.75rem;
  border: 1px solid #ccc;
  border-radius: 0.5rem;
  font: inherit;
}
```

## 8. Run and verify [#8-run-and-verify]

Check the types first, then start the dev server:

  

#### bun

```bash
bunx tsc --noEmit
bun run dev
```

#### pnpm

```bash
pnpm tsc --noEmit
pnpm run dev
```

#### yarn

```bash
yarn tsc --noEmit
yarn dev
```

#### npm

```bash
npx tsc --noEmit
npm run dev
```

```text no-copy
▲ Next.js 16.1.6 (Turbopack)
- Local:         http://localhost:3000
- Environments: .env

✓ Ready in 5.5s
```

Open [http://localhost:3000](http://localhost:3000). The page redirects to `/?chat=<id>`, and the first request compiles the app, so it takes a few seconds. Send a message, wait for the reply, then reload the page: both messages come back from the database.

You can also read a session directly from the API. Replace the id with the one in your address bar. The session below was captured with AI SDK's mock language model instead of a live OpenAI call, which is why the assistant text reads the way it does; the persistence path is the same:

```bash
curl "http://localhost:3000/api/messages?chat=<id>"
```

```json no-copy
{"messages":[{"id":"user-1789055570091","role":"user","parts":[{"type":"text","text":"Hello from the mock test"}]},{"id":"msg-abc123def456","role":"assistant","parts":[{"type":"step-start"},{"type":"text","text":"Hi! I am a mock model.","state":"done"}]}]}
```

A session that has no messages yet returns `{"messages":[]}`, and a request without `?chat=` returns a `400`.

Finally, make sure the production build passes:

  

#### bun

```bash
bun run build
```

#### pnpm

```bash
pnpm run build
```

#### yarn

```bash
yarn build
```

#### npm

```bash
npm run build
```

```text no-copy
✓ Compiled successfully in 30.9s

Route (app)
┌ ƒ /
├ ○ /_not-found
├ ƒ /api/chat
└ ƒ /api/messages
```

## Where things live [#where-things-live]

* `src/prisma/contract.prisma`: your schema. Edit it, then run `npm run contract:emit` and `npm run db:update`.
* `src/prisma/db.ts`: the Prisma ORM client the template generated. It is a module-level singleton, so its connection pool is shared across requests.
* `src/prisma/chat.ts`: the two functions that touch the database.
* `src/app/api/chat/route.ts` and `src/app/api/messages/route.ts`: the write path and the read path.

## Common gotchas [#common-gotchas]

> [!WARNING]
> If the model reply is `An error occurred.` and the server log shows `AI_LoadAPIKeyError: OpenAI API key is missing`, `OPENAI_API_KEY` is not in `.env`. The route handler returns a `200` with the error inside the stream, so check the terminal running `next dev` rather than the network tab.

> [!WARNING]
> Do not call `db.close()` in a route handler. The client in `src/prisma/db.ts` lives for the whole process and its pool is shared across requests; close it only on process shutdown.

* `db:init` and the other `prisma` scripts read `DATABASE_URL` from the environment, while Next.js reads `.env`. If a Prisma command reports a missing connection string, export the variable in that shell.
* If you keep the template's `migrations/` directory and later run `npm run migration:plan`, the plan starts from the starter `User` and `Post` schema instead of from an empty database. Delete the directory before your first emit, as in step 2, and run `npx prisma migration plan --name init` when you want a checked-in migration for your own contract.
* `parts` needs the `as JsonValue` cast on the way in. AI SDK types the parts array with interfaces, and Prisma ORM's `Json` input type wants plain JSON values; the cast is safe because the parts are serializable objects.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add a `title` field to `Session` and a `PATCH /api/sessions/:id` route that updates it."
* "Add a `GET /api/sessions` route that lists sessions with their message count, using `include` with a `count()` reducer."
* "Add a `DELETE /api/sessions/:id` route and confirm the cascade removes the session's messages."

## Next steps [#next-steps]

* [Deploy the app to Prisma Compute](https://www.prisma.io/docs/guides/frameworks/nextjs#4-deploy-to-prisma-compute): the template already declares it in `module.ts` and `service.ts`.
* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.
* [AI SDK documentation](https://ai-sdk.dev/docs/ai-sdk-ui/chatbot-message-persistence) on message persistence, including sending only the last message and handling client disconnects.

## Related pages

- [`Datadog`](https://www.prisma.io/docs/guides/integrations/datadog): Learn how to configure Datadog tracing for a Prisma ORM project. Capture spans for every query using the @prisma/instrumentation package, dd-trace, and view them in Datadog
- [`Embedded Prisma Studio (with Next.js)`](https://www.prisma.io/docs/guides/integrations/embed-studio): Learn how to embed Prisma Studio directly in your Next.js application for database management
- [`GitHub Actions`](https://www.prisma.io/docs/guides/integrations/github-actions): Provision a Prisma Postgres database for every pull request with GitHub Actions and the Prisma CLI, apply your migrations and seed data to it, and delete it when the pull request closes.
- [`Permit.io`](https://www.prisma.io/docs/guides/integrations/permit-io): Learn how to implement access control with Prisma ORM with Permit.io
- [`pgfence`](https://www.prisma.io/docs/guides/integrations/pgfence): Analyze Prisma Migrate SQL files for dangerous lock patterns, risk levels, and safe rewrite recipes before deploying to production

# Datadog (/docs/guides/integrations/datadog)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to configure Datadog tracing for a Prisma ORM project. Capture spans for every query using the @prisma/instrumentation package, dd-trace, and view them in Datadog

Location: Guides > Integrations > Datadog

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is planned.

## Introduction [#introduction]

In this guide, you'll learn how to set up Datadog tracing for a new Prisma project. By combining the `@prisma/instrumentation` package with Prisma Client extensions, you can capture detailed spans for every database query. These spans are enriched with query metadata and sent to Datadog [using `dd-trace`](https://www.npmjs.com/package/dd-trace), Datadog's official APM library for Node.js, so you can see how each query performs inside your application's requests.

### Spans and tracing [#spans-and-tracing]

* **Spans** are the individual operations or units of work within a distributed system or complex application. Each database query, service call, or external request is represented by a span.
* **Tracing** ties these spans together to form a complete, end-to-end picture of a request's lifecycle. With tracing, you can visualize bottlenecks, identify problematic queries, and pinpoint where errors occur from your queries.

### Datadog and Prisma ORM [#datadog-and-prisma-orm]

[Datadog](https://www.datadoghq.com/) provides application performance monitoring (APM), metrics, logs, and dashboards to help you observe and debug production systems.

Prisma ORM generates the SQL for you, which can hide how each query performs unless you instrument it. By integrating Datadog with Prisma using `@prisma/instrumentation` and [`dd-trace`](https://www.npmjs.com/package/dd-trace), you can automatically capture spans for every database query.

This enables you to:

* Measure latency per query.
* Inspect query arguments and raw SQL.
* Trace Prisma operations in the context of application-level requests.
* Identify bottlenecks related to database access.

With this in place, slow queries and errors show up in Datadog as they happen.

## Prerequisites [#prerequisites]

Before you begin, ensure you have the following:

* **Node.js** installed (v18+ recommended).
* A local or hosted **PostgreSQL** database.
* A **Datadog** account. If you do not have one, [sign up here](https://www.datadoghq.com/).
* The **Datadog Agent** installed and running on your machine or server where this application will run. You can follow the [Datadog Agent installation docs](https://docs.datadoghq.com/agent/) to set it up.

## 1. Create a new project [#1-create-a-new-project]

We will start by creating a new Node.js project to demonstrate tracing with Datadog and Prisma ORM. This will be a minimal, standalone setup focused on running and tracing Prisma queries, to understand the instrumentation flow in isolation.

If you're integrating tracing into an existing Prisma project, you can skip this step and directly follow from [the setup tracing section](#4-set-up-datadog-tracing). Apply the changes in your project's equivalent folder structure.

  

#### bun

```bash
mkdir prisma-datadog-tracing
cd prisma-datadog-tracing
bun init
```

#### pnpm

```bash
mkdir prisma-datadog-tracing
cd prisma-datadog-tracing
pnpm init
```

#### yarn

```bash
mkdir prisma-datadog-tracing
cd prisma-datadog-tracing
yarn init
```

#### npm

```bash
mkdir prisma-datadog-tracing
cd prisma-datadog-tracing
npm init
```

In this setup, you'll:

* Define a Prisma schema with basic models.
* Connect to a Postgres database (Prisma Postgres or your own).
* Configure Datadog tracing for all queries using `@prisma/instrumentation` and `dd-trace`.
* Run a sample script that executes Prisma operations and sends spans to Datadog.

## 2. Set up Prisma ORM [#2-set-up-prisma-orm]

In this section, you will install Prisma, create your schema, and generate the Prisma Client. This prepares your application to run the database queries that you will trace with Datadog.

### 2.1. Install and initialize Prisma ORM [#21-install-and-initialize-prisma-orm]

Run the following commands to install Prisma and a minimal TypeScript runner:

  

#### bun

```bash
bun add --dev prisma@prev tsx
```

#### pnpm

```bash
pnpm add -D prisma@prev tsx
```

#### yarn

```bash
yarn add --dev prisma@prev tsx
```

#### npm

```bash
npm install -D prisma@prev tsx
```

Then initialize Prisma:

  

#### bun

```bash
bunx --bun prisma init --output ../src/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../src/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../src/generated/prisma
```

#### npm

```bash
npx prisma init --output ../src/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This command does the following:

* Creates a `prisma` directory with a `schema.prisma` file.
* Generates the Prisma Client in the `/src/generated/prisma` directory (as specified in the `--output` flag).
* Creates a `.env` file at the project root with your database connection string (`DATABASE_URL`).

The `.env` file should contain a standard connection string:

```text title=".env"
# Placeholder url you have to replace
DATABASE_URL="postgresql://janedoe:mypassword@localhost:5432/mydb?schema=sample"
```

Install the driver adapter for PostgreSQL:

  

#### bun

```bash
bun add @prisma/adapter-pg pg
```

#### pnpm

```bash
pnpm add @prisma/adapter-pg pg
```

#### yarn

```bash
yarn add @prisma/adapter-pg pg
```

#### npm

```bash
npm i @prisma/adapter-pg pg
```

  

#### bun

```bash
bun add --dev @types/pg
```

#### pnpm

```bash
pnpm add -D @types/pg
```

#### yarn

```bash
yarn add --dev @types/pg
```

#### npm

```bash
npm i -D @types/pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define models [#22-define-models]

Now, open `prisma/schema.prisma` and update your generator block and models. Replace the `generator` block with the following, and add a `User` and a `Post` model:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]
```

Create a `prisma.config.ts` file to configure Prisma:

```typescript title="prisma.config.ts"
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config"; // [!code ++]
// [!code ++]
export default defineConfig({
  // [!code ++]
  schema: "prisma/schema.prisma", // [!code ++]
  migrations: {
    // [!code ++]
    path: "prisma/migrations", // [!code ++]
  }, // [!code ++]
  datasource: {
    // [!code ++]
    url: env("DATABASE_URL"), // [!code ++]
  }, // [!code ++]
}); // [!code ++]
```

> [!NOTE]
> You'll need to install the `dotenv` package if you haven't already:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 

### 2.3. Generate the Prisma Client and run migrations [#23-generate-the-prisma-client-and-run-migrations]

Generate the Prisma Client and apply your schema to your database:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

  

#### bun

```bash
bunx prisma migrate dev --name "init"
```

#### pnpm

```bash
pnpm prisma migrate dev --name "init"
```

#### yarn

```bash
yarn prisma migrate dev --name "init"
```

#### npm

```bash
npx prisma migrate dev --name "init"
```

This creates the tables according to your schema in the Postgres database and generates a client for you to interact with the database.

## 3. Install required dependencies for tracing [#3-install-required-dependencies-for-tracing]

In addition to Prisma, you will need the following packages for Datadog tracing:

  

#### bun

```bash
bun add @prisma/instrumentation \
  dd-trace
```

#### pnpm

```bash
pnpm add @prisma/instrumentation \
  dd-trace
```

#### yarn

```bash
yarn add @prisma/instrumentation \
  dd-trace
```

#### npm

```bash
npm install @prisma/instrumentation \
  dd-trace
```

Also ensure you have development dependencies for TypeScript:

  

#### bun

```bash
bun add --dev typescript
```

#### pnpm

```bash
pnpm add -D typescript
```

#### yarn

```bash
yarn add --dev typescript
```

#### npm

```bash
npm install -D typescript
```

Here's a quick overview:

* **`@prisma/instrumentation`**: Instruments Prisma queries so they appear as spans in your tracer.
* **`dd-trace`**: Official Node.js tracing library from Datadog.

## 4. Set up Datadog tracing [#4-set-up-datadog-tracing]

Create a `tracer.ts` file in the `src` folder to instantiate your tracing logic:

```bash
touch src/tracer.ts
```

### 4.1. Configure the tracer [#41-configure-the-tracer]

Open `src/tracer.ts` and add the following code:

```ts title="src/tracer.ts"
import tracer from "dd-trace";

tracer.init({
  profiling: true,
  logInjection: true,
  runtimeMetrics: true,
  dbmPropagationMode: "full",
  env: "dev",
  sampleRate: 1,
  service: "prisma-datadog-tracing",
  version: "1.0.0",
});

export { tracer };
```

#### Explanation [#explanation]

* **`tracer.init`** configures `dd-trace` with a `service` name. This name appears in Datadog under your `APM` > `Services` list.
* **`@prisma/instrumentation`** automatically logs each Prisma query as a Datadog span.

## 5. Instantiate Prisma and run queries [#5-instantiate-prisma-and-run-queries]

### 5.1. Create the Prisma Client instance [#51-create-the-prisma-client-instance]

Create a `src/client.ts` to hold your Prisma Client instantiation:

```ts title="src/client.ts"
import { tracer } from "./tracer";
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
  log: [{ emit: "event", level: "query" }],
})
  .$on("query", (e) => {
    const span = tracer.startSpan(`prisma_raw_query`, {
      childOf: tracer.scope().active() || undefined,
      tags: {
        "prisma.rawquery": e.query,
      },
    });
    span.finish();
  })
  .$extends({
    query: {
      async $allOperations({ operation, model, args, query }) {
        const span = tracer.startSpan(`prisma_query_${model?.toLowerCase()}_${operation}`, {
          tags: {
            "prisma.operation": operation,
            "prisma.model": model,
            "prisma.args": JSON.stringify(args),
            "prisma.rawQuery": query,
          },
          childOf: tracer.scope().active() || undefined,
        });

        try {
          const result = await query(args);
          span.finish();
          return result;
        } catch (error) {
          span.setTag("error", error);
          span.finish();
          throw error;
        }
      },
    },
  });

export { prisma };
```

The setup above gives you more control over how queries are traced:

* Tracing is initialized as early as possible by importing the `tracer` before creating the Prisma Client.
* The `$on("query")` hook captures raw SQL queries and sends them as standalone spans.
* The `$allOperations` extension wraps all Prisma operations in custom spans, allowing you to tag them with metadata like the model, operation type, and arguments.

Unlike the `@prisma/instrumentation` package, which offers automatic tracing out of the box, this manual setup gives you full control over how each span is structured and tagged. It's helpful when you need custom span names, additional metadata, a simpler setup, or when working around limitations or compatibility issues in the OpenTelemetry ecosystem. It also allows you to adapt tracing behavior based on query context, which can be especially useful in complex applications.

### 5.2. Add a script that performs queries [#52-add-a-script-that-performs-queries]

Create a `src/index.ts` file and add code to perform queries to your database and send traces to Datadog:

```typescript title="src/index.ts"
import { tracer } from "./tracer";
import { PrismaInstrumentation, registerInstrumentations } from "@prisma/instrumentation";
import { prisma } from "./client";

const provider = new tracer.TracerProvider();

registerInstrumentations({
  instrumentations: [new PrismaInstrumentation()],
  tracerProvider: provider,
});

provider.register();

async function main() {
  const user1Email = `alice${Date.now()}@prisma.io`;
  const user2Email = `bob${Date.now()}@prisma.io`;

  let alice, bob;

  // 1. Create users concurrently
  try {
    [alice, bob] = await Promise.all([
      prisma.user.create({
        data: {
          email: user1Email,
          name: "Alice",
          posts: {
            create: {
              title: "Join the Prisma community on Discord",
              content: "https://pris.ly/discord",
              published: true,
            },
          },
        },
        include: { posts: true },
      }),
      prisma.user.create({
        data: {
          email: user2Email,
          name: "Bob",
          posts: {
            create: [
              {
                title: "Check out Prisma on YouTube",
                content: "https://pris.ly/youtube",
                published: true,
              },
              {
                title: "Follow Prisma on Twitter",
                content: "https://twitter.com/prisma/",
                published: false,
              },
            ],
          },
        },
        include: { posts: true },
      }),
    ]);
    console.log(
      `✅ Created users: ${alice.name} (${alice.posts.length} post) and ${bob.name} (${bob.posts.length} posts)`,
    );
  } catch (err) {
    console.error("❌ Error creating users:", err);
    return;
  }

  // 2. Fetch all published posts
  try {
    const publishedPosts = await prisma.post.findMany({
      where: { published: true },
    });
    console.log(`✅ Retrieved ${publishedPosts.length} published post(s).`);
  } catch (err) {
    console.error("❌ Error fetching published posts:", err);
  }

  // 3. Create & publish a post for Alice
  let post;
  try {
    post = await prisma.post.create({
      data: {
        title: "Join the Prisma Discord community",
        content: "https://pris.ly/discord",
        published: false,
        author: { connect: { email: user1Email } },
      },
    });
    console.log(`✅ Created draft post for Alice (ID: ${post.id})`);
  } catch (err) {
    console.error("❌ Error creating draft post for Alice:", err);
    return;
  }

  try {
    post = await prisma.post.update({
      where: { id: post.id },
      data: { published: true },
    });
    console.log("✅ Published Alice’s post:", post);
  } catch (err) {
    console.error("❌ Error publishing Alice's post:", err);
  }

  // 4. Fetch all posts by Alice
  try {
    const alicePosts = await prisma.post.findMany({
      where: { author: { email: user1Email } },
    });
    console.log(`✅ Retrieved ${alicePosts.length} post(s) by Alice.`, alicePosts);
  } catch (err) {
    console.error("❌ Error fetching Alice's posts:", err);
  }
}

// Entrypoint
main()
  .catch((err) => {
    console.error("❌ Unexpected error:", err);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
    console.log("🔌 Disconnected from database.");
  });
```

> [!NOTE]
> If you encounter a linting error on the line `tracerProvider: provider` due to incompatible types, it's likely caused by a version mismatch in the `@opentelemetry/api` package.
> 
> To resolve this, add the following override to your package.json:
> 
> ```json
> "overrides": { // [!code ++]
>   "@opentelemetry/api": "1.8.0" // [!code ++]
> } // [!code ++]
> ```
>
> This is necessary because [`dd-trace` does not yet support version `1.9.0` or above of `@opentelemetry/api`](https://github.com/DataDog/dd-trace-js#datadog-with-opentelemetery).
> 
> After updating the `package.json`, reinstall your dependencies:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun install
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm i
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn install
>     ```
>
> 
>   #### npm

>     ```bash
>     npm i
>     ```
>
> 
> 
> This should resolve the linting error.

## 6. Run your queries and see the traces [#6-run-your-queries-and-see-the-traces]

Run the queries:

  

#### bun

```bash
bunx tsx src/index.ts
```

#### pnpm

```bash
pnpm dlx tsx src/index.ts
```

#### yarn

```bash
yarn dlx tsx src/index.ts
```

#### npm

```bash
npx tsx src/index.ts
```

This executes your script, which:

* Registers the Datadog tracer.
* Performs multiple Prisma queries.
* Logs the result of each operation.

Then, confirm the traces in Datadog:

* Open your [Datadog APM page](https://docs.datadoghq.com/tracing/).
* Navigate to **APM > Traces > Explorer** in the side panel.
* Explore the list of traces and spans, each representing a Prisma query (e.g. `prisma:query`).

> [!NOTE]
> Depending on your Datadog setup, it may take a minute or two for new data to appear. Refresh or wait briefly if you do not see traces right away.

## Next steps [#next-steps]

You have successfully:

* Created a Prisma ORM project with [Prisma Postgres](https://www.prisma.io/docs/postgres).
* Set up Datadog tracing using `@prisma/instrumentation` and `dd-trace`.
* Verified that database operations show up as spans in Datadog.

To improve your observability further:

* Add more instrumentation for your HTTP server or other services (e.g., Express, Fastify).
* [Create Dashboards to view](https://docs.datadoghq.com/dashboards/) key metrics from your data.

For additional guidance, check out:

* [Datadog APM documentation](https://docs.datadoghq.com/tracing/).
* [Prisma tracing docs](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/opentelemetry-tracing).

## Related pages

- [`AI SDK (with Next.js)`](https://www.prisma.io/docs/guides/integrations/ai-sdk): Build a chat application with AI SDK, Prisma ORM, and Next.js that stores chat sessions and messages in Prisma Postgres.
- [`Embedded Prisma Studio (with Next.js)`](https://www.prisma.io/docs/guides/integrations/embed-studio): Learn how to embed Prisma Studio directly in your Next.js application for database management
- [`GitHub Actions`](https://www.prisma.io/docs/guides/integrations/github-actions): Provision a Prisma Postgres database for every pull request with GitHub Actions and the Prisma CLI, apply your migrations and seed data to it, and delete it when the pull request closes.
- [`Permit.io`](https://www.prisma.io/docs/guides/integrations/permit-io): Learn how to implement access control with Prisma ORM with Permit.io
- [`pgfence`](https://www.prisma.io/docs/guides/integrations/pgfence): Analyze Prisma Migrate SQL files for dangerous lock patterns, risk levels, and safe rewrite recipes before deploying to production

# Prisma Postgres on Deno (/docs/guides/integrations/deno)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to integrate Prisma Postgres in a Deno Deploy project using a minimal Deno application

Location: Guides > Integrations > Prisma Postgres on Deno

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is planned.

[Deno Deploy](https://deno.com/deploy) includes a feature that allows you to provision a Prisma Postgres database directly within the platform. This guide demonstrates how to integrate Prisma Postgres in a Deno Deploy project using a minimal Deno application that logs HTTP requests to the database.

By the end of this guide, you will have a deployed Deno app that writes to and reads from a Prisma Postgres database provisioned in Deno Deploy, using Prisma Client with `runtime = "deno"`.

## Prerequisites [#prerequisites]

* A [Deno Deploy](https://deno.com/deploy) account
* Deno runtime installed ([installation guide](https://docs.deno.com/runtime/#install-deno))
* [Deno extension for VS Code](https://docs.deno.com/runtime/reference/vscode/)

## 1. Create and set up a new Deno project [#1-create-and-set-up-a-new-deno-project]

Create a new Deno project using the `deno init` command, which generates a basic project structure with a main entry file and configuration.

```bash
deno init prisma-postgres-deno-deploy
cd prisma-postgres-deno-deploy
```

### 1.1 Configure VS Code for Deno [#11-configure-vs-code-for-deno]

To ensure VS Code recognizes this as a Deno project and provides proper TypeScript validation, you need to initialize the workspace. Without this, VS Code will show errors when using Deno-specific APIs like `Deno.serve`.

Install the [Deno extension for VS Code](https://docs.deno.com/runtime/reference/vscode/), then:

1. Select **View** > **Command Palette*&#x2A; &#x2A;(or press `Cmd+Shift+P` on macOS or `Ctrl+Shift+P` on Windows)*
2. Run the command **Deno: Initialize Workspace Configuration**

### 1.2 Create a basic HTTP server [#12-create-a-basic-http-server]

Update the `main.ts` file to create a minimal HTTP server that responds with "Hello, World!". You will add database access to this handler later.

```tsx title="main.ts"
function handler(_req: Request): Response {
  return new Response("Hello, World!");
}

Deno.serve(handler);
```

You can test the server locally by running:

```bash
deno run dev
```

Visit `localhost:8000` in your browser to see the application running.

### 1.3 Push initial project to GitHub [#13-push-initial-project-to-github]

To connect your project to Deno Deploy and get a database connection string, you need to have a successful deployment. Set up a GitHub repository and push your project to it.

## 2. Deploy the project to Deno Deploy [#2-deploy-the-project-to-deno-deploy]

Deploy your repository to Deno Deploy. Any subsequent commits will trigger automatic redeployments. You need to deploy now, as the database string requires a successful deployment to generate.

1. Navigate to the [Deno Deploy dashboard](https://dash.deno.com/) and select **New App**
2. Configure GitHub app permissions by following GitHub's prompts
3. Choose your GitHub repository in the Deno Deploy interface
4. Click **Create App** to complete the deployment

The application will deploy automatically.

## 3. Provision a Prisma Postgres database [#3-provision-a-prisma-postgres-database]

Provision a Prisma Postgres database in Deno Deploy, and link it to your application:

1. Go to the **Databases** section in the Deno Deploy dashboard
2. Select **Provision Database** and choose **Prisma Postgres**
3. Complete the database configuration and confirm provisioning
4. Click **Assign** and select your application
5. Copy the **Production connection string**
6. Add the connection string to your `.env` file:

```text
DATABASE_URL="postgresql://<username>:<password>@db.prisma.io:5432/<database_name>-production"
```

## 4. Configure Prisma ORM [#4-configure-prisma-orm]

### 4.1 Enable environment variables [#41-enable-environment-variables]

To access the database connection string during local development, configure Deno to load environment variables from your `.env` file using the `--env-file` flag.

Update the `dev` task in `deno.json`:

```json title="deno.json"
{
  "tasks": {
    "dev": "deno run --watch --env-file main.ts" // [!code highlight]
  }
}
```

### 4.2 Initialize Prisma and create schema [#42-initialize-prisma-and-create-schema]

Install the Prisma Client, PostgreSQL adapter, and development dependencies:

  

#### bun

```bash
deno install npm 
# couldn't auto-convert command:@prisma/client@7 npm 
# couldn't auto-convert command:@prisma/adapter-pg npm 
# couldn't auto-convert command:pg npm 
# couldn't auto-convert command:prisma@prev npm 
# couldn't auto-convert command:@types/pg
```

#### pnpm

```bash
deno install npm undefined
# couldn't auto-convert command:@prisma/client@7 npm undefined
# couldn't auto-convert command:@prisma/adapter-pg npm undefined
# couldn't auto-convert command:pg npm undefined
# couldn't auto-convert command:prisma@prev npm undefined
# couldn't auto-convert command:@types/pg
```

#### yarn

```bash
deno install npm undefined
# couldn't auto-convert command:@prisma/client@7 npm undefined
# couldn't auto-convert command:@prisma/adapter-pg npm undefined
# couldn't auto-convert command:pg npm undefined
# couldn't auto-convert command:prisma@prev npm undefined
# couldn't auto-convert command:@types/pg
```

#### npm

```bash
deno install npm:@prisma/client@7 npm:@prisma/adapter-pg npm:pg npm:prisma@prev npm:@types/pg
```

Initialize Prisma in your project, which creates the necessary configuration files and folder structure for defining your database models.

  

#### bun

```bash
bunx --bun prisma@prev init
```

#### pnpm

```bash
pnpm dlx prisma@prev init
```

#### yarn

```bash
yarn dlx prisma@prev init
```

#### npm

```bash
npx prisma@prev init
```

Update the Prisma schema with these changes:

1. Change the client output from `prisma-client-js` to `prisma-client`.
2. Add the Deno runtime configuration. &#x2A;(This is required for Deno to run properly)*
3. Add the Log model for storing request information.

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client" // [!code highlight]
  output   = "../generated/prisma"
  runtime  = "deno" // [!code ++]
}

datasource db {
  provider = "postgresql"
}

model Log { // [!code ++]
  id      Int    @id @default(autoincrement()) // [!code ++]
  level   Level // [!code ++]
  message String // [!code ++]
  meta    Json // [!code ++]
} // [!code ++]
 // [!code ++]
enum Level { // [!code ++]
  Info // [!code ++]
  Warn // [!code ++]
  Error // [!code ++]
} // [!code ++]
```

### 4.3 Generate and apply migrations [#43-generate-and-apply-migrations]

Migrations create the actual database tables based on your Prisma schema. This command generates SQL migration files and executes them against your database, creating the `Log` table with the specified fields.

  

#### bun

```bash
deno run -A npm 
# couldn't auto-convert command:prisma@prev migrate dev --name init
deno run -A npm 
# couldn't auto-convert command:prisma@prev generate
```

#### pnpm

```bash
deno run -A npm undefined
# couldn't auto-convert command:prisma@prev migrate dev --name init
deno run -A npm undefined
# couldn't auto-convert command:prisma@prev generate
```

#### yarn

```bash
deno run -A npm undefined
# couldn't auto-convert command:prisma@prev migrate dev --name init
deno run -A npm undefined
# couldn't auto-convert command:prisma@prev generate
```

#### npm

```bash
deno run -A npm:prisma@prev migrate dev --name init
deno run -A npm:prisma@prev generate
```

## 5. Update the application to use Prisma [#5-update-the-application-to-use-prisma]

Now that the database is configured, update your application to interact with it. This implementation creates a logging system that captures every HTTP request, stores it in the database, and returns the logged entry as JSON.

```tsx title="main.ts"
import { PrismaClient } from "./generated/prisma/client.ts";
import { PrismaPg } from "npm:@prisma/adapter-pg";
import process from "node:process";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
});

const prisma = new PrismaClient({
  adapter,
});

async function handler(request: Request) {
  const url = new URL(request.url);
  if (url.pathname === "/favicon.ico") {
    return new Response(null, { status: 204 });
  }

  const log = await prisma.log.create({
    data: {
      level: "Info",
      message: `${request.method} ${request.url}`,
      meta: {
        headers: JSON.stringify(request.headers),
      },
    },
  });
  const body = JSON.stringify(log, null, 2);
  return new Response(body, {
    headers: { "content-type": "application/json; charset=utf-8" },
  });
}

Deno.serve(handler);
```

Test the application locally by running:

```bash
deno run dev
```

> [!NOTE]
> It may ask you for access to your environment variables. Select **Allow** to grant access.

Visit `localhost:8000` in your browser to see the application running. You should see a JSON response containing the log entry:

```json
{
  "id": 1,
  "level": "Info",
  "message": "GET http://localhost:8000/",
  "meta": {
    "headers": "..."
  }
}
```

## 6. Deploy the application [#6-deploy-the-application]

The build command must generate the Prisma Client code to ensure it is available in production.

### 6.1 Update build command in Deno Deploy [#61-update-build-command-in-deno-deploy]

1. Go to the application in Deno Deploy and click **Settings**
2. Under **Build configuration**, hit **Edit** and add `deno run -A npm:prisma@prev generate` to the build command
3. Click **Save**

### 6.2 Push changes to GitHub [#62-push-changes-to-github]

Commit and push your changes to trigger an automatic deployment:

```bash
git add .
git commit -m "added prisma"
git push
```

Navigate back to Deno Deploy and you should see a successful build. Once deployed, click the deployment URL at the top right of the dashboard.

### 6.3 Verify the deployment [#63-verify-the-deployment]

When you visit your deployed application, you should see a response that looks like this:

```json
{
  "id": 1,
  "level": "Info",
  "message": "GET https://prisma-postgres-deno-deploy.<org-name>.deno.net/",
  "meta": {
    "headers": "{}"
  }
}
```

Each time you refresh the page, a new log entry is created in your database.

## Next Steps [#next-steps]

Now that you have a working Deno app connected to a Prisma Postgres database, you can:

* **Extend your data model** - Add relationships, validations, and indexes to your Prisma schema
* **Secure your API** - Implement authentication, rate limiting, and proper error handling
* **Improve deployment** - Set up CI/CD, monitoring, and database backups for production

## More info [#more-info]

* [Prisma ORM Documentation](https://www.prisma.io/docs/orm/v7)
* [Deno Deploy Documentation](https://docs.deno.com/deploy)

## Related pages

- [`AI SDK (with Next.js)`](https://www.prisma.io/docs/guides/integrations/ai-sdk): Build a chat application with AI SDK, Prisma ORM, and Next.js that stores chat sessions and messages in Prisma Postgres.
- [`Datadog`](https://www.prisma.io/docs/guides/integrations/datadog): Learn how to configure Datadog tracing for a Prisma ORM project. Capture spans for every query using the @prisma/instrumentation package, dd-trace, and view them in Datadog
- [`Embedded Prisma Studio (with Next.js)`](https://www.prisma.io/docs/guides/integrations/embed-studio): Learn how to embed Prisma Studio directly in your Next.js application for database management
- [`GitHub Actions`](https://www.prisma.io/docs/guides/integrations/github-actions): Provision a Prisma Postgres database for every pull request with GitHub Actions and the Prisma CLI, apply your migrations and seed data to it, and delete it when the pull request closes.
- [`Permit.io`](https://www.prisma.io/docs/guides/integrations/permit-io): Learn how to implement access control with Prisma ORM with Permit.io

# Embedded Prisma Studio (with Next.js) (/docs/guides/integrations/embed-studio)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to embed Prisma Studio directly in your Next.js application for database management

Location: Guides > Integrations > Embedded Prisma Studio (with Next.js)

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is planned.

Prisma Studio can be embedded directly into your Next.js application using the [`@prisma/studio-core`](https://www.npmjs.com/package/@prisma/studio-core) package. This guide walks you through the setup so you can manage your database from within your app instead of running Prisma Studio separately.

After completing the guide, you'll have a Next.js app with Prisma Studio embedded, allowing you to browse and edit your database directly from your application interface:

![Prisma Studio embedded in Next.js app](https://www.prisma.io/img/guides/embedded-studio.gif)

Embedding Prisma Studio can be useful in scenarios such as:

* Building a quick admin dashboard for editing data
* Supporting multi-tenant applications where each user has their own database
* Giving users a UI to view and edit their own data

> [!NOTE]
> [**Embeddable Prisma Studio**](https://www.prisma.io/docs/studio/integrations/embedding) is *free* and licensed under Apache 2.0.
> 
> ✔️ Free to use in production
> ⚠️ Prisma branding must remain visible and unchanged
> 🔐 To remove branding or learn about upcoming partner-only features, reach out at [partnerships@prisma.io](mailto\:partnerships@prisma.io)
> 
> Currently, Embedded Prisma Studio supports **PostgreSQL, SQLite, and MySQL** databases.

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* Basic knowledge of React and Next.js
* A database (PostgreSQL, SQLite, or MySQL)

## 1. Setting up Next.js [#1-setting-up-nextjs]

First, create a new Next.js project from the directory where you want to build your app:

  

#### bun

```bash
bunx create-next-app@latest nextjs-studio-embed
```

#### pnpm

```bash
pnpm dlx create-next-app@latest nextjs-studio-embed
```

#### yarn

```bash
yarn dlx create-next-app@latest nextjs-studio-embed
```

#### npm

```bash
npx create-next-app@latest nextjs-studio-embed
```

You will be prompted to answer a few questions about your project. Select all of the defaults.

> [!NOTE]
> For reference, those are:
> 
> * TypeScript
> * ESLint
> * Tailwind CSS
> * No `src` directory
> * App Router
> * Turbopack
> * Select default import alias

Then, navigate to the project directory:

```bash
cd nextjs-studio-embed
```

## 2. Setting up Prisma ORM and Prisma Postgres [#2-setting-up-prisma-orm-and-prisma-postgres]

### 2.1. Install Prisma dependencies [#21-install-prisma-dependencies]

Install the required Prisma packages:

### Prisma Postgres (PostgreSQL) [#prisma-postgres-postgresql]

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
bun add @prisma/extension-accelerate @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
pnpm add @prisma/extension-accelerate @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
yarn add @prisma/extension-accelerate @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
npm install @prisma/extension-accelerate @prisma/client@7 @prisma/adapter-pg dotenv pg
```

### SQLite [#sqlite]

  

#### bun

```bash
bun add prisma@prev tsx --dev
bun add @prisma/client@7 @prisma/adapter-sqlite dotenv better-sqlite3
```

#### pnpm

```bash
pnpm add prisma@prev tsx --save-dev
pnpm add @prisma/client@7 @prisma/adapter-sqlite dotenv better-sqlite3
```

#### yarn

```bash
yarn add prisma@prev tsx --dev
yarn add @prisma/client@7 @prisma/adapter-sqlite dotenv better-sqlite3
```

#### npm

```bash
npm install prisma@prev tsx --save-dev
npm install @prisma/client@7 @prisma/adapter-sqlite dotenv better-sqlite3
```

### MySQL [#mysql]

  

#### bun

```bash
bun add prisma@prev tsx @types/mysql2 --dev
bun add @prisma/client@7 @prisma/adapter-mysql dotenv mysql2
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/mysql2 --save-dev
pnpm add @prisma/client@7 @prisma/adapter-mysql dotenv mysql2
```

#### yarn

```bash
yarn add prisma@prev tsx @types/mysql2 --dev
yarn add @prisma/client@7 @prisma/adapter-mysql dotenv mysql2
```

#### npm

```bash
npm install prisma@prev tsx @types/mysql2 --save-dev
npm install @prisma/client@7 @prisma/adapter-mysql dotenv mysql2
```

> [!NOTE]
> For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

### 2.2. Initialize Prisma with Prisma Postgres [#22-initialize-prisma-with-prisma-postgres]

Initialize Prisma in your project:

### Prisma Postgres (PostgreSQL) [#prisma-postgres-postgresql-1]

  

#### bun

```bash
bunx --bun prisma init --output ../app/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../app/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../app/generated/prisma
```

#### npm

```bash
npx prisma init --output ../app/generated/prisma
```

### SQLite [#sqlite-1]

  

#### bun

```bash
bunx --bun prisma init --datasource-provider sqlite --output ../app/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider sqlite --output ../app/generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider sqlite --output ../app/generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider sqlite --output ../app/generated/prisma
```

### MySQL [#mysql-1]

  

#### bun

```bash
bunx --bun prisma init --datasource-provider mysql --output ../app/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider mysql --output ../app/generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider mysql --output ../app/generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider mysql --output ../app/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. If you choose Prisma Postgres below, create a database in the next step and replace that value with a direct `postgres://...` connection string.

The `prisma init` command creates:

* A `prisma/` directory with your `schema.prisma` file
* A `prisma.config.ts` file for configuring Prisma
* A `.env` file with your `DATABASE_URL`
* An output directory at `app/generated/prisma` for the Prisma Client

If you're using Prisma Postgres, create a database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.3. Define your database schema [#23-define-your-database-schema]

Open `prisma/schema.prisma` and replace the content with:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql" // this will change depending on the --datasource-provider flag used in the init command
}

 // [!code ++]
model User { // [!code ++]
  id    Int    @id @default(autoincrement()) // [!code ++]
  name  String // [!code ++]
  email String @unique // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
  createdAt DateTime @default(now()) // [!code ++]
} // [!code ++]
 // [!code ++]
```

### 2.4 Add `dotenv` to `prisma.config.ts` [#24-add-dotenv-to-prismaconfigts]

To get access to the variables in the `.env` file, they can either be loaded by your runtime, or by using `dotenv`.
Include an import for `dotenv` at the top of the `prisma.config.ts`

```ts
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.5. Apply the schema to your database [#25-apply-the-schema-to-your-database]

Generate the Prisma Client and apply the schema:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This creates the tables in your Prisma Postgres database and generates the Prisma Client.

> [!NOTE]
> If you are using SQLite or MySQL, this creates the tables in your database and generates the Prisma Client.

### 2.6. Seed your database (optional) [#26-seed-your-database-optional]

Create a seed file to add some sample data. Create a `seed.ts` file in the `prisma` folder and add the following code:

  

#### Prisma Postgres (PostgreSQL)

```typescript title="prisma/seed.ts" 
import { PrismaClient } from "../app/generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

async function main() {
  // Create users
  const user1 = await prisma.user.create({
    data: {
      name: "Alice Johnson",
      email: "alice@example.com",
    },
  });

  const user2 = await prisma.user.create({
    data: {
      name: "Bob Smith",
      email: "bob@example.com",
    },
  });

  // Create posts
  await prisma.post.create({
    data: {
      title: "Getting Started with Next.js",
      content: "Next.js is a powerful React framework...",
      published: true,
      authorId: user1.id,
    },
  });

  await prisma.post.create({
    data: {
      title: "Database Management with Prisma",
      content: "Prisma makes database management easy...",
      published: false,
      authorId: user2.id,
    },
  });

  console.log("Database seeded successfully!");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

#### SQLite

```typescript title="prisma/seed.ts" 
import { PrismaClient } from "../app/generated/prisma/client";
import { PrismaSQLite } from "@prisma/adapter-sqlite";

const adapter = new PrismaSQLite({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

async function main() {
  // Create users
  const user1 = await prisma.user.create({
    data: {
      name: "Alice Johnson",
      email: "alice@example.com",
    },
  });

  const user2 = await prisma.user.create({
    data: {
      name: "Bob Smith",
      email: "bob@example.com",
    },
  });

  // Create posts
  await prisma.post.create({
    data: {
      title: "Getting Started with Next.js",
      content: "Next.js is a powerful React framework...",
      published: true,
      authorId: user1.id,
    },
  });

  await prisma.post.create({
    data: {
      title: "Database Management with Prisma",
      content: "Prisma makes database management easy...",
      published: false,
      authorId: user2.id,
    },
  });

  console.log("Database seeded successfully!");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

#### MySQL

```typescript title="prisma/seed.ts" 
import { PrismaClient } from "../app/generated/prisma/client";
import { PrismaMySQL } from "@prisma/adapter-mysql";

const adapter = new PrismaMySQL({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

async function main() {
  // Create users
  const user1 = await prisma.user.create({
    data: {
      name: "Alice Johnson",
      email: "alice@example.com",
    },
  });

  const user2 = await prisma.user.create({
    data: {
      name: "Bob Smith",
      email: "bob@example.com",
    },
  });

  // Create posts
  await prisma.post.create({
    data: {
      title: "Getting Started with Next.js",
      content: "Next.js is a powerful React framework...",
      published: true,
      authorId: user1.id,
    },
  });

  await prisma.post.create({
    data: {
      title: "Database Management with Prisma",
      content: "Prisma makes database management easy...",
      published: false,
      authorId: user2.id,
    },
  });

  console.log("Database seeded successfully!");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

Add a seed script to your `prisma.config.ts`:

  

#### Prisma Postgres (PostgreSQL)

```ts title="prisma.config.ts" 
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: `tsx prisma/seed.ts`,
  },
  datasource: {
    url: env("DIRECT_URL"),
  },
});
```

#### SQLite

```ts title="prisma.config.ts" 
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: `tsx prisma/seed.ts`,
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

#### MySQL

```ts title="prisma.config.ts" 
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: `tsx prisma/seed.ts`,
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Run the seed script:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

## 3. Setting up the embedded Prisma Studio in your app [#3-setting-up-the-embedded-prisma-studio-in-your-app]

Now that you have Prisma ORM and Prisma Postgres set up, you can embed Prisma Studio in your Next.js app.

### 3.1. Install the Prisma Studio Core package [#31-install-the-prisma-studio-core-package]

Install the [`@prisma/studio-core` package](https://www.npmjs.com/package/@prisma/studio-core) that provides the embeddable components:

  

#### bun

```bash
bun add @prisma/studio-core
```

#### pnpm

```bash
pnpm add @prisma/studio-core
```

#### yarn

```bash
yarn add @prisma/studio-core
```

#### npm

```bash
npm install @prisma/studio-core
```

> [!NOTE]
> If you encounter a dependency resolution error while installing `@prisma/studio-core`, you can force the install with:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add @prisma/studio-core --force
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add @prisma/studio-core --force
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add @prisma/studio-core --force
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install @prisma/studio-core --force
>     ```
>
> 
> 
> If you are using yarn, pnpm, or another package manager, use the equivalent flag for your tool.

The `@prisma/studio-core` provides `Studio`, a React component which renders Prisma Studio for your database. The `Studio` component accepts an *executor* which accesses a custom endpoint in your backend. The backend uses your API key to identify the correct Prisma Postgres instance and sends the SQL query to it.

### 3.2. Create a Studio wrapper component [#32-create-a-studio-wrapper-component]

Create a `components` folder and add a new file called `StudioWrapper.tsx`. This file will wrap the Studio component and provide a consistent layout:

```tsx title="components/StudioWrapper.tsx"
"use client";
import "@prisma/studio-core/ui/index.css";
import { ReactNode } from "react";

interface StudioWrapperProps {
  children: ReactNode;
}

export default function StudioWrapper({ children }: StudioWrapperProps) {
  return (
    <div className="min-h-screen bg-gray-50">
      <header className="bg-white shadow-sm border-b">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <div className="flex justify-between items-center py-4">
            <h1 className="text-2xl font-bold text-gray-900">Database Studio</h1>
            <div className="text-sm text-gray-500">Powered by Prisma Studio</div>
          </div>
        </div>
      </header>
      <main className="max-w-7xl mx-auto">
        <div className="h-[calc(100vh-80px)]">{children}</div>
      </main>
    </div>
  );
}
```

### 3.3. Create an API endpoint to send the SQL queries to Prisma Studio [#33-create-an-api-endpoint-to-send-the-sql-queries-to-prisma-studio]

Next, set up a backend endpoint that Prisma Studio can communicate with. This endpoint receives SQL queries from the embedded Studio UI, forwards them to your Prisma Postgres database, and then returns the results (or errors) back to the frontend.

> [!NOTE]
> If you are using SQLite or MySQL, you can still embed Studio, but your `/api/studio` implementation needs to use the correct executor for your database.

To do this, create a new folder called `api` inside the `app` directory. Inside it, add a `studio` folder with a `route.ts` file. This file will handle all requests sent to `/api/studio` and act as the bridge between the Studio component in your frontend and the database in your backend:

  

#### PostgreSQL

```typescript title="app/api/studio/route.ts" 
import "dotenv/config";
import { createPrismaPostgresHttpClient } from "@prisma/studio-core/data/ppg";
import { serializeError } from "@prisma/studio-core/data/bff";

const CORS_HEADERS = {
  "Access-Control-Allow-Origin": "*", // Change to your domain in production
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
};

// Use dynamic rendering for database operations
export const dynamic = "force-dynamic";

export async function GET() {
  return Response.json({ message: "Studio API endpoint is running" }, { headers: CORS_HEADERS });
}

export async function POST(request: Request) {
  try {
    const body = await request.json();
    const query = body.query;

    if (!query) {
      return Response.json([serializeError(new Error("Query is required"))], {
        status: 400,
        headers: CORS_HEADERS,
      });
    }

    const url = process.env.DATABASE_URL;
    if (!url) {
      const message = "❌ Environment variable DATABASE_URL is missing.";
      return Response.json([serializeError(new Error(message))], {
        status: 500,
        headers: CORS_HEADERS,
      });
    }

    const [error, results] = await createPrismaPostgresHttpClient({
      url,
    }).execute(query);

    if (error) {
      return Response.json([serializeError(error)], {
        headers: CORS_HEADERS,
      });
    }

    return Response.json([null, results], { headers: CORS_HEADERS });
  } catch (err) {
    return Response.json([serializeError(err)], {
      status: 400,
      headers: CORS_HEADERS,
    });
  }
}

// Handle preflight requests for CORS
export async function OPTIONS() {
  return new Response(null, { status: 204, headers: CORS_HEADERS });
}
```

#### SQLite

```typescript title="app/api/studio/route.ts" 
import "dotenv/config";
import { createNodeSQLiteExecutor } from "@prisma/studio-core/data/node-sqlite";
import { serializeError } from "@prisma/studio-core/data/bff";
import DatabaseSync from "better-sqlite3";

const CORS_HEADERS = {
  "Access-Control-Allow-Origin": "*", // Change to your domain in production
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
};

// Use dynamic rendering for database operations
export const dynamic = "force-dynamic";

export async function GET() {
  return Response.json({ message: "Studio API endpoint is running" }, { headers: CORS_HEADERS });
}

export async function POST(request: Request) {
  try {
    const body = await request.json();
    const query = body.query;

    if (!query) {
      return Response.json([serializeError(new Error("Query is required"))], {
        status: 400,
        headers: CORS_HEADERS,
      });
    }

    const url = process.env.DATABASE_URL;
    if (!url) {
      const message = "❌ Environment variable DATABASE_URL is missing.";
      return Response.json([serializeError(new Error(message))], {
        status: 500,
        headers: CORS_HEADERS,
      });
    }

    const dbPath = url.replace("file:", "");
    const database = new DatabaseSync(dbPath);
    const [error, results] = await createNodeSQLiteExecutor(database).execute(query);

    if (error) {
      return Response.json([serializeError(error)], {
        headers: CORS_HEADERS,
      });
    }

    return Response.json([null, results], { headers: CORS_HEADERS });
  } catch (err) {
    return Response.json([serializeError(err)], {
      status: 400,
      headers: CORS_HEADERS,
    });
  }
}

// Handle preflight requests for CORS
export async function OPTIONS() {
  return new Response(null, { status: 204, headers: CORS_HEADERS });
}
```

#### MySQL

```typescript title="app/api/studio/route.ts" 
import "dotenv/config";
import { createMySQL2Executor } from "@prisma/studio-core/data/mysql2";
import { serializeError } from "@prisma/studio-core/data/bff";
import mysql from "mysql2/promise";

const CORS_HEADERS = {
  "Access-Control-Allow-Origin": "*", // Change to your domain in production
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
};

// Use dynamic rendering for database operations
export const dynamic = "force-dynamic";

export async function GET() {
  return Response.json({ message: "Studio API endpoint is running" }, { headers: CORS_HEADERS });
}

export async function POST(request: Request) {
  try {
    const body = await request.json();
    const query = body.query;

    if (!query) {
      return Response.json([serializeError(new Error("Query is required"))], {
        status: 400,
        headers: CORS_HEADERS,
      });
    }

    const url = process.env.DATABASE_URL;
    if (!url) {
      const message = "❌ Environment variable DATABASE_URL is missing.";
      return Response.json([serializeError(new Error(message))], {
        status: 500,
        headers: CORS_HEADERS,
      });
    }

    const pool = mysql.createPool(url);
    const [error, results] = await createMySQL2Executor(pool).execute(query);

    if (error) {
      return Response.json([serializeError(error)], {
        headers: CORS_HEADERS,
      });
    }

    return Response.json([null, results], { headers: CORS_HEADERS });
  } catch (err) {
    return Response.json([serializeError(err)], {
      status: 400,
      headers: CORS_HEADERS,
    });
  }
}

// Handle preflight requests for CORS
export async function OPTIONS() {
  return new Response(null, { status: 204, headers: CORS_HEADERS });
}
```

### 3.4. Create the main Studio page [#34-create-the-main-studio-page]

Open the `app/page.tsx` file and replace the existing code to render the embedded Studio with the following:

  

#### PostgreSQL

```tsx title="app/page.tsx" 
"use client";

import dynamic from "next/dynamic";
import { createPostgresAdapter } from "@prisma/studio-core/data/postgres-core";
import { createStudioBFFClient } from "@prisma/studio-core/data/bff";
import { useMemo, Suspense } from "react";
import StudioWrapper from "@/components/StudioWrapper";

// Dynamically import Studio with no SSR to avoid hydration issues
const Studio = dynamic(() => import("@prisma/studio-core/ui").then((mod) => mod.Studio), {
  ssr: false,
});

// Loading component
const StudioLoading = () => (
  <div className="flex items-center justify-center h-full">
    <div className="text-center">
      <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto"></div>
      <p className="mt-4 text-gray-600">Loading Studio...</p>
    </div>
  </div>
);

// Client-only Studio component
const ClientOnlyStudio = () => {
  const adapter = useMemo(() => {
    // Create the HTTP client that communicates with our API endpoint
    const executor = createStudioBFFClient({
      url: "/api/studio",
    });

    // Create the Postgres adapter using the executor
    return createPostgresAdapter({ executor });
  }, []);

  return <Studio adapter={adapter} />;
};

export default function App() {
  return (
    <StudioWrapper>
      <Suspense fallback={<StudioLoading />}>
        <ClientOnlyStudio />
      </Suspense>
    </StudioWrapper>
  );
}
```

#### SQLite

```tsx title="app/page.tsx" 
"use client";

import dynamic from "next/dynamic";
import { createSQLiteAdapter } from "@prisma/studio-core/data/sqlite-core";
import { createStudioBFFClient } from "@prisma/studio-core/data/bff";
import { useMemo, Suspense } from "react";
import StudioWrapper from "@/components/StudioWrapper";

// Dynamically import Studio with no SSR to avoid hydration issues
const Studio = dynamic(() => import("@prisma/studio-core/ui").then((mod) => mod.Studio), {
  ssr: false,
});

// Loading component
const StudioLoading = () => (
  <div className="flex items-center justify-center h-full">
    <div className="text-center">
      <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto"></div>
      <p className="mt-4 text-gray-600">Loading Studio...</p>
    </div>
  </div>
);

// Client-only Studio component
const ClientOnlyStudio = () => {
  const adapter = useMemo(() => {
    // Create the HTTP client that communicates with our API endpoint
    const executor = createStudioBFFClient({
      url: "/api/studio",
    });

    // Create the SQLite adapter using the executor
    return createSQLiteAdapter({ executor });
  }, []);

  return <Studio adapter={adapter} />;
};

export default function App() {
  return (
    <StudioWrapper>
      <Suspense fallback={<StudioLoading />}>
        <ClientOnlyStudio />
      </Suspense>
    </StudioWrapper>
  );
}
```

#### MySQL

```tsx title="app/page.tsx" 
"use client";

import dynamic from "next/dynamic";
import { createMySQLAdapter } from "@prisma/studio-core/data/mysql-core";
import { createStudioBFFClient } from "@prisma/studio-core/data/bff";
import { useMemo, Suspense } from "react";
import StudioWrapper from "@/components/StudioWrapper";

// Dynamically import Studio with no SSR to avoid hydration issues
const Studio = dynamic(() => import("@prisma/studio-core/ui").then((mod) => mod.Studio), {
  ssr: false,
});

// Loading component
const StudioLoading = () => (
  <div className="flex items-center justify-center h-full">
    <div className="text-center">
      <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto"></div>
      <p className="mt-4 text-gray-600">Loading Studio...</p>
    </div>
  </div>
);

// Client-only Studio component
const ClientOnlyStudio = () => {
  const adapter = useMemo(() => {
    // Create the HTTP client that communicates with our API endpoint
    const executor = createStudioBFFClient({
      url: "/api/studio",
    });

    // Create the MySQL adapter using the executor
    return createMySQLAdapter({ executor });
  }, []);

  return <Studio adapter={adapter} />;
};

export default function App() {
  return (
    <StudioWrapper>
      <Suspense fallback={<StudioLoading />}>
        <ClientOnlyStudio />
      </Suspense>
    </StudioWrapper>
  );
}
```

### 3.5. Start your development server and test the embedded Studio [#35-start-your-development-server-and-test-the-embedded-studio]

Start your Next.js development server:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open your browser and go to `http://localhost:3000`. You should now see Prisma Studio running inside your application:

![Prisma Studio embedded in Next.js app](https://www.prisma.io/img/guides/embedded-studio.gif)

Here's what to look for:

1. **Prisma Studio interface**: The full Prisma Studio UI should render within your app layout.
2. **Your data**: The `User` and `Post` tables you defined (plus any seeded data) should appear.
3. **Interactive features**:
   * Browse and filter records in your tables
   * Edit values inline by double-clicking cells
   * Add new records using the "Add record" button
   * Delete records you no longer need
   * Explore relationships by navigating between related tables

Verify whether everything works by testing the basics:

* Click on different tables to confirm your data loads.
* Update a record to check that changes are saved.
* Add a new record and confirm it appears instantly.
* Try filtering data to make sure queries run correctly.
* Navigate through relationships (for example, view a user's posts) to confirm associations work.

Once these actions work as expected, your embedded Prisma Studio is set up and connected to your database.

## Next steps [#next-steps]

At this point you have Prisma Studio running inside your Next.js application and connected to your database. You can browse, edit, and manage your data without leaving your app. To make this setup production-ready, consider these improvements:

1. **Add authentication**: Currently, anyone who can open your app has access to Prisma Studio. [Add user authentication](https://www.prisma.io/docs/studio/integrations/embedding#adding-user-authentication) and only allow specific roles (for example, admins) to use the embedded Studio. You can do this by checking authentication tokens in your `/api/studio` endpoint before running queries.

2. **Use environment-specific configuration**: In development you may want a test database, while in production you'll need a separate live database. Update your `.env` file to use different `DATABASE_URL` values for each environment, and confirm that your `/api/studio` endpoint is reading the correct one.

3. **Apply custom styling**: The Studio component ships with a default look. Pass in [your own theme](https://www.prisma.io/docs/studio/integrations/embedding#custom-styling) and adjust colors, typography, or branding to match the rest of your application. This helps Studio feel like a native part of your app rather than a standalone tool.

By adding authentication, environment-specific settings, and styling, you move from a working demo to a production setup.

For more patterns and examples, see the [Prisma Studio Core demo repository](https://github.com/prisma/studio-core-demo), which includes an alternative implementation using Hono.js and React. If you prefer a guided walkthrough, watch the YouTube video: [\*\*Use Prisma Studio in Your Own Applications
\*\*](https://www.youtube.com/watch?v=Up5vG2YHPvc).

## Related pages

- [`AI SDK (with Next.js)`](https://www.prisma.io/docs/guides/integrations/ai-sdk): Build a chat application with AI SDK, Prisma ORM, and Next.js that stores chat sessions and messages in Prisma Postgres.
- [`Datadog`](https://www.prisma.io/docs/guides/integrations/datadog): Learn how to configure Datadog tracing for a Prisma ORM project. Capture spans for every query using the @prisma/instrumentation package, dd-trace, and view them in Datadog
- [`GitHub Actions`](https://www.prisma.io/docs/guides/integrations/github-actions): Provision a Prisma Postgres database for every pull request with GitHub Actions and the Prisma CLI, apply your migrations and seed data to it, and delete it when the pull request closes.
- [`Permit.io`](https://www.prisma.io/docs/guides/integrations/permit-io): Learn how to implement access control with Prisma ORM with Permit.io
- [`pgfence`](https://www.prisma.io/docs/guides/integrations/pgfence): Analyze Prisma Migrate SQL files for dangerous lock patterns, risk levels, and safe rewrite recipes before deploying to production

# GitHub Actions (/docs/guides/integrations/github-actions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Provision a Prisma Postgres database for every pull request with GitHub Actions and the Prisma CLI, apply your migrations and seed data to it, and delete it when the pull request closes.

Location: Guides > Integrations > GitHub Actions

## Introduction [#introduction]

This guide shows you how to create and delete [Prisma Postgres](https://www.prisma.io/docs/postgres) databases from GitHub Actions with the Prisma CLI. The workflow provisions a database for every pull request, applies your checked-in migrations, seeds it with sample data, and leaves a comment on the pull request with the database name and status.

![GitHub Actions comment](https://www.prisma.io/img/guides/github-comment.png)

When the pull request is closed, the workflow deletes the database. Every pull request gets its own isolated database, so migrations and data changes can be tested without touching a shared development database.

The project setup, migrations, seed script, and the `postgres create`, `postgres list`, and `postgres connection create` commands below were run against a live Prisma Postgres database. The workflow file is assembled from those commands.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/integrations/github-actions](https://www.prisma.io/docs/guides/v7/integrations/github-actions).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* A [Prisma Data Platform](https://console.prisma.io?utm_source=actions_guide\&utm_medium=docs) account
* A GitHub repository
* `jq`, to read the CLI's JSON output (GitHub-hosted runners have it preinstalled)

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Set up per-pull-request Prisma Postgres databases for this project with GitHub Actions and Prisma ORM.

1. Add Prisma ORM to the project with `npx prisma@latest orm init --yes --target postgres --authoring psl` (run it after a lockfile exists), then run `npx prisma@latest init` so the Prisma agent skills are installed and stay current, and use them. Define User and Post models in `src/prisma/contract.prisma`, run `npx prisma contract emit`, then `npx prisma migration plan --name init` and `npx prisma db migrate` against the DATABASE_URL I give you (or one from `npx create-db@latest`).
2. Write `src/prisma/seed.ts` that creates two users with posts through `db.orm.public.User.create` and `db.orm.public.Post.create`, skips when users already exist (use `.aggregate((a) => ({ total: a.count() }))`, not `.count()`), and ends with `await db.close()`. Add a `seed` script and verify `npm run seed` works twice.
3. Check `npx prisma auth whoami`; if I am not signed in, stop and ask me to run `npx prisma auth login`. Create a dedicated platform project with `npx prisma project create <name>` and show me the project id.
4. Write `.github/workflows/prisma-postgres-preview.yml` following https://www.prisma.io/docs/guides/integrations/github-actions.md: a provision job that finds or creates a database named after the pull request with `npx prisma postgres list|create --project "$PRISMA_PROJECT_ID" --json`, reads `.envelope.result.connectionString` with jq, runs `db migrate --db`, `db verify --db`, and `npm run seed`, then comments on the pull request; and a cleanup job that deletes the database with `postgres delete <id> --confirm <id>` when the pull request closes. Always pass `--project`; the CLI does not read PRISMA_PROJECT_ID from the environment for these commands.
5. Tell me which GitHub secrets to add: PRISMA_SERVICE_TOKEN, PRISMA_WORKSPACE_ID, PRISMA_PROJECT_ID.
```

## 1. Set up the project [#1-set-up-the-project]

Create a project and make it an ES module:

  

#### bun

```bash
mkdir prisma-gha-demo && cd prisma-gha-demo
bun init
npm pkg set type module
# couldn't auto-convert command
bun install
```

#### pnpm

```bash
mkdir prisma-gha-demo && cd prisma-gha-demo
pnpm init
npm pkg set type=module
# couldn't auto-convert command
pnpm install
```

#### yarn

```bash
mkdir prisma-gha-demo && cd prisma-gha-demo
yarn init
npm pkg set type=module
# couldn't auto-convert command
yarn install
```

#### npm

```bash
mkdir prisma-gha-demo && cd prisma-gha-demo
npm init
npm pkg set type=module
npm install
```

The empty `npm install` writes a `package-lock.json`. `orm init` picks the package manager from the lockfile it finds, so creating one first keeps the setup on npm.

## 2. Add Prisma ORM [#2-add-prisma-orm]

In this step you add Prisma ORM to the project, define the data model, create the first migration, and seed the database locally. Everything you do here runs again inside GitHub Actions in step 4, against a fresh database.

### 2.1. Initialize Prisma ORM [#21-initialize-prisma-orm]

  

#### bun

```bash
bunx prisma@latest orm init --yes --target postgres --authoring psl
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### yarn

```bash
yarn dlx prisma@latest orm init --yes --target postgres --authoring psl
```

#### npm

```bash
npx prisma@latest orm init --yes --target postgres --authoring psl
```

This writes `prisma.config.ts`, `src/prisma/contract.prisma`, `src/prisma/db.ts`, `.env.example`, `tsconfig.json`, and `prisma-8.md`, installs `@prisma/orm-postgres` and `dotenv` plus the `prisma`, `@types/node`, and `@prisma/cli-engine` dev dependencies, and emits `src/prisma/contract.json` and `src/prisma/contract.d.ts`.

Those two emitted files are the whole client. There is no generated client package, no `prisma generate`, and no driver adapter to install: the runtime in `src/prisma/db.ts` reads `contract.json` and connects with the `DATABASE_URL` it finds in `.env`.

```typescript title="src/prisma/db.ts" no-copy
import 'dotenv/config';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});
```

### 2.2. Define the contract [#22-define-the-contract]

`orm init` starts you with `User` and `Post` models. Add a `published` flag to `Post`:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  username  String?
  name      String?
  posts     Post[]
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false) // [!code ++]
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt TimestamptzString @default(now())
  updatedAt temporal.updatedAtString()
}
```

Emit the contract again so `contract.json` and the types match:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

```text no-copy
✔ Emitted contract.json and contract.d.ts

storageHash:    0c3a18eb65d5a5027c444cf0626d843cdb41dfd5fe8e66d6fce8d2eab460c971
executionHash:  796fa270d853489edb1c3e0d332d596412292127a259b856b495a498c752882a
profileHash:    3916f444a8a17ad749191acf9e08dad97d1a327b88c2f1d45d12f240296aa8b2
```

### 2.3. Connect a development database [#23-connect-a-development-database]

Copy `.env.example` to `.env` and set `DATABASE_URL` to a PostgreSQL database you can use for development. A local PostgreSQL works, or create a Prisma Postgres database with `npx create-db@latest` and paste the connection string it prints:

```bash title=".env"
DATABASE_URL="postgres://user:password@localhost:5432/prisma_gha_demo"
```

`prisma.config.ts` loads `.env`, so every CLI command below reads this value. The workflow overrides it per run with `--db`.

### 2.4. Plan and apply the first migration [#24-plan-and-apply-the-first-migration]

The workflow applies migrations that are committed to the repository, so create the first one now:

  

#### bun

```bash
bunx prisma migration plan --name init
```

#### pnpm

```bash
pnpm prisma migration plan --name init
```

#### yarn

```bash
yarn prisma migration plan --name init
```

#### npm

```bash
npx prisma migration plan --name init
```

```text no-copy
✔ Planned 6 operation(s)

migrations/app/20260910T1549_init
├─ Create schema "public"
├─ Create table "Post"
├─ Create table "User"
├─ Add unique constraint on "User" (email)
├─ Create index "Post_authorId_idx_e47547ed" on "Post"
└─ Add foreign key "Post_authorId_fkey" on "Post"

from:       (baseline)
to:         0c3a18eb65d5a5027c444cf0626d843cdb41dfd5fe8e66d6fce8d2eab460c971
app space:  migrations/app/20260910T1549_init
```

`migration plan` is offline. It writes a migration directory under `migrations/app/` and prints a DDL preview; it does not touch the database. Apply it to your development database:

  

#### bun

```bash
bunx prisma db migrate
```

#### pnpm

```bash
pnpm prisma db migrate
```

#### yarn

```bash
yarn prisma db migrate
```

#### npm

```bash
npx prisma db migrate
```

```text no-copy
✔ Applied 1 migration(s) (6 operation(s)) across 1 contract space(s)

App space
├─ Create schema "public"
├─ Create table "Post"
├─ Create table "User"
├─ Add unique constraint on "User" (email)
├─ Create index "Post_authorId_idx_e47547ed" on "Post"
├─ Add foreign key "Post_authorId_fkey" on "Post"
└─ marker 0c3a18eb65d5a5027c444cf0626d843cdb41dfd5fe8e66d6fce8d2eab460c971
```

Commit the `migrations/` directory. Whenever you change the contract, run `contract emit`, `migration plan --name <change>`, and `db migrate` again; the pull request's database then receives exactly the migrations the pull request adds. See [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work) for the full loop.

### 2.5. Seed the database [#25-seed-the-database]

Create `src/prisma/seed.ts`. Prisma ORM writes take one row at a time and return the inserted row, so create each user, then create its posts with the returned `id`:

```typescript title="src/prisma/seed.ts"
import { db } from "./db.ts";

const users = [
  {
    name: "Alice",
    email: "alice@prisma.io",
    posts: [
      { title: "Join the Prisma Discord", content: "https://pris.ly/discord", published: true },
      { title: "Prisma on YouTube", content: "https://pris.ly/youtube", published: false },
    ],
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
    posts: [
      { title: "Follow Prisma on Twitter", content: "https://twitter.com/prisma", published: true },
    ],
  },
];

async function main() {
  const { total } = await db.orm.public.User.aggregate((a) => ({ total: a.count() }));
  if (total > 0) {
    console.log(`Database already has ${total} users, skipping seed`);
    return;
  }

  for (const { posts, ...user } of users) {
    const created = await db.orm.public.User.create(user);
    for (const post of posts) {
      await db.orm.public.Post.create({ ...post, authorId: created.id });
    }
    console.log(`Seeded ${created.email} with ${posts.length} posts`);
  }
}

main()
  .catch((error) => {
    console.error(error);
    process.exitCode = 1;
  })
  .finally(() => db.close());
```

The guard at the top makes the script safe to run twice, which matters when a pull request is reopened and the workflow runs against a database that already has data. The `db.close()` at the end releases the connection pool; without it the process keeps running after the seed finishes.

Add a script for it:

```json title="package.json"
{
  "scripts": {
    "contract:emit": "prisma contract emit",
    "seed": "node src/prisma/seed.ts" // [!code ++]
  }
}
```

Node.js 24 runs the TypeScript file directly. Run it:

  

#### bun

```bash
bun run seed
```

#### pnpm

```bash
pnpm run seed
```

#### yarn

```bash
yarn seed
```

#### npm

```bash
npm run seed
```

```text no-copy
Seeded alice@prisma.io with 2 posts
Seeded bob@prisma.io with 1 posts
```

Run it again and the guard reports `Database already has 2 users, skipping seed`.

To check the data, put a query in `query.ts` and run it with `node query.ts`:

```typescript title="query.ts"
import { db } from "./src/prisma/db.ts";

const users = await db.orm.public.User.select("id", "email", "name")
  .include("posts", (post) => post.select("title", "published"))
  .all();
console.log(JSON.stringify(users, null, 2));
await db.close();
```

```json no-copy
[
  {
    "id": 1,
    "email": "alice@prisma.io",
    "name": "Alice",
    "posts": [
      { "title": "Join the Prisma Discord", "published": true },
      { "title": "Prisma on YouTube", "published": false }
    ]
  },
  {
    "id": 2,
    "email": "bob@prisma.io",
    "name": "Bob",
    "posts": [{ "title": "Follow Prisma on Twitter", "published": true }]
  }
]
```

The project now works locally. Next, set up the platform side that the workflow will drive.

## 3. Create a platform project for preview databases [#3-create-a-platform-project-for-preview-databases]

The Prisma CLI manages Prisma Postgres databases with the [`postgres`](https://www.prisma.io/docs/cli/postgres) commands. Databases live inside a platform [project](https://www.prisma.io/docs/cli/project), so create a dedicated project for the workflow. That keeps preview databases away from your development databases and gives the workflow a single project id to target.

Sign in once (it opens a browser):

  

#### bun

```bash
bunx prisma auth login
```

#### pnpm

```bash
pnpm prisma auth login
```

#### yarn

```bash
yarn prisma auth login
```

#### npm

```bash
npx prisma auth login
```

Create the project from your project directory:

  

#### bun

```bash
bunx prisma project create prisma-gha-preview
```

#### pnpm

```bash
pnpm prisma project create prisma-gha-preview
```

#### yarn

```bash
yarn prisma project create prisma-gha-preview
```

#### npm

```bash
npx prisma project create prisma-gha-preview
```

This creates the project in your workspace and links the directory to it by writing `.prisma/local.json`, which it also adds to `.gitignore`. Show the link to get the project id:

  

#### bun

```bash
bunx prisma project show
```

#### pnpm

```bash
pnpm prisma project show
```

#### yarn

```bash
yarn prisma project show
```

#### npm

```bash
npx prisma project show
```

```text no-copy
ℹ This directory is linked to the following platform project.

local repo:  ~/prisma-gha-demo
platform:    Prisma Sandbox / prisma-gha-preview
url:         https://api.prisma.io/v1/projects/proj_abc123def456
```

The `proj_...` segment at the end of the URL is the project id. Keep it; you store it as a GitHub secret in step 6.

Now try the exact commands the workflow runs. Create a database and ask for JSON output:

  

#### bun

```bash
bunx prisma postgres create pr-test --project proj_abc123def456 --json
```

#### pnpm

```bash
pnpm prisma postgres create pr-test --project proj_abc123def456 --json
```

#### yarn

```bash
yarn prisma postgres create pr-test --project proj_abc123def456 --json
```

#### npm

```bash
npx prisma postgres create pr-test --project proj_abc123def456 --json
```

```json no-copy
{
  "kind": "result",
  "envelope": {
    "ok": true,
    "commandId": "postgres.create",
    "result": {
      "projectId": "proj_abc123def456",
      "projectName": "prisma-gha-preview",
      "database": {
        "id": "db_abc123def456",
        "name": "pr-test",
        "region": "us-east-1",
        "status": "ready"
      },
      "connection": { "id": "con_abc123def456", "name": "Prisma Postgres API Key" },
      "connectionString": "postgres://<credentials>@pooled.db.prisma.io:5432/postgres?sslmode=require"
    }
  }
}
```

The connection string is shown once, in this result, and never again. In `--json` mode every command prints newline-delimited events and ends with one `"kind": "result"` line whose `envelope` carries `ok`, `result`, and on failure `error.code`. The workflow reads the connection string with `jq` from that line. Apply the migration and seed the new database by passing the connection string explicitly:

```bash
export PREVIEW_URL="<the connectionString from above>"
npx prisma db migrate --db "$PREVIEW_URL"
npx prisma db verify --db "$PREVIEW_URL"
DATABASE_URL="$PREVIEW_URL" npm run seed
```

```text no-copy
✔ Applied 1 migration(s) (6 operation(s)) across 1 contract space(s)
✔ Database marker and schema match contract
Seeded alice@prisma.io with 2 posts
Seeded bob@prisma.io with 1 posts
```

`--db` overrides the `DATABASE_URL` from `.env` for the CLI, and the environment variable in front of `npm run seed` does the same for the seed script.

List the project's databases to see it:

  

#### bun

```bash
bunx prisma postgres list --project proj_abc123def456
```

#### pnpm

```bash
pnpm prisma postgres list --project proj_abc123def456
```

#### yarn

```bash
yarn prisma postgres list --project proj_abc123def456
```

#### npm

```bash
npx prisma postgres list --project proj_abc123def456
```

```text no-copy
project:  prisma-gha-preview

Name     Branch                       Region     Status  Id
pr-test  br_abc123def456  us-east-1  ready   db_abc123def456
```

Deleting a database is destructive, so `postgres delete` asks you to type the database id. In a script there is nobody to type it, so pass it with `--confirm`:

  

#### bun

```bash
bunx prisma postgres delete db_abc123def456 --project proj_abc123def456 --confirm db_abc123def456
```

#### pnpm

```bash
pnpm prisma postgres delete db_abc123def456 --project proj_abc123def456 --confirm db_abc123def456
```

#### yarn

```bash
yarn prisma postgres delete db_abc123def456 --project proj_abc123def456 --confirm db_abc123def456
```

#### npm

```bash
npx prisma postgres delete db_abc123def456 --project proj_abc123def456 --confirm db_abc123def456
```

Without `--confirm`, a non-interactive run stops with `CLI.CONSENT_REQUIRED` and tells you the exact token to pass. The delete itself did not complete while validating this guide (the platform returned a server error for every delete that day), so no success output is shown.

## 4. Add the GitHub Actions workflow [#4-add-the-github-actions-workflow]

In this step you set up a GitHub Actions workflow that provisions a Prisma Postgres database when a pull request is opened, reopened, or updated, and deletes it when the pull request is closed.

### 4.1. Create the workflow file [#41-create-the-workflow-file]

```bash
mkdir -p .github/workflows
touch .github/workflows/prisma-postgres-preview.yml
```

The workflow:

* Finds or creates a database named after the pull request
* Applies the repository's migrations with `db migrate` and checks them with `db verify`
* Seeds the database
* Comments on the pull request
* Deletes the database when the pull request is closed
* Supports manual runs for both provisioning and cleanup

> [!NOTE]
> The workflow creates databases in `us-east-1`. Change `PRISMA_POSTGRES_REGION` in the `env` block to the [region](https://www.prisma.io/docs/postgres/npx-create-db#available-cli-options) closest to your runners.

### 4.2. Add the base configuration [#42-add-the-base-configuration]

Paste the following into `.github/workflows/prisma-postgres-preview.yml`. It sets the triggers, the secrets the CLI reads, and the raw database name:

```yaml title=".github/workflows/prisma-postgres-preview.yml"
name: Prisma Postgres preview database

on:
  pull_request:
    types: [opened, reopened, synchronize, closed]
  workflow_dispatch:
    inputs:
      action:
        description: "Action to perform"
        required: true
        default: "provision"
        type: choice
        options:
          - provision
          - cleanup
      database_name:
        description: "Database name (optional, sanitized before use)"
        required: false
        type: string

env:
  PRISMA_SERVICE_TOKEN: ${{ secrets.PRISMA_SERVICE_TOKEN }}
  PRISMA_WORKSPACE_ID: ${{ secrets.PRISMA_WORKSPACE_ID }}
  PRISMA_PROJECT_ID: ${{ secrets.PRISMA_PROJECT_ID }}
  PRISMA_POSTGRES_REGION: us-east-1
  RAW_DB_NAME: ${{ github.event.pull_request.number != null && format('pr-{0}-{1}', github.event.pull_request.number, github.event.pull_request.head.ref) || (inputs.database_name != '' && inputs.database_name || format('test-{0}', github.run_number)) }}

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
```

`PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` are how the CLI authenticates without a browser: with those two variables set, every platform command in the job runs as the service token. `PRISMA_PROJECT_ID` is passed to each command as `--project`, because the `postgres` commands do not pick the project up from the environment on their own.

### 4.3. Add the provision job [#43-add-the-provision-job]

Append the following under a `jobs:` key. The job installs dependencies, finds or creates the database, applies migrations, seeds, and comments on the pull request:

```yaml title=".github/workflows/prisma-postgres-preview.yml"
jobs:
  provision-database:
    if: (github.event_name == 'pull_request' && github.event.action != 'closed') || (github.event_name == 'workflow_dispatch' && inputs.action == 'provision')
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    timeout-minutes: 15
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "24"
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Validate secrets
        run: |
          for name in PRISMA_SERVICE_TOKEN PRISMA_WORKSPACE_ID PRISMA_PROJECT_ID; do
            if [ -z "${!name}" ]; then
              echo "Error: $name secret is not set"
              exit 1
            fi
          done

      - name: Sanitize database name
        run: |
          DB_NAME="$(echo "$RAW_DB_NAME" | tr '/' '-' | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9-\n' '-' | cut -c1-63)"
          echo "DB_NAME=$DB_NAME" >> "$GITHUB_ENV"

      - name: Find existing database
        id: find-db
        run: |
          DB_ID="$(npx prisma postgres list --project "$PRISMA_PROJECT_ID" --json \
            | jq -r --arg name "$DB_NAME" 'select(.kind == "result") | .envelope.result.items[] | select(.name == $name) | .id')"
          if [ -n "$DB_ID" ]; then
            echo "Database $DB_NAME exists with id $DB_ID"
            echo "db-id=$DB_ID" >> "$GITHUB_OUTPUT"
          else
            echo "No database named $DB_NAME yet"
          fi

      - name: Create database
        id: create-db
        if: steps.find-db.outputs.db-id == ''
        run: |
          RESULT="$(npx prisma postgres create "$DB_NAME" --project "$PRISMA_PROJECT_ID" --region "$PRISMA_POSTGRES_REGION" --json \
            | jq -c 'select(.kind == "result") | .envelope')"
          if [ "$(echo "$RESULT" | jq -r '.ok')" != "true" ]; then
            echo "Failed to create database:"
            echo "$RESULT" | jq '.error'
            exit 1
          fi
          DATABASE_URL="$(echo "$RESULT" | jq -r '.result.connectionString')"
          echo "::add-mask::$DATABASE_URL"
          echo "DATABASE_URL=$DATABASE_URL" >> "$GITHUB_ENV"
          echo "Created database $DB_NAME ($(echo "$RESULT" | jq -r '.result.database.id'))"

      - name: Create a connection for the existing database
        if: steps.find-db.outputs.db-id != ''
        run: |
          RESULT="$(npx prisma postgres connection create "${{ steps.find-db.outputs.db-id }}" --project "$PRISMA_PROJECT_ID" --json \
            | jq -c 'select(.kind == "result") | .envelope')"
          if [ "$(echo "$RESULT" | jq -r '.ok')" != "true" ]; then
            echo "Failed to create a connection:"
            echo "$RESULT" | jq '.error'
            exit 1
          fi
          DATABASE_URL="$(echo "$RESULT" | jq -r '.result.connectionString')"
          echo "::add-mask::$DATABASE_URL"
          echo "DATABASE_URL=$DATABASE_URL" >> "$GITHUB_ENV"

      - name: Apply migrations
        run: |
          npx prisma db migrate --db "$DATABASE_URL"
          npx prisma db verify --db "$DATABASE_URL"

      - name: Seed database
        run: npm run seed

      - name: Comment on the pull request
        if: success() && github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `Database provisioned successfully!\n\nDatabase name: ${process.env.DB_NAME}\nStatus: Ready and seeded with sample data`
            })
```

Two details are worth knowing:

* A database name is only known once; the connection string is not. When the pull request is reopened or gets a new commit, the database already exists, so the job asks for a fresh connection string with `postgres connection create` instead of creating a second database.
* The connection string goes into `$GITHUB_ENV` as `DATABASE_URL` after `::add-mask::` hides it from the logs. The seed script and `src/prisma/db.ts` read `process.env.DATABASE_URL`, and the CLI steps pass it with `--db`, so no `.env` file is needed in CI.

### 4.4. Add the cleanup job [#44-add-the-cleanup-job]

Append the cleanup job after `provision-database`, at the same indentation. It looks the database up by name and deletes it:

```yaml title=".github/workflows/prisma-postgres-preview.yml"
  cleanup-database:
    if: (github.event_name == 'pull_request' && github.event.action == 'closed') || (github.event_name == 'workflow_dispatch' && inputs.action == 'cleanup')
    runs-on: ubuntu-latest
    permissions:
      contents: read
    timeout-minutes: 5
    steps:
      - name: Check out the repository
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "24"
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Validate secrets
        run: |
          for name in PRISMA_SERVICE_TOKEN PRISMA_WORKSPACE_ID PRISMA_PROJECT_ID; do
            if [ -z "${!name}" ]; then
              echo "Error: $name secret is not set"
              exit 1
            fi
          done

      - name: Sanitize database name
        run: |
          DB_NAME="$(echo "$RAW_DB_NAME" | tr '/' '-' | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9-\n' '-' | cut -c1-63)"
          echo "DB_NAME=$DB_NAME" >> "$GITHUB_ENV"

      - name: Delete database
        run: |
          DB_ID="$(npx prisma postgres list --project "$PRISMA_PROJECT_ID" --json \
            | jq -r --arg name "$DB_NAME" 'select(.kind == "result") | .envelope.result.items[] | select(.name == $name) | .id')"
          if [ -z "$DB_ID" ]; then
            echo "No database named $DB_NAME, nothing to delete"
            exit 0
          fi
          echo "Deleting $DB_NAME ($DB_ID)"
          npx prisma postgres delete "$DB_ID" --project "$PRISMA_PROJECT_ID" --confirm "$DB_ID"
```

The cleanup job checks out the repository and installs dependencies too, so `npx prisma` runs the same CLI version as the provision job.

## 5. Store the code in GitHub [#5-store-the-code-in-github]

If you do not have a repository yet, [create one on GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository). Then push the project, including `migrations/` and the workflow file:

```bash
git init
git add .
git commit -m "Add Prisma 8 and the preview database workflow"
git branch -M main
git remote add origin https://github.com/<your-username>/<repository-name>.git
git push -u origin main
```

`.env` and `.prisma/` are gitignored, so neither your development connection string nor your local project link is pushed.

## 6. Add the secrets in GitHub [#6-add-the-secrets-in-github]

The workflow needs three secrets.

### 6.1. Service token [#61-service-token]

A service token lets the CLI act on your workspace without a browser:

1. Open [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides) and select the workspace that holds your `prisma-gha-preview` project.
2. Go to **Settings** and then **Service Tokens**.
3. Click **New Service Token**, then copy the token. It is shown once.

Service tokens do not expire; revoke it from the same page when you no longer need it.

### 6.2. Workspace id and project id [#62-workspace-id-and-project-id]

The CLI needs the workspace the token belongs to and the project to create databases in. Print both from your project directory:

  

#### bun

```bash
bunx prisma auth whoami --json
bunx prisma project show --json
```

#### pnpm

```bash
pnpm prisma auth whoami --json
pnpm prisma project show --json
```

#### yarn

```bash
yarn prisma auth whoami --json
yarn prisma project show --json
```

#### npm

```bash
npx prisma auth whoami --json
npx prisma project show --json
```

Copy `workspace.id` from the first result and `project.id` (the `proj_...` value) from the second.

### 6.3. Add them to the repository [#63-add-them-to-the-repository]

1. Open your GitHub repository and go to **Settings**.
2. Expand **Secrets and variables** and click **Actions**.
3. Click **New repository secret** and add each of the following:
   * `PRISMA_SERVICE_TOKEN`: the service token
   * `PRISMA_WORKSPACE_ID`: the workspace id
   * `PRISMA_PROJECT_ID`: the project id

The workflow reads them through the `env` block in step 4.2.

## 7. Try the workflow [#7-try-the-workflow]

You can test the setup in two ways. The workflow run itself was not executed while validating this guide; the commands it runs were, in step 3.

**Option 1: Open a pull request**

1. Create a branch, change something, and open a pull request.
2. The `provision-database` job creates a database named `pr-<number>-<branch>`, applies the migrations, seeds it, and comments on the pull request.
3. Push another commit and the job runs again against the same database with a fresh connection string.
4. Close the pull request and the `cleanup-database` job deletes the database.

**Option 2: Run it manually**

1. Open the **Actions** tab and select **Prisma Postgres preview database**.
2. Click **Run workflow**, choose `provision`, and optionally enter a database name.
3. Run it again with `cleanup` and the same name to delete the database.

## 8. Migrate a shared database from a workflow [#migrate-a-shared-database]

The preview job creates a new database per pull request. A database other people share, such as staging, is migrated by a job that runs on every push to `main`, and that job is one command: `db migrate`. It is safe to run unattended. Before any operation runs, it reads the database's marker and refuses with `MIGRATION.MARKER_MISMATCH` if that marker names a state that no migration in your files ends at, which is what a `db update` run against the database, or a migration from a branch that never merged, leaves behind. Each operation then checks that the database is in the state it expects before it runs, and a successful run writes the new marker.

Three terms come up in this section, so here is what they mean. `contract emit` prints a `storageHash`, and that hash identifies one version of your contract. Prisma ORM calls that version a contract state. The database records which state it matches in a marker, a row Prisma ORM keeps in the database. A ref is a name you give a state, like a Git tag. The job applies migrations only up to the state a ref called `staging` points at, so a migration merged after that point waits until you point the ref at it. [Name important states with refs](https://www.prisma.io/docs/orm/migrations/the-migration-graph#name-important-states-with-refs) has the details.

Create the `staging` ref in the pull request that adds the migration. `migration ref set` takes the migration directory's bare name, `20260910T1549_init` from the path `migration plan` printed in step 2.4. It points the ref at the state after that migration and writes `migrations/app/refs/staging.json`. Commit that file with the migration:

  

#### bun

```bash
bunx prisma migration ref set staging 20260910T1549_init
```

#### pnpm

```bash
pnpm prisma migration ref set staging 20260910T1549_init
```

#### yarn

```bash
yarn prisma migration ref set staging 20260910T1549_init
```

#### npm

```bash
npx prisma migration ref set staging 20260910T1549_init
```

Do this again in every pull request that adds a migration: run `migration ref set staging <new directory name>` and commit the updated `staging.json`. The job applies migrations only up to the state the ref names, so if you forget, the new migration never runs. On a repository that already has migrations, point the ref at the newest one staging should have. If `staging.json` does not exist at all, the job fails with `MIGRATION.REF_NOT_FOUND`.

Add the connection string of your staging database, whether you created it with `postgres create` as in step 3 or host it elsewhere, as a repository secret named `STAGING_DATABASE_URL`, as in step 6.3. Then add the workflow. It needs no platform secrets, because it runs no `postgres` commands, and no `contract emit`, because the emitted contract is committed with the migrations:

```yaml title=".github/workflows/migrate-staging.yml"
name: Migrate staging

on:
  push:
    branches: [main]

jobs:
  migrate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: npm
      - run: npm ci
      - run: npx prisma db migrate --to staging --db "$DATABASE_URL"
        env:
          DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
```

When the job fails with `MIGRATION.MARKER_MISMATCH`, [Drift](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery#drift-when-the-database-isnt-where-migrations-left-it) says what to do. To see what the job would apply before you push, run `npx prisma migration status --to staging --db "$STAGING_DATABASE_URL"` from your machine; it changes nothing.

The workflow has no `db verify` step. `db verify` compares the database with the contract you last emitted, so if you point the `staging` ref at an earlier state on purpose, `db verify` would fail even though nothing is wrong.

As in step 7, this workflow was not run on GitHub while validating the guide; its command was run against a local database, including one that had been changed outside the migration system, which failed with `MIGRATION.MARKER_MISMATCH`.

## Common gotchas [#common-gotchas]

> [!WARNING]
> Always pass `--project` to the `postgres` commands in CI. From a fresh checkout there is no `.prisma/local.json`, and the commands do not fall back to the `PRISMA_PROJECT_ID` environment variable; without the flag they stop with `PROJECT.SETUP_REQUIRED`.

> [!WARNING]
> Keep the seed script's `db.close()`. The runtime owns a connection pool that keeps the Node.js process alive, so a script that forgets to close it never exits and the job runs until its timeout.

> [!NOTE]
> Use `--json` in every CI step that needs a value back. The `--json` stream ends with a `"kind": "result"` line; select that line with `jq 'select(.kind == "result")'` before reading `.envelope`, because progress events come first on the same stream.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add a `Comment` model to the contract, plan a migration for it, and update the seed script."
* "Add a test job to the preview workflow that runs `npm test` against the provisioned database after the seed step."
* "Change the workflow to create the preview database in `eu-central-1` and to skip the seed when the pull request is a draft."
* "Add a `migrate-production.yml` workflow like the staging one in step 8 that runs on a published release, with a `production` ref and a `PRODUCTION_DATABASE_URL` secret."

## Next steps [#next-steps]

You now have an automated GitHub Actions setup for ephemeral Prisma Postgres databases: one database per pull request, migrations applied and checked, sample data seeded, and cleanup on close. Extend it by running your test suite against the provisioned database, or by writing the connection string into a preview deployment.

* [`postgres` command reference](https://www.prisma.io/docs/cli/postgres): connections, backups, usage, and regions.
* [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration): what `db migrate` checks before and after each step.
* [Writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data): the create, update, and upsert calls the seed script uses.

## Related pages

- [`AI SDK (with Next.js)`](https://www.prisma.io/docs/guides/integrations/ai-sdk): Build a chat application with AI SDK, Prisma ORM, and Next.js that stores chat sessions and messages in Prisma Postgres.
- [`Datadog`](https://www.prisma.io/docs/guides/integrations/datadog): Learn how to configure Datadog tracing for a Prisma ORM project. Capture spans for every query using the @prisma/instrumentation package, dd-trace, and view them in Datadog
- [`Embedded Prisma Studio (with Next.js)`](https://www.prisma.io/docs/guides/integrations/embed-studio): Learn how to embed Prisma Studio directly in your Next.js application for database management
- [`Permit.io`](https://www.prisma.io/docs/guides/integrations/permit-io): Learn how to implement access control with Prisma ORM with Permit.io
- [`pgfence`](https://www.prisma.io/docs/guides/integrations/pgfence): Analyze Prisma Migrate SQL files for dangerous lock patterns, risk levels, and safe rewrite recipes before deploying to production

# Permit.io (/docs/guides/integrations/permit-io)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to implement access control with Prisma ORM with Permit.io

Location: Guides > Integrations > Permit.io

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version is not available yet: `@permitio/permit-prisma` is a Prisma Client extension, and Prisma ORM 8 uses [middleware](https://www.prisma.io/docs/orm/middleware/how-middleware-works) instead of client extensions.

## Introduction [#introduction]

[Permit.io](https://www.permit.io/) is an authorization-as-a-service platform that lets you implement fine-grained access control
rules based on real-world relationships.

This guide explains how to connect Permit.io to a new Express + Prisma app, define a
[Relationship-Based Access Control (ReBAC)](https://www.permit.io/blog/what-is-rebac) policy,
and automatically filter Prisma queries so users only see the data they're allowed to access.

You'll build a small project-task API to demonstrate access inheritance in action - no manual `WHERE` clauses required.

You can find a complete example of this guide in [Permit.io's ReBAC filtering walkthrough](https://www.permit.io/blog/prisma-orm-data-filtering-with-rebac).

## Prerequisites [#prerequisites]

* [Node.js v20+](https://nodejs.org/)
* [PostgreSQL](https://www.postgresql.org/) (local or hosted)
* [Prisma CLI](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference) (`npx prisma`)
* [TypeScript](https://www.typescriptlang.org/)
* [Permit CLI](https://github.com/permitio/permit-cli) (`npm install -g @permitio/cli`)

## 1. Set up your project [#1-set-up-your-project]

First of all, you'll create a new Express + Prisma project from scratch using TypeScript.
You'll also install the tools needed to support ReBAC filtering with Permit.io.

### 1.1 Create the project folder [#11-create-the-project-folder]

  

#### bun

```bash
mkdir prisma-rebac-filtering
cd prisma-rebac-filtering
bun init
```

#### pnpm

```bash
mkdir prisma-rebac-filtering
cd prisma-rebac-filtering
pnpm init
```

#### yarn

```bash
mkdir prisma-rebac-filtering
cd prisma-rebac-filtering
yarn init
```

#### npm

```bash
mkdir prisma-rebac-filtering
cd prisma-rebac-filtering
npm init
```

### 1.2 Install the required dependencies [#12-install-the-required-dependencies]

Install application and development dependencies:

  

#### bun

```bash
bun add express cors dotenv @prisma/client@7 @prisma/adapter-pg pg
```

#### pnpm

```bash
pnpm add express cors dotenv @prisma/client@7 @prisma/adapter-pg pg
```

#### yarn

```bash
yarn add express cors dotenv @prisma/client@7 @prisma/adapter-pg pg
```

#### npm

```bash
npm install express cors dotenv @prisma/client@7 @prisma/adapter-pg pg
```

  

#### bun

```bash
bun add --dev prisma@prev typescript tsx @types/pg
```

#### pnpm

```bash
pnpm add -D prisma@prev typescript tsx @types/pg
```

#### yarn

```bash
yarn add --dev prisma@prev typescript tsx @types/pg
```

#### npm

```bash
npm install -D prisma@prev typescript tsx @types/pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Then, initialize your Prisma setup:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

This creates:

* A `prisma/` directory with a default `schema.prisma` file
* A `prisma.config.ts` file for configuring Prisma
* A `.env` file at the root.

### 1.3 Set up your TypeScript config [#13-set-up-your-typescript-config]

Create a `tsconfig.json` file:

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "outDir": "dist"
  },
  "include": ["src", "scripts"]
}
```

### 1.4 Create your folder structure [#14-create-your-folder-structure]

Set up your project folders:

```bash
mkdir -p src/controllers src/middleware src/config scripts
```

You're now ready to define your Prisma data model.

## 2. The authorization model [#2-the-authorization-model]

Before continuing with the setup, define how access control will work in your application.

This guide uses &#x2A;*Relationship-Based Access Control (ReBAC)** to automatically restrict database queries based on a user's relationship to the data.

Here is what this looks like:

![ReBAC authorization model](https://www.prisma.io/img/guides/permitio/rebac.png)

### Scenario overview [#scenario-overview]

You're building a **project management API** that supports team-level access controls. Each project belongs to a team (like Marketing or Engineering), and users should only be able to access the projects, and their associated tasks, that they're assigned to.

ReBAC fits this case because:

* Access depends on relationships between users and data (e.g., team membership)
* You want task access to inherit from project access
* You want to avoid manually checking permissions in every controller

### Resources [#resources]

These are the main data entities you'll protect:

* `Project`: Represents a team-specific workspace that may contain business-critical data (timelines, budgets, client deliverables).
* `Task`: Represents an item of work that belongs to a project

### Relationships [#relationships]

* Projects contain tasks (`Project → Task`)
* Users are members of projects (`User → Project`)

### Instance-level roles [#instance-level-roles]

Instance-level roles describe what users can do with specific resources:

| Role             | Description                           |
| ---------------- | ------------------------------------- |
| `project#Member` | User can access a specific project    |
| `task#Member`    | User can access tasks in that project |

### Role derivation [#role-derivation]

ReBAC lets you **automatically derive roles** based on relationships. In this case:

* If a user is a `project#Member`, they automatically become a `task#Member` for all tasks within that project.
* New tasks inherit project access, so you do not need to update permissions manually.

### Access policies [#access-policies]

Once relationships and roles are defined, access policies determine what users can do:

| Role             | Action | Resource |
| ---------------- | ------ | -------- |
| `project#Member` | `read` | Project  |
| `task#Member`    | `read` | Task     |

This model ensures that:

* Users can only access the projects and tasks they're assigned to
* No cross-team visibility
* Access automatically stays in sync with the business structure

![Access control planning](https://www.prisma.io/img/guides/permitio/planning.png)

## 3. Define your data model [#3-define-your-data-model]

To support permission-aware data filtering, you need to structure your database so that relationships are clearly defined. In this case, every `Task` belongs to a `Project`, and users gain access to tasks by being members of the parent project.

### 3.1 Update your Prisma schema [#31-update-your-prisma-schema]

Open `prisma/schema.prisma` and replace the contents with the following:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
}

datasource db {
  provider = "postgresql"
}

model Project {
  id        String   @id @default(uuid())
  name      String
  tasks     Task[]   // One-to-many relationship for permission inheritance
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Task {
  id          String   @id @default(uuid())
  name        String
  description String?
  projectId   String
  project     Project  @relation(fields: [projectId], references: [id])
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}
```

### 3.2 Add `dotenv` to `prisma.config.ts` [#32-add-dotenv-to-prismaconfigts]

To get access to the variables in the `.env` file, they can either be loaded by your runtime, or by using `dotenv`.
Include an import for `dotenv` at the top of the `prisma.config.ts`

```ts
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 3.3 Run your first migration [#33-run-your-first-migration]

To create the database schema:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This will:

* Apply your schema to the connected PostgreSQL database
* Generate your Prisma Client
* Create tables for `Project` and `Task` with a one-to-many relationship

### 3.3 Confirm the structure [#33-confirm-the-structure]

You can open Prisma Studio to inspect your database:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

This structure allows the `@permitio/permit-prisma` extension to filter records by user relationships at query time. Next, you'll seed test data to simulate distinct team ownership over projects and tasks.

## 4. Seed test data with project boundaries [#4-seed-test-data-with-project-boundaries]

To test your data filtering logic, you'll create two projects, each with its own set of tasks. This separation simulates team ownership and will allow you to validate that users only see the data of their assigned project.

### 4.1 Create the seed script [#41-create-the-seed-script]

Create a new file at `scripts/seed.ts` and add the following:

```ts
import { PrismaClient } from "../src/generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

async function main() {
  console.log("🌱 Seeding test data...");

  // Clear existing records
  await prisma.task.deleteMany();
  await prisma.project.deleteMany();

  // Create Project Alpha for the Marketing team
  const projectAlpha = await prisma.project.create({
    data: {
      id: "project_alpha",
      name: "Marketing Campaign Q2",
    },
  });

  // Create Project Beta for the Engineering team
  const projectBeta = await prisma.project.create({
    data: {
      id: "project_beta",
      name: "API Development Sprint",
    },
  });

  // Add tasks to Project Alpha
  await prisma.task.createMany({
    data: [
      {
        id: "task-alpha-1",
        name: "Strategy Planning",
        description: "Define campaign goals and KPIs",
        projectId: projectAlpha.id,
      },
      {
        id: "task-alpha-2",
        name: "Budget Review",
        description: "Review marketing budget with finance",
        projectId: projectAlpha.id,
      },
    ],
  });

  // Add tasks to Project Beta
  await prisma.task.createMany({
    data: [
      {
        id: "task-beta-1",
        name: "Implement Auth API",
        description: "Create endpoints for user login/signup",
        projectId: projectBeta.id,
      },
      {
        id: "task-beta-2",
        name: "Schema Migration",
        description: "Update tables for new user roles",
        projectId: projectBeta.id,
      },
    ],
  });

  console.log("✅ Seeded 2 projects and 4 tasks with distinct ownership");
}

main()
  .catch((e) => {
    console.error("❌ Error seeding data:", e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

### 4.2 Run the seed script [#42-run-the-seed-script]

  

#### bun

```bash
bunx tsx scripts/seed.ts
```

#### pnpm

```bash
pnpm dlx tsx scripts/seed.ts
```

#### yarn

```bash
yarn dlx tsx scripts/seed.ts
```

#### npm

```bash
npx tsx scripts/seed.ts
```

If successful, you'll see:

✅ Seeded 2 projects and 4 tasks with distinct ownership

At this point, if you run a query like `prisma.task.findMany()`, it will return all tasks. In the next steps, you'll connect Permit.io to filter these results automatically based on the user's access rights.

## 5. Install and configure ReBAC filtering [#5-install-and-configure-rebac-filtering]

In this section, you'll install the `@permitio/permit-prisma` extension and configure it to automatically filter Prisma queries based on your access control policies.

### 5.1 Install the Permit extension [#51-install-the-permit-extension]

Install the `permit-prisma` package:

  

#### bun

```bash
bun add @permitio/permit-prisma
```

#### pnpm

```bash
pnpm add @permitio/permit-prisma
```

#### yarn

```bash
yarn add @permitio/permit-prisma
```

#### npm

```bash
npm install @permitio/permit-prisma
```

### 5.2 Configure the Permit client [#52-configure-the-permit-client]

Create a new file at `src/config/permit-config.ts`:

```ts
import dotenv from "dotenv";
dotenv.config();

export const clientExtensionConfig = {
  permitConfig: {
    token: process.env.PERMIT_API_KEY!, // Your Permit.io API key
    pdp: process.env.PERMIT_PDP_URL || "http://localhost:7766", // Local or cloud PDP
    debug: true,
  },
  enableAutomaticChecks: true,
  enableDataFiltering: true, // Enables automatic query filtering
  enableResourceSync: true, // (Optional) Keeps Permit in sync with resource changes
};
```

> [!NOTE]
> API Key
> 
> You can find your API key and PDP URL in your [Permit.io dashboard](https://app.permit.io/).

### 5.3 What this configuration does [#53-what-this-configuration-does]

When you later extend the Prisma Client with this config:

* All Prisma queries will automatically check access rules
* `findMany()` and similar methods will **only return data the user is allowed to access**
* You no longer need to manually add `WHERE` clauses to enforce permissions

You're now ready to define your ReBAC policy using the Permit CLI.

## 6. Define your access control policy in Permit.io [#6-define-your-access-control-policy-in-permitio]

Next, you'll use the **Permit CLI** to apply a ready-made ReBAC template that matches your project-task structure.

### 6.1 Install the Permit CLI [#61-install-the-permit-cli]

  

#### bun

```bash
bun add --global @permitio/cli
```

#### pnpm

```bash
pnpm add -g @permitio/cli
```

#### yarn

```bash
yarn global add @permitio/cli
```

#### npm

```bash
npm install -g @permitio/cli
```

### 6.2 Log in to your Permit account [#62-log-in-to-your-permit-account]

Use the CLI to authenticate:

```bash
permit login
```

This opens a browser window where you can log in to your Permit.io account and link your CLI session to an environment.

### 6.3 Apply the ReBAC policy template [#63-apply-the-rebac-policy-template]

Permit provides a prebuilt policy structure for hierarchical data filtering.

Apply it using:

```bash
permit env template apply --template orm-data-filtering
```

This will create:

* **Resources**: `project`, `task`
* **Relationships**: `project` is the parent of `task`
* **Roles**:
  * `project#Member`: User can access a specific project
  * `task#Member`: Derived from project membership
* **Access policies**: Users with the appropriate roles can `read` each resource

### 6.4 View the policy in the Permit UI [#64-view-the-policy-in-the-permit-ui]

Go to the [Permit.io dashboard](https://app.permit.io/) and navigate to your environment to explore:

* Your resource graph
* Role derivations
* Relationship mappings
* Policy rules for `read` access

> [!NOTE]
> These rules are used by the @permitio/permit-prisma extension to determine which records to return for each user.

With your policy in place, you're now ready to wire up user context and filtering logic in your Express middleware.

## 7. Add middleware to set user context [#7-add-middleware-to-set-user-context]

To filter Prisma queries per user, you need to:

1. Identify the current user (simulated via an email header)
2. Attach the filtered Prisma Client instance to the request
3. Set the user in the Permit context (`prisma.$permit.setUser()`)

### 7.1 Create the middleware file [#71-create-the-middleware-file]

Create a new file: `src/middleware/auth.middleware.ts`

```ts
import { Request, Response, NextFunction } from "express";
import { PrismaClient } from "../generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";
import createPermitClientExtension from "@permitio/permit-prisma";
import { clientExtensionConfig } from "../config/permit-config";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

// Extend PrismaClient with Permit
const prisma = new PrismaClient({
  adapter,
}).$extends(createPermitClientExtension(clientExtensionConfig));

// Extend Request type with Prisma and user context
export interface AuthRequest extends Request {
  user?: { email: string };
  prisma?: typeof prisma;
}

export const authenticate = (req: AuthRequest, res: Response, next: NextFunction): void => {
  const userEmail = req.headers["x-user-email"] as string;

  if (!userEmail) {
    res.status(401).json({ error: "Missing user email" });
    return;
  }

  // Register the user in Permit context
  prisma.$permit.setUser(userEmail);

  // Add user + Prisma client to request
  req.user = { email: userEmail };
  req.prisma = prisma;

  next();
};
```

> [!WARNING]
> Going to prod.
> 
> In a production app, you'd replace the x-user-email header with proper authentication logic (e.g. JWT or session validation).

### 7.2 What this middleware does [#72-what-this-middleware-does]

* Reads the user's email from the request header
* Sets the user identity in the Permit context (used for query filtering)
* Adds the filtered Prisma client to the request object (`req.prisma`)
* Makes the user and database client available to all downstream route handlers

You're now ready to build your API endpoints without writing a single line of access control logic.

## 8. Build your API endpoints [#8-build-your-api-endpoints]

You'll now create two endpoints:

* `GET /api/projects`: returns all projects the user has access to
* `GET /api/tasks`: returns all tasks the user has access to (inherited from project membership)

Thanks to the Permit-Prisma integration, **you won't need to add any manual filtering logic**; the extension handles it.

### 8.1 Get user-visible projects [#81-get-user-visible-projects]

Create a controller file: `src/controllers/project.controller.ts`

```ts
import { Response } from "express";
import { AuthRequest } from "../middleware/auth.middleware";

export const getProjects = async (req: AuthRequest, res: Response) => {
  try {
    const prisma = req.prisma!;

    const projects = await prisma.project.findMany(); // Auto-filtered

    res.json({
      user: req.user?.email,
      count: projects.length,
      projects,
    });
  } catch (error: any) {
    console.error("Error fetching projects:", error);
    res.status(500).json({ error: error.message });
  }
};
```

> Even though this is a raw findMany() query, only authorized records will be returned for the current user.

### 8.2 Get user-visible tasks [#82-get-user-visible-tasks]

Create another controller: `src/controllers/task.controller.ts`

```ts
import { Response } from "express";
import { AuthRequest } from "../middleware/auth.middleware";

export const getTasks = async (req: AuthRequest, res: Response) => {
  try {
    const prisma = req.prisma!;
    const projectId = req.query.projectId as string;

    const where = projectId ? { projectId } : undefined;

    const tasks = await prisma.task.findMany({ where }); // Still filtered

    res.json({
      user: req.user?.email,
      count: tasks.length,
      tasks,
    });
  } catch (error: any) {
    console.error("Error fetching tasks:", error);
    res.status(500).json({ error: error.message });
  }
};
```

> [!NOTE]
> projectId
> 
> Even if you provide a projectId manually, the query results are still filtered by permissions.

### 8.3 What this demonstrates [#83-what-this-demonstrates]

* You can write **normal Prisma queries**
* Users will only get records they're allowed to see
* You don't need custom role-checking logic in every handler
* Task access is **automatically derived** from project membership

You're now ready to wire it all together and launch the app.

### 9.1 Create your Express app [#91-create-your-express-app]

Create `src/app.ts`:

```ts
import express from "express";
import cors from "cors";
import { authenticate } from "./middleware/auth.middleware";
import { getProjects } from "./controllers/project.controller";
import { getTasks } from "./controllers/task.controller";

const app = express();
const PORT = process.env.PORT || 3000;

app.use(cors());
app.use(express.json());

// Auth middleware applies ReBAC filtering per request
app.get("/api/projects", authenticate, getProjects);
app.get("/api/tasks", authenticate, getTasks);

app.listen(PORT, () => {
  console.log(`🚀 Server running at http://localhost:${PORT}`);
  console.log(`🔐 ReBAC filtering is now active`);
});
```

### 9.2 Run the server [#92-run-the-server]

Start the development server with:

  

#### bun

```bash
bunx tsx src/app.ts
```

#### pnpm

```bash
pnpm dlx tsx src/app.ts
```

#### yarn

```bash
yarn dlx tsx src/app.ts
```

#### npm

```bash
npx tsx src/app.ts
```

If everything is set up correctly, the console will display:

```
🚀 Server running at http://localhost:3000
🔐 ReBAC filtering is now active
```

### 9.3 Test your API [#93-test-your-api]

You can simulate requests as different users by setting the `x-user-email` header. This mimics logged-in users with access to specific projects.

### Example: John (Marketing team member) [#example-john-marketing-team-member]

```bash
curl -H "x-user-email: john@company.com" http://localhost:3000/api/projects
```

This should only return Project Alpha (and its tasks).

### Example: Mary (Engineering team member) [#example-mary-engineering-team-member]

```bash
curl -H "x-user-email: mary@company.com" http://localhost:3000/api/tasks
```

This should only return tasks from Project Beta.

> [!NOTE]
> If you haven't yet assigned users to project memberships in the Permit.io UI, visit the Policy Editor and assign users to roles (project#Member).

Once you've confirmed these results, your Prisma API is now enforcing secure, relationship-based access control, all &#x2A;*without adding manual filtering logic anywhere in your code.**

You've now built a secure API that:

* Filters query results based on user relationships
* Uses ReBAC to avoid role explosion and brittle permission logic
* Keeps permission checks out of your Prisma queries

## 10. Next steps [#10-next-steps]

Now that you've successfully implemented data filtering with Prisma and ReBAC, you can extend this foundation to support more complex authorization use cases and developer tooling.

### Extend your model [#extend-your-model]

* Add a `User` model and create a many-to-many `Membership` relationship between users and projects.
* Introduce instance-level roles like `Editor` or `Owner` with different permissions.
* Support additional actions like `create`, `update`, and `delete`, using Permit.io's role policies.

### Add authentication [#add-authentication]

Integrate your API with an auth provider (e.g., [Clerk](https://www.prisma.io/docs/guides/authentication/clerk/nextjs), Auth0) and replace the `x-user-email` header with a secure identity mechanism (like a JWT token).

### Use Permit Elements [#use-permit-elements]

Permit.io provides UI components for:

* Managing user access visually
* Reviewing access logs
* Approving access requests (MCP)

Explore [Permit Elements](https://docs.permit.io/embeddable-uis/overview/) to make access management easier for your end users or admins.

### More resources [#more-resources]

* [Permit.io ReBAC Policy Setup Guide](https://docs.permit.io/overview/create-a-rebac-policy)
* [Read the full guide: Data Filtering with Prisma and ReBAC](https://docs.permit.io/how-to/enforce-permissions/data-filtering)
* [ReBAC vs RBAC - Learn when to use which](https://www.permit.io/blog/rbac-vs-rebac)

## Related pages

- [`AI SDK (with Next.js)`](https://www.prisma.io/docs/guides/integrations/ai-sdk): Build a chat application with AI SDK, Prisma ORM, and Next.js that stores chat sessions and messages in Prisma Postgres.
- [`Datadog`](https://www.prisma.io/docs/guides/integrations/datadog): Learn how to configure Datadog tracing for a Prisma ORM project. Capture spans for every query using the @prisma/instrumentation package, dd-trace, and view them in Datadog
- [`Embedded Prisma Studio (with Next.js)`](https://www.prisma.io/docs/guides/integrations/embed-studio): Learn how to embed Prisma Studio directly in your Next.js application for database management
- [`GitHub Actions`](https://www.prisma.io/docs/guides/integrations/github-actions): Provision a Prisma Postgres database for every pull request with GitHub Actions and the Prisma CLI, apply your migrations and seed data to it, and delete it when the pull request closes.
- [`pgfence`](https://www.prisma.io/docs/guides/integrations/pgfence): Analyze Prisma Migrate SQL files for dangerous lock patterns, risk levels, and safe rewrite recipes before deploying to production

# pgfence (/docs/guides/integrations/pgfence)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Analyze Prisma Migrate SQL files for dangerous lock patterns, risk levels, and safe rewrite recipes before deploying to production

Location: Guides > Integrations > pgfence

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version is not available yet: pgfence reads `migration.sql` files, and Prisma ORM 8 migrations are TypeScript and JSON files with no SQL output to scan.

## Introduction [#introduction]

[pgfence](https://pgfence.com) is a PostgreSQL migration safety CLI that analyzes SQL migration files and reports lock modes, risk levels, and safe rewrite recipes. It uses PostgreSQL's actual parser ([libpg-query](https://github.com/launchql/libpg-query-node)) to understand exactly what each DDL statement does, what locks it acquires, and what it blocks.

Prisma Migrate generates plain SQL files at `prisma/migrations/*/migration.sql`. pgfence can analyze those files directly, catching dangerous patterns before they reach production.

Common issues pgfence detects include:

* `CREATE INDEX` without `CONCURRENTLY` (blocks writes)
* `ALTER COLUMN TYPE` (full table rewrite with `ACCESS EXCLUSIVE` lock)
* `ADD COLUMN ... NOT NULL` without a safe default (blocks reads and writes)
* Missing `lock_timeout` settings (risk of lock queue death spirals)

For each dangerous pattern, pgfence provides the exact safe alternative, the expand/contract sequence you should use instead.

## Prerequisites [#prerequisites]

* [Node.js v20+](https://nodejs.org/)
* A Prisma project using PostgreSQL as the database provider
* Existing migrations in `prisma/migrations/`

## 1. Install pgfence [#1-install-pgfence]

Add pgfence as a development dependency in your project:

  

#### bun

```bash
bun add --dev @flvmnt/pgfence
```

#### pnpm

```bash
pnpm add -D @flvmnt/pgfence
```

#### yarn

```bash
yarn add --dev @flvmnt/pgfence
```

#### npm

```bash
npm install -D @flvmnt/pgfence
```

## 2. Analyze your migrations locally [#2-analyze-your-migrations-locally]

Run pgfence against your Prisma migration files:

  

#### bun

```bash
bunx @flvmnt/pgfence analyze prisma/migrations/**/migration.sql
```

#### pnpm

```bash
pnpm dlx @flvmnt/pgfence analyze prisma/migrations/**/migration.sql
```

#### yarn

```bash
yarn dlx @flvmnt/pgfence analyze prisma/migrations/**/migration.sql
```

#### npm

```bash
npx @flvmnt/pgfence analyze prisma/migrations/**/migration.sql
```

pgfence parses every SQL statement and reports the lock mode, risk level, and any safe rewrites available.

### Understanding the output [#understanding-the-output]

pgfence assigns a risk level to each statement based on the PostgreSQL lock it acquires:

| Risk level   | Meaning                                                                                                           |
| ------------ | ----------------------------------------------------------------------------------------------------------------- |
| **LOW**      | Safe operations with minimal locking (e.g., `ADD COLUMN` with a constant default on PG 11+)                       |
| **MEDIUM**   | Operations that block writes but not reads (e.g., `CREATE INDEX` without `CONCURRENTLY`)                          |
| **HIGH**     | Operations that block writes and competing DDL, but not plain reads (e.g., `ADD FOREIGN KEY` without `NOT VALID`) |
| **CRITICAL** | Operations that take `ACCESS EXCLUSIVE` locks on large tables (e.g., `DROP TABLE`, `TRUNCATE`)                    |

Here is an example of pgfence analyzing a migration that adds an index without `CONCURRENTLY`:

```sql
-- prisma/migrations/20240115_add_index/migration.sql
CREATE INDEX "User_email_idx" ON "User"("email");
```

  

#### bun

```bash
bunx @flvmnt/pgfence analyze prisma/migrations/20240115_add_index/migration.sql
```

#### pnpm

```bash
pnpm dlx @flvmnt/pgfence analyze prisma/migrations/20240115_add_index/migration.sql
```

#### yarn

```bash
yarn dlx @flvmnt/pgfence analyze prisma/migrations/20240115_add_index/migration.sql
```

#### npm

```bash
npx @flvmnt/pgfence analyze prisma/migrations/20240115_add_index/migration.sql
```

pgfence will flag this as a `MEDIUM` risk because `CREATE INDEX` takes a `SHARE` lock, which blocks all writes to the table for the duration of the index build. It will suggest using `CREATE INDEX CONCURRENTLY` instead.

> [!WARNING]
> Prisma Migrate does not generate `CONCURRENTLY` variants automatically. If pgfence flags an index creation, you should manually edit the generated migration SQL file to add `CONCURRENTLY` before applying it. Note that `CREATE INDEX CONCURRENTLY` cannot run inside a transaction, so you will also need to ensure the migration runs outside a transaction block.

## 3. Use JSON output for programmatic checks [#3-use-json-output-for-programmatic-checks]

pgfence supports JSON output, which is useful for integrating with other tools or scripts:

  

#### bun

```bash
bunx @flvmnt/pgfence analyze --output json prisma/migrations/**/migration.sql
```

#### pnpm

```bash
pnpm dlx @flvmnt/pgfence analyze --output json prisma/migrations/**/migration.sql
```

#### yarn

```bash
yarn dlx @flvmnt/pgfence analyze --output json prisma/migrations/**/migration.sql
```

#### npm

```bash
npx @flvmnt/pgfence analyze --output json prisma/migrations/**/migration.sql
```

You can also set a maximum risk threshold for CI pipelines. The command exits with code 1 if any statement exceeds the threshold:

  

#### bun

```bash
bunx @flvmnt/pgfence analyze --ci --max-risk medium prisma/migrations/**/migration.sql
```

#### pnpm

```bash
pnpm dlx @flvmnt/pgfence analyze --ci --max-risk medium prisma/migrations/**/migration.sql
```

#### yarn

```bash
yarn dlx @flvmnt/pgfence analyze --ci --max-risk medium prisma/migrations/**/migration.sql
```

#### npm

```bash
npx @flvmnt/pgfence analyze --ci --max-risk medium prisma/migrations/**/migration.sql
```

## 4. Add pgfence to your CI pipeline [#4-add-pgfence-to-your-ci-pipeline]

Add pgfence as a safety check that runs before `prisma migrate deploy` in your CI/CD pipeline. This catches dangerous migration patterns before they reach your production database.

Here is a GitHub Actions workflow that runs pgfence on every pull request that includes migration changes:

```yaml title=".github/workflows/migration-safety.yml"
name: Migration safety check

on:
  pull_request:
    paths:
      - prisma/migrations/**

jobs:
  pgfence:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Install dependencies
        run: npm ci

      - name: Run pgfence analysis
        run: |
          shopt -s globstar
          npx @flvmnt/pgfence analyze --ci --max-risk medium prisma/migrations/**/migration.sql
```

This workflow only triggers when migration files change. If pgfence detects any statement with risk higher than `MEDIUM`, the check fails and blocks the pull request from merging.

> [!NOTE]
> You can adjust the `--max-risk` threshold to match your team's risk tolerance. Options are `low`, `medium`, `high`, and `critical`.

### Combining pgfence with deploy [#combining-pgfence-with-deploy]

If you have an existing deployment workflow, add pgfence as a step before `prisma migrate deploy`:

```yaml title=".github/workflows/deploy.yml"
- name: Run pgfence migration safety check
  run: |
    shopt -s globstar
    npx @flvmnt/pgfence analyze --ci --max-risk medium prisma/migrations/**/migration.sql

- name: Apply pending migrations
  run: npx prisma migrate deploy
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
```

## 5. Size-aware risk scoring (optional) [#5-size-aware-risk-scoring-optional]

pgfence can adjust risk levels based on actual table sizes. A `CREATE INDEX` on a 100-row table is very different from the same operation on a 10-million-row table.

To use size-aware scoring without giving pgfence direct database access, export a stats snapshot from your database and pass it to pgfence:

  

#### bun

```bash
bunx @flvmnt/pgfence analyze --stats-file pgfence-stats.json prisma/migrations/**/migration.sql
```

#### pnpm

```bash
pnpm dlx @flvmnt/pgfence analyze --stats-file pgfence-stats.json prisma/migrations/**/migration.sql
```

#### yarn

```bash
yarn dlx @flvmnt/pgfence analyze --stats-file pgfence-stats.json prisma/migrations/**/migration.sql
```

#### npm

```bash
npx @flvmnt/pgfence analyze --stats-file pgfence-stats.json prisma/migrations/**/migration.sql
```

The stats file contains row counts and table sizes from `pg_stat_user_tables`. Run `npx @flvmnt/pgfence extract-stats --db-url <connection-string>` to generate this file, or see the [pgfence README](https://github.com/flvmnt/pgfence#db-size-aware-risk-scoring) for details.

## Next steps [#next-steps]

* [pgfence documentation and source code](https://github.com/flvmnt/pgfence)
* [pgfence on npm](https://www.npmjs.com/package/@flvmnt/pgfence)
* [Prisma Migrate overview](https://www.prisma.io/docs/orm/v7/prisma-migrate)
* [Deploying database changes with Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-database-changes-with-prisma-migrate)

## Related pages

- [`AI SDK (with Next.js)`](https://www.prisma.io/docs/guides/integrations/ai-sdk): Build a chat application with AI SDK, Prisma ORM, and Next.js that stores chat sessions and messages in Prisma Postgres.
- [`Datadog`](https://www.prisma.io/docs/guides/integrations/datadog): Learn how to configure Datadog tracing for a Prisma ORM project. Capture spans for every query using the @prisma/instrumentation package, dd-trace, and view them in Datadog
- [`Embedded Prisma Studio (with Next.js)`](https://www.prisma.io/docs/guides/integrations/embed-studio): Learn how to embed Prisma Studio directly in your Next.js application for database management
- [`GitHub Actions`](https://www.prisma.io/docs/guides/integrations/github-actions): Provision a Prisma Postgres database for every pull request with GitHub Actions and the Prisma CLI, apply your migrations and seed data to it, and delete it when the pull request closes.
- [`Permit.io`](https://www.prisma.io/docs/guides/integrations/permit-io): Learn how to implement access control with Prisma ORM with Permit.io

# Plasmic (/docs/guides/integrations/plasmic)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create websites and apps visually with Prisma and Plasmic

Location: Guides > Integrations > Plasmic

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version is not available yet: the Plasmic starter project is built on Prisma Client 7.

## Introduction [#introduction]

[Plasmic](https://www.plasmic.app/) is a visual builder for React websites and applications. In this guide, you will connect Plasmic to Prisma using the [starter blog application](https://github.com/plasmicapp/plasmic-prisma-starter) and display query results in a UI created in Plasmic Studio.

Your Prisma connection credentials remain in the application environment and are not sent to Plasmic. Queries run through server functions hosted by your Next.js application. In Plasmic Studio, you configure each query by selecting the Prisma model, operation, filters, and related options.

## Prerequisites [#prerequisites]

* [Node.js 20 or later](https://nodejs.org/en/download/)
* [pnpm](https://pnpm.io/installation)
* A [Prisma account](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides)
* A [Plasmic account](https://studio.plasmic.app/)
* [Git](https://git-scm.com/downloads)

## 1. Clone the starter [#1-clone-the-starter]

Clone the starter so you have the registered Plasmic data query, Prisma schema, seed data, and example Next.js routes used in this guide.

```bash title="Terminal"
git clone https://github.com/plasmicapp/plasmic-prisma-starter.git
cd plasmic-prisma-starter
pnpm install
```

The project includes `prisma/schema.prisma`, `functions/prismaQuery.tsx`, and the Plasmic registration in `plasmic-init.ts`.

## 2. Create a Prisma Postgres database [#2-create-a-prisma-postgres-database]

Provision a Prisma Postgres database for the starter. The command signs you in to the Prisma Console, asks for a region and project name, and prints a connection string.

```bash title="Terminal"
pnpm exec prisma init --db
```

Copy the `postgres://...` connection string from the command output. You will add it to the starter in the next step.

## 3. Configure the environment and seed the database [#3-configure-the-environment-and-seed-the-database]

Create the local environment file from the example so the application can connect to Prisma Postgres and initialize Auth.js.

```bash title="Terminal"
cp .env.example .env
pnpm dlx auth secret
```

Open `.env`, replace the placeholder `DATABASE_URL` with the connection string from the previous step, and confirm that `AUTH_SECRET` contains the generated value:

```text title=".env"
DATABASE_URL="postgres://USER:PASSWORD@HOST:5432/postgres?sslmode=require"
AUTH_SECRET="YOUR_GENERATED_SECRET"
```

Apply the included schema, generate Prisma Client, and load the sample roles, users, and posts:

```bash title="Terminal"
pnpm exec prisma migrate dev --name init
pnpm exec prisma generate
pnpm exec prisma db seed
```

The final command should print:

```text no-copy title="Expected output"
Seeding completed.
```

If `prisma migrate dev` reports error `P3005` because the database schema is not empty, follow the [baselining workflow](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining) before applying migrations.

## 4. Connect your Plasmic project [#4-connect-your-plasmic-project]

Create an empty project in [Plasmic Studio](https://studio.plasmic.app/). Copy the project ID from the Studio URL and the public project token from the **Code** panel, then add both values to `.env`:

```text title=".env"
DATABASE_URL="postgres://USER:PASSWORD@HOST:5432/postgres?sslmode=require"
AUTH_SECRET="YOUR_GENERATED_SECRET"
NEXT_PUBLIC_PLASMIC_PROJECT_ID="YOUR_PROJECT_ID"
NEXT_PUBLIC_PLASMIC_PROJECT_TOKEN="YOUR_PUBLIC_PROJECT_TOKEN"
```

The starter reads these variables in `plasmic-init.ts`. Its loader has `preview: true` so Studio can render unpublished changes during development. Set `preview` to `false` before using the application in production.

## 5. Run the app and set the app host [#5-run-the-app-and-set-the-app-host]

Start the Next.js development server so Plasmic Studio can load the registered data query from your application.

```bash title="Terminal"
pnpm dev
```

In your browser, verify that the Plasmic host page is available by visiting this URL:

```text no-copy title="Plasmic host URL"
http://localhost:3000/plasmic-host
```

Follow Plasmic's [app host setup guide](https://docs.plasmic.app/learn/app-hosting/#3-set-your-plasmic-project-to-use-your-app-host) and set your project's app host to:

```text no-copy title="App host URL"
http://localhost:3000/plasmic-host
```

![App host configuration modal](https://www.prisma.io/img/guides/plasmic/plasmic-host.png)

Studio reloads after you save the host. The **Prisma Query** function is now available under **Data Queries** in the page data panel.

## 6. Query published posts in Plasmic Studio [#6-query-published-posts-in-plasmic-studio]

Create or open a page that will display the seeded posts. Add a page data query named `Get Recent Posts` with these settings:

* **Function:** `Prisma Query` (`prismaQuery`)
* **Table:** `Post`
* **Operation:** `findMany`
* **Where:** `published` equals `true`
* **Include Relations:** `author`
* **Order By Field:** `createdAt`
* **Order Direction:** `desc`

![Query results preview](https://www.prisma.io/img/guides/plasmic/posts-query.png)

Select **Execute** to preview the query in Studio. The result under `$q.getRecentPosts?.data` should be an array of published posts with their authors.

Add a container to the page and repeat it over `$q.getRecentPosts?.data`. Inside the repeated item, bind text elements to the current post's `title`, `content`, and `author.name` fields.

> [!NOTE]
> The starter checks every operation in `functions/prismaQuery.tsx` against the current user's role before it reaches Prisma Client. The seeded `guest` role can read data, so this `findMany` query works without signing in. Keep authorization checks in application code when you adapt the starter.

## Verify the integration [#verify-the-integration]

Preview the page in Plasmic Studio. You should see the published sample posts created by `prisma db seed`, ordered with the newest post first. Change a post in [Prisma Studio](https://www.prisma.io/docs/studio) and execute `Get Recent Posts` again to confirm that the page reads from your Prisma Postgres database.

## Next steps [#next-steps]

* Read the detailed [Using Prisma with Plasmic](https://www.plasmic.app/blog/prisma-plasmic-integration) article for dynamic routes, write operations, authentication, and permissions.
* Review the complete [Plasmic Prisma starter](https://github.com/plasmicapp/plasmic-prisma-starter) implementation.
* Learn how to [filter and sort with Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting).

## Related pages

- [`AI SDK (with Next.js)`](https://www.prisma.io/docs/guides/integrations/ai-sdk): Build a chat application with AI SDK, Prisma ORM, and Next.js that stores chat sessions and messages in Prisma Postgres.
- [`Datadog`](https://www.prisma.io/docs/guides/integrations/datadog): Learn how to configure Datadog tracing for a Prisma ORM project. Capture spans for every query using the @prisma/instrumentation package, dd-trace, and view them in Datadog
- [`Embedded Prisma Studio (with Next.js)`](https://www.prisma.io/docs/guides/integrations/embed-studio): Learn how to embed Prisma Studio directly in your Next.js application for database management
- [`GitHub Actions`](https://www.prisma.io/docs/guides/integrations/github-actions): Provision a Prisma Postgres database for every pull request with GitHub Actions and the Prisma CLI, apply your migrations and seed data to it, and delete it when the pull request closes.
- [`Permit.io`](https://www.prisma.io/docs/guides/integrations/permit-io): Learn how to implement access control with Prisma ORM with Permit.io

# Shopify (/docs/guides/integrations/shopify)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma Postgres with Shopify

Location: Guides > Integrations > Shopify

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version is not available yet: `@shopify/shopify-app-session-storage-prisma` requires Prisma Client, which Prisma ORM 8 replaces with the `@prisma/orm-postgres` runtime.

## Introduction [#introduction]

[Shopify](https://www.shopify.com/) is a popular platform for building e-commerce stores. This guide will show you how to connect a Shopify app to a [Prisma Postgres](https://www.prisma.io/postgres) database in order to create internal notes for products.

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org/en/download/)
* [Shopify CLI](https://shopify.dev/docs/api/shopify-cli)
* [Shopify Partner Account](https://www.shopify.com/partners) and a [development store](https://shopify.dev/docs/api/development-stores#create-a-development-store-to-test-your-app)

## 1. Set up your project [#1-set-up-your-project]

> [!NOTE]
> If you do not have the Shopify CLI installed, you can install it with `npm install -g @shopify/cli`.

To start, initialize a new Shopify app using the Shopify CLI:

```bash
shopify app init
```

During setup, you'll be prompted to customize your app. Choose the following options:

> [!NOTE]
> * *Get started building your app:* `Build a Remix app (recommended)`
> * *For your Remix template, which language do you want:* `JavaScript`
> * *App Name:* `prisma-store&#x60; &#x2A;(name cannot contain `shopify`)*

Navigate to the `prisma-store` directory:

```bash
cd prisma-store
```

## 2. Set up Prisma [#2-set-up-prisma]

Prisma comes pre-installed in your project. In this section, you update it to Prisma ORM 7 and switch the app from SQLite to Prisma Postgres.

You will be swapping to a Prisma Postgres database, so delete the `migrations` folder along with the `dev.sqlite` file, inside of the `prisma` directory.

You need to update a few things in the `schema.prisma` file to get it working with Remix and Prisma Postgres.

* Swap to the new `prisma-client` generator.
* Update the provider to `postgresql`.
* Update the url to the new database URL.

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client-js" // [!code --]
  provider = "prisma-client" // [!code ++]
  output   = "../app/generated/prisma" // [!code ++]
}

datasource db {
  provider = "sqlite" // [!code --]
  provider = "postgresql" // [!code ++]
  url      = "file:../dev.db" // [!code --]
}

model Session {
  // ... existing model
}
```

Create a `prisma.config.ts` file to configure Prisma:

```typescript title="prisma.config.ts"
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config"; // [!code ++]
// [!code ++]
export default defineConfig({
  // [!code ++]
  schema: "prisma/schema.prisma", // [!code ++]
  migrations: {
    // [!code ++]
    path: "prisma/migrations", // [!code ++]
  }, // [!code ++]
  datasource: {
    // [!code ++]
    url: env("DATABASE_URL"), // [!code ++]
  }, // [!code ++]
}); // [!code ++]
```

> [!NOTE]
> Since Shopify apps typically have dotenv pre-installed, you should already have access to it. If not, install it with:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 

To enable your app to store notes for each product, add a new `ProductNote` model to your Prisma schema.

This model will allow you to save and organize notes linked to individual products in your database through the `productGid` field.

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model Session {
  // ... existing model
}

model ProductNote { // [!code ++]
  id         String   @id @default(uuid()) // [!code ++]
  productGid String // [!code ++]
  body       String? // [!code ++]
  createdAt  DateTime @default(now()) // [!code ++]
  updatedAt  DateTime @updatedAt // [!code ++]
} // [!code ++]
```

Next, Prisma will need to be updated to the latest version. Run:

  

#### bun

```bash
bun add prisma@prev @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev @types/pg --dev
```

#### npm

```bash
npm install prisma@prev @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

Then create a Prisma Postgres database:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

Copy the connection string from the CLI output. It should look similar to this:

```text
DATABASE_URL="postgresql://user:password@host:5432/database?sslmode=require"
```

Replace the generated `DATABASE_URL` in your `.env` file with the value from `npx create-db`.

Apply your database schema:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

Then generate Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

Next, update your `db.server.ts` file to use the newly generated Prisma client with the driver adapter:

```tsx title="app/db.server.ts"
import { PrismaClient } from "@prisma/client"; // [!code --]
import { PrismaClient } from "./generated/prisma/client.js"; // [!code ++]
import { PrismaPg } from "@prisma/adapter-pg"; // [!code ++]
// [!code ++]
const adapter = new PrismaPg({
  // [!code ++]
  connectionString: process.env.DATABASE_URL, // [!code ++]
}); // [!code ++]

if (process.env.NODE_ENV !== "production") {
  if (!global.prismaGlobal) {
    global.prismaGlobal = new PrismaClient(); // [!code --]
    global.prismaGlobal = new PrismaClient({ adapter }); // [!code ++]
  }
}

const prisma = global.prismaGlobal ?? new PrismaClient(); // [!code --]
const prisma = global.prismaGlobal ?? new PrismaClient({ adapter }); // [!code ++]

export default prisma;
```

> [!WARNING]
> It is recommended to add `app/generated/prisma` to your `.gitignore` file.

## 3. Create your Remix model [#3-create-your-remix-model]

Create a new `models/` folder. Inside this folder, add a file named `notes.server.js` to hold the note-related database logic.

The `notes.server.js` file will contain two functions:

* `getNotes` - This will get all the notes for a given product.
* `createNote` - This will create a new note for a given product.

Start by importing the Prisma client from `db.server.ts` and creating the `getNotes` function:

```js title="models/notes.server.js"
import prisma from "../db.server"; // [!code ++]
// [!code ++]
export const getNotes = async (productGid) => {
  // [!code ++]
  const notes = await prisma.productNote.findMany({
    // [!code ++]
    where: { productGid: productGid.toString() }, // [!code ++]
    orderBy: { createdAt: "desc" }, // [!code ++]
  }); // [!code ++]
  return notes; // [!code ++]
}; // [!code ++]
```

To enable users to add new notes to your database, create a function in `notes.server.js` that uses `prisma.productNote.create`:

```js title="models/notes.server.js"
import prisma from "../db.server";

export const getNotes = async (productGid) => {
  const notes = await prisma.productNote.findMany({
    where: { productGid: productGid.toString() },
    orderBy: { createdAt: "desc" },
  });
  return notes;
};

export const createNote = async (note) => {
  // [!code ++]
  const newNote = await prisma.productNote.create({
    // [!code ++]
    data: {
      // [!code ++]
      body: note.body, // [!code ++]
      productGid: note.productGid, // [!code ++]
    }, // [!code ++]
  }); // [!code ++]
  return newNote; // [!code ++]
}; // [!code ++]
```

## 4. Create your layout route [#4-create-your-layout-route]

Before those functions are able to be called, our route needs a layout to sit in. This layout route will feature a button for selecting a product, and will act as the parent for your `ProductNotes` route.

### 4.1. Create the ProductNotesLayout component [#41-create-the-productnoteslayout-component]

Start by creating the folder `routes/app.product-notes.jsx` and adding the `ProductNotesLayout` component inside of it:

```jsx title="app/routes/app.product-notes.jsx"
import { Page, Layout } from "@shopify/polaris"; // [!code ++]
// [!code ++]
export default function ProductNotesLayout() {
  // [!code ++]
  return (
    // [!code ++]
    <Page title="Product Notes">
      {" "}
      // [!code ++]
      <Layout>
        {" "}
        // [!code ++]
        <Layout.Section></Layout.Section> // [!code ++]
      </Layout>{" "}
      // [!code ++]
    </Page> // [!code ++]
  ); // [!code ++]
} // [!code ++]
```

Next, create the `selectProduct` function and a `Button` to let the user pick a product:

```jsx title="app/routes/app.product-notes.jsx"
import { useNavigate } from "@remix-run/react";
import { Page, Layout } from "@shopify/polaris"; // [!code --]
import { Button, Page, Layout } from "@shopify/polaris"; // [!code ++]

export default function ProductNotesLayout() {
  const navigate = useNavigate(); // [!code ++]

  async function selectProduct() {
    // [!code ++]
    const products = await window.shopify.resourcePicker({
      // [!code ++]
      type: "product", // [!code ++]
      action: "select", // [!code ++]
    }); // [!code ++]
    const selectedGid = products[0].id; // [!code ++]
    navigate(`/app/product-notes/${encodeURIComponent(selectedGid)}`); // [!code ++]
  } // [!code ++]

  return (
    <Page title="Product Notes">
      <Layout>
        <Layout.Section>
          <Button onClick={selectProduct} fullWidth size="large">
            {" "}
            // [!code ++] Select Product // [!code ++]
          </Button>{" "}
          // [!code ++]
        </Layout.Section>
      </Layout>
    </Page>
  );
}
```

Remix renders provides the ability to render a nested route. Add an `<Outlet />` to the `routes/app.product-notes.jsx` file where the `ProductNotes` route will be rendered:

```jsx title="app/routes/app.product-notes.jsx"
import { useNavigate } from "@remix-run/react"; // [!code --]
import { Outlet, useNavigate } from "@remix-run/react"; // [!code ++]
import { Page, Button, Layout } from "@shopify/polaris";

export default function ProductNotesLayout() {
  const navigate = useNavigate();

  async function selectProduct() {
    const products = await window.shopify.resourcePicker({
      type: "product",
      action: "select",
    });
    const selectedGid = products[0].id;
    navigate(`/app/product-notes/${encodeURIComponent(selectedGid)}`);
  }

  return (
    <Page title="Product Notes">
      <Layout>
        <Layout.Section>
          <Button onClick={selectProduct} fullWidth size="large">
            Select Product
          </Button>
        </Layout.Section>
        <Outlet /> // [!code ++]
      </Layout>
    </Page>
  );
}
```

### 4.2. Add the ProductNotesLayout to the sidebar [#42-add-the-productnoteslayout-to-the-sidebar]

If you run `npm run dev`, you won't be able to see the `Product Notes` route. To fix this, you need to add the `ProductNotesLayout` to the `app.jsx` file so it shows up in the sidebar:

```jsx title="app/routes/app.jsx"
import { Link, Outlet, useLoaderData, useRouteError } from "@remix-run/react";
import { boundary } from "@shopify/shopify-app-remix/server";
import { AppProvider } from "@shopify/shopify-app-remix/react";
import { NavMenu } from "@shopify/app-bridge-react";
import polarisStyles from "@shopify/polaris/build/esm/styles.css?url";
import { authenticate } from "../shopify.server";

export const links = () => [{ rel: "stylesheet", href: polarisStyles }];

export const loader = async ({ request }) => {
  await authenticate.admin(request);

  return { apiKey: process.env.SHOPIFY_API_KEY || "" };
};

export default function App() {
  const { apiKey } = useLoaderData();

  return (
    <AppProvider isEmbeddedApp apiKey={apiKey}>
      <NavMenu>[ Home ](/app) [Product Notes](/app/product-notes) // [!code ++]</NavMenu>
      <Outlet />
    </AppProvider>
  );
}

// Shopify needs Remix to catch some thrown responses, so that their headers are included in the response.
export function ErrorBoundary() {
  return boundary.error(useRouteError());
}

export const headers = (headersArgs) => {
  return boundary.headers(headersArgs);
};
```

## 5. Create your product notes route [#5-create-your-product-notes-route]

Currently, if you run `npm run dev` and navigate to the `Product Notes` route, you will see nothing once selecting a product.

Follow these steps to create the product notes route:

Create a new `routes/app/app.notes.$productGid.jsx` file which will take in the productGid as a parameter, and return the product notes associated with the product as well as a form to create a new note:

```jsx title="app/routes/app/app.notes.$productGid.jsx"
export default function ProductNotes() {
  // [!code ++]
  return (
    // [!code ++]
    <></> // [!code ++]
  ); // [!code ++]
} // [!code ++]
```

### 5.1. Render the notes [#51-render-the-notes]

On load, the route will need to fetch the notes for the product and display them.

Add a `loader` function to the route:

```jsx title="app/routes/app/app.notes.$productGid.jsx"
import { json } from "@remix-run/node"; // [!code ++]
import { useLoaderData } from "@remix-run/react"; // [!code ++]
import { getNotes } from "../models/note.server"; // [!code ++]

export const loader = async ({ params }) => {
  // [!code ++]
  const { productGid } = params; // [!code ++]
  const notes = await getNotes(productGid); // [!code ++]
  return json({ notes, productGid }); // [!code ++]
}; // [!code ++]

export default function ProductNotes() {
  const { notes, productGid } = useLoaderData(); // [!code ++]

  return <></>;
}
```

Map out the notes in the `ProductNotes` component, using Polaris components:

```jsx title="app/routes/app/app.notes.$productGid.jsx"
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { getNotes } from "../models/note.server";
import { Card, Layout, Text, BlockStack } from "@shopify/polaris"; // [!code ++]

export const loader = async ({ params }) => {
  const { productGid } = params;
  const notes = await getNotes(productGid);
  return json({ notes, productGid });
};

export default function ProductNotes() {
  const { notes, productGid } = useLoaderData();
  return (
    <>
      <Layout.Section>
        {" "}
        // [!code ++]
        <BlockStack gap="200">
          {" "}
          // [!code ++]
          {notes.length === 0 ? ( // [!code ++]
            <Text as="p" variant="bodyMd" color="subdued">
              {" "}
              // [!code ++] No notes yet. // [!code ++]
            </Text> // [!code ++]
          ) : (
            // [!code ++]
            notes.map(
              (
                note, // [!code ++]
              ) => (
                <Card key={note.id} sectioned>
                  {" "}
                  // [!code ++]
                  <BlockStack gap="100">
                    {" "}
                    // [!code ++]
                    {note.body && ( // [!code ++]
                      <Text as="p" variant="bodyMd">
                        {" "}
                        // [!code ++]
                        {note.body} // [!code ++]
                      </Text> // [!code ++]
                    )}{" "}
                    // [!code ++]
                    <Text as="p" variant="bodySm" color="subdued">
                      {" "}
                      // [!code ++] Added: {new Date(note.createdAt).toLocaleString()} // [!code ++]
                    </Text>{" "}
                    // [!code ++]
                  </BlockStack>{" "}
                  // [!code ++]
                </Card> // [!code ++]
              ),
            ) // [!code ++]
          )}{" "}
          // [!code ++]
        </BlockStack>{" "}
        // [!code ++]
      </Layout.Section>{" "}
      // [!code ++]
    </>
  );
}
```

You should be seeing "No notes yet.". If so, you're on the right track.

### 5.2. Add the form [#52-add-the-form]

A few things need to be added to the route in order to create a new note:

* Add an `action` function to the route.
* Display a `Toast` notification when a note is created.
* Import the `createNote` function from `models/note.server.js`.
* Import the `useActionData` and `useAppBridge`

```jsx title="app/routes/app/app.notes.$productGid.jsx"
import { json, redirect } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react"; // [!code --]
import { useLoaderData, useActionData } from "@remix-run/react"; // [!code ++]
import { getNotes } from "../models/note.server"; // [!code --]
import { getNotes, createNote } from "../models/note.server"; // [!code ++]
import { Card, Layout, Text, BlockStack } from "@shopify/polaris";
import { useAppBridge } from "@shopify/app-bridge-react"; // [!code ++]

export const loader = async ({ params }) => {
  const { productGid } = params;
  const notes = await getNotes(productGid);
  return json({ notes, productGid });
};

export const action = async ({ request, params }) => {
  // [!code ++]
  const formData = await request.formData(); // [!code ++]
  const body = formData.get("body")?.toString() || null; // [!code ++]
  const { productGid } = params; // [!code ++]
  // [!code ++]
  await createNote({ productGid, body }); // [!code ++]
  return redirect(`/app/product-notes/${encodeURIComponent(productGid)}`); // [!code ++]
}; // [!code ++]

export default function ProductNotes() {
  const { notes, productGid } = useLoaderData();
  const actionData = useActionData(); // [!code ++]
  const app = useAppBridge(); // [!code ++]

  useEffect(() => {
    // [!code ++]
    if (actionData?.ok) {
      // [!code ++]
      app.toast.show("Note saved", { duration: 3000 }); // [!code ++]
      setBody(""); // [!code ++]
    } // [!code ++]
  }, [actionData, app]); // [!code ++]

  return (
    <>
      <Layout.Section>
        <BlockStack gap="200">
          {notes.length === 0 ? (
            <Text as="p" variant="bodyMd" color="subdued">
              No notes yet.
            </Text>
          ) : (
            notes.map((note) => (
              <Card key={note.id} sectioned>
                <BlockStack gap="100">
                  {note.body && (
                    <Text as="p" variant="bodyMd">
                      {note.body}
                    </Text>
                  )}
                  <Text as="p" variant="bodySm" color="subdued">
                    Added: {new Date(note.createdAt).toLocaleString()}
                  </Text>
                </BlockStack>
              </Card>
            ))
          )}
        </BlockStack>
      </Layout.Section>
    </>
  );
}
```

Now, you can build out the form that will call the `action` function:

```jsx title="app/routes/app/app.notes.$productGid.jsx"
import { json, redirect } from "@remix-run/node";
import { useLoaderData, useActionData } from "@remix-run/react";
import { getNotes, createNote } from "../models/note.server";
import { Card, Layout, Text, BlockStack } from "@shopify/polaris"; // [!code --]
import {
  Card,
  Layout,
  Text,
  BlockStack,
  Form,
  FormLayout,
  TextField,
  Button,
} from "@shopify/polaris"; // [!code ++]
import { useAppBridge } from "@shopify/app-bridge-react";

export const loader = async ({ params }) => {
  const { productGid } = params;
  const notes = await getNotes(productGid);
  return json({ notes, productGid });
};

export const action = async ({ request, params }) => {
  const formData = await request.formData();
  const body = formData.get("body")?.toString() || null;
  const { productGid } = params;

  await createNote({ productGid, body });
  return redirect(`/app/product-notes/${encodeURIComponent(productGid)}`);
};

export default function ProductNotes() {
  const { notes, productGid } = useLoaderData();
  const actionData = useActionData(); // [!code ++]
  const app = useAppBridge(); // [!code ++]

  useEffect(() => {
    // [!code ++]
    if (actionData?.ok) {
      // [!code ++]
      app.toast.show("Note saved", { duration: 3000 }); // [!code ++]
      setBody(""); // [!code ++]
    } // [!code ++]
  }, [actionData, app]); // [!code ++]

  return (
    <>
      <Layout.Section>
        {" "}
        // [!code ++]
        <Card sectioned>
          {" "}
          // [!code ++]
          <Form method="post">
            {" "}
            // [!code ++]
            <FormLayout>
              {" "}
              // [!code ++]
              <BlockStack gap="200">
                {" "}
                // [!code ++]
                <input type="hidden" name="productGid" value={productGid} /> // [!code ++]
                <TextField // [!code ++]
                  label="Note" // [!code ++]
                  value={body} // [!code ++]
                  onChange={setBody} // [!code ++]
                  name="body" // [!code ++]
                  autoComplete="off" // [!code ++]
                  multiline={4} // [!code ++]
                />{" "}
                // [!code ++]
                <Button submit primary>
                  {" "}
                  // [!code ++] Add Note // [!code ++]
                </Button>{" "}
                // [!code ++]
              </BlockStack>{" "}
              // [!code ++]
            </FormLayout>{" "}
            // [!code ++]
          </Form>{" "}
          // [!code ++]
        </Card>{" "}
        // [!code ++]
      </Layout.Section>{" "}
      // [!code ++]
      <Layout.Section>
        <BlockStack gap="200">
          {notes.length === 0 ? (
            <Text as="p" variant="bodyMd" color="subdued">
              No notes yet.
            </Text>
          ) : (
            notes.map((note) => (
              <Card key={note.id} sectioned>
                <BlockStack gap="100">
                  {note.body && (
                    <Text as="p" variant="bodyMd">
                      {note.body}
                    </Text>
                  )}
                  <Text as="p" variant="bodySm" color="subdued">
                    Added: {new Date(note.createdAt).toLocaleString()}
                  </Text>
                </BlockStack>
              </Card>
            ))
          )}
        </BlockStack>
      </Layout.Section>
    </>
  );
}
```

You should now be able to add a note to a product and see it displayed.

### 6. Test your route [#6-test-your-route]

Run `npm run dev` and navigate to the `Product Notes` route.

* Navigate to Product Notes on the sidebar
* Select a product
* Add a note
* Verify that notes are displayed and saved correctly.

## Next Steps [#next-steps]

Now that you have a working Shopify app connected to a Prisma Postgres database, you can:

* Extend your Prisma schema with more models and relationships
* Add create/update/delete routes and forms

### More Info [#more-info]

* [Prisma Documentation](https://www.prisma.io/docs/orm/v7)
* [Shopify Dev Documentation](https://shopify.dev/docs)

## Related pages

- [`AI SDK (with Next.js)`](https://www.prisma.io/docs/guides/integrations/ai-sdk): Build a chat application with AI SDK, Prisma ORM, and Next.js that stores chat sessions and messages in Prisma Postgres.
- [`Datadog`](https://www.prisma.io/docs/guides/integrations/datadog): Learn how to configure Datadog tracing for a Prisma ORM project. Capture spans for every query using the @prisma/instrumentation package, dd-trace, and view them in Datadog
- [`Embedded Prisma Studio (with Next.js)`](https://www.prisma.io/docs/guides/integrations/embed-studio): Learn how to embed Prisma Studio directly in your Next.js application for database management
- [`GitHub Actions`](https://www.prisma.io/docs/guides/integrations/github-actions): Provision a Prisma Postgres database for every pull request with GitHub Actions and the Prisma CLI, apply your migrations and seed data to it, and delete it when the pull request closes.
- [`Permit.io`](https://www.prisma.io/docs/guides/integrations/permit-io): Learn how to implement access control with Prisma ORM with Permit.io

# Vercel app deployment (/docs/guides/integrations/vercel-deployment)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Programmatically deploy full-stack apps to Vercel with a provisioned Prisma Postgres database. Built for AI app builders, agent platforms, and no-code tools.

Location: Guides > Integrations > Vercel app deployment

## Introduction [#introduction]

This guide shows you how to deploy a full-stack application to [Vercel](https://vercel.com) with a ready-to-use [Prisma Postgres](https://www.prisma.io/docs/postgres) database, entirely through API calls. The flow takes six Vercel API requests: create a project, authorize the Prisma integration, provision a database, connect it to the project, deploy the application code, and generate a claim code that transfers ownership to your user. No dashboard steps are required at any point.

This is the deployment pattern used by AI app builders, agent platforms, no-code tools, and educational platforms that generate applications on behalf of their users. Your platform deploys the app and database programmatically, the user claims it with one click, and billing moves to their Vercel account. Every database provisioned through this flow is a full Prisma Postgres instance: managed PostgreSQL with connection pooling built in, so deployed apps handle serverless traffic without extra pooling infrastructure.

> [!NOTE]
> Other Vercel guides
> 
> * To deploy **your own app** that uses Prisma ORM, see the [Next.js guide](https://www.prisma.io/docs/guides/frameworks/nextjs) for Prisma ORM 8, or [Deploy to Vercel](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-vercel) for Prisma ORM 7.
> * To add a **Prisma Postgres database to an existing Vercel project** via the Marketplace integration, see [Prisma Postgres on Vercel](https://www.prisma.io/docs/guides/postgres/vercel).
> * To create and manage Prisma Postgres databases programmatically **outside of Vercel**, see the [REST API](https://www.prisma.io/docs/rest-api).
> 
> This guide covers **platforms deploying apps on behalf of their users** with Vercel's deployment API.

## Try the live demo [#try-the-live-demo]

Experience the instant deployment flow with [our interactive demo](https://pris.ly/vercel-app-demo-live). You can deploy and claim real applications to see the complete process in action.

![Vercel App Deployment Demo](https://www.prisma.io/img/guides/vercel_complete_claim_demo_mini.gif)

**Available examples:**

* **Next.js + Prisma**: Basic full-stack application with database integration
* **Next.js + Prisma + Better Auth**: Complete application with authentication using [Better Auth](https://www.better-auth.com/)

**Demo features:**

* Deploy applications with one click
* Generate claim codes for user transfer
* Experience the complete claiming flow
* View source code and implementation details

[Visit the GitHub repository for the demo](https://pris.ly/vercel_app_deployment_demo?utm_source=docs).

## Who is this for [#who-is-this-for]

This guide is designed for developers building:

* **AI-powered development platforms** that generate full applications and need instant deployment
* **No-code/low-code tools** that want to offer hosting without managing infrastructure
* **Educational platforms** where students need to deploy projects quickly
* **CI/CD systems** that need programmatic deployment capabilities
* **Rapid prototyping tools** that transform ideas into deployed applications

## Core concepts [#core-concepts]

The deployment flow relies on these concepts:

### Vercel deployment architecture [#vercel-deployment-architecture]

* **Projects**: Containers that hold your application code and configuration
* **Deployments**: Specific instances of your project deployed to Vercel's edge network
* **Teams**: Organizational units that own projects and manage billing
* **Integrations**: Third-party services (like Prisma) that connect to your projects

### Prisma integration components [#prisma-integration-components]

* **Integration configuration**: Your team's connection to the Prisma service
* **Authorization**: Permission to create resources on behalf of your team
* **Database stores**: Individual Prisma Postgres instances
* **Resource connections**: Links between databases and Vercel projects

### API endpoints overview [#api-endpoints-overview]

The deployment process uses several key Vercel API endpoints:

* `POST /v10/projects` - Create a new Vercel project
* `POST /v1/integrations/billing/authorization` - Authorize Prisma integration
* `POST /v1/storage/stores/integration` - Create Prisma Postgres database
* `POST /v13/deployments` - Deploy application code
* `POST /v9/projects/{id}/transfer-request` - Generate claim code for user transfer

## Required API keys and environment variables [#required-api-keys-and-environment-variables]

> [!NOTE]
> Contact us for elevated partner level access for db creation
> 
> By default, every new partner is on our free plan which limited to 5 dbs per account, so if you are trying out this API and need higher db creation limits (which we suspect that most of you will), then please [contact us](https://www.prisma.io/partners#contact-us) to get partner level access.

### Vercel access token [#vercel-access-token]

Your primary authentication token for Vercel API calls.

**Where to get it:**

1. Go to [Vercel Account Settings](https://vercel.com/account/tokens)
2. Click **Create Token**
3. Name it (e.g., "Instant Deployment API")
4. Set scope to your **team** (not personal account)
5. Copy the token immediately (you won't see it again)

> [!NOTE]
> You need "Owner" level access to the Vercel team to ensure the `ACCESS_TOKEN` works for all the API calls.

```bash
ACCESS_TOKEN="vercel_token_here"
```

> [!NOTE]
> Credit card requirement
> 
> Vercel requires a credit card to be attached to your account (even on the Hobby plan) to use the deployment APIs. Make sure to add payment information in your Vercel account settings before proceeding.

### Team ID [#team-id]

Your Vercel team identifier for API requests.

**Where to get it:**

1. Go to the [Vercel Dashboard](https://vercel.com)
2. Switch to your **Team** (not personal account)
3. Go to **Team Settings**
4. Copy the Team ID displayed at the top (format: `team_abc123xyz`)

```bash
TEAM_ID="team_abc123xyz"
```

### Prisma integration config ID [#prisma-integration-config-id]

Your team's Prisma integration configuration identifier.

**Where to get it:**

1. In Vercel Dashboard, go to your **Team**
2. Click **Integrations** tab
3. Find **Prisma** and click **Manage** (install it first if needed)
4. In the browser URL, copy the config ID: `https://vercel.com/teams/your-team/integrations/icfg_abc123xyz`
5. Copy the `icfg_abc123xyz` part

```bash
INTEGRATION_CONFIG_ID="icfg_abc123xyz"
```

### Prisma Product ID [#prisma-product-id]

The Prisma Product ID is used to identify the Prisma integration in the Vercel API and it's a constant value of: `iap_yVdbiKqs5fLkYDAB` or `prisma-postgres`.

```bash
PRISMA_PRODUCT_ID="iap_yVdbiKqs5fLkYDAB"
```

### Prisma Postgres region [#prisma-postgres-region]

The region where your Prisma Postgres database will be deployed. Choose a region close to your users to reduce latency.

**Available regions:**

* `iad1` - US East (Virginia)
* `fra1` - Europe (Frankfurt)
* `sfo1` - US West (San Francisco)
* `sin1` - Asia Pacific (Singapore)
* `hnd1` - Asia Pacific (Tokyo)
* `cdg1` - Europe (Paris)

```bash
PRISMA_POSTGRES_REGION="iad1"
```

See the complete list of [supported Prisma Postgres regions](https://www.prisma.io/docs/postgres/faq#what-regions-is-prisma-postgres-available-in) and their corresponding [Vercel region codes](https://vercel.com/docs/regions#region-list).

### Prisma billing plan [#prisma-billing-plan]

> [!NOTE]
> Updated database limits
> 
> Database limits have been increased across all plans. The **Free** plan now includes **50 databases**, and **paid plans** (Starter, Pro, Business) each include **1,000 databases**. See the [pricing page](https://www.prisma.io/pricing) for the full breakdown.

The billing plan determines database limits and features. Available plans:

* `free` - Limited to 50 databases, suitable for development
* `pro` - Higher limits
* `business` - Enterprise features with priority support
* `enterprise` - Custom limits and dedicated support
* `partnerEntry` - Partner-level access with high database limits

```bash
PRISMA_BILLING_PLAN="partnerEntry"
```

> [!NOTE]
> Partner access recommended
> 
> For production deployments requiring multiple databases, we recommend the `partnerEntry` plan which provides higher database creation limits. [Apply for partner access](https://www.prisma.io/partners) to get these limits.

## Complete deployment example [#complete-deployment-example]

The code snippet below shows the complete deployment flow:

```typescript
const CONFIG = {
  ACCESS_TOKEN: process.env.ACCESS_TOKEN,
  TEAM_ID: process.env.TEAM_ID,
  INTEGRATION_CONFIG_ID: process.env.INTEGRATION_CONFIG_ID,
  PRISMA_PRODUCT_ID: process.env.PRISMA_PRODUCT_ID || "iap_yVdbiKqs5fLkYDAB", // or can be `prisma-postgres`
  PRISMA_POSTGRES_REGION: process.env.PRISMA_POSTGRES_REGION || "iad1",
  PRISMA_BILLING_PLAN: process.env.PRISMA_BILLING_PLAN || "partnerEntry",
  VERCEL_API_URL: "https://api.vercel.com",
};

async function deployApp() {
  console.log("🚀 Starting instant deployment...");

  // 1. Create project
  const project = await createProject();

  // 2. Authorize Prisma integration
  const auth = await createPrismaAuthorization();

  // 3. Create database
  const database = await createPrismaDatabase(project.name, auth.id, auth.configId);

  // 4. Connect database to project
  await connectDatabaseToProject(project.id, database.id, auth.configId);

  // 5. Deploy application (assumes files already uploaded)
  const deployment = await deployApplication(project.name, fileSha);

  // 6. Generate claim code
  const transfer = await createProjectTransfer(project.id);

  console.log("🎉 Deployment completed!");
  console.log(`Live URL: https://${deployment.url}`);
  console.log(`Claim URL: ${transfer.claimUrl}`);

  return {
    projectId: project.id,
    deploymentUrl: `https://${deployment.url}`,
    claimCode: transfer.code,
    claimUrl: transfer.claimUrl,
  };
}
```

## Step-by-step deployment process [#step-by-step-deployment-process]

The complete example above shows the entire deployment process. The sections below break down each step.

### Step 1: Create a Vercel project [#step-1-create-a-vercel-project]

Every deployment starts with creating a project container.

```typescript
async function createProject(): Promise<{ id: string; name: string }> {
  const projectName = `demo-project-${Date.now()}`;

  const response = await fetch(`${CONFIG.VERCEL_API_URL}/v10/projects?teamId=${CONFIG.TEAM_ID}`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ name: projectName }),
  });

  const project = await response.json();
  console.log(`✅ Project created: ${project.name} (${project.id})`);

  return { id: project.id, name: project.name };
}
```

**Key parameters:**

* `name`: Unique project identifier (auto-generated with timestamp)
* `teamId`: Your team ID for proper project ownership

Learn more in the [Vercel Projects API documentation](https://vercel.com/docs/rest-api/reference/endpoints/projects/create-a-new-project).

### Step 2: Authorize Prisma integration [#step-2-authorize-prisma-integration]

Before creating databases, you need authorization to use Prisma on behalf of your team.

```typescript
async function createPrismaAuthorization(): Promise<{
  id: string;
  configId: string;
}> {
  const response = await fetch(
    `${CONFIG.VERCEL_API_URL}/v1/integrations/billing/authorization?teamId=${CONFIG.TEAM_ID}`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        integrationIdOrSlug: "prisma",
        productId: CONFIG.PRISMA_PRODUCT_ID,
        billingPlanId: CONFIG.PRISMA_BILLING_PLAN,
        metadata: JSON.stringify({ region: CONFIG.PRISMA_POSTGRES_REGION }),
        integrationConfigurationId: CONFIG.INTEGRATION_CONFIG_ID,
      }),
    },
  );

  const authData = await response.json();

  return {
    id: authData.authorization.id,
    configId: authData.authorization.integrationConfigurationId,
  };
}
```

**Key parameters:**

* `billingPlanId`: Billing plan ("partnerEntry" recommended for production)
* `region`: Database region; pick one close to your users
* `metadata`: JSON string containing region and other configuration

Learn more in the [Vercel Integrations API documentation](https://vercel.com/docs/integrations/create-integration/marketplace-api).

### Step 3: Provision Prisma Postgres database [#step-3-provision-prisma-postgres-database]

Create a new database instance with built-in connection pooling.

```typescript
async function createPrismaDatabase(
  projectName: string,
  authId: string,
  configId: string,
): Promise<{ id: string }> {
  const response = await fetch(
    `${CONFIG.VERCEL_API_URL}/v1/storage/stores/integration?teamId=${CONFIG.TEAM_ID}`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        metadata: { region: CONFIG.PRISMA_POSTGRES_REGION },
        billingPlanId: CONFIG.PRISMA_BILLING_PLAN,
        name: `postgres-${projectName}`,
        integrationConfigurationId: configId,
        integrationProductIdOrSlug: CONFIG.PRISMA_PRODUCT_ID,
        authorizationId: authId,
        source: "marketplace",
      }),
    },
  );

  const storageData = await response.json();

  return {
    id: storageData.store.id,
  };
}
```

**Key parameters:**

* `name`: Database identifier (typically matches project name)
* `source`: "marketplace" for Vercel marketplace integrations
* `billingPlanId`: Billing plan that determines features and limits

Learn more in the [Vercel Storage API documentation](https://vercel.com/docs/rest-api/reference/endpoints/integrations/create-integration-store-free-and-paid-plans).

### Step 4: Connect database to project [#step-4-connect-database-to-project]

Link the database to your Vercel project for automatic environment variable injection.

```typescript
async function connectDatabaseToProject(
  projectId: string,
  storeId: string,
  configId: string,
): Promise<void> {
  await fetch(
    `${CONFIG.VERCEL_API_URL}/v1/integrations/installations/${configId}/products/${CONFIG.PRISMA_PRODUCT_ID}/resources/${storeId}/connections?teamId=${CONFIG.TEAM_ID}`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ projectId }),
    },
  );

  console.log("✅ Database connected to project");
}
```

This connection automatically adds `DATABASE_URL` and other environment variables to your project.

Learn more in the [Vercel Integration Resources documentation](https://vercel.com/docs/rest-api/reference/endpoints/integrations/connect-integration-resource-to-project).

### Step 5: Deploy the application [#step-5-deploy-the-application]

Deploy your application code to Vercel.

```typescript
async function deployApplication(
  projectName: string,
  fileSha: string,
): Promise<{ id: string; url: string }> {
  const response = await fetch(
    `${CONFIG.VERCEL_API_URL}/v13/deployments?teamId=${CONFIG.TEAM_ID}`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        files: [{ file: ".vercel/source.tgz", sha: fileSha }],
        name: `deployment-${Date.now()}`,
        projectSettings: { framework: "nextjs" },
        project: projectName,
      }),
    },
  );

  const deploymentData = await response.json();

  return {
    id: deploymentData.id,
    url: deploymentData.alias?.[0] || deploymentData.url,
  };
}
```

**Key parameters:**

* `files`: Array of uploaded files (requires prior file upload in `tgz` format)
* `framework`: "nextjs", "react", "vue", etc. for automatic configuration
* `projectSettings`: Framework-specific build and runtime settings

Learn more in the [Vercel Deployments API documentation](https://vercel.com/docs/rest-api/reference/endpoints/deployments/create-a-new-deployment) or see the [Vercel API Reference](https://vercel.com/docs/rest-api/reference).

### Step 6: Generate claim code for user transfer [#step-6-generate-claim-code-for-user-transfer]

Create a transfer code that allows users to claim ownership of the deployed project.

```typescript
async function createProjectTransfer(
  projectId: string,
): Promise<{ code: string; claimUrl: string }> {
  const response = await fetch(
    `${CONFIG.VERCEL_API_URL}/v9/projects/${projectId}/transfer-request?teamId=${CONFIG.TEAM_ID}`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({}),
    },
  );

  const transferData = await response.json();
  const claimUrl = `https://vercel.com/claim-deployment?code=${transferData.code}&returnUrl=https://myapp.com/dashboard/projects`;

  return {
    code: transferData.code,
    claimUrl,
  };
}
```

**Key details:**

* Transfer codes are valid for **24 hours**
* Users can claim projects to any team in their Vercel account
* The `returnUrl` redirects users to a specific page if the claim URL is invalid or expired

Learn more in the [Vercel Claim Deployments documentation](https://vercel.com/docs/deployments/claim-deployments).

## User claim flow [#user-claim-flow]

After deployment, users can claim ownership through a secure transfer process:

### How claiming works [#how-claiming-works]

1. **User receives claim URL**: Your platform provides the generated claim URL
2. **User authentication**: Vercel prompts for login if not authenticated
3. **Team selection**: User chooses which Vercel team should own the project
4. **Transfer completion**: Project and database transfer to user's selected team
5. **Billing transfer**: User's team becomes responsible for hosting costs

### Claim URL structure [#claim-url-structure]

```
https://vercel.com/claim-deployment?code=xxx&returnUrl=https://myapp.com/dashboard/projects
```

**Parameters:**

* `code`: The transfer code from Step 6 (valid 24 hours)
* `returnUrl`: Redirects users to a specific page if the claim URL is invalid or expired

### What gets transferred [#what-gets-transferred]

When a user claims a deployment, they receive:

* **Full project ownership** with all source code and configuration
* **Database ownership** including all data and connection strings
* **Environment variables** automatically updated for the new team
* **Deployment history** and build logs

Learn more in the [Claim Deployments documentation](https://vercel.com/docs/deployments/claim-deployments).

## Error handling and best practices [#error-handling-and-best-practices]

### Common error scenarios [#common-error-scenarios]

```typescript
async function handleApiErrors(response: Response, operation: string) {
  if (!response.ok) {
    const errorData = await response.text();

    // Handle specific error cases
    switch (response.status) {
      case 401:
        throw new Error(`Authentication failed: Check your ACCESS_TOKEN`);
      case 403:
        throw new Error(`Permission denied: Verify team access and scopes`);
      case 429:
        throw new Error(`Rate limit exceeded: Implement retry logic`);
      case 404:
        throw new Error(`Resource not found: Check IDs and configuration`);
      default:
        throw new Error(`${operation} failed: ${response.status} - ${errorData}`);
    }
  }
}
```

### Rate limiting considerations [#rate-limiting-considerations]

Vercel enforces rate limits on API endpoints. You can implement exponential backoff to handle rate limits:

```typescript
async function apiCallWithRetry(url: string, options: RequestInit, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      if (response.status === 429) {
        const waitTime = Math.pow(2, attempt) * 1000; // Exponential backoff
        await new Promise((resolve) => setTimeout(resolve, waitTime));
        continue;
      }

      return response;
    } catch (error) {
      if (attempt === maxRetries) throw error;
    }
  }
}
```

Learn more in the [Vercel API Limits documentation](https://vercel.com/docs/limits).

### Security best practices [#security-best-practices]

* **Store tokens securely**: Never expose API tokens in client-side code
* **Validate inputs**: Sanitize project names and user-provided data
* **Monitor usage**: Track API calls to prevent abuse
* **Implement timeouts**: Set reasonable request timeouts for reliability

## Production considerations [#production-considerations]

The following are some production considerations for your deployment service:

### Integration with existing platforms [#integration-with-existing-platforms]

You can call the deployment flow from your existing platform code:

```typescript
// Example integration with an AI coding platform
class DeploymentService {
  async deployGeneratedApp(code: string, userId: string) {
    // 1. Package generated code
    const packagedCode = await this.packageCode(code);

    // 2. Deploy with Vercel + Prisma
    const deployment = await this.deployApp(packagedCode);

    // 3. Store deployment info
    await this.storeDeployment(userId, deployment);

    // 4. Notify user
    await this.notifyUser(userId, deployment.claimUrl);

    return deployment;
  }
}
```

### Monitoring and analytics [#monitoring-and-analytics]

Track key metrics for your deployment service:

* **Deployment success rate**: Monitor API failures and timeouts
* **Claim conversion rate**: Track how many users claim their deployments
* **Performance metrics**: Measure deployment time and time to first claim
* **Cost analysis**: Monitor Vercel and Prisma usage costs

## FAQ [#faq]

### Can I deploy an app to Vercel with a database in a single API flow? [#can-i-deploy-an-app-to-vercel-with-a-database-in-a-single-api-flow]

Yes. The six-step flow in this guide creates a Vercel project, provisions a Prisma Postgres database, connects the two, and deploys the application code using only Vercel API endpoints. There is no dashboard interaction, which makes the flow suitable for automated pipelines and AI agents.

### How many databases can I create programmatically? [#how-many-databases-can-i-create-programmatically]

The Prisma Postgres Free plan includes 50 databases per account, and paid plans (Starter, Pro, Business) each include 1,000. Platforms that deploy on behalf of many users should [apply for partner access](https://www.prisma.io/partners), which uses the `partnerEntry` billing plan and provides higher database creation limits.

### What happens to billing when a user claims a deployment? [#what-happens-to-billing-when-a-user-claims-a-deployment]

Ownership of both the Vercel project and the Prisma Postgres database transfers to the user's Vercel team, and that team becomes responsible for hosting and database costs from that point on. Claim codes are valid for 24 hours.

### Which frameworks can be deployed this way? [#which-frameworks-can-be-deployed-this-way]

Anything Vercel can build and host, including Next.js, Nuxt, SvelteKit, and Remix. The demo templates use Next.js with Prisma ORM, and one variant adds authentication with Better Auth.

### Do deployed apps need a connection pooler like pgBouncer? [#do-deployed-apps-need-a-connection-pooler-like-pgbouncer]

No. Prisma Postgres includes connection pooling by default, so apps deployed through this flow handle Vercel's serverless function scaling without a separate pooler.

### Can I provision Prisma Postgres databases without Vercel? [#can-i-provision-prisma-postgres-databases-without-vercel]

Yes. The [Prisma Postgres REST API](https://www.prisma.io/docs/rest-api) lets you create and manage databases directly, which is useful for platforms that host applications elsewhere but still want programmatic database provisioning.

## Next steps [#next-steps]

Now that you understand instant app deployment with Vercel and Prisma Postgres, you can:

* **Integrate into your platform**: Add deployment capabilities to your existing application
* **Customize the flow**: Adapt the process for your specific use case and user experience
* **Scale your implementation**: Handle high-volume deployments with proper queuing and error handling
* **Monitor and optimize**: Track performance and user adoption metrics

### Additional resources [#additional-resources]

* [Vercel REST API Documentation](https://vercel.com/docs/rest-api)
* [Vercel Claim Deployments Guide](https://vercel.com/docs/deployments/claim-deployments)
* [Vercel Integration API Reference](https://vercel.com/docs/integrations/create-integration/marketplace-api)
* [Prisma Postgres Documentation](https://www.prisma.io/docs/postgres)
* [Vercel Limits and Quotas](https://vercel.com/docs/limits)

For questions or support with your integration, reach out through the [Prisma Community Discord](https://pris.ly/discord) or [Vercel Support](https://vercel.com/help).

## Related pages

- [`AI SDK (with Next.js)`](https://www.prisma.io/docs/guides/integrations/ai-sdk): Build a chat application with AI SDK, Prisma ORM, and Next.js that stores chat sessions and messages in Prisma Postgres.
- [`Datadog`](https://www.prisma.io/docs/guides/integrations/datadog): Learn how to configure Datadog tracing for a Prisma ORM project. Capture spans for every query using the @prisma/instrumentation package, dd-trace, and view them in Datadog
- [`Embedded Prisma Studio (with Next.js)`](https://www.prisma.io/docs/guides/integrations/embed-studio): Learn how to embed Prisma Studio directly in your Next.js application for database management
- [`GitHub Actions`](https://www.prisma.io/docs/guides/integrations/github-actions): Provision a Prisma Postgres database for every pull request with GitHub Actions and the Prisma CLI, apply your migrations and seed data to it, and delete it when the pull request closes.
- [`Permit.io`](https://www.prisma.io/docs/guides/integrations/permit-io): Learn how to implement access control with Prisma ORM with Permit.io

# Fly.io (/docs/guides/postgres/flyio)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy applications using Prisma Postgres to Fly.io

Location: Guides > Postgres > Fly.io

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is planned.

[Fly.io](https://fly.io/) is a cloud application platform that lets you deploy full-stack applications globally. This guide shows you how to deploy a Node.js application using Prisma Postgres to Fly.io.

## Prerequisites [#prerequisites]

* A [Fly.io account](https://fly.io/docs/getting-started/launch/)
* The [Fly CLI](https://fly.io/docs/flyctl/install/) installed
* An existing application using [Prisma Postgres](https://www.prisma.io/docs/postgres) (see [Quickstart](https://www.prisma.io/docs/v7/prisma-postgres/quickstart/prisma-orm))

## Deploy your application [#deploy-your-application]

### 1. Generate Prisma Client in `postinstall` [#1-generate-prisma-client-in-postinstall]

Ensure your `package.json` includes a `postinstall` script to generate Prisma Client during deployment:

```json title="package.json"
{
  // ...
  "scripts": {
    // ...
    "postinstall": "prisma generate" // [!code ++]
  }
}
```

### 2. Launch your app with Fly.io [#2-launch-your-app-with-flyio]

From your project directory, run:

```bash
fly launch
```

Follow the prompts to configure your application. Fly.io will auto-detect your Node.js application and create the necessary configuration.

### 3. Set your database connection string [#3-set-your-database-connection-string]

Add your Prisma Postgres `DATABASE_URL` as a secret in Fly.io:

```bash
fly secrets set DATABASE_URL="your-prisma-postgres-connection-string"
```

> [!NOTE]
> You can find your `DATABASE_URL` in your `.env` file or in the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides).

### 4. Deploy [#4-deploy]

If not already deployed during `fly launch`, deploy your application:

```bash
fly deploy
```

Once the deployment completes, you'll see a success message with your app's URL:

```
🎉  SUCCESS! Your app is live and ready to use!  🎉

Visit: https://your-app-name.fly.dev/
```

> [!NOTE]
> In the Fly.io dashboard, your app's status may show as "Pending" initially. It typically transitions to "Deployed" within a few minutes.

## Additional considerations [#additional-considerations]

### Ensure your project uses the correct environment variable [#ensure-your-project-uses-the-correct-environment-variable]

Ensure that the data source in your `prisma.config.ts` file is configured to use the `DATABASE_URL` environment variable:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  datasource: {
    url: env("DATABASE_URL"),
  },
  schema: "prisma/schema.prisma",
});
```

### Running migrations in production [#running-migrations-in-production]

To run migrations on your deployed Fly.io app, you can use:

```bash
fly ssh console -C "npx prisma migrate deploy"
```

Or add a release command to your `fly.toml`:

```toml title="fly.toml"
[deploy]
  release_command = "npx prisma migrate deploy"
```

### Scaling and regions [#scaling-and-regions]

Fly.io lets you scale and place your application in [multiple regions](https://fly.io/docs/reference/regions/). To reduce latency, deploy your app in a region close to your Prisma Postgres database region.

```bash
fly scale count 2 --region iad
```

## Troubleshooting [#troubleshooting]

### Prisma schema not found or Client not generated correctly [#prisma-schema-not-found-or-client-not-generated-correctly]

If you're using a custom Dockerfile and your build fails because the Prisma Client cannot be found, it's likely due to one of two reasons:

1. **Order of operations**: `npm install` (which runs `postinstall`) runs before the schema is copied.
2. **Incorrect copy path**: The schema is copied to the root instead of the `prisma` folder.

**Solution:** In your Dockerfile, copy the `prisma/` directory to `./prisma` **before** running `npm install`:

```dockerfile
# ❌ Wrong order or path
COPY package*.json ./
COPY prisma .                   # Copies contents to root (wrong structure)
RUN npm install                 # postinstall runs but might fail or generate in wrong place

# ✅ Correct order and path
COPY package*.json ./
COPY prisma ./prisma            # Copies to ./prisma folder (preserves structure)
RUN npm install                 # postinstall finds schema in expected location
COPY . .
```

## More information [#more-information]

* [Fly.io Node.js documentation](https://fly.io/docs/languages-and-frameworks/node/)
* [Fly.io Prisma documentation](https://fly.io/docs/js/prisma/)
* [Prisma Postgres documentation](https://www.prisma.io/docs/postgres)

## Related pages

- [`Firebase Studio`](https://www.prisma.io/docs/guides/postgres/idx): Learn how to use Prisma Postgres in the online Firebase Studio
- [`Netlify`](https://www.prisma.io/docs/guides/postgres/netlify): Learn how to create Prisma Postgres databases via the official Netlify extension and deploy your applications with it
- [`Vercel`](https://www.prisma.io/docs/guides/postgres/vercel): Learn how to create Prisma Postgres databases via the Vercel Marketplace and deploy your Next.js, Nuxt, and SvelteKit applications.
- [`Viewing data`](https://www.prisma.io/docs/guides/postgres/viewing-data): Viewing and editing data in Prisma Postgres via Prisma Studio or other database GUIs
- [`VS Code`](https://www.prisma.io/docs/guides/postgres/vscode): The Prisma VS Code extension provides a management UI for Prisma Postgres and agent-mode support for GitHub Copilot

# Firebase Studio (/docs/guides/postgres/idx)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma Postgres in the online Firebase Studio

Location: Guides > Postgres > Firebase Studio

If you want to explore Prisma Postgres without leaving your browser, you can try it out the via Google's [Firebase Studio](https://studio.firebase.google.com/), a fully-fledged online IDE:

1. Open the [**Prisma**](https://pris.ly/idx-starter) template.
2. Select **Prisma Postgres** as your database.
3. Give a **Name** to your workspace and click the **Create** button.
4. Wait until the Firebase Studio workspace has initialized and then follow the instructions in the README.

## Related pages

- [`Fly.io`](https://www.prisma.io/docs/guides/postgres/flyio): Learn how to deploy applications using Prisma Postgres to Fly.io
- [`Netlify`](https://www.prisma.io/docs/guides/postgres/netlify): Learn how to create Prisma Postgres databases via the official Netlify extension and deploy your applications with it
- [`Vercel`](https://www.prisma.io/docs/guides/postgres/vercel): Learn how to create Prisma Postgres databases via the Vercel Marketplace and deploy your Next.js, Nuxt, and SvelteKit applications.
- [`Viewing data`](https://www.prisma.io/docs/guides/postgres/viewing-data): Viewing and editing data in Prisma Postgres via Prisma Studio or other database GUIs
- [`VS Code`](https://www.prisma.io/docs/guides/postgres/vscode): The Prisma VS Code extension provides a management UI for Prisma Postgres and agent-mode support for GitHub Copilot

# Netlify (/docs/guides/postgres/netlify)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to create Prisma Postgres databases via the official Netlify extension and deploy your applications with it

Location: Guides > Postgres > Netlify

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is planned.

The [Netlify extension for Prisma Postgres](https://www.netlify.com/integrations/prisma) connects your Netlify sites with Prisma Postgres instances. Once connected, the extension will automatically set the `DATABASE_URL` environment variable on your deployed Netlify sites.

## Features [#features]

* Automatic generation of Prisma Postgres connection strings for production and preview environments.
* Simplified environment configuration for your Netlify site.

## Usage [#usage]

### Install the extension [#install-the-extension]

To install the extension, click **Install** at the top of the [Prisma Postgres extension page](https://www.netlify.com/integrations/prisma).

### Add the Prisma Platform integration token to your Netlify team [#add-the-prisma-platform-integration-token-to-your-netlify-team]

Perform the following steps *once* to connect your Netlify team with a Prisma Platform workspace:

1. Log in to your [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides).
2. Select the workspace you want to connect to Netlify.
3. Navigate to the **Integrations** menu in the left-hand sidebar.
4. Follow the prompts to create a new Netlify integration token and copy the token value.
5. Paste the token into the **Integration Token** field above. The workspace ID will be automatically filled in.
6. Click **Save** to complete the setup.

Once this setup is complete, your Netlify team is connected to your Prisma workspace. You can now configure individual Netlify sites to use Prisma Postgres.

### Add Prisma Postgres to a Netlify site [#add-prisma-postgres-to-a-netlify-site]

Perform the following steps *for every Netlify site* in which you want to use Prisma Postgres:

1. Go to the site view in Netlify and click **Prisma Postgres** under the **Extensions** section.
2. From the **Project** selector, choose the Prisma project you want to connect to your Netlify site.
3. Configure the environment for your **Production environment**.
4. Configure the environment for your **Preview environment**.
5. Click **Save** to complete the site setup.
6. The extension will automatically create a Prisma Postgres instance and store its connection URL in the `DATABASE_URL` environment variable.

## Additional considerations [#additional-considerations]

### Ensure your project uses the `DATABASE_URL` environment variable [#ensure-your-project-uses-the-database_url-environment-variable]

The extension sets `DATABASE_URL` to a Prisma Postgres [connection string](https://www.prisma.io/docs/postgres/database/connecting-to-your-database) that starts with `postgres://`. Netlify Functions run on a conventional Node.js runtime, so use the pooled connection string for application queries and the direct connection string for Prisma CLI commands:

```bash title=".env"
# Application queries
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"

# Prisma CLI commands, which bypass the connection pooler
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

> [!WARNING]
> Accelerate retirement
> 
> Hosted Prisma Postgres `prisma+postgres://accelerate.prisma-data.net` connections will be retired on December 1, 2026. If an existing Netlify site still receives such a URL in `DATABASE_URL`, [switch to pooled TCP or the Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/switch-from-accelerate) and update the environment variable on the site.

Ensure that the data source in your `prisma.config.ts` file is configured to use the `DIRECT_URL` environment variable:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DIRECT_URL"),
  },
});
```

Set `DIRECT_URL` in your Netlify site's environment variables too, so that Prisma CLI commands that run during a deploy, such as the `postinstall` script below, can resolve it.

### Generate Prisma Client in a `postinstall` script in `package.json` [#generate-prisma-client-in-a-postinstall-script-in-packagejson]

To ensure the generated Prisma Client library is available on your deployed Netlify site, you should add a `postinstall` script to the `scripts` section of your `package.json` file:

```js title="package.json"
{
  // ...
  "scripts": {
    // ...
    "postinstall": "prisma generate" // [!code ++]
  }
  //
}
```

## Example: Deploy a Next.js template with Prisma Postgres [#example-deploy-a-nextjs-template-with-prisma-postgres]

This section contains step-by-step instructions for deploying a Netlify site and connecting it to Prisma Postgres from scratch using Netlify's official [Next.js Platform Starter](https://github.com/netlify-templates/next-platform-starter) template.

### 1. Create a new site using the template [#1-create-a-new-site-using-the-template]

In your Netlify team, create a new site using the template:

1. Select **Sites** in the left sidenav.
2. Click the **Add new site** button.
3. In the dropdown, select **Start from a template**.
4. Select the **Next.js Platform Starter**.
5. Follow the prompts to **Clone this template to your Git provider**.
6. Enter a **Site name** and click the **Deploy site** button.

Once you're done with this, you'll be able to access the deployed version of this starter project.

### 2. Set up a Prisma Postgres instance [#2-set-up-a-prisma-postgres-instance]

Next, set up a Prisma Postgres instance:

1. Log in to [Prisma Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides) and open the Console.
2. In a [workspace](https://www.prisma.io/docs/console/concepts#workspace) of your choice, click the **New project** button.
3. Type a name for your project in the **Name** field, e.g. **hello-ppg**.
4. In the **Prisma Postgres** section, click the **Get started** button.
5. In the **Region** dropdown, select the region that's closest to your current location, e.g. &#x2A;*US East (N. Virginia)**.
6. Click the **Create project** button.
7. Click the **Connect to your Database** button
8. Generate a connection string and copy both the pooled value (host `pooled.db.prisma.io`) and the direct value (host `db.prisma.io`). Both start with `postgres://`.
9. Save both values, you'll need them in the next section: the pooled value becomes `DATABASE_URL`, the direct value becomes `DIRECT_URL`.

### 3. Locally add Prisma Postgres to the project [#3-locally-add-prisma-postgres-to-the-project]

In this section, you are going to add Prisma Postgres to the starter project *on your local machine*:

#### 3.1. Set up Prisma ORM [#31-set-up-prisma-orm]

1. Clone the Next.js Platform Starter repo that was added to your GitHub account in step 1.
2. Navigate into the project directory, e.g.: `cd next-platform-starter`.
3. Install the Prisma CLI as a development dependency:

  

#### bun

```bash
bun add prisma@prev --dev
```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
```

#### yarn

```bash
yarn add prisma@prev --dev
```

#### npm

```bash
npm install prisma@prev --save-dev
```

4. Install the PostgreSQL driver adapter that Prisma Client uses to connect over TCP:

  

#### bun

```bash title="Terminal"
bun add @prisma/adapter-pg pg
```

#### pnpm

```bash title="Terminal"
pnpm add @prisma/adapter-pg pg
```

#### yarn

```bash title="Terminal"
yarn add @prisma/adapter-pg pg
```

#### npm

```bash title="Terminal"
npm install @prisma/adapter-pg pg
```

5. Initialize Prisma ORM to create Prisma schema, config and `.env` file:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

#### 3.2. Run migration and create sample data [#32-run-migration-and-create-sample-data]

1. Open the newly created `schema.prisma` file and add the following model to it:

   ```prisma title="schema.prisma"
   generator client {
     provider = "prisma-client"
     output   = "../src/generated/prisma"
   }

   datasource db {
     provider = "postgresql"
   }

   model User { // [!code ++]
     id    Int     @id @default(autoincrement()) // [!code ++]
     name  String? // [!code ++]
     email String  @unique // [!code ++]
   } // [!code ++]
   ```

2. Open the newly created `.env` file and add the pooled connection string as `DATABASE_URL` and the direct connection string as `DIRECT_URL`, as shown [above](#ensure-your-project-uses-the-database_url-environment-variable). Prisma Client uses the pooled value, the Prisma CLI uses the direct one.

3. Open the newly created `prisma.config.ts` file and point the datasource at `DIRECT_URL`. `prisma init` generates it with `DATABASE_URL`, which would send the migration and Studio commands below through the connection pooler:

   ```ts title="prisma.config.ts"
   import "dotenv/config";
   import { defineConfig, env } from "prisma/config";

   export default defineConfig({
     schema: "prisma/schema.prisma",
     datasource: {
       url: env("DATABASE_URL"), // [!code --]
       url: env("DIRECT_URL"), // [!code ++]
     },
   });
   ```

4. Run your first migration to map the `User` model to the database:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

5. Create (at least) one `User` record in the database with Prisma Studio:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

#### 3.3. Update application code to query and show `User` records [#33-update-application-code-to-query-and-show-user-records]

Open the `app/page.jsx` file and replace the entire contents with this code:

```tsx title="app/page.jsx"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../src/generated/prisma/client";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
});
const prisma = new PrismaClient({ adapter });

export default async function Page() {
  const users = await prisma.user.findMany();

  return (
    <main className="p-8">
      <h1 className="text-2xl font-bold mb-4">Users</h1>
      <ul className="space-y-2">
        {users.length > 0 ? (
          users.map((user) => (
            <li key={user.id} className="p-4 border rounded shadow-sm">
              <p>
                <strong>ID:</strong> {user.id}
              </p>
              <p>
                <strong>Name:</strong> {user.name || "N/A"}
              </p>
              <p>
                <strong>Email:</strong> {user.email}
              </p>
            </li>
          ))
        ) : (
          <p>No users found.</p>
        )}
      </ul>
    </main>
  );
}
```

With this code in place, run the app locally:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

You should see a list of the `User` records that you created in the previous step.

#### 3.4. Add the `postinstall` script to generate Prisma Client [#34-add-the-postinstall-script-to-generate-prisma-client]

As mentioned [above](#generate-prisma-client-in-a-postinstall-script-in-packagejson), you need to add a `postinstall` script to your `package.json` to ensure your Prisma Client library gets properly generated:

```json title="package.json"
{
  "name": "next-netlify-platform-starter",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "postinstall": "prisma generate" // [!code ++]
  },
  "dependencies": {
    "@netlify/blobs": "^8.1.0",
    "@prisma/adapter-pg": "^7.10.0",
    "@prisma/client": "^7.10.0",
    "blobshape": "^1.0.0",
    "bright": "^0.8.5",
    "markdown-to-jsx": "^7.4.5",
    "next": "15.1.6",
    "pg": "^8.16.3",
    "react": "18.3.1",
    "react-dom": "18.3.1",
    "unique-names-generator": "^4.7.1"
  },
  "devDependencies": {
    "autoprefixer": "^10.4.18",
    "daisyui": "^4.12.8",
    "eslint": "8.57.1",
    "eslint-config-next": "15.1.6",
    "postcss": "^8.4.36",
    "prisma": "^7.10.0",
    "tailwindcss": "^3.4.1"
  }
}
```

### 4. Configure the Netlify extension for Prisma Postgres [#4-configure-the-netlify-extension-for-prisma-postgres]

In this section, you need to add the Netlify extension to your Netlify site. Follow the instructions in the [Usage](#usage) section above to do that.

After having completed these steps, find the **Trigger deploy** button and select **Clear cache and deploy site** in the dropdown.

### 5. Validate the deployment [#5-validate-the-deployment]

Open the deployed site by clicking the **Open production deploy** button. You should now see the same UI as you did at the end of step 3 when you were running the app locally.

## Related pages

- [`Firebase Studio`](https://www.prisma.io/docs/guides/postgres/idx): Learn how to use Prisma Postgres in the online Firebase Studio
- [`Fly.io`](https://www.prisma.io/docs/guides/postgres/flyio): Learn how to deploy applications using Prisma Postgres to Fly.io
- [`Vercel`](https://www.prisma.io/docs/guides/postgres/vercel): Learn how to create Prisma Postgres databases via the Vercel Marketplace and deploy your Next.js, Nuxt, and SvelteKit applications.
- [`Viewing data`](https://www.prisma.io/docs/guides/postgres/viewing-data): Viewing and editing data in Prisma Postgres via Prisma Studio or other database GUIs
- [`VS Code`](https://www.prisma.io/docs/guides/postgres/vscode): The Prisma VS Code extension provides a management UI for Prisma Postgres and agent-mode support for GitHub Copilot

# Vercel (/docs/guides/postgres/vercel)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to create Prisma Postgres databases via the Vercel Marketplace and deploy your Next.js, Nuxt, and SvelteKit applications.

Location: Guides > Postgres > Vercel

The [Vercel Marketplace integration for Prisma Postgres](https://www.vercel.com/marketplace/prisma) connects your Vercel projects with Prisma Postgres instances. Once connected, the integration automatically sets the following environment variable on your deployed Vercel app:

* `DATABASE_URL`: A Prisma Postgres [connection string](https://www.prisma.io/docs/postgres/database/connecting-to-your-database) starting with `postgres://...`

These enable you to connect to the Prisma Postgres instances via any ORM or database library you want to use (Prisma ORM, Drizzle, Kysely, ...).

## Why Prisma Postgres works well on Vercel [#why-prisma-postgres-works-well-on-vercel]

Vercel scales serverless functions automatically. Each new function instance opens a database connection, and with a traditional Postgres setup, that's how you hit connection limits under load. Prisma Postgres includes connection pooling by default, so you don't need to configure pgBouncer or maintain a separate pooler. The `DATABASE_URL` the Marketplace sets works in local dev, preview deployments, and production.

## Features [#features]

* Create and use Prisma Postgres instances without leaving the Vercel dashboard.
* Automatic generation of Prisma Postgres URLs for production and preview environments.
* Simplified environment configuration for your Vercel project.
* Billing workflows to up-/ and downgrade your Prisma Postgres pricing plan.
* Ready-to-deploy fullstack templates for Next.js, Nuxt, SvelteKit and with various ORMs and DB libraries.

## Templates [#templates]

The fastest way to start with Prisma Postgres on the Vercel Marketplace is one of the templates:

* [Prisma ORM + NextAuth Starter](https://vercel.com/templates/next.js/prisma-postgres)
* [Postgres + Kysely Next.js Starter](https://vercel.com/templates/next.js/postgres-kysely)
* [Postgres + Drizzle Next.js Starter](https://vercel.com/templates/next.js/postgres-drizzle)
* [Postgres + SvelteKit Starter](https://vercel.com/templates/svelte/postgres-sveltekit)

## Usage [#usage]

### Install the extension [#install-the-extension]

To install the extension, click **Install** at the top of the [Prisma Postgres integration page](https://www.vercel.com/marketplace/prisma).

The integration will now show up on your list of integrations, e.g. `https://vercel.com/<VERCEL-TEAM>/~/integrations`.

### Create a new database [#create-a-new-database]

Once installed, you can navigate to the **Storage** tab and click **Create Database**.

Select **Prisma Postgres** and click **Continue**. Then select the **Region** for the database and a **Pricing Plan**, and click **Continue** again.

Finally, give the database a **Name** and click **Create**.

The database is now ready and can be connected to your Vercel projects.

### Connect database to Vercel project [#connect-database-to-vercel-project]

In your Vercel project, you can now click the **Storage** tab, select the database you just created and then click **Connect**. This will automatically set the `DATABASE_URL` environment variable in that project and enable your application to access your newly created Prisma Postgres instance.

### Viewing and editing data in Prisma Studio [#viewing-and-editing-data-in-prisma-studio]

To view and edit the data in your Prisma Postgres instance, you can use the local version of [Prisma Studio](https://www.prisma.io/docs/studio).

Studio ships with the Prisma ORM 7 CLI and works with Prisma ORM 7 and Prisma ORM 8 databases alike. Point it at the connection string from the **Storage** tab:

  

#### bun

```bash
bunx prisma@prev studio --url="$DATABASE_URL"
```

#### pnpm

```bash
pnpm dlx prisma@prev studio --url="$DATABASE_URL"
```

#### yarn

```bash
yarn dlx prisma@prev studio --url="$DATABASE_URL"
```

#### npm

```bash
npx prisma@prev studio --url="$DATABASE_URL"
```

## Using with Next.js [#using-with-nextjs]

If you're building a Next.js app and want a step-by-step walkthrough covering the contract, migrations, querying from Server Components, and deploying, see the [Next.js guide](https://www.prisma.io/docs/guides/frameworks/nextjs).

The key things to set up on the Vercel side:

### Ensure your project uses the correct environment variable [#ensure-your-project-uses-the-correct-environment-variable]

The generated `src/prisma/db.ts` reads `process.env.DATABASE_URL`, which is the variable the **Connect** step above sets on your Vercel project. Nothing else needs to be configured for the runtime to find the database.

### Commit the emitted contract files [#commit-the-emitted-contract-files]

Prisma ORM has no build-time generate step. `npx prisma contract emit` writes `src/prisma/contract.json` and `src/prisma/contract.d.ts`, and those files are committed with your code, so Vercel's `next build` needs no `postinstall` hook. Apply schema changes to the database before you deploy, with `npx prisma db migrate` from your machine or CI. See [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration).

> [!NOTE]
> Using Prisma ORM 7?
> 
> For a Prisma ORM 7 project, keep the `prisma.config.ts` that reads `DATABASE_URL` and add `"postinstall": "prisma generate"` to `package.json` so Prisma Client is generated on every deploy. See the [Prisma ORM 7 Next.js guide](https://www.prisma.io/docs/guides/v7/frameworks/nextjs), and [Release status](https://www.prisma.io/docs/orm/release-status) for where Prisma ORM 8 stands and how to pin Prisma ORM 7.

## Billing and pricing [#billing-and-pricing]

Prisma Postgres uses [usage-based pricing](https://www.prisma.io/pricing) based on operations and storage. The same plans and rates apply when you create a database via the Vercel Marketplace, and your Prisma Postgres usage is billed through your Vercel account.

To change your plan, see [How do I upgrade my plan if I am using Prisma Postgres via Vercel?](https://www.prisma.io/docs/postgres/faq#how-do-i-upgrade-my-plan-if-i-am-using-prisma-postgres-via-vercel) in the Prisma Postgres FAQ.

## Security [#security]

### Rotating your Prisma integration secrets in Vercel [#rotating-your-prisma-integration-secrets-in-vercel]

In security incidents (like [this Vercel security bulletin](https://vercel.com/kb/bulletin/vercel-april-2026-security-incident)) or as a regular security practice, you may need to rotate your Prisma integration secrets. This process generates new authentication credentials for your database connection while keeping your data intact.

Follow these steps to rotate your Prisma integration secrets in Vercel:

1. Open your browser and go to your specific project (e.g., `https://vercel.com/your-team-name/your-project-name`)
2. Click &#x2A;*"Integrations"** in the left sidebar menu to see all connected marketplace apps
3. Click &#x2A;*"Prisma"** to open the Prisma integration management page
4. Under &#x2A;*"Installed Products"**, click on the specific database whose secrets you want to rotate
5. Click the &#x2A;*"Settings"** tab and scroll down to find the security section
6. Click the &#x2A;*"Rotate Secrets"** button to open the rotation dialog
7. Configure rotation settings:
   * **Delay period**: Enter `0` for immediate rotation (urgent incidents) or any other number for delayed rotation in hours (planned maintenance)
   * **Rotation scope**: Select which secrets to rotate (database connection secrets, API tokens, etc.)
8. Click &#x2A;*"Rotate Secrets"** to confirm and wait for the success message
9. Redeploy your applications: This is critical! After rotation completes:
   * Immediately redeploy all applications using this database (Vercel will prompt you)
   * Click &#x2A;*"Redeploy"** for each affected application
   * Verify connections work after redeployment
   * Monitor application logs for connection errors

Reach out to our [Discord community](https://pris.ly/discord) or on [X](https://pris.ly/x) if you need assistance with this process.

## Related pages

- [`Firebase Studio`](https://www.prisma.io/docs/guides/postgres/idx): Learn how to use Prisma Postgres in the online Firebase Studio
- [`Fly.io`](https://www.prisma.io/docs/guides/postgres/flyio): Learn how to deploy applications using Prisma Postgres to Fly.io
- [`Netlify`](https://www.prisma.io/docs/guides/postgres/netlify): Learn how to create Prisma Postgres databases via the official Netlify extension and deploy your applications with it
- [`Viewing data`](https://www.prisma.io/docs/guides/postgres/viewing-data): Viewing and editing data in Prisma Postgres via Prisma Studio or other database GUIs
- [`VS Code`](https://www.prisma.io/docs/guides/postgres/vscode): The Prisma VS Code extension provides a management UI for Prisma Postgres and agent-mode support for GitHub Copilot

# Viewing data (/docs/guides/postgres/viewing-data)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Viewing and editing data in Prisma Postgres via Prisma Studio or other database GUIs

Location: Guides > Postgres > Viewing data

You can view and edit your data in Prisma Postgres using either [Prisma Studio](https://www.prisma.io/docs/studio) or 3rd party database editors.

## Viewing and editing data in Prisma Studio [#viewing-and-editing-data-in-prisma-studio]

With Prisma Postgres, a hosted version of Prisma Studio is available in your project. In your project environment in the [Platform Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides), select the **Studio** tab in the left-hand navigation to view and edit your data:

![View of Prisma Studio open in the console.](https://www.prisma.io/img/ppg-studio.png)

You can also run Prisma Studio locally. Studio ships with the Prisma ORM 7 CLI and works with Prisma ORM 7 and Prisma ORM 8 databases alike. Point it at the **direct** connection string of your database:

  

#### bun

```bash
bunx prisma@prev studio --url="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

#### pnpm

```bash
pnpm dlx prisma@prev studio --url="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

#### yarn

```bash
yarn dlx prisma@prev studio --url="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

#### npm

```bash
npx prisma@prev studio --url="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

This should start a live server in `http://localhost:5555` where you can visit and interact with your database.

If your database is managed with [Prisma ORM](https://www.prisma.io/docs/orm), Studio also shows a **Migrations** view alongside your tables, with a visual diff of what each applied migration changed. See [Studio with Prisma ORM](https://www.prisma.io/docs/studio/prisma-next).

## Connecting to Prisma Postgres instance with 3rd party database editors [#connecting-to-prisma-postgres-instance-with-3rd-party-database-editors]

You can connect to your Prisma Postgres instance using third party database editors like pgAdmin, TablePlus, DataGrip, DBeaver or Postico with the direct connection string of your database. See the examples below.

### 1. Get your direct connection string [#1-get-your-direct-connection-string]

In the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides), select your database, click **Connect to your database** and generate a connection string. Copy the **direct** value, which looks like this:

```bash
postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require
```

Database editors typically ask for the individual parts of that connection string:

| Field        | Value                                        |
| ------------ | -------------------------------------------- |
| **Host**     | `db.prisma.io`                               |
| **Port**     | `5432`                                       |
| **Database** | `postgres`                                   |
| **User**     | The `USER` part of the connection string     |
| **Password** | The `PASSWORD` part of the connection string |
| **SSL mode** | `require`                                    |

Use the direct connection string for database editors, migrations and other administrative tooling. Application traffic should use the pooled connection string instead. Learn more in [Connecting to your database](https://www.prisma.io/docs/postgres/database/connecting-to-your-database).

> [!WARNING]
> Accelerate retirement
> 
> Hosted Prisma Postgres `prisma+postgres://accelerate.prisma-data.net` connections will be retired on December 1, 2026. Connecting a database editor through the `@prisma/ppg-tunnel` package with such a URL is a legacy path: generate a direct connection string in the Prisma Console and connect your editor with it instead. If your application still uses a hosted Accelerate connection, [switch to pooled TCP or the Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/switch-from-accelerate).

### 2a. Connect to Prisma Postgres using TablePlus [#2a-connect-to-prisma-postgres-using-tableplus]

To add the connection in TablePlus:

1. Open TablePlus and click on the &#x2A;*+** icon to add a new connection.
2. Select **PostgreSQL** as the database type.
3. Enter the following details:
   * **Name**: Any name you want to give to your connection.
   * **Host**: `db.prisma.io`.
   * **Port**: `5432`.
   * **User**: The `USER` part of your direct connection string.
   * **Password**: The `PASSWORD` part of your direct connection string.
   * **Database**: `postgres`.
   * **SSL mode**: `require`.
4. Click on **Connect** to connect to your Prisma Postgres instance.

![View of TablePlus connected to Prisma Postgres](https://www.prisma.io/img/ppg-tableplus.png)

### 2b. Connect to Prisma Postgres using DataGrip [#2b-connect-to-prisma-postgres-using-datagrip]

To add the connection in DataGrip:

1. Open DataGrip and click on the &#x2A;*+** icon and select "Datasource".
2. Select **PostgreSQL** as the database type.
3. Enter the following details:
   * **Name**: Any name you want to give to your connection.
   * **Host**: `db.prisma.io`.
   * **Port**: `5432`.
   * **Database**: `postgres`.
   * **User**: The `USER` part of your direct connection string.
   * **Password**: The `PASSWORD` part of your direct connection string.
   * **URL**: Make sure the URL ends with the query parameter `?sslmode=require`.
4. Click on **Test Connection** to ensure that DataGrip can connect to your Prisma Postgres instance. Once successful, click **OK** to save the connection.

![View of DataGrip connected to Prisma Postgres](https://www.prisma.io/img/ppg-datagrip.png)

### 2c. Connect to Prisma Postgres using DBeaver [#2c-connect-to-prisma-postgres-using-dbeaver]

To add the connection in DBeaver:

1. Open DBeaver and click on the **New Database Connection** button or **File** > **New** to add a new connection.
2. Select **PostgreSQL** as the database type.
3. Select **URL** option in Connect by section.
4. Enter the URL in this format:
   * **URL**: Your URL should be in this format: `jdbc:postgresql://db.prisma.io:5432/postgres?sslmode=require`. Enter the `USER` and `PASSWORD` parts of your direct connection string as **Username** and **Password**.
5. Click on **Test Connection** to ensure that DBeaver can connect to your Prisma Postgres instance. If successful, click **Finish**.

![View of DBeaver connected to Prisma Postgres](https://www.prisma.io/img/ppg-dbeaver.png)

### 2d. Connect to Prisma Postgres using Postico [#2d-connect-to-prisma-postgres-using-postico]

To add the connection in Postico:

1. Open Postico and click on the **New Server** button to add a new connection.
2. Enter the following details:
   * **Name**: Any name you want to give to your connection.
   * **Host**: `db.prisma.io`.
   * **Port**: `5432`.
   * **User**: The `USER` part of your direct connection string.
   * **Password**: The `PASSWORD` part of your direct connection string.
   * **Database**: `postgres`.
3. Check "Pre-Connect Shell Script" and enter:
   ```sh
   cat <<eof
   {
   "sslmode":"require",
   }
   eof
   ```
4. Click on **Test Connection** to ensure that Postico can connect to your Prisma Postgres instance. If successful, click **Connect**.

![View of Postico connected to Prisma Postgres](https://www.prisma.io/img/ppg-postico.png)

## Related pages

- [`Firebase Studio`](https://www.prisma.io/docs/guides/postgres/idx): Learn how to use Prisma Postgres in the online Firebase Studio
- [`Fly.io`](https://www.prisma.io/docs/guides/postgres/flyio): Learn how to deploy applications using Prisma Postgres to Fly.io
- [`Netlify`](https://www.prisma.io/docs/guides/postgres/netlify): Learn how to create Prisma Postgres databases via the official Netlify extension and deploy your applications with it
- [`Vercel`](https://www.prisma.io/docs/guides/postgres/vercel): Learn how to create Prisma Postgres databases via the Vercel Marketplace and deploy your Next.js, Nuxt, and SvelteKit applications.
- [`VS Code`](https://www.prisma.io/docs/guides/postgres/vscode): The Prisma VS Code extension provides a management UI for Prisma Postgres and agent-mode support for GitHub Copilot

# VS Code (/docs/guides/postgres/vscode)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The Prisma VS Code extension provides a management UI for Prisma Postgres and agent-mode support for GitHub Copilot

Location: Guides > Postgres > VS Code

## Overview [#overview]

The [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) adds Prisma Postgres management, an embedded Prisma Studio, and agent-mode support to [Visual Studio Code](https://code.visualstudio.com), so you can create databases, edit data, and run migrations without leaving the editor.

> [!NOTE]
> Be sure to update the VS Code extension regularly in order to maintain functionality and take
> advantage of new features in the latest release of Prisma ORM

## Database management UI [#database-management-ui]

The Prisma VS Code extension includes a dedicated UI to manage Prisma Postgres instances (local and remote).

### Workflows [#workflows]

The UI enables the following workflows:

* Authenticate with the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides)
* View, create and delete Prisma Postgres instances (local & remote)
* "Push to cloud": deploy a local Prisma Postgres instance to a remote one
* View and edit data via an embedded Prisma Studio
* Visualize your database schema

### Usage [#usage]

To manage Prisma Postgres instances via the UI in the Prisma VS Code extension:

1. Ensure you have the latest version of the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) installed
2. Find the Prisma logo in the **Activity Bar**
3. Click the **Sign in to get started** button
4. Authenticate with the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides) via the popup and select a target [workspace](https://www.prisma.io/docs/console/concepts#workspace)

## Managing versions [#managing-versions]

The Prisma Extension can support both version 6 and version 7 of Prisma ORM. If you open a project
using either version, you can set the supported version by the command palette or the diagnostics
prompt.

![VS Code command palette showing Prisma ORM version selection between version 6 and version 7.](https://www.prisma.io/img/vscode/version-command-picker.png)

## Prisma Studio built-in [#prisma-studio-built-in]

Beyond managing your database instances, the Prisma VS Code extension embeds Prisma Studio directly in your editor, so you can create, update, and delete records without leaving VS Code. See the [setup steps](https://www.prisma.io/docs/studio/integrations/vscode-integration) to get started.

## Prisma MCP server [#prisma-mcp-server]

Prisma provides its own [Model Context Protocol](https://www.prisma.io/docs/ai/tools/mcp-server) (MCP) server that lets you manage Prisma Postgres databases, model database schemas and chat through migrations.

You can add the Prisma MCP server to VS Code using the one-click installation by clicking on the following link:

<a
  href="vscode:mcp/install?%7B%22name%22%3A%22Prisma%22%2C%22gallery%22%3Atrue%2C%22url%22%3A%22https%3A%2F%2Fmcp.prisma.io%2Fmcp%22%7D"
  aria-label="Install Prisma MCP server in VS Code"
  style="{
  display: &#x22;inline-flex&#x22;,
  alignItems: &#x22;center&#x22;,
  borderRadius: &#x22;6px&#x22;,
  overflow: &#x22;hidden&#x22;,
  textDecoration: &#x22;none&#x22;,
  height: &#x22;2.0rem&#x22;,
}"
>
  <span
    style="{
    backgroundColor: &#x22;#2C2C2C&#x22;,
    color: &#x22;white&#x22;,
    padding: &#x22;0.6rem 0.8rem&#x22;,
  }"
  >
    VS CODE
  </span>

  <span
    style="{
    backgroundColor: &#x22;#0098FF&#x22;,
    color: &#x22;white&#x22;,
    padding: &#x22;0.6rem 1rem&#x22;,
  }"
  >
    INSTALL PRISMA MCP SERVER
  </span>
</a>

This will prompt you to open VS Code. Once opened, you'll be guided to install the Prisma MCP server directly into your VS Code configuration.

If your browser blocks the link, [you can set it up manually](https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_add-an-mcp-server-to-your-workspace) by creating a `.vscode/mcp.json` file in your workspace and adding:

```json title=".vscode/mcp.json"
{
  "servers": {
    "Prisma": {
      "url": "https://mcp.prisma.io/mcp"
    }
  }
}
```

Learn more about the MCP server in our [MCP server documentation](https://www.prisma.io/docs/ai/tools/mcp-server).

## Agent mode [#agent-mode]

VS Code includes an [agent mode](https://pris.ly/vs-code-docs) (powered by GitHub Copilot) that automatically performs code changes and executes Prisma CLI commands based on your prompts.

### Capabilities [#capabilities]

The [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) enables support for VS Code agent mode.

VS Code agent mode can perform the following tasks:

* Check migration status (e.g. Flag unapplied migrations)
* Create and apply schema migrations automatically
* Sign in to the Prisma Data Platform
* Provision Prisma Postgres instances

### How to enable and use the VS Code agent [#how-to-enable-and-use-the-vs-code-agent]

The [latest version of the Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) fully supports agent mode. Since extensions update automatically, no manual action is required to enable it.

> [!NOTE]
> We recommend you to use the latest version of Prisma ORM.

To use the agent mode:

1. Open [GitHub Copilot Chat in VS Code and switch to **Agent** mode](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode#_use-agent-mode).
2. With GitHub Copilot Chat open and the Prisma extension updated, type a request such as: "Create a new database for me and add the connection string to the .env file".
3. The agent will request permission to make changes in your workspace.
4. It automatically handles login to your Prisma Data Platform account before proceeding.
5. Upon approval, the agent creates the new database and adds the connection string to your `.env` file.
6. You can also use agent mode to run migrations, generate the Prisma Client, and perform other tasks.

> [!NOTE]
> Currently, the agent mode uses your default [workspace](https://www.prisma.io/docs/console/concepts#workspace) in the Prisma Data Platform.

### Querying Prisma docs from VS Code using GitHub Copilot [#querying-prisma-docs-from-vs-code-using-github-copilot]

Complementing the agent, the Prisma Copilot extension allows you to query Prisma documentation directly within VS Code.

You need to install the [Prisma for Copilot extension](https://github.com/apps/prisma-for-github-copilot) from the GitHub marketplace.

Then, [switch to **Ask** mode in GitHub Copilot Chat](https://code.visualstudio.com/docs/copilot/chat/chat-ask-mode) and type your question using the `@prisma-for-github-copilot` namespace.

For more details, refer to our [GitHub Copilot documentation](https://www.prisma.io/docs/ai/tools/github-copilot).

## Related pages

- [`Firebase Studio`](https://www.prisma.io/docs/guides/postgres/idx): Learn how to use Prisma Postgres in the online Firebase Studio
- [`Fly.io`](https://www.prisma.io/docs/guides/postgres/flyio): Learn how to deploy applications using Prisma Postgres to Fly.io
- [`Netlify`](https://www.prisma.io/docs/guides/postgres/netlify): Learn how to create Prisma Postgres databases via the official Netlify extension and deploy your applications with it
- [`Vercel`](https://www.prisma.io/docs/guides/postgres/vercel): Learn how to create Prisma Postgres databases via the Vercel Marketplace and deploy your Next.js, Nuxt, and SvelteKit applications.
- [`Viewing data`](https://www.prisma.io/docs/guides/postgres/viewing-data): Viewing and editing data in Prisma Postgres via Prisma Studio or other database GUIs

# Bun (/docs/guides/runtimes/bun)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Scaffold a Prisma ORM app with Bun, run your first typed query, serve users over HTTP, and deploy to Prisma Compute.

Location: Guides > Runtimes > Bun

## Introduction [#introduction]

In this guide, you scaffold a Prisma ORM project with Bun, initialize a PostgreSQL database from your schema, run your first typed query, serve query results over HTTP with `Bun.serve`, and deploy the server to [Prisma Compute](https://www.prisma.io/docs/compute). Bun runs TypeScript directly, so nothing has to be compiled to work locally; the deploy bundles the server with `tsdown`.

Every command and code sample below was run end to end against a live Prisma Postgres database.

## Prerequisites [#prerequisites]

* [Bun](https://bun.sh/) 1.1 or later (`bun --version`)
* A PostgreSQL connection string, or nothing at all: `bunx create-db` can create a [Prisma Postgres](https://www.prisma.io/docs/postgres) database for you

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create a new Bun app with Prisma ORM, run a first typed query, and deploy it to Prisma Compute.

1. Scaffold: `bun create prisma@latest my-bun-app --template minimal --provider postgres --package-manager bun --yes`. Then run `bunx prisma@latest init` in `my-bun-app` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `bunx create-db` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
2. In `my-bun-app`, run `bun run contract:emit`, then `bun run db:init`, with `DATABASE_URL` exported.
3. Replace `src/index.ts` with a script that creates a user and reads all users back via `db.orm.public.User`, following https://www.prisma.io/docs/guides/runtimes/bun.md, and verify `bun src/index.ts` prints the created user (`bun run dev` is `tsx watch`, which does not exit).
4. Add `src/server.ts` with a `Bun.serve` server exposing GET /users, and verify `curl http://localhost:3000/users` returns the users.
5. Deploy: check `bunx prisma@latest auth whoami`; if I am not signed in, stop and ask me to run `bunx prisma@latest auth login`. Then point the build at the server by setting `entry` in `tsdown.config.ts` to `{ server: "src/server.ts" }`, run `bun run build`, then `bunx prisma@latest deploy module.ts`, and verify the live URL's /users endpoint returns `[]`. The deployed app provisions its own fresh Prisma Postgres database, so the local users are not there; do not pass the local DATABASE_URL. If the deploy fails with `HostedStateBootstrapError`, a project with the module's name exists in my workspace but its hosted state cannot be verified; re-run the deploy with `--name <a unique name>`.

Use the installed Prisma ORM skills.
```

## 1. Scaffold the project [#1-scaffold-the-project]

Create the project with `create-prisma`. Pick Bun as the package manager when prompted, or pass everything up front:

```bash
bun create prisma@latest my-bun-app --template minimal --provider postgres --package-manager bun --no-deploy
```

Answer the prompts for contract authoring style and agent skills. The scaffold sets up `src/prisma/` with a starter schema and installs dependencies with Bun.

```bash
cd my-bun-app
```

Next, set the database connection for the local steps. Use your own PostgreSQL connection string, or create a Prisma Postgres database with `bunx create-db`; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the generated scripts read the environment variable, not `.env`:

```bash
export DATABASE_URL="<your connection string>"
```

## 2. Emit the contract and initialize the database [#2-emit-the-contract-and-initialize-the-database]

Prisma ORM compiles your schema (`src/prisma/contract.prisma`) into a contract that your queries are type-checked against. If you chose TypeScript authoring (`--authoring typescript`), the source is `src/prisma/contract.ts` and the emitted files land in `src/prisma/generated/` instead. Emit it, then apply the schema to the database:

```bash
bun run contract:emit
bun run db:init
```

`db:init` creates the tables and signs the database:

```text no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"
```

If `db:init` stops with `Connection terminated unexpectedly`, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports `Applied 0 operation(s)` when there is nothing left to do.

If `db:init` reports that the contract file is missing, run `bun run contract:emit` first; the emit step generates `src/prisma/contract.json`.

## 3. Write your first query [#3-write-your-first-query]

Replace `src/index.ts` with a script that creates a user and reads every user back. Model access is namespace-qualified on PostgreSQL: `db.orm.public.User`, where `public` is the default schema.

```ts title="src/index.ts"
import { db } from "./prisma/db";

// Create a user, then read every user back
const user = await db.orm.public.User.create({
  email: `ada+${Date.now()}@prisma.io`,
  name: "Ada Lovelace",
});
console.log(`created user ${user.email}`);

const users = await db.orm.public.User.select("id", "email", "name").all();
console.log(`there are now ${users.length} users`);

await db.close();
```

`await db.close()` at the end lets the script exit cleanly; without it, the connection pool keeps the process alive.

## 4. Run it [#4-run-it]

The generated `dev` script is `tsx watch src/index.ts`, which re-runs the file on every save. For a single run, call Bun directly:

```bash
bun src/index.ts
```

```text no-copy
created user ada+1784893846026@prisma.io
there are now 1 users
```

The `pg` driver may print an SSL mode deprecation warning above the output; it comes from the `sslmode=require` setting in the generated connection string and does not affect the query.

That is the whole loop: schema to contract, contract to database, typed queries against both.

## 5. Serve it over HTTP [#5-serve-it-over-http]

The script pattern works for one-off jobs. To keep the app running and serve query results, add a small HTTP server with `Bun.serve`. Create `src/server.ts`:

```ts title="src/server.ts"
import { db } from "./prisma/db";

const server = Bun.serve({
  port: Number(process.env.PORT ?? 3000),
  async fetch(req) {
    const { pathname } = new URL(req.url);
    if (pathname === "/users") {
      const users = await db.orm.public.User.select("id", "email", "name").all();
      return Response.json(users);
    }
    return new Response("Not found", { status: 404 });
  },
});

console.log(`Listening on http://localhost:${server.port}`);
```

Start it and check the endpoint:

```bash
bun src/server.ts
```

```bash
curl http://localhost:3000/users
```

```json no-copy
[{ "id": 1, "email": "ada+1784893846026@prisma.io", "name": "Ada Lovelace" }]
```

The server listens on port 3000; set `PORT` to change it. Unlike the script, the server never calls `db.close()`: the connection pool is shared across requests and closes when the process exits.

## 6. Deploy to Prisma Compute [#6-deploy-to-prisma-compute]

Plain Bun servers are supported on [Prisma Compute](https://www.prisma.io/docs/compute). The scaffold declares the app for [Prisma Composer](https://www.prisma.io/docs/composer) in `module.ts` and `service.ts`, which deploy whatever the `build` script bundles into `dist/server.mjs`. That script runs `tsdown`, and the generated `tsdown.config.ts` sets its entry to `src/index.ts`, so point the entry at your server instead:

```ts title="tsdown.config.ts"
export default defineConfig({
  entry: { server: "src/server.ts" },
  // the rest of the generated config is unchanged
});
```

Sign in once (it opens a browser):

```bash
bunx prisma@latest auth login
```

Then build and deploy from the project directory:

```bash
bun run build
bunx prisma@latest deploy module.ts
```

```text no-copy
my-bun-app
├─ database   postgres-database db_abc123
└─ app        compute-service cps_abc123
              https://xyz.ewr.prisma.build
```

The deploy creates a project named after your module in your workspace, and re-running the deploy reuses it: the CLI finds the hosted state it stored on the first run and converges the project to your module. If a project with that name exists but the CLI cannot identify or verify its stored state (one left behind by a different checkout, for example), the deploy stops with `HostedStateBootstrapError`; deploy under another name with `--name <unique-name>`, or rename the module in `module.ts`. The deploy also provisions its own Prisma Postgres database on the platform, declared in `module.ts`; the users you created locally are not in it. Verify the live endpoint responds with an empty list from the fresh database:

```bash
curl https://xyz.ewr.prisma.build/users
```

```json no-copy
[]
```

For previews per Git branch and deploy on push, see [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push).

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`bunx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, add a script that lists the 10 newest users."
* "Add a published flag to the Post model in the starter contract, emit the contract, and update the database."

## Next steps [#next-steps]

* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Deno`](https://www.prisma.io/docs/guides/runtimes/deno): Run a minimal Prisma ORM and PostgreSQL app on Deno.

# Deno (/docs/guides/runtimes/deno)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Run a minimal Prisma ORM and PostgreSQL app on Deno.

Location: Guides > Runtimes > Deno

## Introduction [#introduction]

In this guide, you scaffold a minimal Prisma ORM app for Deno, initialize a PostgreSQL database, and run the generated typed query. The app uses Deno-native tasks and explicit `.ts` extensions for relative imports.

Every command below was run end to end against a live Prisma Postgres database.

## Prerequisites [#prerequisites]

* [Deno](https://deno.com/) 2.6 or later (`deno --version`): the scaffold command passes `--minimum-dependency-age=0`, which earlier releases reject

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Create and verify a minimal Prisma ORM app on Deno.

1. Run `deno run -A --minimum-dependency-age=0 npm:create-prisma@latest my-deno-app --template minimal --provider postgres --package-manager deno --no-deploy --yes`.
2. Enter `my-deno-app`. Run `deno run -A npm:create-db@latest --env .env --ttl 24h` and show me the claim URL so I can keep the temporary database.
3. Run `deno task db:init`, then start `deno task dev` in the background.
4. Request `http://localhost:3000` and verify that it returns Alice, Bob, and Carol. The first request seeds these users automatically; do not add or run a separate seed command.
5. Do not deploy to Prisma Compute because it does not support Deno.

Use the generated tasks instead of invoking a Prisma CLI package directly.
```

## 1. Scaffold the project [#1-scaffold-the-project]

Run `create-prisma` through Deno and select the minimal PostgreSQL template:

```bash
deno run -A --minimum-dependency-age=0 npm:create-prisma@latest my-deno-app --template minimal --provider postgres --package-manager deno --no-deploy
```

The command creates the app, installs its npm dependencies through Deno, and emits the Prisma contract artifacts. Deno 2.9 skips npm packages published in the previous 24 hours by default, so without `--minimum-dependency-age=0` a newly published `create-prisma` release resolves to an older version. Deno support is currently limited to the minimal PostgreSQL template.

```bash
cd my-deno-app
```

The generated project includes:

* `deno.json` with npm compatibility enabled
* Deno-native `dev`, `build`, and Prisma tasks in `package.json`
* explicit `.ts` extensions on relative imports
* no Composer or Prisma Compute deployment files

## 2. Create and initialize the database [#2-create-and-initialize-the-database]

Create a temporary Prisma Postgres database and write its connection string to `.env`:

```bash
deno run -A npm:create-db@latest --env .env --ttl 24h
```

The command prints a claim URL. Open it within 24 hours to keep the database, or replace `DATABASE_URL` in `.env` with your own PostgreSQL connection string.

Apply the starter contract and sign the database:

```bash
deno task db:init
```

## 3. Run the app [#3-run-the-app]

Start the generated HTTP server:

```bash
deno task dev
```

Then request it from another terminal:

```bash
curl http://localhost:3000
```

The response contains the starter users:

```json no-copy
{
  "users": [
    { "id": "1", "email": "alice@prisma.io", "username": "alice", "name": "Alice", "createdAt": "2026-07-24T10:55:54.156Z" },
    { "id": "2", "email": "bob@prisma.io", "username": "bob", "name": "Bob", "createdAt": "2026-07-24T10:55:54.192Z" },
    { "id": "3", "email": "carol@prisma.io", "username": "carol", "name": "Carol", "createdAt": "2026-07-24T10:55:54.228Z" }
  ]
}
```

The first request runs `src/prisma/seed.ts` through the generated query helper. Seeding is idempotent, so later requests read the same rows without creating duplicates. There is no separate seed command.

## 4. Understand the generated query [#4-understand-the-generated-query]

The generated `src/prisma/users.ts` connects the database, seeds on the first query, and reads from the PostgreSQL `public` namespace:

```ts title="src/prisma/users.ts"
import { db } from "./db.ts";
import { seed } from "./seed.ts";

export async function listUsers(limit = 10) {
  await seed();

  const users = await db.orm.public.User
    .select("id", "email", "username", "name", "createdAt")
    .limit(limit)
    .all();

  return users.map((user) => ({
    id: String(user.id),
    email: user.email,
    username: user.username ?? null,
    name: user.name ?? null,
    createdAt: user.createdAt,
  }));
}
```

Deno requires the `.ts` extension on these relative imports. The generated files already include it.

After changing `src/prisma/contract.prisma`, regenerate the typed artifacts and update the database:

```bash
deno task contract:emit
deno task db:update
```

## Current limitations [#current-limitations]

* Prisma Compute does not support Deno deployments yet.
* The generated commands use `-A` for the filesystem, environment, and network permissions required during setup and local development. You can replace it with a narrower allow list for your application after setup.

## Next steps [#next-steps]

* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for contracts, typed queries, and migrations.
* [Use the Bun guide](https://www.prisma.io/docs/guides/runtimes/bun) if you also target Bun.

## Related pages

- [`Bun`](https://www.prisma.io/docs/guides/runtimes/bun): Scaffold a Prisma ORM app with Bun, run your first typed query, serve users over HTTP, and deploy to Prisma Compute.

# Drizzle (/docs/guides/switch-to-prisma-orm/from-drizzle)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Switch an existing Drizzle app to Prisma ORM: infer a contract from your database, sign it, and replace Drizzle queries route by route.

Location: Guides > Switch to Prisma ORM > Drizzle

## Introduction [#introduction]

This guide shows you how to migrate an application from Drizzle to Prisma ORM. The sample app is a Next.js project with API routes for users, profiles, posts and categories. Posts and categories are connected through a `posts_to_categories` join table, the schema was pushed to a local PostgreSQL database with `drizzle-kit push`, and the routes read and write through `drizzle-orm`.

Prisma ORM reads the schema that Drizzle already created, so you do not rebuild the database. You add Prisma ORM to the project, infer a contract from the live tables, sign the database, and then replace Drizzle queries one at a time. The routes keep working during the switch, so you can move as slowly or as quickly as you like.

Every command and response below was run end to end against the sample app and a local PostgreSQL 17 database.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/switch-to-prisma-orm/from-drizzle](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-drizzle).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* A Drizzle project that talks to a PostgreSQL database, and its connection string in `DATABASE_URL`
* Basic familiarity with Drizzle and Next.js

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Migrate this Drizzle project to Prisma ORM without changing the database.

1. Run `npx prisma@latest orm init --target postgres` in the project root, choose PSL and the default schema path. Then run `npx prisma@latest init` so the Prisma agent skills are installed, and use them. Keep the existing `DATABASE_URL` in `.env`; Drizzle and Prisma ORM use the same connection string format.
2. Run `npx prisma contract infer --output ./src/prisma/contract.prisma` to read the live schema into `src/prisma/contract.prisma`. Review it with me: singularize the model names (keep the `@@map` attributes so the table names do not change), replace every `Timestamptz` field type with `TimestamptzString`, and for each many-to-many join model add a direct list field on both sides (for example `categories Category[]` on `Post` and `posts Post[]` on `Category`).
3. Run `npx prisma contract emit`, then `npx prisma db sign`, then `npx prisma db verify`. All three must succeed before you touch application code.
4. Replace the Drizzle queries one route at a time following https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-drizzle.md: import `db` from `src/prisma/db.ts`, use `db.orm.public.<Model>` with `.include(...)`, `.create(...)`, `.where(...).update(...)` and `.where(...).delete(...)`. Run each route with curl before and after, and show me the responses.
5. When no file imports `drizzle-orm` any more, remove `src/db/`, `drizzle.config.ts` and the Drizzle packages, and confirm `next build` passes.
```

## Overview of the migration process [#overview-of-the-migration-process]

The steps are the same for any app that uses Drizzle, whether it serves a REST API, a GraphQL API or server-rendered pages:

1. Add Prisma ORM to the project with `orm init`.
2. Infer a contract from the live database.
3. Review the inferred contract.
4. Emit the contract and sign the database.
5. Replace Drizzle queries with Prisma ORM queries.

Prisma ORM supports incremental adoption. Both ORMs can talk to the same database while you migrate, so you can move one route at a time and ship in between.

If you migrated to Prisma ORM 7 before, you will notice what is missing: there is no `prisma init`, no `db pull`, no baseline migration, no `prisma generate`, and no driver adapter package. The contract you emit is checked in, the runtime is typed from it directly, and `db sign` replaces the baseline migration.

## The sample app [#the-sample-app]

The Drizzle schema declares a `role` enum, four tables and an explicit join table:

```typescript title="src/db/schema.ts"
import { relations } from "drizzle-orm";
import {
  boolean,
  integer,
  pgEnum,
  pgTable,
  primaryKey,
  serial,
  text,
  timestamp,
} from "drizzle-orm/pg-core";

export const roleEnum = pgEnum("role", ["USER", "ADMIN"]);

export const users = pgTable("users", {
  id: serial("id").primaryKey(),
  email: text("email").notNull().unique(),
  name: text("name"),
  role: roleEnum("role").default("USER").notNull(),
  createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
});

export const profiles = pgTable("profiles", {
  id: serial("id").primaryKey(),
  bio: text("bio"),
  userId: integer("user_id")
    .notNull()
    .unique()
    .references(() => users.id, { onDelete: "cascade" }),
});

export const posts = pgTable("posts", {
  id: serial("id").primaryKey(),
  title: text("title").notNull(),
  content: text("content"),
  published: boolean("published").default(false).notNull(),
  authorId: integer("author_id")
    .notNull()
    .references(() => users.id, { onDelete: "cascade" }),
  createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
});

export const categories = pgTable("categories", {
  id: serial("id").primaryKey(),
  name: text("name").notNull().unique(),
});

export const postsToCategories = pgTable(
  "posts_to_categories",
  {
    postId: integer("post_id")
      .notNull()
      .references(() => posts.id, { onDelete: "cascade" }),
    categoryId: integer("category_id")
      .notNull()
      .references(() => categories.id, { onDelete: "cascade" }),
  },
  (t) => [primaryKey({ columns: [t.postId, t.categoryId] })],
);

export const usersRelations = relations(users, ({ one, many }) => ({
  profile: one(profiles, { fields: [users.id], references: [profiles.userId] }),
  posts: many(posts),
}));

export const profilesRelations = relations(profiles, ({ one }) => ({
  user: one(users, { fields: [profiles.userId], references: [users.id] }),
}));

export const postsRelations = relations(posts, ({ one, many }) => ({
  author: one(users, { fields: [posts.authorId], references: [users.id] }),
  postsToCategories: many(postsToCategories),
}));

export const categoriesRelations = relations(categories, ({ many }) => ({
  postsToCategories: many(postsToCategories),
}));

export const postsToCategoriesRelations = relations(postsToCategories, ({ one }) => ({
  post: one(posts, { fields: [postsToCategories.postId], references: [posts.id] }),
  category: one(categories, {
    fields: [postsToCategories.categoryId],
    references: [categories.id],
  }),
}));
```

The Drizzle client reads the same `DATABASE_URL` that Prisma ORM will use:

```typescript title="src/db/drizzle.ts"
import "dotenv/config";
import { drizzle } from "drizzle-orm/node-postgres";
import * as schema from "./schema";

export const db = drizzle(process.env.DATABASE_URL!, { schema });
```

The API routes live under `src/app/api/`: `GET` and `POST /api/users`, `GET` and `POST /api/posts`, `PATCH` and `DELETE /api/posts/[id]`, and `GET /api/categories`. Their Drizzle code is shown next to its Prisma ORM replacement in [step 5](#5-replace-your-drizzle-queries).

## 1. Add Prisma ORM to the project [#1-add-prisma-orm-to-the-project]

Run `orm init` in the root of the Drizzle project. It preselects PostgreSQL and adds Prisma ORM to the app you already have; it does not scaffold a new project.

  

#### bun

```bash
bunx prisma@latest orm init --target postgres
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --target postgres
```

#### yarn

```bash
yarn dlx prisma@latest orm init --target postgres
```

#### npm

```bash
npx prisma@latest orm init --target postgres
```

Choose `PSL` as the authoring style and keep the default schema path, `src/prisma/contract.prisma`. The command installs the runtime and CLI packages, writes the Prisma ORM files, and emits a starter contract:

```text no-copy
✔ npm add @prisma/orm-postgres dotenv
✔ npm add -D prisma@latest
✔ npm add -D @prisma/cli-engine@0.6.1
✔ Emit the contract
│  target:     postgres
│  authoring:  psl
│  schema:     src/prisma/contract.prisma
written
├─ src/prisma/contract.prisma
├─ prisma.config.ts
├─ src/prisma/db.ts
├─ prisma-8.md
├─ .env.example
├─ tsconfig.json
├─ .gitignore
├─ .gitattributes
└─ package.json
✔ Done. Open prisma-8.md to get started.
→ Set DATABASE_URL in your environment (export it or add it to .env)
→ Edit your schema at src/prisma/contract.prisma, then emit again
```

Three files matter for the migration. `prisma.config.ts` tells the CLI where the contract lives and how to reach the database; it loads `.env` through `dotenv/config`, so the `DATABASE_URL` your Drizzle config already uses works unchanged:

```typescript title="prisma.config.ts"
import 'dotenv/config';
import { definePrismaConfig } from '@prisma/cli-engine';
import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./src/prisma/contract.prisma",
    db: {
      connection: process.env['DATABASE_URL']!,
    },
  }),
});
```

`src/prisma/db.ts` is the client your routes will import. It talks to PostgreSQL directly, so there is no driver adapter and no generated client package:

```typescript title="src/prisma/db.ts"
import 'dotenv/config';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});
```

`src/prisma/contract.prisma` holds a placeholder `User` and `Post` model. You replace it in the next step.

`orm init` also sets `"type": "module"` in `package.json` and adds `"types": ["node"]` plus `"module": "preserve"` to `tsconfig.json`. Next.js runs, builds and type-checks with those settings, so leave them in place.

## 2. Infer a contract from your database [#2-infer-a-contract-from-your-database]

Read the schema that Drizzle pushed into a PSL contract. `--output` points at the file `orm init` created, and the command overwrites the placeholder:

  

#### bun

```bash
bunx prisma contract infer --output ./src/prisma/contract.prisma
```

#### pnpm

```bash
pnpm prisma contract infer --output ./src/prisma/contract.prisma
```

#### yarn

```bash
yarn prisma contract infer --output ./src/prisma/contract.prisma
```

#### npm

```bash
npx prisma contract infer --output ./src/prisma/contract.prisma
```

```text no-copy
✔ Connecting to database...
✔ Introspecting database schema...
Overwriting existing file: src/prisma/contract.prisma
│  database:  postgres://****@localhost:5432/drizzle_app
✔ Contract written to src/prisma/contract.prisma
```

For the sample app, the inferred contract looks like this:

```prisma title="src/prisma/contract.prisma"
// use prisma-8
// Contract inferred from the live database schema. Edit as needed, then run `prisma contract emit`.

namespace public {
  model Categories {
    id                Int                 @id(map: "categories_pkey") @default(autoincrement())
    name              String              @unique(map: "categories_name_unique")
    postsToCategories PostsToCategories[]

    @@map("categories")
  }

  model Users {
    id        Int           @id(map: "users_pkey") @default(autoincrement())
    email     String        @unique(map: "users_email_unique")
    name      String?
    role      pg.enum(Role) @default("USER")
    createdAt Timestamptz   @default(now()) @map("created_at")
    posts     Posts[]
    profiles  Profiles?

    @@map("users")
  }

  model Posts {
    id                Int                 @id(map: "posts_pkey") @default(autoincrement())
    title             String
    content           String?
    published         Boolean             @default(false)
    authorId          Int                 @map("author_id")
    createdAt         Timestamptz         @default(now()) @map("created_at")
    postsToCategories PostsToCategories[]
    author            Users               @relation(fields: [authorId], references: [id], onDelete: Cascade, map: "posts_author_id_users_id_fk", index: false)

    @@map("posts")
  }

  model PostsToCategories {
    postId     Int        @map("post_id")
    categoryId Int        @map("category_id")
    category   Categories @relation(fields: [categoryId], references: [id], onDelete: Cascade, map: "posts_to_categories_category_id_categories_id_fk", index: false)
    post       Posts      @relation(fields: [postId], references: [id], onDelete: Cascade, map: "posts_to_categories_post_id_posts_id_fk", index: false)

    @@id([postId, categoryId], map: "posts_to_categories_post_id_category_id_pk")
    @@map("posts_to_categories")
  }

  model Profiles {
    id     Int     @id(map: "profiles_pkey") @default(autoincrement())
    bio    String?
    userId Int     @unique(map: "profiles_user_id_unique") @map("user_id")
    user   Users   @relation(fields: [userId], references: [id], onDelete: Cascade, map: "profiles_user_id_users_id_fk")

    @@map("profiles")
  }

  native_enum Role {
    USER = "USER"
    ADMIN = "ADMIN"
    @@map("role")
  }
}
```

Here is how each part of the Drizzle schema came through:

* **Namespace.** Every model sits inside `namespace public { ... }`, the PostgreSQL schema Drizzle pushed to. This is why queries are written as `db.orm.public.User` later.
* **Names.** Model names are PascalCase versions of the table names, so they are plural (`Users`, `Posts`); `@@map` keeps the real table name. Snake case columns become camelCase fields with `@map`, so `created_at` is `createdAt`.
* **Constraints and defaults.** Primary keys, unique constraints and foreign keys keep their database names through `map:`. `serial` columns become `Int @id @default(autoincrement())`. The `default(false)` and `defaultNow()` calls come back as `@default(false)` and `@default(now())`.
* **Enum.** The `pgEnum("role", ...)` type is a `native_enum Role` block with `@@map("role")`, and the column uses it as `pg.enum(Role) @default("USER")`. The TypeScript type of the field is `'USER' | 'ADMIN'`.
* **Timestamps.** `timestamp(..., { withTimezone: true })` columns are typed `Timestamptz`. You change this in the next step.
* **Relations.** Each `.references(...)` is an `@relation(...)` on the side that holds the foreign key, with `onDelete: Cascade` carried over. `index: false` records that Drizzle created no separate index for the foreign key. The list side (`posts Posts[]`) is derived for you; the `relations(...)` helpers in `schema.ts` have no equivalent because the contract already knows both directions.
* **One-to-one.** The unique `user_id` on `profiles` came through as `profiles Profiles?` on `Users` and `user Users` on `Profiles`.
* **Many-to-many.** The join table is an explicit `PostsToCategories` model with a composite `@@id`, and `Posts` and `Categories` each hold a list of the join model, not of each other. Prisma ORM has no implicit many-to-many; the [many-to-many section](#many-to-many-relations-in-prisma-8) below shows how to add the direct traversal.

## 3. Review the contract [#3-review-the-contract]

Inference is a starting point. Make three edits before you emit.

### 3.1. Singularize the model names [#31-singularize-the-model-names]

Rename the models to singular PascalCase and keep every `@@map`, so the table names do not change: `Categories` becomes `Category`, `Users` becomes `User`, `Posts` becomes `Post`, `Profiles` becomes `Profile`, and `PostsToCategories` becomes `PostToCategory`. Update the relation field types to match, and rename the `profiles` field on `User` to `profile`.

### 3.2. Use string timestamps [#32-use-string-timestamps]

Change both `Timestamptz` fields to `TimestamptzString`. `Timestamptz` reads and writes through the `Temporal` API, which Node.js does not ship yet; with the inferred type, the first query that touches a timestamp fails:

```text no-copy
Error [StructuredError]: Codec 'pg/timestamptz-temporal@1' cannot decode a value because this runtime has no global Temporal implementation.
  code: 'RUNTIME.TEMPORAL_UNAVAILABLE',
  fix: "Run on a runtime with Temporal available, install a Temporal polyfill before creating the client, or author the column with its *String type to read and write PostgreSQL's own text instead."
```

`TimestamptzString` keeps the `timestamptz` column exactly as it is and hands your code the value as a string. Drizzle gave you a `Date` here, so a JSON response changes from `"2026-09-10T15:32:51.298Z"` to `"2026-09-10 21:32:51.298482+06"`. If a client depends on the ISO form, convert with `new Date(value).toISOString()` at the edge.

### 3.3. Add direct many-to-many fields [#33-add-direct-many-to-many-fields]

Add `categories Category[]` to `Post` and `posts Post[]` to `Category`, next to the existing `postsToCategories` lists. The join model stays, and the two new fields resolve through it, so `Post` can include its categories directly. This is a contract-only change: the storage hash stays the same and no migration is needed.

After the three edits the contract looks like this:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

namespace public {
  model Category {
    id                Int              @id(map: "categories_pkey") @default(autoincrement())
    name              String           @unique(map: "categories_name_unique")
    postsToCategories PostToCategory[]
    posts             Post[]

    @@map("categories")
  }

  model User {
    id        Int               @id(map: "users_pkey") @default(autoincrement())
    email     String            @unique(map: "users_email_unique")
    name      String?
    role      pg.enum(Role)     @default("USER")
    createdAt TimestamptzString @default(now()) @map("created_at")
    posts     Post[]
    profile   Profile?

    @@map("users")
  }

  model Post {
    id                Int               @id(map: "posts_pkey") @default(autoincrement())
    title             String
    content           String?
    published         Boolean           @default(false)
    authorId          Int               @map("author_id")
    createdAt         TimestamptzString @default(now()) @map("created_at")
    postsToCategories PostToCategory[]
    categories        Category[]
    author            User              @relation(fields: [authorId], references: [id], onDelete: Cascade, map: "posts_author_id_users_id_fk", index: false)

    @@map("posts")
  }

  model PostToCategory {
    postId     Int      @map("post_id")
    categoryId Int      @map("category_id")
    category   Category @relation(fields: [categoryId], references: [id], onDelete: Cascade, map: "posts_to_categories_category_id_categories_id_fk", index: false)
    post       Post     @relation(fields: [postId], references: [id], onDelete: Cascade, map: "posts_to_categories_post_id_posts_id_fk", index: false)

    @@id([postId, categoryId], map: "posts_to_categories_post_id_category_id_pk")
    @@map("posts_to_categories")
  }

  model Profile {
    id     Int     @id(map: "profiles_pkey") @default(autoincrement())
    bio    String?
    userId Int     @unique(map: "profiles_user_id_unique") @map("user_id")
    user   User    @relation(fields: [userId], references: [id], onDelete: Cascade, map: "profiles_user_id_users_id_fk")

    @@map("profiles")
  }

  native_enum Role {
    USER = "USER"
    ADMIN = "ADMIN"
    @@map("role")
  }
}
```

## 4. Emit the contract and sign the database [#4-emit-the-contract-and-sign-the-database]

Emit the contract to refresh `contract.json` and `contract.d.ts`, the two files the runtime and the CLI read:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

```text no-copy
✔ Emitted contract.json and contract.d.ts
storageHash:  7cbfecc26820132f373d82c4e3ba43ce2ec6d4a4c3f6da73a58e5a31d461d09c
profileHash:  3916f444a8a17ad749191acf9e08dad97d1a327b88c2f1d45d12f240296aa8b2
```

Then sign the database. This records that the live schema matches the emitted contract, and it is the Prisma ORM 8 replacement for the baseline migration you would have created with Prisma ORM 7:

  

#### bun

```bash
bunx prisma db sign
```

#### pnpm

```bash
pnpm prisma db sign
```

#### yarn

```bash
yarn prisma db sign
```

#### npm

```bash
npx prisma db sign
```

```text no-copy
✔ Verifying database schema...
✔ Signing database...
│  contract:  src/prisma/contract.json
│  database:  postgres://****@localhost:5432/drizzle_app
✔ Database signed
from:  none
to:    7cbfecc26820132f373d82c4e3ba43ce2ec6d4a4c3f6da73a58e5a31d461d09c
```

`db sign` verifies the schema before it writes the signature; if a table or column in the contract does not match the database, it exits with code 4 and signs nothing. Confirm the result with `db verify`:

  

#### bun

```bash
bunx prisma db verify
```

#### pnpm

```bash
pnpm prisma db verify
```

#### yarn

```bash
yarn prisma db verify
```

#### npm

```bash
npx prisma db verify
```

```text no-copy
✔ Database marker and schema match contract
storageHash:  7cbfecc26820132f373d82c4e3ba43ce2ec6d4a4c3f6da73a58e5a31d461d09c
profileHash:  3916f444a8a17ad749191acf9e08dad97d1a327b88c2f1d45d12f240296aa8b2
```

From here on, schema changes go through the contract: edit `contract.prisma`, run `contract emit`, then [`db update`](https://www.prisma.io/docs/cli/db-update) for a direct development update or [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) and [`db migrate`](https://www.prisma.io/docs/cli/db-migrate) for a checked-in migration. You can delete `drizzle.config.ts` and stop running `drizzle-kit` once you no longer want it to own the schema.

## 5. Replace your Drizzle queries [#5-replace-your-drizzle-queries]

Every route imports the same client, `db` from `src/prisma/db.ts`, and reaches models as `db.orm.public.<Model>`. Migrate one route, run it, then move to the next. For the full query surface, see [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data), [Writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data) and the [ORM client reference](https://www.prisma.io/docs/orm/reference/orm-client).

### 5.1. Reads with relations [#51-reads-with-relations]

The users route loads each user with their profile and posts. In Drizzle, that is `db.query.users.findMany` with a `with` clause:

```typescript title="src/app/api/users/route.ts"
import { NextResponse } from "next/server";
import { db } from "@/db/drizzle";

export async function GET() {
  const result = await db.query.users.findMany({
    with: { profile: true, posts: true },
    orderBy: (u, { asc }) => [asc(u.id)],
  });
  return NextResponse.json(result);
}
```

With Prisma ORM, each relation is an `.include(...)`, and sorting is `.orderBy(...)` with a lambda over the fields:

```typescript title="src/app/api/users/route.ts"
import { NextResponse } from "next/server";
import { db } from "@/prisma/db";

export async function GET() {
  const result = await db.orm.public.User
    .include("profile")
    .include("posts")
    .orderBy((u) => u.id.asc())
    .all();
  return NextResponse.json(result);
}
```

The response has the same shape as before; the only visible change is the timestamp format from step 3.2:

```bash
curl http://localhost:3000/api/users
```

```json no-copy
[
  {
    "createdAt": "2026-09-10 21:32:51.298482+06",
    "email": "alice@prisma.io",
    "id": 1,
    "name": "Alice",
    "role": "ADMIN",
    "profile": { "bio": "Writes about databases", "id": 1, "userId": 1 },
    "posts": [
      { "authorId": 1, "content": "First post", "createdAt": "2026-09-10 21:32:51.929589+06", "id": 1, "published": true, "title": "Hello Drizzle" }
    ]
  },
  {
    "createdAt": "2026-09-10 21:32:51.298482+06",
    "email": "bob@prisma.io",
    "id": 2,
    "name": "Bob",
    "role": "USER",
    "profile": null,
    "posts": [
      { "authorId": 2, "content": null, "createdAt": "2026-09-10 21:32:51.929589+06", "id": 2, "published": false, "title": "Typed queries" }
    ]
  }
]
```

### 5.2. Reads through a join table [#52-reads-through-a-join-table]

The posts route loads the author and the categories. Drizzle traverses the join table explicitly, so every post carries `postsToCategories` entries with a nested `category`:

```typescript title="src/app/api/posts/route.ts"
import { NextResponse } from "next/server";
import { db } from "@/db/drizzle";

export async function GET() {
  const result = await db.query.posts.findMany({
    with: {
      author: true,
      postsToCategories: { with: { category: true } },
    },
    orderBy: (p, { asc }) => [asc(p.id)],
  });
  return NextResponse.json(result);
}
```

With the `categories` field you added in step 3.3, Prisma ORM includes the categories directly and drops the join records from the result:

```typescript title="src/app/api/posts/route.ts"
import { NextResponse } from "next/server";
import { db } from "@/prisma/db";

export async function GET() {
  const result = await db.orm.public.Post
    .include("author")
    .include("categories")
    .orderBy((p) => p.id.asc())
    .all();
  return NextResponse.json(result);
}
```

```bash
curl http://localhost:3000/api/posts
```

```json no-copy
[
  {
    "authorId": 1,
    "content": "First post",
    "createdAt": "2026-09-10 21:32:51.929589+06",
    "id": 1,
    "published": true,
    "title": "Hello Drizzle",
    "author": { "createdAt": "2026-09-10 21:32:51.298482+06", "email": "alice@prisma.io", "id": 1, "name": "Alice", "role": "ADMIN" },
    "categories": [
      { "id": 1, "name": "databases" },
      { "id": 2, "name": "typescript" }
    ]
  },
  {
    "authorId": 2,
    "content": null,
    "createdAt": "2026-09-10 21:32:51.929589+06",
    "id": 2,
    "published": false,
    "title": "Typed queries",
    "author": { "createdAt": "2026-09-10 21:32:51.298482+06", "email": "bob@prisma.io", "id": 2, "name": "Bob", "role": "USER" },
    "categories": [{ "id": 2, "name": "typescript" }]
  }
]
```

If you want the join records in the response, keep the shape Drizzle produced with a nested include: `.include("postsToCategories", (link) => link.include("category"))`.

### 5.3. Creates [#53-creates]

Creating a post with Drizzle is an insert with `.returning()` followed by a second insert into the join table:

```typescript title="src/app/api/posts/route.ts"
import { NextResponse } from "next/server";
import { db } from "@/db/drizzle";
import { posts, postsToCategories } from "@/db/schema";

export async function POST(request: Request) {
  const body = (await request.json()) as {
    title: string;
    content?: string;
    authorId: number;
    categoryIds?: number[];
  };
  const [post] = await db
    .insert(posts)
    .values({ title: body.title, content: body.content, authorId: body.authorId })
    .returning();
  if (body.categoryIds?.length) {
    await db
      .insert(postsToCategories)
      .values(body.categoryIds.map((categoryId) => ({ postId: post.id, categoryId })));
  }
  return NextResponse.json(post, { status: 201 });
}
```

`.create(...)` returns the inserted row, defaults included, and a nested `connect` writes the join rows in the same transaction:

```typescript title="src/app/api/posts/route.ts"
import { NextResponse } from "next/server";
import { db } from "@/prisma/db";

export async function POST(request: Request) {
  const body = (await request.json()) as {
    title: string;
    content?: string;
    authorId: number;
    categoryIds?: number[];
  };
  const post = await db.orm.public.Post.create({
    title: body.title,
    content: body.content ?? null,
    authorId: body.authorId,
    categories: (c) => c.connect((body.categoryIds ?? []).map((id) => ({ id }))),
  });
  return NextResponse.json(post, { status: 201 });
}
```

```bash
curl -X POST http://localhost:3000/api/posts \
  -H "content-type: application/json" \
  -d '{"title":"Drizzle to Prisma","content":"Migration notes","authorId":1,"categoryIds":[1,2]}'
```

```json no-copy
{ "authorId": 1, "content": "Migration notes", "createdAt": "2026-09-10 21:58:28.179323+06", "id": 5, "published": false, "title": "Drizzle to Prisma" }
```

Optional fields are explicit: pass `null` for a nullable column you do not set, as `content` shows. The users route follows the same pattern with two plain creates, `User.create(...)` and then `Profile.create({ userId: user.id, bio })`.

### 5.4. Updates and deletes [#54-updates-and-deletes]

The toggle route flips `published`. Drizzle can do that in place with `not(posts.published)`:

```typescript title="src/app/api/posts/[id]/route.ts"
import { eq, not } from "drizzle-orm";
import { NextResponse } from "next/server";
import { db } from "@/db/drizzle";
import { posts } from "@/db/schema";

type Params = { params: Promise<{ id: string }> };

export async function PATCH(_request: Request, { params }: Params) {
  const id = Number((await params).id);
  const [post] = await db
    .update(posts)
    .set({ published: not(posts.published) })
    .where(eq(posts.id, id))
    .returning();
  if (!post) return NextResponse.json({ error: "Not found" }, { status: 404 });
  return NextResponse.json(post);
}

export async function DELETE(_request: Request, { params }: Params) {
  const id = Number((await params).id);
  const [post] = await db.delete(posts).where(eq(posts.id, id)).returning();
  if (!post) return NextResponse.json({ error: "Not found" }, { status: 404 });
  return NextResponse.json(post);
}
```

Prisma ORM updates take a data object, so read the row first with `.first({ id })` and write the negated value. `.update()` and `.delete()` act on one row selected by `.where(...)`, return that row, and return `null` when nothing matched:

```typescript title="src/app/api/posts/[id]/route.ts"
import { NextResponse } from "next/server";
import { db } from "@/prisma/db";

type Params = { params: Promise<{ id: string }> };

export async function PATCH(_request: Request, { params }: Params) {
  const id = Number((await params).id);
  const current = await db.orm.public.Post.first({ id });
  if (!current) return NextResponse.json({ error: "Not found" }, { status: 404 });
  const post = await db.orm.public.Post.where({ id }).update({ published: !current.published });
  return NextResponse.json(post);
}

export async function DELETE(_request: Request, { params }: Params) {
  const id = Number((await params).id);
  const post = await db.orm.public.Post.where({ id }).delete();
  if (!post) return NextResponse.json({ error: "Not found" }, { status: 404 });
  return NextResponse.json(post);
}
```

```bash
curl -X PATCH http://localhost:3000/api/posts/2
curl -X DELETE http://localhost:3000/api/posts/5
curl -X DELETE http://localhost:3000/api/posts/5
```

```json no-copy
{ "authorId": 2, "content": null, "createdAt": "2026-09-10 21:32:51.929589+06", "id": 2, "published": true, "title": "Typed queries" }
{ "authorId": 1, "content": "Migration notes", "createdAt": "2026-09-10 21:58:28.179323+06", "id": 5, "published": false, "title": "Drizzle to Prisma" }
{ "error": "Not found" }
```

The `onDelete: Cascade` that came through inference still applies: deleting post 5 removed its two `posts_to_categories` rows. To update or delete several rows at once, use `.updateAll(...)` and `.deleteAll()` instead.

### 5.5. Remove Drizzle [#55-remove-drizzle]

When no file imports `drizzle-orm` any more, delete `src/db/` and `drizzle.config.ts` and uninstall the packages:

  

#### bun

```bash
bun remove drizzle-orm drizzle-kit pg
```

#### pnpm

```bash
pnpm remove drizzle-orm drizzle-kit pg
```

#### yarn

```bash
yarn remove drizzle-orm drizzle-kit pg
```

#### npm

```bash
npm uninstall drizzle-orm drizzle-kit pg
```

Keep `pg` if other code uses it directly; Prisma ORM brings its own copy. Run `next build` to confirm the app compiles and type-checks without Drizzle.

## Many-to-many relations in Prisma ORM [#many-to-many-relations-in-prisma-8]

Drizzle has no implicit many-to-many relations: you always declare the join table, as `postsToCategories` shows. Prisma ORM works the same way. `contract infer` gives you the join table as an explicit model with a composite primary key, and a list field on both sides that points at the join model:

```prisma title="src/prisma/contract.prisma"
model Post {
  postsToCategories PostToCategory[]
}

model Category {
  postsToCategories PostToCategory[]
}

model PostToCategory {
  postId     Int      @map("post_id")
  categoryId Int      @map("category_id")
  category   Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
  post       Post     @relation(fields: [postId], references: [id], onDelete: Cascade)

  @@id([postId, categoryId])
  @@map("posts_to_categories")
}
```

The implicit form from Prisma ORM 7, list fields on both sides with no join model, is not supported: the contract compiler rejects it and asks for an explicit join model. If you are coming from Prisma ORM 7 and expected a hidden `_CategoryToPost` table, there is none; the join table you already have is the model.

What you can do is add direct list fields on both sides next to the join model, as step 3.3 did. The contract records the relation as many-to-many through the join table's columns, the storage hash does not change, and the direct fields unlock three query shapes:

```typescript
// Categories nested directly under each post, without the join records
const posts = await db.orm.public.Post
  .select("id", "title")
  .include("categories")
  .all();

// Posts that carry a given category
const tagged = await db.orm.public.Post
  .where((p) => p.categories.some((c) => c.name.eq("databases")))
  .select("id", "title")
  .all();

// Link and unlink without touching the join model by hand
await db.orm.public.Post.where({ id: postId }).update({
  categories: (c) => c.disconnect([{ id: 2 }]),
});
await db.orm.public.Post.where({ id: postId }).update({
  categories: (c) => c.connect([{ id: 2 }]),
});
```

```js no-copy
[
  { id: 1, title: 'Hello Drizzle', categories: [ { id: 1, name: 'databases' }, { id: 2, name: 'typescript' } ] },
  { id: 2, title: 'Typed queries', categories: [ { id: 2, name: 'typescript' } ] }
]
[ { id: 1, title: 'Hello Drizzle' } ]
```

`disconnect` removes only the join row; the `Category` record stays. The join model remains available for anything that needs the pair itself, for example `db.orm.public.PostToCategory.create({ postId, categoryId })`, and for a flat one-row-per-pair result you can [join through it with the SQL builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#join-tables-with-precise-control). See [Relational data modeling](https://www.prisma.io/docs/orm/data-modeling/relational-databases#many-to-many) for the modeling rules and [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins#many-to-many) for the query side.

## Common gotchas [#common-gotchas]

> [!WARNING]
> If you edit the contract after signing, `db verify` fails with `CONTRACT.MARKER_MISMATCH` (`Contract storageHash does not match database marker`). When the database still matches the new contract, as with a type change from `Timestamptz` to `TimestamptzString`, run `contract emit` and then `db sign` again; the signature moves from the old hash to the new one. When the change needs new columns or tables, use `db update` or `migration plan` instead of re-signing.

* Inferred `Timestamptz` fields fail at query time with `RUNTIME.TEMPORAL_UNAVAILABLE` on Node.js. Change them to `TimestamptzString` before you emit, as in step 3.2.
* `.count()` is only valid inside an `.include(...)` callback. To count rows, use `.aggregate((a) => ({ total: a.count() }))`.
* In a long-running server, do not call `db.close()` in route handlers; the connection pool is shared across requests. Close it only on process shutdown, and never in a Next.js route.
* Bare `.update()` and `.delete()` need a `.where(...)` and touch one row. Use `.updateAll(...)` and `.deleteAll()` for many rows.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, migrate `src/app/api/categories/route.ts` from Drizzle to `db.orm.public.Category` and run it with curl."
* "Rename the inferred models in `src/prisma/contract.prisma` to singular names and keep every `@@map`, then emit and verify."
* "Add a `GET /api/categories/[id]/posts` route that uses the `posts` list field on `Category`."

## Next steps [#next-steps]

* [Learn the fundamentals](https://www.prisma.io/docs/orm/fundamentals/reading-data): filtering, sorting, pagination, and writes.
* [Evolve the schema with migrations](https://www.prisma.io/docs/orm/migrations/how-migrations-work) now that Prisma ORM owns it.
* [Read the Prisma ORM overview](https://www.prisma.io/docs/orm) for the concepts behind contracts and typed queries.

## Related pages

- [`Mongoose`](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-mongoose): Migrate an existing Mongoose app to Prisma ORM step by step, against the same MongoDB database, without moving any data.
- [`SQL ORMs`](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-sql-orms): Learn how to migrate from Sequelize or TypeORM to Prisma ORM

# Mongoose (/docs/guides/switch-to-prisma-orm/from-mongoose)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Migrate an existing Mongoose app to Prisma ORM step by step, against the same MongoDB database, without moving any data.

Location: Guides > Switch to Prisma ORM > Mongoose

## Introduction [#introduction]

This guide shows you how to migrate an application from Mongoose to Prisma ORM. The migration is gradual and runs against the database you already have: you add Prisma ORM next to Mongoose, describe the collections Mongoose manages in a contract, replace queries route by route, and remove Mongoose when nothing calls it anymore. Your data never moves.

The examples use a small Express API with three Mongoose models (`User`, `Category`, `Post`) and four routes. Every command, code block, and response below was run end to end against a local MongoDB replica set.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported but has no MongoDB connector; the Prisma ORM 7 version of this guide, which uses Prisma ORM 6.19 for MongoDB, is at [/guides/v7/switch-to-prisma-orm/from-mongoose](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-mongoose).

## Prerequisites [#prerequisites]

* A Mongoose project you want to migrate (this guide uses TypeScript and Express)
* [Node.js](https://nodejs.org) 24 or later
* A MongoDB replica set. MongoDB Atlas is one already; locally, start `mongod` with `--replSet rs0` and run `rs.initiate()` once
* Basic familiarity with Mongoose

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Migrate this Mongoose app to Prisma ORM against the same MongoDB database, following https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-mongoose.md.

1. Run `npx prisma@latest orm init --target mongodb` in the project root, choose PSL, then run `npx prisma@latest init` so the Prisma agent skills are installed, and use them. Make sure `.env` has DATABASE_URL pointing at the database the Mongoose app already uses.
2. `contract infer` does not support MongoDB. Write `src/prisma/contract.prisma` by hand from the Mongoose schemas: one model per collection with `id ObjectId @id @map("_id")` and `@@map("<collection>")`, a `type` block per nested schema, `ObjectId` plus `@relation` for each `ref`, and `ObjectId[]` for arrays of refs. Then run `npx prisma contract emit`.
3. Replace the Mongoose queries route by route with `db.orm.<collection>` calls and `.include(...)` for `populate` on single references. For `populate` on arrays of references, use the pipeline builder with `.lookup(...)`. Run the app and verify every route with curl before and after.
4. When no code imports mongoose: run `npm uninstall mongoose && npm install mongodb`, remove the `__v` field from all documents, preview the validators with `npx prisma db update --dry-run`, apply the previewed collMod statements, then run `npx prisma db sign` and `npx prisma db verify`.
```

## 1. Prepare for migration [#1-prepare-for-migration]

### 1.1. Understand the migration process [#11-understand-the-migration-process]

The steps for migrating from Mongoose to Prisma ORM are the same for any application, whether it is a REST API with Express, a GraphQL server, or a background worker:

1. Add Prisma ORM to the project with `orm init`
2. Describe the collections Mongoose manages in a contract and emit it
3. Replace Mongoose queries with Prisma ORM queries, one route at a time
4. Remove Mongoose and let Prisma ORM own the schema

Prisma ORM does not generate a client. There is no `prisma generate` step and no `schema.prisma`: `contract emit` writes the contract to `contract.json` and `contract.d.ts`, and your app reads those two files.

### 1.2. The example app [#12-the-example-app]

The app has three Mongoose models. `User` has a nested `profile`, `Post` references a `User` and an array of `Category` documents:

```typescript title="src/models/user.ts"
import { Schema, model } from "mongoose";

const userSchema = new Schema({
  email: { type: String, required: true, unique: true },
  name: { type: String, required: true },
  profile: { bio: String },
});

export const User = model("User", userSchema);
```

```typescript title="src/models/post.ts"
import { Schema, model } from "mongoose";

const postSchema = new Schema({
  title: { type: String, required: true },
  content: { type: String, required: true },
  published: { type: Boolean, default: false },
  author: { type: Schema.Types.ObjectId, ref: "User", required: true },
  categories: [{ type: Schema.Types.ObjectId, ref: "Category" }],
});

export const Post = model("Post", postSchema);
```

The Express server exposes `GET /users`, `GET /users/:id`, `POST /users`, and `GET /posts`, which populates `author` and `categories`:

```typescript title="src/server.ts"
import express from "express";
import mongoose from "mongoose";
import { User } from "./models/user";
import { Post } from "./models/post";
import "./models/category";

await mongoose.connect(process.env.DATABASE_URL!);

const app = express();
app.use(express.json());

app.get("/users", async (_req, res) => {
  const users = await User.find().sort({ name: 1 });
  res.json(users);
});

app.get("/users/:id", async (req, res) => {
  const user = await User.findById(req.params.id);
  if (!user) return res.status(404).json({ error: "Not found" });
  res.json(user);
});

app.post("/users", async (req, res) => {
  const user = await User.create({ email: req.body.email, name: req.body.name });
  res.status(201).json(user);
});

app.get("/posts", async (_req, res) => {
  const posts = await Post.find({ published: true }).populate("author").populate("categories");
  res.json(posts);
});

const port = Number(process.env.PORT ?? 3000);
app.listen(port, () => console.log(`Listening on http://localhost:${port}`));
```

The database is seeded with two users, two categories, and three posts. With the Mongoose server running, `GET /users` returns:

```json no-copy
[{"profile":{"bio":"Writes about databases"},"_id":"6aa2cd2ed97f8d7357dc9bd1","email":"alice@prisma.io","name":"Alice","__v":0},{"_id":"6aa2cd2ed97f8d7357dc9bd2","email":"bob@prisma.io","name":"Bob","__v":0}]
```

Keep this response to compare against later, because the Prisma ORM version of the route returns the same documents.

### 1.3. Add Prisma ORM to the project [#13-add-prisma-orm-to-the-project]

Run `orm init` in the project root. It adds Prisma ORM to the existing app; it does not scaffold a new one:

  

#### bun

```bash
bunx prisma@latest orm init --target mongodb
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --target mongodb
```

#### yarn

```bash
yarn dlx prisma@latest orm init --target mongodb
```

#### npm

```bash
npx prisma@latest orm init --target mongodb
```

Choose `PSL` when asked for the contract authoring style and keep the default schema path. The command installs the packages, writes the Prisma ORM files, and emits a starter contract:

```text no-copy
✔ npm add @prisma/orm-mongo dotenv
✔ npm add -D prisma@latest
✔ npm add -D @prisma/cli-engine@0.6.1
✔ Emit the contract
│  target:     mongodb
│  authoring:  psl
│  schema:     src/prisma/contract.prisma
written
├─ src/prisma/contract.prisma
├─ prisma.config.ts
├─ src/prisma/db.ts
├─ prisma-8.md
├─ .env.example
├─ tsconfig.json
├─ .gitignore
├─ .gitattributes
└─ package.json
installed
├─ @prisma/orm-mongo
├─ dotenv
├─ prisma@latest (dev)
└─ @prisma/cli-engine@0.6.1 (dev)
✔ Done. Open prisma-8.md to get started.
```

`@prisma/orm-mongo` is the library your app imports to query MongoDB. It uses the `mongodb` driver, the same one Mongoose already depends on, so you do not need a second database driver.

`orm init` also changes the `module` settings in `tsconfig.json`, and adds `"type": "module"` to `package.json` when the file has no `"type"` field. If your app is CommonJS, follow [In a CommonJS project](https://www.prisma.io/docs/cli/orm-init#in-a-commonjs-project) before you start the server again.

Install the [Prisma agent skills](https://www.prisma.io/docs/cli/skills) for your coding agent with [`init`](https://www.prisma.io/docs/cli/init), which also adds a `postinstall` hook that resyncs them on every install:

  

#### bun

```bash
bunx --bun prisma@latest init
```

#### pnpm

```bash
pnpm dlx prisma@latest init
```

#### yarn

```bash
yarn dlx prisma@latest init
```

#### npm

```bash
npx prisma@latest init
```

If a later CLI command reports that the skills are out of date, run `npx prisma skills sync`.

### 1.4. Configure the connection [#14-configure-the-connection]

`orm init` wrote a `prisma.config.ts` that loads `.env` and points at the contract:

```typescript title="prisma.config.ts"
import 'dotenv/config';
import { definePrismaConfig } from '@prisma/cli-engine';
import { defineConfig as ormConfig } from '@prisma/orm-mongo/config';

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./src/prisma/contract.prisma",
    db: {
      connection: process.env['DATABASE_URL']!,
    },
  }),
});
```

It also wrote `src/prisma/db.ts`, the client the rest of the app imports. There is no adapter and no engine; the factory takes the emitted contract and the connection string:

```typescript title="src/prisma/db.ts"
import 'dotenv/config';
import mongo from '@prisma/orm-mongo/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = mongo<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});
```

Both read `DATABASE_URL`, so point it at the database your Mongoose app already uses. `orm init` writes an `.env.example` but never touches an existing `.env`:

```bash title=".env"
DATABASE_URL="mongodb://localhost:27017/blog?replicaSet=rs0&directConnection=true"
```

## 2. Describe your collections in a contract [#2-describe-your-collections-in-a-contract]

### 2.1. Write the contract by hand [#21-write-the-contract-by-hand]

On PostgreSQL, `contract infer` reads the live schema and writes a starter contract. MongoDB has no schema to read, so the command stops:

  

#### bun

```bash
bunx prisma contract infer --output ./src/prisma/contract.prisma
```

#### pnpm

```bash
pnpm prisma contract infer --output ./src/prisma/contract.prisma
```

#### yarn

```bash
yarn prisma contract infer --output ./src/prisma/contract.prisma
```

#### npm

```bash
npx prisma contract infer --output ./src/prisma/contract.prisma
```

```text no-copy
✘ [CONTRACT.INFER_UNSUPPORTED] contract infer is not supported for this family
  why: The configured family does not implement the PslContractInferCapable capability, so an inferred PSL contract cannot be produced from the live database schema.
```

Your Mongoose schemas are the source of truth instead. Translate them with these rules:

| Mongoose                                  | Prisma ORM contract                                                                                   |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `model("User", schema)` stores in `users` | `model User { ... @@map("users") }`                                                                   |
| `_id` (implicit)                          | `id ObjectId @id @map("_id")`                                                                         |
| `{ type: String, required: true }`        | `name String`                                                                                         |
| `{ type: String }`                        | `name String?`                                                                                        |
| `{ type: String, unique: true }`          | `email String @unique`                                                                                |
| nested schema `profile: { bio: String }`  | `type Profile { bio String? }` and `profile Profile?`                                                 |
| `{ type: ObjectId, ref: "User" }`         | `authorId ObjectId @map("author")` plus `author User @relation(fields: [authorId], references: [id])` |
| `[{ type: ObjectId, ref: "Category" }]`   | `categoryIds ObjectId[] @map("categories")`                                                           |

Mongoose stores a model named `User` in the `users` collection, so every model needs `@@map` with the pluralized, lowercased collection name. Replace the starter contract with the models from the example app:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

type Profile {
  bio String?
}

model User {
  id      ObjectId @id @map("_id")
  email   String   @unique
  name    String
  profile Profile?
  posts   Post[]
  @@map("users")
}

model Category {
  id   ObjectId @id @map("_id")
  name String
  @@map("categories")
}

model Post {
  id          ObjectId   @id @map("_id")
  title       String
  content     String
  published   Bool
  author      User       @relation(fields: [authorId], references: [id])
  authorId    ObjectId   @map("author")
  categoryIds ObjectId[] @map("categories")
  @@map("posts")
}
```

Before you go on, check these differences from Mongoose:

* Prisma ORM reads and writes MongoDB fields by their stored names. `authorId @map("author")` is exposed by the query API as `author`, the key Mongoose stores, and `.include("author")` fills it with the user document the way `populate("author")` does. `db.orm.posts.where({ authorId })` is a type error.
* Mongoose adds a `__v` version key to every document. It is not in the contract and Prisma ORM passes it through on reads. You remove it in step 4, before Prisma ORM adds validators.

You do not have to model every collection on day one. Start with the ones the routes you migrate first touch.

### 2.2. Emit the contract [#22-emit-the-contract]

Turn the contract into the artifacts the runtime and the CLI read:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

```text no-copy
✔ Resolving contract source...
✔ Emitting contract...
│  contract:  src/prisma/contract.json
│  types:     src/prisma/contract.d.ts

✔ Emitted contract.json and contract.d.ts
```

Run this again whenever you edit `contract.prisma`. Nothing else needs regenerating.

## 3. Replace Mongoose queries with Prisma ORM [#3-replace-mongoose-queries-with-prisma-orm]

### 3.1. Query equivalents [#31-query-equivalents]

Prisma ORM addresses collections by their storage name (`db.orm.users`, not `db.orm.User`) and chains a filter before every read or write except `create`:

  

#### Mongoose

```typescript
// Find many, sorted
const users = await User.find().sort({ name: 1 });

// Find one by id
const user = await User.findById(id);

// Find one by field
const alice = await User.findOne({ email: "alice@prisma.io" });

// Create
const user = await User.create({ email: "alice@prisma.io", name: "Alice" });

// Update one
await User.findByIdAndUpdate(id, { name: "New name" });

// Delete one
await User.findByIdAndDelete(id);

// Populate a single reference
const posts = await Post.find({ published: true }).populate("author");
```

#### Prisma ORM

```typescript
// Find many, sorted (1 ascending, -1 descending)
const users = await db.orm.users.orderBy({ name: 1 }).all();

// Find one by id
const user = await db.orm.users.where({ _id: id }).first();

// Find one by field
const alice = await db.orm.users.where({ email: "alice@prisma.io" }).first();

// Create; returns the inserted document with its _id
const user = await db.orm.users.create({ email: "alice@prisma.io", name: "Alice", profile: null });

// Update one; returns the updated document
await db.orm.users.where({ _id: id }).update({ name: "New name" });

// Delete one
await db.orm.users.where({ _id: id }).delete();

// Populate a single reference
const posts = await db.orm.posts.where({ published: true }).include("author").all();
```

`.where(...)` takes a plain object matched by equality. `.update(...)` and `.delete()` act on one document; use `.updateAll(...)` and `.deleteAll()` for many. Optional fields such as `profile` are required in the `create` input, so pass `null` when there is no value. For filters the object form does not cover, and for anything Mongoose did with `aggregate`, use the [pipeline builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#mongodb-pipeline-builder).

### 3.2. Populate an array of references [#32-populate-an-array-of-references]

`.include(...)` covers a single reference, but `populate("categories")` on an array of ids has no `.include` equivalent yet, so express it as a pipeline: `.lookup(...)` is a typed `$lookup`, and MongoDB matches an array on the local side against `_id` on the foreign side. Adding `.unwind("author")` after a lookup on a single reference turns the one-element array `$lookup` produces into the object Mongoose returns:

```typescript
const runtime = await db.runtime();
const plan = db.query
  .from("posts")
  .match((f) => f.published.eq(true))
  .lookup((from) =>
    from("users")
      .on((post, user) => ({ local: post.author, foreign: user._id }))
      .as("author"),
  )
  .unwind("author")
  .lookup((from) =>
    from("categories")
      .on((post, category) => ({ local: post.categories, foreign: category._id }))
      .as("categories"),
  )
  .build();
const posts = await runtime.query(plan);
```

Run read plans with `runtime.query(plan)`, because `runtime.execute(plan)` is for write plans and rejects an `aggregate` command.

### 3.3. Update the routes [#33-update-the-routes]

Replace the Mongoose imports and the `mongoose.connect` call with the `db` client, then rewrite each handler. The finished server:

```typescript title="src/server.ts"
import express from "express";
import { db } from "./prisma/db";

const app = express();
app.use(express.json());

app.get("/users", async (_req, res) => {
  const users = await db.orm.users.orderBy({ name: 1 }).all();
  res.json(users);
});

app.get("/users/:id", async (req, res) => {
  const user = await db.orm.users.where({ _id: req.params.id }).first();
  if (!user) return res.status(404).json({ error: "Not found" });
  res.json(user);
});

app.post("/users", async (req, res) => {
  const user = await db.orm.users.create({
    email: req.body.email,
    name: req.body.name,
    profile: req.body.bio ? { bio: req.body.bio } : null,
  });
  res.status(201).json(user);
});

app.get("/posts", async (_req, res) => {
  const runtime = await db.runtime();
  const plan = db.query
    .from("posts")
    .match((f) => f.published.eq(true))
    .lookup((from) =>
      from("users")
        .on((post, user) => ({ local: post.author, foreign: user._id }))
        .as("author"),
    )
    .unwind("author")
    .lookup((from) =>
      from("categories")
        .on((post, category) => ({ local: post.categories, foreign: category._id }))
        .as("categories"),
    )
    .build();
  const posts = await runtime.query(plan);
  res.json(posts);
});

const port = Number(process.env.PORT ?? 3000);
app.listen(port, () => console.log(`Listening on http://localhost:${port}`));
```

There is no connect call: the client connects on the first query. Do not call `db.close()` in a handler; the connection pool is shared across requests and closes with the process.

Start the server and check the routes:

```bash
curl http://localhost:3000/users
```

```json no-copy
[{"profile":{"bio":"Writes about databases"},"__v":0,"_id":"6aa2cd2ed97f8d7357dc9bd1","email":"alice@prisma.io","name":"Alice"},{"__v":0,"_id":"6aa2cd2ed97f8d7357dc9bd2","email":"bob@prisma.io","name":"Bob"}]
```

The same documents Mongoose returned, `__v` included, because both read the same collection.

```bash
curl http://localhost:3000/posts
```

```json no-copy
[{"_id":"6aa2cd2ed97f8d7357dc9bd5","title":"Hello MongoDB","content":"First post","published":true,"author":{"_id":"6aa2cd2ed97f8d7357dc9bd1","email":"alice@prisma.io","name":"Alice","profile":{"bio":"Writes about databases"},"__v":0},"categories":[{"_id":"6aa2cd2ed97f8d7357dc9bd3","name":"Databases","__v":0}],"__v":0},{"_id":"6aa2cd2ed97f8d7357dc9bd7","title":"Bob's post","content":"Hi","published":true,"author":{"_id":"6aa2cd2ed97f8d7357dc9bd2","email":"bob@prisma.io","name":"Bob","__v":0},"categories":[],"__v":0}]
```

```bash
curl -X POST http://localhost:3000/users \
  -H "content-type: application/json" \
  -d '{"email":"carol@prisma.io","name":"Carol"}'
```

```json no-copy
{"_id":"6aa2d3fcc0a1a4429529ba2c","email":"carol@prisma.io","name":"Carol","profile":null}
```

`.create(...)` returns the inserted document with its server-assigned `_id`, so the handler needs no second query.

### 3.4. Run both side by side [#34-run-both-side-by-side]

You do not have to migrate every route in one go. Mongoose and Prisma ORM can read and write the same collections while you work through the app: Prisma ORM reads Mongoose documents as shown above, and Mongoose reads documents Prisma ORM created. After the `POST /users` call above, the untouched Mongoose `GET /users` route returns Carol too, without a `__v` key:

```json no-copy
[{"profile":{"bio":"Writes about databases"},"_id":"6aa2cd2ed97f8d7357dc9bd1","email":"alice@prisma.io","name":"Alice","__v":0},{"_id":"6aa2cd2ed97f8d7357dc9bd2","email":"bob@prisma.io","name":"Bob","__v":0},{"profile":null,"_id":"6aa2d3fcc0a1a4429529ba2c","email":"carol@prisma.io","name":"Carol"}]
```

Hold off on `db update`, `db sign`, and migrations until step 4. They add strict validators to the collections, and Mongoose writes stop passing them.

## 4. Finish the migration [#4-finish-the-migration]

### 4.1. Remove Mongoose [#41-remove-mongoose]

When no module imports `mongoose`, remove it and keep the driver Prisma ORM needs. `mongodb` was a transitive dependency of Mongoose; make it a direct one:

  

#### bun

```bash
bun remove mongoose
bun add mongodb
```

#### pnpm

```bash
pnpm remove mongoose
pnpm add mongodb
```

#### yarn

```bash
yarn remove mongoose
yarn add mongodb
```

#### npm

```bash
npm uninstall mongoose
npm install mongodb
```

Delete the `models/` directory and any `mongoose.connect` call that is left.

### 4.2. Remove the version key [#42-remove-the-version-key]

Mongoose wrote `__v` on every document. The validators Prisma ORM adds in the next step reject fields the contract does not declare, so strip it first. In `mongosh`, against your database:

```javascript
for (const c of ["users", "posts", "categories"]) {
  const r = db[c].updateMany({}, { $unset: { __v: "" } });
  print(c, r.modifiedCount);
}
```

```text no-copy
users 2
posts 3
categories 2
```

If you cannot do this yet, add `v Int? @map("__v")` to every model instead and drop it later. The field must be optional, because documents Prisma ORM creates have no `__v` key.

### 4.3. Let Prisma ORM own the schema [#43-let-prisma-orm-own-the-schema]

Prisma ORM tracks a database by a signature and, on MongoDB, by a `$jsonSchema` validator per collection. Preview what it wants to apply:

  

#### bun

```bash
bunx prisma db update --dry-run
```

#### pnpm

```bash
pnpm prisma db update --dry-run
```

#### yarn

```bash
yarn prisma db update --dry-run
```

#### npm

```bash
npx prisma db update --dry-run
```

```text no-copy
✔ Planned 3 operation(s) across 1 contract space

App space
├─ ⚠ Add validator on categories
├─ ⚠ Add validator on posts
└─ ⚠ Add validator on users

⚠ This migration contains destructive operations that may cause data loss.

ℹ Operation preview

db.runCommand({ collMod: "categories", validator: {"$jsonSchema":{"additionalProperties":false,"bsonType":"object","properties":{"_id":{"bsonType":"objectId"},"name":{"bsonType":"string"}},"required":["_id","name"]}}, validationLevel: "strict", validationAction: "error" })
db.runCommand({ collMod: "posts", validator: {"$jsonSchema":{"additionalProperties":false,"bsonType":"object","properties":{"_id":{"bsonType":"objectId"},"author":{"bsonType":"objectId"},"categories":{"bsonType":"array","items":{"bsonType":"objectId"}},"content":{"bsonType":"string"},"published":{"bsonType":"bool"},"title":{"bsonType":"string"}},"required":["_id","author","categories","content","published","title"]}}, validationLevel: "strict", validationAction: "error" })
db.runCommand({ collMod: "users", validator: {"$jsonSchema":{"additionalProperties":false,"bsonType":"object","properties":{"_id":{"bsonType":"objectId"},"email":{"bsonType":"string"},"name":{"bsonType":"string"},"profile":{"oneOf":[{"bsonType":"null"},{"additionalProperties":false,"bsonType":"object","properties":{"bio":{"bsonType":["null","string"]}}}]}},"required":["_id","email","name"]}}, validationLevel: "strict", validationAction: "error" })

ℹ This is a dry run. No changes were applied.
```

Adding a validator to a populated collection counts as destructive, so `db update` asks you to type the database name before applying it. On MongoDB it currently cannot resolve that name and stops with `CLI.CONSENT_TOKEN_UNRESOLVED`. Apply the three previewed `collMod` commands yourself: paste them into `mongosh` against your database. Each returns `{ ok: 1 }`.

Then record that the database matches the contract, and verify it:

  

#### bun

```bash
bunx prisma db sign
bunx prisma db verify
```

#### pnpm

```bash
pnpm prisma db sign
pnpm prisma db verify
```

#### yarn

```bash
yarn prisma db sign
yarn prisma db verify
```

#### npm

```bash
npx prisma db sign
npx prisma db verify
```

```text no-copy
✔ Database signed

from:  none
to:    7a7760fc1ac91a781b0f6509b8c495fa3f6ae2be1ba2815bceccbf75286b93c6
```

```text no-copy
✔ Database marker and schema match contract
```

From here on, schema changes go through the contract: edit `contract.prisma`, run `contract emit`, then `db update` for a direct development update or [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) followed by `db migrate` for a checked-in migration.

The validators are strict: a write that includes a field the contract does not declare now fails, which is what a leftover Mongoose model produces:

```text no-copy
Document failed validation
{ operatorName: 'additionalProperties', specifiedAs: { additionalProperties: false }, additionalProperties: [ '__v' ] }
```

## Common gotchas [#common-gotchas]

> [!WARNING]
> Field names are storage names
> 
> The query API uses the field names stored in MongoDB, not the names on the left of `@map`. With `authorId ObjectId @map("author")`, filter with `.where({ author: id })` and read `post.author`. TypeScript rejects the contract-side name.

> [!WARNING]
> Writing arrays of ObjectIds
> 
> Passing a whole `ObjectId[]` value, such as `categories: [id]`, to `.create(...)` or `.update({...})` fails with `Failed to encode parameter mongo/objectId@1`. Create the document without the array and add ids with a field operation: `db.orm.posts.where({ _id }).update((p) => [p.categories.push(id)])`.

> [!WARNING]
> ObjectId filters in the pipeline builder
> 
> `.match((f) => f._id.eq(id))` and `MongoFieldFilter.eq("_id", id)` send the id as a plain string and match nothing. Filter ObjectId fields through the ORM, `db.orm.posts.where({ _id: id })`, which encodes them for you.

> [!WARNING]
> No transactions on MongoDB yet
> 
> The MongoDB client has no `db.transaction(...)`. For multi-document atomicity, pass your own `MongoClient` to `mongo({ contractJson, mongoClient, dbName })` and use the driver's `session.withTransaction(...)`, as shown in the [transactions](https://www.prisma.io/docs/orm/fundamentals/transactions) docs.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, translate the Mongoose schemas in `src/models` into `src/prisma/contract.prisma` and emit it."
* "Replace the Mongoose queries in `src/controllers/posts.ts` with `db.orm.posts` calls; use a `.lookup` pipeline for `populate` on arrays."
* "Add `GET /users/:id/posts` that returns a user's published posts with `.where` and `.include`."

## Next steps [#next-steps]

* [Model documents, embedded types, and references](https://www.prisma.io/docs/orm/data-modeling/mongodb) for MongoDB.
* [Read data](https://www.prisma.io/docs/orm/fundamentals/reading-data) and [write data](https://www.prisma.io/docs/orm/fundamentals/writing-data) with the ORM API.
* [Aggregate with the pipeline builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#mongodb-pipeline-builder).
* [Understand migrations](https://www.prisma.io/docs/orm/migrations/how-migrations-work) now that Prisma ORM owns the schema.
* Coming from Prisma ORM 6 on MongoDB instead of Mongoose? See the [MongoDB upgrade guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb).

## Related pages

- [`Drizzle`](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-drizzle): Switch an existing Drizzle app to Prisma ORM: infer a contract from your database, sign it, and replace Drizzle queries route by route.
- [`SQL ORMs`](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-sql-orms): Learn how to migrate from Sequelize or TypeORM to Prisma ORM

# SQL ORMs (/docs/guides/switch-to-prisma-orm/from-sql-orms)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to migrate from Sequelize or TypeORM to Prisma ORM

Location: Guides > Switch to Prisma ORM > SQL ORMs

## Introduction [#introduction]

This guide shows you how to migrate an application from Sequelize or TypeORM to Prisma ORM. Your database already exists and your current ORM already shaped it, so Prisma ORM starts from the live schema: it reads the tables into a contract, records that the database matches it, and lets you replace queries one at a time while the old ORM keeps running.

The example is a small TypeORM app with users and posts. Every command and query below was run against it on a local PostgreSQL database; the Sequelize calls in the [query mapping](#6-query-mapping) table map onto the same Prisma ORM calls.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release. Prisma ORM 7 remains fully supported; the Prisma ORM 7 version of this guide is at [/guides/v7/switch-to-prisma-orm/from-sql-orms](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-sql-orms).

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) 24 or later
* A Sequelize or TypeORM project that already connects to a PostgreSQL database
* A TypeScript project. The scripts in this guide are written for an app that runs as ES modules, and steps 2 and 5 say what to change in a CommonJS app

## Use with your agent [#use-with-your-agent]

To delegate this guide to your coding agent, copy the prompt below and hand it over:

```text
Add Prisma ORM to this Sequelize or TypeORM project so I can migrate queries incrementally.

1. From the project root, run `npx prisma@latest orm init --yes --target postgres --authoring psl`, then `npx prisma@latest init` so the Prisma agent skills are installed, and use them. Before you run `orm init`, note whether package.json has "type": "module". If it does not, and the code uses `require` or compiles to `require` calls, the app is CommonJS: after `orm init`, apply the changes under "In a CommonJS project" in https://www.prisma.io/docs/cli/orm-init.md. Make sure `.env` contains the DATABASE_URL the app already uses.
2. Run `npx prisma contract infer --output ./src/prisma/contract.prisma` to read the existing tables into a contract. Open the file, change every `Timestamptz` field type to `TimestamptzString`, and keep the `@@map` attributes so model names stay clean while table names stay as they are.
3. Run `npx prisma contract emit`, then `npx prisma db sign`, then `npx prisma db verify`. Do not run `db init` or `db update`; the tables already exist.
4. Following https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-sql-orms.md, rewrite the read queries first, then the writes, importing `db` from `src/prisma/db.ts`. Run each rewritten query with `node <script>.ts` and show me the output. In a CommonJS project, import `db` from `./prisma/db` without the `.ts` extension, put the `await` calls inside an `async` function, and run the script with `npx tsx <script>.ts` instead. Leave the old ORM in place for queries you have not rewritten yet, but turn off its schema sync (`synchronize` in TypeORM, `sequelize.sync()` in Sequelize).
```

## 1. The starting point [#1-the-starting-point]

The app has two TypeORM entities. `synchronize: true` in the data source created the `user` and `post` tables in PostgreSQL, and a script inserted two users and a post through TypeORM repositories.

```typescript title="src/entities/User.ts"
@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column({ type: "varchar", unique: true })
  email!: string;

  @Column({ type: "varchar", nullable: true })
  name!: string | null;

  @Column({ type: "boolean", default: true })
  active!: boolean;

  @CreateDateColumn({ type: "timestamptz" })
  createdAt!: Date;

  @OneToMany(() => Post, (post) => post.author)
  posts!: Post[];
}
```

```typescript title="src/entities/Post.ts"
@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column({ type: "varchar" })
  title!: string;

  @Column({ type: "text", nullable: true })
  content!: string | null;

  @Column({ type: "boolean", default: false })
  published!: boolean;

  @CreateDateColumn({ type: "timestamptz" })
  createdAt!: Date;

  @ManyToOne(() => User, (user) => user.posts, { nullable: false, onDelete: "CASCADE" })
  author!: User;
}
```

The project reads its connection string from `DATABASE_URL`:

```bash title=".env"
DATABASE_URL="postgres://user:password@localhost:5432/mydb"
```

Nothing about the database changes in this guide. Prisma ORM adopts the tables as they are, TypeORM keeps working next to it, and both read and write the same rows.

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

From the project root, run:

  

#### bun

```bash
bunx prisma@latest orm init --target postgres
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --target postgres
```

#### yarn

```bash
yarn dlx prisma@latest orm init --target postgres
```

#### npm

```bash
npx prisma@latest orm init --target postgres
```

Pick `PSL` as the authoring style and keep the default contract path, `src/prisma/contract.prisma`. The command adds `@prisma/orm-postgres` and `dotenv` to your dependencies, adds `prisma` and `@prisma/cli-engine` as dev dependencies, and finishes by emitting the starter contract:

```json no-copy
"target": "postgres",
"authoring": "psl",
"schemaPath": "src/prisma/contract.prisma",
"filesWritten": ["src/prisma/contract.prisma", "prisma.config.ts", "src/prisma/db.ts", ".env.example", "tsconfig.json"],
"packagesInstalled": { "status": "installed", "deps": ["@prisma/orm-postgres", "dotenv"], "devDeps": ["prisma", "@prisma/cli-engine"] },
"contractEmitted": true
```

You will use these files during the migration:

* `prisma.config.ts` loads `.env` and points the CLI at the contract and `DATABASE_URL`. Every command below reads the connection string from there.
* `src/prisma/db.ts` creates the client your code imports.
* `src/prisma/contract.prisma` is the starter contract. The next step overwrites it with your real schema.

```typescript title="src/prisma/db.ts"
import 'dotenv/config';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});
```

There is no `prisma generate` and no driver adapter in Prisma ORM: the runtime reads `contract.json`, which `contract emit` writes, and connects with the `url` you pass. `orm init` also changes `tsconfig.json`: it sets `"module": "preserve"`, `"moduleResolution": "bundler"`, and `"resolveJsonModule": true`, and it keeps `experimentalDecorators` and `emitDecoratorMetadata` in place for TypeORM. In `package.json`, it adds `"type": "module"` if the file has no `"type"` field. If your app is CommonJS, those changes stop it from starting, so follow [In a CommonJS project](https://www.prisma.io/docs/cli/orm-init#in-a-commonjs-project) before you run the app again.

## 3. Infer the contract from your database [#3-infer-the-contract-from-your-database]

Read the live schema into the contract:

  

#### bun

```bash
bunx prisma contract infer --output ./src/prisma/contract.prisma
```

#### pnpm

```bash
pnpm prisma contract infer --output ./src/prisma/contract.prisma
```

#### yarn

```bash
yarn prisma contract infer --output ./src/prisma/contract.prisma
```

#### npm

```bash
npx prisma contract infer --output ./src/prisma/contract.prisma
```

```json no-copy
"summary": "Contract inferred successfully",
"target": { "familyId": "sql", "id": "postgres" },
"psl": { "path": "src/prisma/contract.prisma" }
```

The inferred contract mirrors what TypeORM created, down to the constraint names and the `CASCADE` on the foreign key. Model names are PascalCase; `@@map` keeps the physical table names, so no table is renamed:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model User {
  id        Int         @id(map: "PK_cace4a159ff9f2512dd42373760") @default(autoincrement())
  email     VarChar     @unique(map: "UQ_e12875dfb3b1d92d7d7c5377e22")
  name      VarChar?
  active    Boolean     @default(true)
  createdAt Timestamptz @default(now())
  posts     Post[]

  @@map("user")
}

model Post {
  id        Int         @id(map: "PK_be5fda3aac270b134ff9c21cdee") @default(autoincrement())
  title     VarChar
  content   String?
  published Boolean     @default(false)
  createdAt Timestamptz @default(now())
  authorId  Int
  author    User        @relation(fields: [authorId], references: [id], onDelete: Cascade, map: "FK_c6fb082a3114f35d0cc27c518e0", index: false)

  @@map("post")
}
```

Review the file before you go on. One edit is required for this schema: the `timestamptz` columns come back as `Timestamptz`, which reads each value as a `Temporal` value. On Node.js 24 that fails with `RUNTIME.TEMPORAL_UNAVAILABLE`, because Node.js 24 has no global `Temporal`. Change them to `TimestamptzString`, which reads and writes PostgreSQL's own text form and maps to the same column type:

```prisma title="src/prisma/contract.prisma"
model User {
  createdAt Timestamptz @default(now()) // [!code --]
  createdAt TimestamptzString @default(now()) // [!code ++]
}

model Post {
  createdAt Timestamptz @default(now()) // [!code --]
  createdAt TimestamptzString @default(now()) // [!code ++]
}
```

This is also the moment to delete from `contract.prisma` the models you do not want Prisma ORM to use yet, or to rename a model while keeping its `@@map`. The [PSL syntax](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax) page lists the attributes.

## 4. Emit and sign [#4-emit-and-sign]

Turn the reviewed contract into the artifacts the runtime and CLI use:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

```json no-copy
"files": { "json": "src/prisma/contract.json", "dts": "src/prisma/contract.d.ts" }
```

Then record that the live database matches the contract:

  

#### bun

```bash
bunx prisma db sign
```

#### pnpm

```bash
pnpm prisma db sign
```

#### yarn

```bash
yarn prisma db sign
```

#### npm

```bash
npx prisma db sign
```

```json no-copy
"summary": "Database signed (marker created)",
"target": { "expected": "postgres", "actual": "postgres" },
"marker": { "created": true, "updated": false }
```

`db sign` verifies the schema first and refuses to sign if the database does not satisfy the contract. It replaces the baseline migration from Prisma ORM 7 (`migrate diff` plus `migrate resolve`): the database is not touched, only marked. Check it at any time with:

  

#### bun

```bash
bunx prisma db verify
```

#### pnpm

```bash
pnpm prisma db verify
```

#### yarn

```bash
yarn prisma db verify
```

#### npm

```bash
npx prisma db verify
```

```json no-copy
"summary": "Database marker and schema match contract"
```

If you edit the contract again later, run `contract emit` and then `db sign` again; `db verify` reports `Hash mismatch` until you do.

## 5. Replace queries [#5-replace-queries]

Rewrite queries one at a time. The TypeORM tab shows the queries the app runs today; the Prisma ORM tab shows the same operations rewritten, in a script that runs against the rows TypeORM created (it uses new emails so both scripts can run against the same database). The sequence covers the calls most apps live on: create, a transaction, find many, find one with a relation, update, and delete.

  

#### TypeORM

```typescript  title="src/typeorm-queries.ts"
import { AppDataSource } from "./data-source.js";
import { User } from "./entities/User.js";
import { Post } from "./entities/Post.js";

await AppDataSource.initialize();
const userRepository = AppDataSource.getRepository(User);
const postRepository = AppDataSource.getRepository(Post);

// Create
const alice = userRepository.create({ email: "alice@prisma.io", name: "Alice" });
await userRepository.save(alice);

// Transaction
await AppDataSource.transaction(async (manager) => {
  const bob = manager.create(User, { email: "bob@prisma.io", name: "Bob" });
  await manager.save(bob);
  const post = manager.create(Post, { title: "Hello from TypeORM", author: bob });
  await manager.save(post);
});

// Find many
const users = await userRepository.find({
  where: { active: true },
  take: 10,
  order: { createdAt: "DESC" },
});

// Find one with relation
const bobWithPosts = await userRepository.findOne({
  where: { email: "bob@prisma.io" },
  relations: { posts: true },
});

// Update
await userRepository.update(alice.id, { name: "Alicia" });

// Delete
await userRepository.delete(alice.id);

console.log("count", await userRepository.count());
await AppDataSource.destroy();
```

#### Prisma ORM

```typescript  title="src/prisma-queries.ts"
import { db } from "./prisma/db.ts";

// Create
const carol = await db.orm.public.User.create({ email: "carol@prisma.io", name: "Carol" });
console.log("created", carol);

// Transaction
const result = await db.transaction(async (tx) => {
  const dave = await tx.orm.public.User.create({ email: "dave@prisma.io", name: "Dave" });
  const post = await tx.orm.public.Post.create({ title: "Hello from Prisma 8", authorId: dave.id });
  return { dave, post };
});
console.log("transaction", result);

// Find many
const users = await db.orm.public.User
  .where({ active: true })
  .orderBy((u) => u.createdAt.desc())
  .limit(10)
  .all();
console.log("users", users);

// Find one with relation
const bobWithPosts = await db.orm.public.User
  .where({ email: "bob@prisma.io" })
  .include("posts")
  .first();
console.log("bobWithPosts", bobWithPosts);

// Update
const updated = await db.orm.public.User.where({ id: carol.id }).update({ name: "Caroline" });
console.log("updated", updated);

// Delete
const deleted = await db.orm.public.User.where({ id: carol.id }).delete();
console.log("deleted", deleted);

const totals = await db.orm.public.User.aggregate((a) => ({ users: a.count() }));
console.log("totals", totals);
await db.close();
```

Run it with Node.js 24, which executes TypeScript directly:

```bash
node src/prisma-queries.ts
```

In a CommonJS project this command fails, because the script uses top-level `await` and imports a file by its `.ts` name. Change the script as follows: import `db` from `"./prisma/db"`, move every line below the imports into an `async function main()`, and call `main()` on the last line. Then run it with `npx tsx src/prisma-queries.ts`, or compile it with the rest of your app and run the compiled file with `node`.

```text no-copy
created { active: true, createdAt: '2026-09-10 21:57:22.667511+06', email: 'carol@prisma.io', id: 9, name: 'Carol' }
transaction {
  dave: { active: true, createdAt: '2026-09-10 21:57:22.67978+06', email: 'dave@prisma.io', id: 10, name: 'Dave' },
  post: { authorId: 10, content: null, createdAt: '2026-09-10 21:57:22.67978+06', id: 4, published: false, title: 'Hello from Prisma 8' }
}
users [
  { active: true, createdAt: '2026-09-10 21:57:22.67978+06', email: 'dave@prisma.io', id: 10, name: 'Dave' },
  { active: true, createdAt: '2026-09-10 21:57:22.667511+06', email: 'carol@prisma.io', id: 9, name: 'Carol' },
  { active: true, createdAt: '2026-09-10 21:29:00.614611+06', email: 'bob@prisma.io', id: 2, name: 'Bob' }
]
bobWithPosts {
  active: true, createdAt: '2026-09-10 21:29:00.614611+06', email: 'bob@prisma.io', id: 2, name: 'Bob',
  posts: [ { authorId: 2, content: null, createdAt: '2026-09-10 21:29:00.614611+06', id: 1, published: false, title: 'Hello from TypeORM' } ]
}
updated { active: true, createdAt: '2026-09-10 21:57:22.667511+06', email: 'carol@prisma.io', id: 9, name: 'Caroline' }
deleted { active: true, createdAt: '2026-09-10 21:57:22.667511+06', email: 'carol@prisma.io', id: 9, name: 'Caroline' }
totals { users: 2 }
```

What changed, in the order the script runs:

* On PostgreSQL you write the schema name, usually `public`, between `db.orm` and the model name: `db.orm.public.User`. You do not use a repository or a model class. There is no `save()` step; `create` inserts and returns the full row, defaults included.
* `db.transaction` gives the callback a `tx` with the same `orm` methods. Use `tx.orm` inside it; whatever the callback returns comes out of `db.transaction`.
* Filters and sorting chain: `.where({ active: true })` for equality, a lambda such as `(u) => u.createdAt.desc()` for sorting, `.limit()` for `take`, and `.all()` or `.first()` to run the query.
* `.include("posts")` replaces `relations: { posts: true }`. The row Prisma ORM returned for Bob carries the post TypeORM wrote, because both ORMs read the same table.
* `.update()` and `.delete()` act on one row and return it. For many rows use `updateAll()` and `deleteAll()`, or `updateAndCount()` and `deleteAndCount()` when you only need the number.
* A total count is an aggregate: `.aggregate((a) => ({ users: a.count() }))`.
* The script closes the pool with `db.close()` because it is a one-off process. A server keeps the client open for its lifetime.

TypeORM still reads everything Prisma ORM wrote; a `find({ relations: { posts: true } })` after the script returned Dave and his post alongside Bob. Keep TypeORM for the queries you have not rewritten yet, and remove it when the last one is gone.

## 6. Query mapping [#6-query-mapping]

Every Prisma ORM call in this table was run against the sandbox app above. The Sequelize and TypeORM columns show the call it replaces.

| Operation                        | Sequelize                                                                                        | TypeORM                                                                                    | Prisma ORM                                                                                      |
| -------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- |
| Find many                        | `User.findAll({ where: { active: true }, order: [["createdAt", "DESC"]], limit: 10 })`           | `repo.find({ where: { active: true }, order: { createdAt: "DESC" }, take: 10 })`           | `db.orm.public.User.where({ active: true }).orderBy((u) => u.createdAt.desc()).limit(10).all()` |
| Find one                         | `User.findOne({ where: { email } })`                                                             | `repo.findOne({ where: { email } })`                                                       | `db.orm.public.User.where({ email }).first()`                                                   |
| Find by primary key              | `User.findByPk(id)`                                                                              | `repo.findOneBy({ id })`                                                                   | `db.orm.public.User.first({ id })`                                                              |
| Pattern filter, selected columns | `User.findAll({ where: { email: { [Op.iLike]: "%@prisma.io" } }, attributes: ["id", "email"] })` | `repo.find({ where: { email: ILike("%@prisma.io") }, select: { id: true, email: true } })` | `db.orm.public.User.where((u) => u.email.ilike("%@prisma.io")).select("id", "email").all()`     |
| Offset pagination                | `User.findAll({ offset: 20, limit: 10 })`                                                        | `repo.find({ skip: 20, take: 10 })`                                                        | `db.orm.public.User.orderBy((u) => u.id.asc()).offset(20).limit(10).all()`                      |
| Load a relation                  | `User.findAll({ include: [Post] })`                                                              | `repo.find({ relations: { posts: true } })`                                                | `db.orm.public.User.include("posts").all()`                                                     |
| Load the parent                  | `Post.findAll({ include: [User] })`                                                              | `postRepo.find({ relations: { author: true } })`                                           | `db.orm.public.Post.include("author").all()`                                                    |
| Shape a relation                 | `include: [{ model: Post, attributes: ["id", "title"], limit: 5 }]`                              | separate query                                                                             | `.include("posts", (p) => p.select("id", "title").orderBy((x) => x.createdAt.desc()).limit(5))` |
| Count a relation                 | `Post.count({ group: ["authorId"] })`                                                            | `postRepo.countBy({ author: { id } })` per user                                            | `db.orm.public.User.include("posts", (p) => p.count()).all()`                                   |
| Count rows                       | `User.count()`                                                                                   | `repo.count()`                                                                             | `db.orm.public.User.aggregate((a) => ({ users: a.count() }))`                                   |
| Create                           | `User.create({ email, name })`                                                                   | `repo.save(repo.create({ email, name }))`                                                  | `db.orm.public.User.create({ email, name })`                                                    |
| Create many                      | `User.bulkCreate([...])`                                                                         | `repo.save([...])`                                                                         | `db.orm.public.User.createAll([...])`                                                           |
| Update one                       | `User.update({ name }, { where: { id } })`                                                       | `repo.update(id, { name })`                                                                | `db.orm.public.User.where({ id }).update({ name })`                                             |
| Update many                      | `User.update({ active: false }, { where: { email: emails } })`                                   | `repo.update({ email: In(emails) }, { active: false })`                                    | `db.orm.public.User.where((u) => u.email.in(emails)).updateAll({ active: false })`              |
| Update many, count only          | `const [count] = await User.update(...)`                                                         | `(await repo.update(...)).affected`                                                        | `db.orm.public.User.where({ active: false }).updateAndCount({ active: true })`                  |
| Delete one                       | `User.destroy({ where: { id } })`                                                                | `repo.delete(id)`                                                                          | `db.orm.public.User.where({ id }).delete()`                                                     |
| Delete many                      | `User.destroy({ where: { email: emails } })`                                                     | `repo.delete({ email: In(emails) })`                                                       | `db.orm.public.User.where((u) => u.email.in(emails)).deleteAll()`                               |
| Transaction                      | `sequelize.transaction(async (t) => { ... { transaction: t } })`                                 | `dataSource.transaction(async (manager) => { ... })`                                       | `db.transaction(async (tx) => { ... tx.orm.public.User.create(...) })`                          |

Two differences to keep in mind while you translate:

* Prisma ORM queries return plain objects, not entity instances. There is nothing to `save()` after changing a field; call `.update()` with the fields.
* A thrown error inside `db.transaction` rolls everything back, the same as both ORMs. The sandbox confirmed that a user created before a `throw` did not exist afterwards.

## Common gotchas [#common-gotchas]

> [!WARNING]
> Turn off schema synchronization in the ORM you are leaving once the database is signed: `synchronize: false` in the TypeORM data source, and no `sequelize.sync()` on startup. Prisma ORM only knows the columns in the contract, so a column the old ORM adds behind it is invisible to your Prisma ORM queries until you update the contract and run `contract emit` again. `db verify` accepts extra columns, so it will not warn you.

* `.update()` and `.delete()` change exactly one row, even when the filter matches several. Use `updateAll()` or `deleteAll()` for bulk changes; this is the opposite default from TypeORM's `repo.update(criteria, ...)`, which updates every match.
* `contract infer` writes `Timestamptz` for `timestamptz` columns. Change them to `TimestamptzString` before you emit, as in step 3, or every query that reads the column fails with `RUNTIME.TEMPORAL_UNAVAILABLE` on Node.js.
* If `package.json` declares `"type": "commonjs"`, `orm init` keeps it and prints a warning. If it has no `"type"` field, `orm init` adds `"type": "module"`. Either way, a CommonJS app needs the changes in [In a CommonJS project](https://www.prisma.io/docs/cli/orm-init#in-a-commonjs-project).
* Do not run `db init` or `db update` on the existing database. `db sign` is the step for a database that already has the tables; `db update` and `migration plan` come later, when you change the contract yourself.
* Do not call `db.close()` in a request handler. The pool is shared across requests; close it only when a script or the process ends.

## Prompt your coding agent [#prompt-your-coding-agent]

Run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init) once to install the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

* "Using the prisma-8 skill, rewrite every TypeORM read in `src/services/users.ts` as a Prisma ORM query and leave the writes on TypeORM."
* "Translate the Sequelize `include` in the posts list to a Prisma ORM `.include()` with only `id` and `title` selected."
* "Move the signup flow's two inserts into a single [`db.transaction`](https://www.prisma.io/docs/orm/fundamentals/transactions)."

## Next steps [#next-steps]

* [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data) and [writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data): the full filter, sort, pagination, and mutation surface.
* [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins): `.include()` with refinements and relation filters.
* [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work): once Prisma ORM owns the schema, change the contract and use [`db update`](https://www.prisma.io/docs/cli/db-update) in development or [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) for checked-in migrations.
* [Add Prisma ORM to an existing PostgreSQL project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql): the same `orm init`, `contract infer`, `db sign` flow without the ORM context.

## Related pages

- [`Drizzle`](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-drizzle): Switch an existing Drizzle app to Prisma ORM: infer a contract from your database, sign it, and replace Drizzle queries route by route.
- [`Mongoose`](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-mongoose): Migrate an existing Mongoose app to Prisma ORM step by step, against the same MongoDB database, without moving any data.

# Migrate from Neon (/docs/guides/switch-to-prisma-postgres/from-neon)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Move a Neon database to Prisma Postgres and reconnect your application.

Location: Guides > Switch to Prisma Postgres > Migrate from Neon

Move one Neon branch and database to Prisma Postgres with `pg_dump` and `pg_restore`, then reconnect and verify your application.

This guide works with Prisma ORM 8, Prisma ORM 7, earlier Prisma ORM versions, and standard PostgreSQL clients. Moving your database does not require changing your ORM version.

> [!WARNING]
> What this guide does not migrate
> 
> The dump copies the selected database's PostgreSQL schemas and data. It does not reproduce Neon branch history, other branches or databases, compute endpoints, project roles, integrations, or provider configuration.
> 
> The final dump is a snapshot. For a production cutover, stop or drain source writes before the final dump and keep them stopped until validation succeeds and traffic switches to Prisma Postgres.

## Prerequisites [#prerequisites]

You need:

* access to the Neon project and the branch and database you want to move
* a new, empty [Prisma Postgres database](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides)
* the [direct and pooled Prisma Postgres connection strings](https://www.prisma.io/docs/postgres/database/connecting-to-your-database)
* enough local disk space for the compressed database dump
* PostgreSQL 17 command-line tools: `pg_dump`, `pg_restore`, and `psql`

Confirm that all three tools use PostgreSQL 17:

```bash title="Terminal"
pg_dump --version
pg_restore --version
psql --version
```

Each command should report version `17.x`. PostgreSQL 17 `pg_dump` cannot dump a source server newer than version 17.

## 1. Select the Neon branch and database [#1-select-the-neon-branch-and-database]

Open the Neon project dashboard and click **Connect**. Select the branch, database, and role you want to migrate, then disable **Connection pooling** before copying the connection string.

Set the resulting direct connection URL:

```bash title="Terminal"
export SOURCE_DATABASE_URL='postgresql://ROLE:PASSWORD@EP-ENDPOINT.REGION.aws.neon.tech/DATABASE?sslmode=require'
```

The hostname must not contain `-pooler`. Neon recommends a direct connection for `pg_dump` because session settings do not persist through its transaction pooler.

Check the selected database, source version, and database size:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT current_database(), current_setting('server_version') AS server_version, pg_size_pretty(pg_database_size(current_database())) AS database_size;"
```

Confirm that the result names the database you intended to move. Stop if the source is newer than PostgreSQL 17 or if you do not have enough local disk space for the dump.

## 2. Check schemas, extensions, and policies [#2-check-schemas-extensions-and-policies]

List the non-system schemas and installed extensions in the selected Neon database:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema') AND schema_name NOT LIKE 'pg_%' ORDER BY schema_name;" \
  --command="SELECT extname FROM pg_extension ORDER BY extname;"
```

Compare the result with the [extensions supported by Prisma Postgres](https://www.prisma.io/docs/postgres/database/postgres-extensions). Stop and decide how to replace or remove an unsupported extension before continuing.

`pg_dump` does not copy PostgreSQL roles. Inspect policies that name roles so you can adapt them for the target database:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT schemaname, tablename, policyname, roles FROM pg_policies ORDER BY schemaname, tablename, policyname;"
```

If a policy depends on a Neon role that will not exist in Prisma Postgres, record its policy name. You will omit that policy during restore and recreate it for your target access model before switching the application.

## 3. Create the Prisma Postgres destination [#3-create-the-prisma-postgres-destination]

Create a new Prisma Postgres database in [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides):

1. Open your project and select the database.
2. Click **Connect to your database**.
3. Click **Generate new connection string**.
4. Copy both the **direct** and **pooled** connection strings.

Set the direct connection string for the import:

```bash title="Terminal"
export PRISMA_POSTGRES_DIRECT_URL='postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require'
```

Confirm that the target is reachable and empty:

```bash title="Terminal"
psql "$PRISMA_POSTGRES_DIRECT_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT current_database(), current_setting('server_version');" \
  --command="SELECT schemaname, tablename FROM pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema') ORDER BY schemaname, tablename;"
```

The first query should report the Prisma Postgres database and PostgreSQL 17. The second query should not list any application tables.

## 4. Stop source writes and export the final snapshot [#4-stop-source-writes-and-export-the-final-snapshot]

You can rehearse this process while the Neon database remains active, but do not use a rehearsal dump for the production cutover. Before the final dump, stop or drain every application, worker, scheduled job, integration, and administrative operation that can write to the selected Neon database. Confirm that writes have stopped, and keep the source frozen until step 8 switches traffic to Prisma Postgres.

If you cannot keep the Neon database frozen for the dump, restore, and validation window, stop here. Use a separately tested migration process that durably captures and replays every post-snapshot write. This snapshot-only process does not provide a zero-downtime cutover.

Create a private, compressed archive of all non-system schemas in the selected database. See the [PostgreSQL 17 `pg_dump` reference](https://www.postgresql.org/docs/17/app-pgdump.html) for the other options:

```bash title="Terminal"
umask 077

pg_dump \
  --format=custom \
  --verbose \
  --no-owner \
  --no-privileges \
  --dbname="$SOURCE_DATABASE_URL" \
  --file=neon-to-prisma-postgres.dump
```

`pg_dump` should finish without an error and create `neon-to-prisma-postgres.dump`. Treat this file as sensitive because it contains your application data.

Create the restore manifest and confirm that PostgreSQL can read the archive:

```bash title="Terminal"
pg_restore --list neon-to-prisma-postgres.dump > neon-restore.list
sed -n '1,20p' neon-restore.list
```

You should see an archive header followed by database objects. If `pg_dump` reports that it cannot use a pooled connection, copy the Neon connection string again with **Connection pooling** disabled. If it reports a version mismatch, make sure the PostgreSQL 17 tools appear first in your `PATH`.

If the policy check found policies that reference source-only roles, list the policy entries:

```bash title="Terminal"
grep ' POLICY ' neon-restore.list
```

In a text editor, prefix with `;` only the `POLICY` lines for the policy names you recorded. This omits the incompatible policies without omitting their tables or data. Recreate each omitted policy with target-compatible roles after the restore and before switching the application.

## 5. Restore into Prisma Postgres [#5-restore-into-prisma-postgres]

Restore the archive through the direct Prisma Postgres connection:

```bash title="Terminal"
pg_restore \
  --verbose \
  --single-transaction \
  --exit-on-error \
  --no-owner \
  --no-privileges \
  --use-list=neon-restore.list \
  --dbname="$PRISMA_POSTGRES_DIRECT_URL" \
  neon-to-prisma-postgres.dump
```

The command should finish with exit code `0`. The single transaction leaves the target unchanged if an error stops the restore. Errors about missing roles usually mean a policy still references a source-only role; errors about extensions mean the source depends on an extension that Prisma Postgres does not provide.

Refresh PostgreSQL's query-planner statistics after the restore:

```bash title="Terminal"
psql "$PRISMA_POSTGRES_DIRECT_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="ANALYZE;"
```

## 6. Verify the imported data [#6-verify-the-imported-data]

Create a reusable query that returns an exact row count for every non-system table:

```sql title="row-counts.sql"
\pset tuples_only on
\pset format unaligned

SELECT format(
  'SELECT %L || ''='' || count(*) FROM %I.%I;',
  schemaname || '.' || tablename,
  schemaname,
  tablename
)
FROM pg_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY schemaname, tablename
\gexec
```

With source writes still stopped, run the query against both databases and compare the results:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" -X --set ON_ERROR_STOP=1 --file=row-counts.sql > source-row-counts.txt
psql "$PRISMA_POSTGRES_DIRECT_URL" -X --set ON_ERROR_STOP=1 --file=row-counts.sql > target-row-counts.txt
diff -u source-row-counts.txt target-row-counts.txt
```

`diff` should print nothing and exit with code `0`. Also rerun the schema, extension, and policy queries from step 2 against `PRISMA_POSTGRES_DIRECT_URL`. Resolve every unexpected difference while source writes remain stopped. Do not send production traffic to Prisma Postgres yet.

## 7. Connect your application [#7-connect-your-application]

Choose the path that matches your application:

* [I already use Prisma ORM 8](#already-use-prisma-8)
* [I use Prisma ORM 7 or earlier](#use-prisma-7-or-earlier)
* [I do not use Prisma ORM](#do-not-use-prisma-orm)

Every path uses the two connection strings from step 3: the pooled URL for application queries and the direct URL for migrations and other CLI tools.

### Already use Prisma ORM 8 [#already-use-prisma-8]

Keep your existing contract, migrations, and application code. The dump copied the `prisma_contract` schema, so the imported database still carries the marker that ties it to your contract.

Set the pooled URL for runtime queries and the direct URL for Prisma CLI commands:

```bash title=".env"
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

If your `prisma.config.ts` sets `db.connection`, point it at `DIRECT_URL`.

Confirm that the imported database still matches your contract:

  

#### bun

```bash title="Terminal"
bunx prisma db verify --db "$DIRECT_URL"
```

#### pnpm

```bash title="Terminal"
pnpm prisma db verify --db "$DIRECT_URL"
```

#### yarn

```bash title="Terminal"
yarn prisma db verify --db "$DIRECT_URL"
```

#### npm

```bash title="Terminal"
npx prisma db verify --db "$DIRECT_URL"
```

The command exits with code `0` when the marker and schema match the contract. Exit code `4` means the database does not match. Check that the restore included the `prisma_contract` schema before you change anything else. Do not run `orm init` or `contract infer` against the new database; your existing contract already describes it.

### Use Prisma ORM 7 or earlier [#use-prisma-7-or-earlier]

Set the pooled URL for runtime queries and the direct URL for Prisma CLI commands:

```bash title=".env"
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

Prisma ORM 7 reads the CLI connection from `datasource.url` in `prisma.config.ts`. Point it at `DIRECT_URL` as shown in the [Prisma ORM 7 PostgreSQL setup](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql). Prisma ORM 6 and earlier read `url` and `directUrl` from the `datasource` block in `schema.prisma`.

If your application did not use Prisma Accelerate, run `npx prisma generate` and continue to step 8.

#### Remove Prisma Accelerate [#remove-prisma-accelerate]

If your application connected through Accelerate, remove it now. Prisma Postgres connection pooling replaces the Accelerate connection pool. It does not replace Accelerate query caching, so remove the cache calls as well.

Uninstall the extension:

  

#### bun

```bash title="Terminal"
bun remove @prisma/extension-accelerate
```

#### pnpm

```bash title="Terminal"
pnpm remove @prisma/extension-accelerate
```

#### yarn

```bash title="Terminal"
yarn remove @prisma/extension-accelerate
```

#### npm

```bash title="Terminal"
npm uninstall @prisma/extension-accelerate
```

In your Prisma Client setup, remove the `@prisma/extension-accelerate` import, `withAccelerate()`, and `accelerateUrl`. Remove `cacheStrategy` options from queries, and remove calls to `withAccelerateInfo`, `$accelerate.invalidate`, and `$accelerate.invalidateAll`.

Undo any build settings you added for Accelerate: imports from `@prisma/client/edge`, `engineType = "client"` in the generator block, and the `--no-engine`, `--accelerate`, or `--data-proxy` flags on `prisma generate`. For Prisma ORM 7, connect through the PostgreSQL driver adapter. For Prisma ORM 6 or earlier, use Prisma Client with its bundled query engine or a driver adapter your version supports.

Accelerate reached edge runtimes over HTTP. For an edge or TCP-constrained runtime, use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver). For a conventional Node.js or Bun runtime, use the Prisma Postgres pooled TCP connection.

Regenerate Prisma Client:

  

#### bun

```bash title="Terminal"
bunx prisma generate
```

#### pnpm

```bash title="Terminal"
pnpm prisma generate
```

#### yarn

```bash title="Terminal"
yarn prisma generate
```

#### npm

```bash title="Terminal"
npx prisma generate
```

Search your project for `@prisma/extension-accelerate` and `prisma://`. Neither should appear.

### Do not use Prisma ORM [#do-not-use-prisma-orm]

Keep your existing PostgreSQL client library. Point its runtime connection at the pooled URL, and use the direct URL for migrations, `pg_dump`, `pg_restore`, and other administrative tools:

```bash title=".env"
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

## 8. Verify and switch the application [#8-verify-and-switch-the-application]

Start the application with the new environment variables while production traffic remains paused, then run its existing test suite. At minimum, verify one read and one rolled-back or disposable write through the pooled connection.

Only after the database comparison and application checks succeed, route production traffic to Prisma Postgres and resume writes there. Do not re-enable writes on Neon. Keep the Neon project available in a read-only state until the application is healthy on Prisma Postgres and the rollback window has ended.

## 9. Delete the local dump files [#9-delete-the-local-dump-files]

After you have verified the application and retained any audit evidence you need, delete the local dump and row-count files:

```bash title="Terminal"
rm neon-to-prisma-postgres.dump neon-restore.list row-counts.sql source-row-counts.txt target-row-counts.txt
```

## Recommended next step: adopt Prisma ORM [#recommended-next-step-adopt-prisma-orm]

Your database migration is complete. Prisma ORM 8 is the current release, but upgrading is a separate application change. Follow the [incremental Prisma ORM 7 to 8 guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql) after the application is stable on Prisma Postgres.

If you want to complete both changes on the same day, deploy and verify the Prisma Postgres connection first. Upgrade Prisma ORM in a separate commit or deployment so failures have one clear cause.

## Other migration guides [#other-migration-guides]

* [Migrate from Supabase to Prisma Postgres](https://www.prisma.io/docs/guides/switch-to-prisma-postgres/from-supabase)
* [Migrate another PostgreSQL database to Prisma Postgres](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql)

> [!NOTE]
> Postgres, PostgreSQL, and the Slonik Logo
> 
> Postgres, PostgreSQL, and the Slonik Logo are trademarks or registered trademarks of the PostgreSQL Community Association of Canada and are used with permission.

## Related pages

- [`Migrate from Supabase`](https://www.prisma.io/docs/guides/switch-to-prisma-postgres/from-supabase): Move application data from Supabase to Prisma Postgres and reconnect your application.

# Migrate from Supabase (/docs/guides/switch-to-prisma-postgres/from-supabase)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Move application data from Supabase to Prisma Postgres and reconnect your application.

Location: Guides > Switch to Prisma Postgres > Migrate from Supabase

Move your PostgreSQL application data from Supabase to Prisma Postgres with `pg_dump` and `pg_restore`, then reconnect and verify your application.

This guide works with Prisma ORM 8, Prisma ORM 7, earlier Prisma ORM versions, and standard PostgreSQL clients. Moving your database does not require changing your ORM version.

> [!WARNING]
> What this guide does not migrate
> 
> This guide migrates PostgreSQL schemas and data you own. It does not migrate Supabase Auth users and configuration, Storage objects, Realtime configuration, Edge Functions, API settings, or other Supabase platform services. Plan replacements for any services your application uses before switching it to Prisma Postgres.
> 
> The final dump is a snapshot. For a production cutover, stop or drain source writes before the final dump and keep them stopped until validation succeeds and traffic switches to Prisma Postgres.

## Prerequisites [#prerequisites]

You need:

* your Supabase database password
* access to the Supabase project's **Connect** panel
* a new, empty [Prisma Postgres database](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides)
* the [direct and pooled Prisma Postgres connection strings](https://www.prisma.io/docs/postgres/database/connecting-to-your-database)
* enough local disk space for the compressed database dump
* PostgreSQL 17 command-line tools: `pg_dump`, `pg_restore`, and `psql`

Confirm that all three tools use PostgreSQL 17:

```bash title="Terminal"
pg_dump --version
pg_restore --version
psql --version
```

Each command should report version `17.x`. PostgreSQL 17 `pg_dump` cannot dump a source server newer than version 17.

## 1. Connect directly to Supabase [#1-connect-directly-to-supabase]

In your Supabase project, click **Connect** and copy the **Direct connection** URI. Set it as an environment variable:

```bash title="Terminal"
export SOURCE_DATABASE_URL='postgresql://postgres:PASSWORD@db.PROJECT_REF.supabase.co:5432/postgres'
```

Supabase direct connections use IPv6 unless the project has the IPv4 add-on. If your network cannot reach the direct endpoint, copy the **Session pooler** URI instead:

```bash title="Terminal"
export SOURCE_DATABASE_URL='postgresql://postgres.PROJECT_REF:PASSWORD@aws-0-REGION.pooler.supabase.com:5432/postgres'
```

Use only one of these URLs. Do not use the transaction pooler on port `6543`. `pg_dump` needs session-level settings that transaction pooling does not preserve.

Check the connection, source version, and database size:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT current_setting('server_version') AS server_version, pg_size_pretty(pg_database_size(current_database())) AS database_size;"
```

The command should print the server version and database size. Stop if the source is newer than PostgreSQL 17 or if you do not have enough local disk space for the dump.

## 2. Check schemas, extensions, and policies [#2-check-schemas-extensions-and-policies]

This guide exports the `public` schema by default. List your non-system schemas to identify any additional application schemas you created:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema') AND schema_name NOT LIKE 'pg_%' ORDER BY schema_name;" \
  --command="SELECT extname FROM pg_extension ORDER BY extname;"
```

Do not add Supabase-managed schemas such as `auth`, `storage`, `realtime`, `supabase_functions`, or `supabase_migrations` to the dump. Compare the extension list with the [extensions supported by Prisma Postgres](https://www.prisma.io/docs/postgres/database/postgres-extensions). Stop and decide how to replace or remove an unsupported extension before continuing.

Inspect row-level security policies in the schemas you plan to migrate:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT schemaname, tablename, policyname, roles FROM pg_policies WHERE schemaname = 'public' ORDER BY tablename, policyname;"
```

Add any other application schema names from the list above to the query filter. `pg_dump` does not copy PostgreSQL roles. Record the name of every policy that depends on Supabase roles such as `anon`, `authenticated`, or `service_role`. You will omit those policies during restore and recreate them for your new authorization design before switching the application.

## 3. Create the Prisma Postgres destination [#3-create-the-prisma-postgres-destination]

Create a new Prisma Postgres database in [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides):

1. Open your project and select the database.
2. Click **Connect to your database**.
3. Click **Generate new connection string**.
4. Copy both the **direct** and **pooled** connection strings.

Set the direct connection string for the import:

```bash title="Terminal"
export PRISMA_POSTGRES_DIRECT_URL='postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require'
```

Confirm that the target is reachable and empty:

```bash title="Terminal"
psql "$PRISMA_POSTGRES_DIRECT_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="SELECT current_database(), current_setting('server_version');" \
  --command="SELECT schemaname, tablename FROM pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema') ORDER BY schemaname, tablename;"
```

The first query should report the Prisma Postgres database and PostgreSQL 17. The second query should not list any application tables.

## 4. Stop source writes and export the final snapshot [#4-stop-source-writes-and-export-the-final-snapshot]

You can rehearse this process while the Supabase database remains active, but do not use a rehearsal dump for the production cutover. Before the final dump, stop or drain every application, worker, scheduled job, integration, and administrative operation that can write to the Supabase database. Confirm that writes have stopped, and keep the source frozen until step 8 switches traffic to Prisma Postgres.

If you cannot keep the Supabase database frozen for the dump, restore, and validation window, stop here. Use a separately tested migration process that durably captures and replays every post-snapshot write. This snapshot-only process does not provide a zero-downtime cutover.

Create a private, compressed archive of the `public` schema. See the [PostgreSQL 17 `pg_dump` reference](https://www.postgresql.org/docs/17/app-pgdump.html) for the other options:

```bash title="Terminal"
umask 077

pg_dump \
  --format=custom \
  --verbose \
  --no-owner \
  --no-privileges \
  --schema=public \
  --dbname="$SOURCE_DATABASE_URL" \
  --file=supabase-to-prisma-postgres.dump
```

If you identified another application-owned schema in step 2, add another `--schema=SCHEMA_NAME` option. Do not add Supabase-managed schemas.

If the application already uses Prisma ORM, also add `--schema=prisma_contract`. This copies the database marker that connects the imported schema to your existing Prisma ORM contract.

Schema-filtered dumps do not automatically include extensions. For every supported extension from step 2 except `plpgsql`, add an `--extension=EXTENSION_NAME` option. For example, add `--extension=pgcrypto` if the application uses `pgcrypto`.

`pg_dump` should finish without an error and create `supabase-to-prisma-postgres.dump`. Treat this file as sensitive because it contains your application data.

Confirm that PostgreSQL can read the archive:

```bash title="Terminal"
pg_restore --list supabase-to-prisma-postgres.dump | sed -n '1,20p'
```

You should see an archive header followed by database objects. If `pg_dump` reports a version mismatch, make sure the PostgreSQL 17 tools appear first in your `PATH`.

## 5. Restore into Prisma Postgres [#5-restore-into-prisma-postgres]

Prisma Postgres already contains an empty `public` schema. Create a restore manifest that keeps that schema and restores its contents:

```bash title="Terminal"
pg_restore --list supabase-to-prisma-postgres.dump \
  | sed -E '/SCHEMA - public |COMMENT - SCHEMA public /s/^/;/' \
  > supabase-restore.list
```

The `SCHEMA - public` and `COMMENT - SCHEMA public` lines in `supabase-restore.list` should begin with `;`.

If the policy check found policies that reference Supabase-only roles, list the policy entries:

```bash title="Terminal"
grep ' POLICY ' supabase-restore.list
```

In a text editor, prefix with `;` only the `POLICY` lines for the policy names you recorded. This omits the incompatible policies without omitting their tables or data. Recreate each omitted policy with target-compatible roles after the restore and before switching the application.

Restore the remaining archive entries through the direct Prisma Postgres connection:

```bash title="Terminal"
pg_restore \
  --verbose \
  --single-transaction \
  --exit-on-error \
  --no-owner \
  --no-privileges \
  --use-list=supabase-restore.list \
  --dbname="$PRISMA_POSTGRES_DIRECT_URL" \
  supabase-to-prisma-postgres.dump
```

The command should finish with exit code `0`. The single transaction leaves the target unchanged if an error stops the restore. Errors about missing roles usually mean a row-level security policy still references a Supabase-only role; errors about extensions mean the source depends on an extension that Prisma Postgres does not provide.

Refresh PostgreSQL's query-planner statistics after the restore:

```bash title="Terminal"
psql "$PRISMA_POSTGRES_DIRECT_URL" \
  -X \
  --set ON_ERROR_STOP=1 \
  --command="ANALYZE;"
```

## 6. Verify the imported data [#6-verify-the-imported-data]

Create a reusable query that returns exact row counts for the migrated schemas:

```sql title="row-counts.sql"
\pset tuples_only on
\pset format unaligned

SELECT format(
  'SELECT %L || ''='' || count(*) FROM %I.%I;',
  schemaname || '.' || tablename,
  schemaname,
  tablename
)
FROM pg_tables
WHERE schemaname IN ('public', 'prisma_contract')
ORDER BY schemaname, tablename
\gexec
```

Add any other application schema names from step 2 to the `IN` list. With source writes still stopped, run the query against both databases and compare the results:

```bash title="Terminal"
psql "$SOURCE_DATABASE_URL" -X --set ON_ERROR_STOP=1 --file=row-counts.sql > source-row-counts.txt
psql "$PRISMA_POSTGRES_DIRECT_URL" -X --set ON_ERROR_STOP=1 --file=row-counts.sql > target-row-counts.txt
diff -u source-row-counts.txt target-row-counts.txt
```

`diff` should print nothing and exit with code `0`. Also rerun the extension and policy queries from step 2 against `PRISMA_POSTGRES_DIRECT_URL`. Resolve every unexpected difference while source writes remain stopped. Do not send production traffic to Prisma Postgres yet.

## 7. Connect your application [#7-connect-your-application]

Choose the path that matches your application:

* [I already use Prisma ORM 8](#already-use-prisma-8)
* [I use Prisma ORM 7 or earlier](#use-prisma-7-or-earlier)
* [I do not use Prisma ORM](#do-not-use-prisma-orm)

Every path uses the two connection strings from step 3: the pooled URL for application queries and the direct URL for migrations and other CLI tools.

### Already use Prisma ORM 8 [#already-use-prisma-8]

Keep your existing contract, migrations, and application code. Because you added `--schema=prisma_contract` in step 4, the imported database still carries the marker that ties it to your contract.

Set the pooled URL for runtime queries and the direct URL for Prisma CLI commands:

```bash title=".env"
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

If your `prisma.config.ts` sets `db.connection`, point it at `DIRECT_URL`.

Confirm that the imported database still matches your contract:

  

#### bun

```bash title="Terminal"
bunx prisma db verify --db "$DIRECT_URL"
```

#### pnpm

```bash title="Terminal"
pnpm prisma db verify --db "$DIRECT_URL"
```

#### yarn

```bash title="Terminal"
yarn prisma db verify --db "$DIRECT_URL"
```

#### npm

```bash title="Terminal"
npx prisma db verify --db "$DIRECT_URL"
```

The command exits with code `0` when the marker and schema match the contract. Exit code `4` means the database does not match. Check that the restore included the `prisma_contract` schema before you change anything else. Do not run `orm init` or `contract infer` against the new database; your existing contract already describes it.

### Use Prisma ORM 7 or earlier [#use-prisma-7-or-earlier]

Set the pooled URL for runtime queries and the direct URL for Prisma CLI commands:

```bash title=".env"
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

Prisma ORM 7 reads the CLI connection from `datasource.url` in `prisma.config.ts`. Point it at `DIRECT_URL` as shown in the [Prisma ORM 7 PostgreSQL setup](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql). Prisma ORM 6 and earlier read `url` and `directUrl` from the `datasource` block in `schema.prisma`.

If your application did not use Prisma Accelerate, run `npx prisma generate` and continue to step 8.

#### Remove Prisma Accelerate [#remove-prisma-accelerate]

If your application connected through Accelerate, remove it now. Prisma Postgres connection pooling replaces the Accelerate connection pool. It does not replace Accelerate query caching, so remove the cache calls as well.

Uninstall the extension:

  

#### bun

```bash title="Terminal"
bun remove @prisma/extension-accelerate
```

#### pnpm

```bash title="Terminal"
pnpm remove @prisma/extension-accelerate
```

#### yarn

```bash title="Terminal"
yarn remove @prisma/extension-accelerate
```

#### npm

```bash title="Terminal"
npm uninstall @prisma/extension-accelerate
```

In your Prisma Client setup, remove the `@prisma/extension-accelerate` import, `withAccelerate()`, and `accelerateUrl`. Remove `cacheStrategy` options from queries, and remove calls to `withAccelerateInfo`, `$accelerate.invalidate`, and `$accelerate.invalidateAll`.

Undo any build settings you added for Accelerate: imports from `@prisma/client/edge`, `engineType = "client"` in the generator block, and the `--no-engine`, `--accelerate`, or `--data-proxy` flags on `prisma generate`. For Prisma ORM 7, connect through the PostgreSQL driver adapter. For Prisma ORM 6 or earlier, use Prisma Client with its bundled query engine or a driver adapter your version supports.

Accelerate reached edge runtimes over HTTP. For an edge or TCP-constrained runtime, use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver). For a conventional Node.js or Bun runtime, use the Prisma Postgres pooled TCP connection.

Regenerate Prisma Client:

  

#### bun

```bash title="Terminal"
bunx prisma generate
```

#### pnpm

```bash title="Terminal"
pnpm prisma generate
```

#### yarn

```bash title="Terminal"
yarn prisma generate
```

#### npm

```bash title="Terminal"
npx prisma generate
```

Search your project for `@prisma/extension-accelerate` and `prisma://`. Neither should appear.

### Do not use Prisma ORM [#do-not-use-prisma-orm]

Keep your existing PostgreSQL client library. Point its runtime connection at the pooled URL, and use the direct URL for migrations, `pg_dump`, `pg_restore`, and other administrative tools:

```bash title=".env"
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

## 8. Verify and switch the application [#8-verify-and-switch-the-application]

Start the application with the new environment variables while production traffic remains paused, then run its existing test suite. At minimum, verify one read and one rolled-back or disposable write through the pooled connection.

Test every feature that previously depended on Supabase Auth, Storage, Realtime, or role-based RLS against its replacement. Only after the database comparison and application checks succeed, route production traffic to Prisma Postgres and resume writes there. Do not re-enable writes on Supabase. Keep the Supabase project available in a read-only state until the application is healthy on Prisma Postgres and the rollback window has ended.

## 9. Delete the local dump files [#9-delete-the-local-dump-files]

After you have verified the application and retained any audit evidence you need, delete the local dump and row-count files:

```bash title="Terminal"
rm supabase-to-prisma-postgres.dump supabase-restore.list row-counts.sql source-row-counts.txt target-row-counts.txt
```

## Recommended next step: adopt Prisma ORM [#recommended-next-step-adopt-prisma-orm]

Your database migration is complete. Prisma ORM 8 is the current release, but upgrading is a separate application change. Follow the [incremental Prisma ORM 7 to 8 guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql) after the application is stable on Prisma Postgres.

If you want to complete both changes on the same day, deploy and verify the Prisma Postgres connection first. Upgrade Prisma ORM in a separate commit or deployment so failures have one clear cause.

## Other migration guides [#other-migration-guides]

* [Migrate from Neon to Prisma Postgres](https://www.prisma.io/docs/guides/switch-to-prisma-postgres/from-neon)
* [Migrate another PostgreSQL database to Prisma Postgres](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql)

## Related pages

- [`Migrate from Neon`](https://www.prisma.io/docs/guides/switch-to-prisma-postgres/from-neon): Move a Neon database to Prisma Postgres and reconnect your application.

# Prisma ORM 6 to 8 (MongoDB) (/docs/guides/upgrade-prisma-orm/mongodb)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Migrate a MongoDB project from Prisma ORM 6 to Prisma ORM 8

Location: Guides > Upgrade Prisma ORM > Prisma ORM 6 to 8 (MongoDB)

This guide is for developers moving a Prisma ORM 6 MongoDB project to **Prisma ORM 8**. Prisma ORM 7 has **no MongoDB connector**, so Prisma ORM 8 is the successor path. This is a **code and workflow migration against the same database**: your data never moves.

> [!NOTE]
> Using an AI coding agent
> 
> Install the companion [prisma-mongodb-upgrade](https://github.com/prisma/skills/tree/main/prisma-mongodb-upgrade) skill with `npx skills add prisma/skills` to help your agent with this migration.

## Prerequisites [#prerequisites]

* **Node.js 22.18 or newer (on the 24 line, 24.11 or newer)**; Node.js 24 recommended
* **TypeScript 5.9+**
* **MongoDB 8.0+**
* **The mongodb node driver 7.x** as a peer dependency
* **A replica set** if your app uses [transactions](https://www.prisma.io/docs/orm/fundamentals/transactions). The ORM API in Prisma ORM 8 doesn't wrap `$transaction` yet, so multi-document atomicity goes through the driver's sessions (see step 3d), which MongoDB only allows on a replica set.

> [!NOTE]
> Install the `latest` version of `@prisma/orm-mongo`, which is what `orm init` in step 1 does. This guide was written for `8.0.0-rc.13`, and MongoDB support in Prisma ORM 8 still changes between release candidates, so a newer version may behave differently from what this guide shows. To see which version you have, run `npm ls @prisma/orm-mongo`.

> [!WARNING]
> The `mongodb@^7` driver no longer accepts AWS credentials embedded in the connection string. See the [driver v7 breaking changes](https://github.com/mongodb/node-mongodb-native/blob/HEAD/etc/notes/CHANGES_7.0.0.md#-aws-authentication).

## 1. Set up Prisma ORM 8 [#1-set-up-prisma-orm-8]

Scaffold the project:

```bash
npx prisma@latest orm init --yes --target mongodb --authoring psl
```

`init` writes a `prisma.config.ts` at the repo root. You select MongoDB by importing the `@prisma/orm-mongo` facade instead of setting a `provider` string in the schema. Point the connection at the **same database** your v6 app uses.

  

#### After

```typescript
// prisma.config.ts
import 'dotenv/config';
import { definePrismaConfig } from 'prisma/config';
import { defineConfig as ormConfig } from '@prisma/orm-mongo/config';

export default definePrismaConfig({
  orm: ormConfig({
    contract: './src/prisma/contract.prisma',
    db: {
      connection: process.env['DATABASE_URL']!,
    },
  }),
});
```

#### Before

```prisma
// schema.prisma
datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

// Rest of schema...
```

### Generate the contract [#generate-the-contract]

Run `npx prisma contract emit` to generate `contract.json` from your `.prisma` contract file. Re-run this whenever you change the contract.

### Import the client [#import-the-client]

Instantiate the Prisma client from the emitted contract. Replace `my-app-db` with the database name your v6 connection string uses. If the connection URL already carries the database name in its path, omit `dbName` and the client reads it from the URL:

  

#### After

```typescript
// src/prisma/db.ts
import mongo from '@prisma/orm-mongo/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

const db = mongo<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
  dbName: 'my-app-db',
});

export { db };
```

#### Before

```typescript
// src/prisma/db.ts
import { PrismaClient } from '../generated/prisma/client';

const prisma = new PrismaClient();

export { prisma };
```

## 2. Port the schema to a contract [#2-port-the-schema-to-a-contract]

> [!NOTE]
> On MongoDB, `db.orm` holds your models by collection name. The collection name is the model's `@@map` value, or the model name exactly as written when the model has no `@@map`. So a model `User` with `@@map("users")` is `db.orm.users`, and `db.orm.User` does not exist. PostgreSQL works differently: there `db.orm` uses the model name, as in `db.orm.public.User`. Whatever you `@@map` in this step is the exact name every client call uses in step 3.

This step ports the v6 `schema.prisma` to a **contract**, authored in PSL (shown here) or TypeScript. The syntax is close to v6, with a few differences.

To start without porting, Prisma ORM 8 can also read the v6 `schema.prisma` directly: set `contract: prisma6Schema("prisma/schema.prisma")` in `prisma.config.ts`, as [Use a Prisma ORM 6 MongoDB schema](https://www.prisma.io/docs/cli/configuration#use-a-prisma-orm-6-mongodb-schema) shows. Port the schema when you want to use what the v6 syntax cannot express, such as polymorphism.

In the table below, the left column is how you wrote it in v6 and the right column is the Prisma ORM 8 equivalent:

> [!NOTE]
> You can use the [prisma-mongodb-upgrade](https://github.com/prisma/skills/tree/main/prisma-mongodb-upgrade) skill to help your agent map the contract to your schema.

| Concept           | v6 (`schema.prisma`)                                      | Prisma ORM 8 (`contract.prisma`)                                                                                                                                                  |
| ----------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| First line        | (nothing)                                                 | `// use prisma-8`. Without it, `contract emit` fails with `CONTRACT.SOURCE_LOAD_FAILED`                                                                                           |
| Datasource        | `datasource db { provider = "mongodb" }`                  | no `provider` (configured in `prisma.config.ts`)                                                                                                                                  |
| Id field          | `id String @id @default(auto()) @map("_id") @db.ObjectId` | `id ObjectId @id @map("_id")`                                                                                                                                                     |
| Scalar types      | `Int`, `Float`, `Boolean`, `DateTime`                     | `Int32`, `Double`, `Bool`, `Date`. The v6 names still work, with a `PSL_DEPRECATED_SCALAR_NAME` warning, and a later release removes them                                         |
| More scalar types | `BigInt`, `Decimal`, `Bytes`, `Json`                      | `Int64`, `Decimal128`, `Binary`, `Json`. A `Json` field holds only JSON values; type a field that holds other BSON values, such as a `Date`, as `Bson`                            |
| Timestamps        | `@default(now())`, `@updatedAt`                           | `createdAt temporal.createdAt()`, `updatedAt temporal.updatedAt()`                                                                                                                |
| Embedded document | `type Address { ... }`                                    | `type Address { ... }` (unchanged)                                                                                                                                                |
| Index             | `@@index(...)`, synced by `db push`                       | `@@index(...)` / `@@unique(...)`, applied by migrations                                                                                                                           |
| Polymorphism      | not supported                                             | `@@discriminator(field)` on the base + `@@base(Base, "value")` on each variant. <br />See [Base models and variants](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#base-models-and-variants) |

A fuller contract putting together enum, embedded type, relation, and polymorphism:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

enum UserRole {
  @@type("mongo/string@1")
  Admin  = "admin"
  Author = "author"
  Reader = "reader"
}

type Address {
  street  String
  city    String
  country String
}

model User {
  id      ObjectId @id @map("_id")
  email   String
  role    UserRole
  address Address?
  posts   Post[]
  @@map("users")
}

model Post {
  id        ObjectId @id @map("_id")
  title     String
  kind      String
  authorId  ObjectId
  createdAt Date
  author    User @relation(fields: [authorId], references: [id])
  @@discriminator(kind)
  @@index([createdAt(sort: Desc), authorId])
  @@map("posts")
}

model Article {
  summary String
  @@base(Post, "article")
}
```

When you use `@@discriminator`, declare a variant for every value the field takes in your existing data: the generated validator only accepts declared values, so writes to documents with an undeclared value fail once the validators are live. A variant model must declare at least one field (an optional one is enough).

## 3. Port client calls [#3-port-client-calls]

Many method names look similar, but they do not behave the same way. This section breaks down each category of operation.

### 3a. Basic CRUD [#3a-basic-crud]

Prisma ORM 8 uses a chained API instead of v6's single options object: you start from a collection (like `db.orm.users`), add filters and options step by step, then finish with a method that runs the query:

  

#### After

```typescript
import { db } from './db';

// Find one
await db.orm.users.where({ email: 'alice@example.com' }).first();

// Create
const user = await db.orm.users.create({ email: 'a@e.com', role: 'author', address: null });

// Update one
await db.orm.users.where({ _id: user._id }).update({ role: 'author' });

// Update many
await db.orm.users.where({ role: 'reader' }).updateAll({ role: 'author' });

// Delete one
await db.orm.users.where({ _id: user._id }).delete();
```

#### Before

```typescript
import { prisma } from './db';

// Find one
await prisma.user.findFirst({ where: { email } });

// Create
const user = await prisma.user.create({ data: { email, role: 'author' } });

// Update one
await prisma.user.update({ where: { id }, data: { role: 'author' } });

// Update many
await prisma.user.updateMany({ where: { role: 'reader' }, data: { role: 'author' } });

// Delete one
await prisma.user.delete({ where: { id } });
```

**Common mistakes:**

| Don't                                    | Do                            | Why                                                        |
| ---------------------------------------- | ----------------------------- | ---------------------------------------------------------- |
| `db.orm.User`                            | `db.orm.users`                | address by storage name, not model name                    |
| `.where({ email: { equals: 'x' } })`     | `.where({ email: 'x' })`      | `.where(...)` takes a plain equality object                |
| `.update({ ... })` with no `.where(...)` | `.where(...).update({ ... })` | every mutation except `create` needs a `.where(...)` first |
| `role: 'Author'`                         | `role: 'author'`              | enums read and write their storage value, not the key name |

### 3b. Relations and polymorphism [#3b-relations-and-polymorphism]

  

#### After

```typescript
import { db } from './db';

// Eager-load a relation
const withAuthor = await db.orm.posts.include('author').all();

// Query one variant of a polymorphic collection
const articles = await db.orm.posts.variant('Article').all();
```

#### Before

```typescript
import { prisma } from './db';

// Eager-load a relation
const withAuthor = await prisma.post.findMany({ include: { author: true } });

// Query one variant of a polymorphic collection
const articles = await prisma.post.findMany({ where: { kind: 'article' } });
```

### 3c. Aggregations [#3c-aggregations]

v6's `groupBy` / `aggregate` become a typed pipeline: build a plan with `db.query`, then run it with `(await db.runtime()).query`. `acc` provides the group totals (`acc.count()`, `acc.max(...)`, and friends), the equivalent of v6's `_count` / `_sum` / `_max`.

  

#### After

```typescript
import { acc } from '@prisma/orm-mongo/query-builder';

const plan = db.query
  .from('posts')
  .group((f) => ({ _id: f.kind, postCount: acc.count(), latest: acc.max(f.createdAt) }))
  .sort({ postCount: -1 })
  .build();
const byKind = await (await db.runtime()).query(plan).toArray();
```

#### Before

```typescript
await prisma.post.groupBy({
  by: ['kind'],
  _count: { _all: true },
  _max: { createdAt: true },
  orderBy: { _count: { kind: 'desc' } },
});
```

> [!WARNING]
> ObjectId filters need a raw command
> 
> Don't add `.match((f) => f.authorId.eq(authorId))` to filter by an `ObjectId` field (`_id`, or a foreign key like `authorId`): the typed builder sends the id through as a plain string, so the stage silently matches nothing. Filter ObjectId fields with the ORM client instead (`db.orm.posts.where({ authorId })` encodes them for you), or run the aggregation as a raw command carrying a real `ObjectId`:
> 
> ```typescript
> import { RawAggregateCommand } from '@prisma/orm-mongo/query-ast/execution';
> import { ObjectId } from 'mongodb';
>
> const plan = db.query.rawCommand(
>   new RawAggregateCommand('posts', [
>     { $match: { authorId: new ObjectId(String(authorId)) } },
>     { $group: { _id: '$kind', postCount: { $count: {} }, latest: { $max: '$createdAt' } } },
>     { $sort: { postCount: -1 } },
>   ]),
> );
> const byKind = await (await db.runtime()).query(plan).toArray();
> ```

### 3d. Transactions [#3d-transactions]

Prisma ORM 8 has no `transaction` method for MongoDB yet. For multi-document transactions, use the `mongodb` driver's [Transaction API](https://www.mongodb.com/docs/drivers/node/current/crud/transactions/transaction-conv/).

  

#### After

```typescript
import { MongoClient } from 'mongodb';

const client = new MongoClient(process.env['DATABASE_URL']!);
const session = client.startSession();
const mdb = client.db('my-app-db');

try {
  await session.withTransaction(async () => {
    // Pass { session } to EVERY operation: an op without it silently
    // runs outside the transaction.
    await mdb
      .collection('users')
      .insertOne({ email: 'a@e.com', role: 'author' }, { session });
    await mdb
      .collection('posts')
      .updateOne({ _id: postId }, { $set: { authorId } }, { session });
  });
} finally {
  await session.endSession();
}
```

#### Before

```typescript
await prisma.$transaction(async (tx) => {
  // ...writes...
});
```

### 3e. Raw operations [#3e-raw-operations]

#### Aggregations [#aggregations]

The direct replacement for v6's `findRaw` and `aggregateRaw` is `db.raw`.

  

#### After

```typescript
import { db } from './db';

// Raw aggregation on a collection, replaces v6's aggregateRaw / findRaw.
const plan = db.raw
  .collection('posts')
  .aggregate([ ... ])
  .build();
const rows = await (await db.runtime()).query(plan).toArray();
```

#### Before

```typescript
import { prisma } from './db';

// Raw aggregation on a collection.
const rows = await prisma.post.aggregateRaw({
  pipeline: [ ... ],
});
```

#### Commands [#commands]

`db.raw` is collection-scoped, so v6's database-level `$runCommandRaw` has no ORM equivalent. Construct your own `MongoClient` and pass it to the binding from step 1 in place of `url`: the same client then powers the typed ORM and runs arbitrary commands, sharing one connection pool.

  

#### After

```typescript
// src/prisma/db.ts
import mongo from '@prisma/orm-mongo/runtime';
import { MongoClient } from 'mongodb';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const mongoClient = new MongoClient(process.env['DATABASE_URL']!);
export const db = mongo<Contract>({ contractJson, mongoClient, dbName: 'my-app-db' });

// Elsewhere: typed ORM and raw commands from the same client.
await db.orm.users.where({ email: 'alice@example.com' }).first();
await mongoClient.db('my-app-db').command({ ping: 1 });
```

#### Before

```typescript
import { prisma } from './db';

await prisma.$runCommandRaw({ ping: 1 });
```

For raw reads and writes scoped to a single collection (anything the typed builder can't express), you don't need the driver: `db.query.rawCommand(...)` packages a raw command into a plan, as shown in [3c](#3c-aggregations). See [Raw queries](https://www.prisma.io/docs/orm/reference/raw-queries) for the full surface.

### Quick reference table [#quick-reference-table]

| v6                                        | Prisma ORM 8                                                                                                        |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `prisma.user.findMany(...)`               | `db.orm.users.where({ ... }).all()`                                                                                 |
| `prisma.user.findFirst(...)`              | `db.orm.users.where({ ... }).first()`                                                                               |
| `create` / `update` / `delete` / `upsert` | same names on `db.orm.<collection>`                                                                                 |
| `updateMany` / `deleteMany`               | `updateAll` / `deleteAll`                                                                                           |
| `aggregate` / `groupBy`                   | `db.query.from(...).group(...).build()` → `(await db.runtime()).query(plan)`                                        |
| `findRaw` / `aggregateRaw`                | `db.raw.collection(...).aggregate(...).build()` → `(await db.runtime()).query(plan)`, or `db.query.rawCommand(...)` |
| `$runCommandRaw`                          | share a `MongoClient` with the binding, then `mongoClient.db(...).command(...)` (see 3e)                            |
| `$transaction(...)`                       | no wrapper yet. Use driver sessions on a replica set (see 3d)                                                       |
| `$connect` / `$disconnect`                | connects lazily on first use. Call `db.close()` to disconnect                                                       |

## 4. Adopt the migration lifecycle [#4-adopt-the-migration-lifecycle]

v6 MongoDB had no Prisma Migrate, only `db push` (ephemeral, no history). Prisma ORM 8 gives MongoDB first-class, contract-driven migrations: reviewable diffs you commit, reproducible across environments, and an auditable schema history.

### Bring the v6 database under management [#bring-the-v6-database-under-management]

Your database already has collections and data, so bootstrap it with `db update`. The command diffs the live database against your contract, applies the delta (the strict validators, plus any indexes the contract declares that v6 never created), and signs the database so Prisma ORM 8 recognizes it from then on. The `--advance-ref db` flag records the resulting contract state as the [`db` ref](https://www.prisma.io/docs/orm/migrations/the-migration-graph#name-important-states-with-refs), the starting point later migration plans diff from.

```bash
npx prisma contract emit
npx prisma db update --db "$DATABASE_URL" --dry-run   # preview the delta first
npx prisma db update --db "$DATABASE_URL" --advance-ref db
```

Don't reach for `db init` here. It bootstraps only additively, and on a populated database it refuses the validator changes this migration needs, because adding a validator to a collection with existing documents is classed destructive. `db update` applies them after a confirmation prompt.

### Every schema change after that [#every-schema-change-after-that]

Use `db update` for local experiments (the `db push` analogue, no history kept) and the migration workflow for shared branches and production:

```bash
npx prisma contract emit                             # planning diffs the emitted contract
npx prisma migration plan --name add_posts_indexes   # plans from the db ref
npx prisma db migrate --db "$DATABASE_URL" --advance-ref db
npx prisma db verify --db "$DATABASE_URL"   # check the DB matches the contract
```

**Good to know:**

* You never hand-write migration steps: declare indexes and validators in the contract (step 2) and `migration plan` derives the changes.
* If a `migrate` run is interrupted, rerun it to resume. After fixing anything by hand, run `db sign` so the signature matches the database again.
* Prisma ORM 8 adds strict `$jsonSchema` validators by default. Make sure existing documents pass them before running in production: once the validators are live, writes to documents that don't match the contract fail with `Document failed validation`.

## 5. Pre-flight checklist (before production cutover) [#5-pre-flight-checklist-before-production-cutover]

Work through this list before you switch production traffic over:

* **Same database.** Your Prisma ORM 8 config points at the **same** database and connection string as v6.
* **Server version.** Your MongoDB server is on 8.0 or newer.
* **Dry run first.** Rehearse the whole flow on a throwaway copy of your database (`contract emit`, `db update --dry-run`, `db update`, `db verify`) and make sure `db verify` passes before you touch production.
* **Index parity.** The indexes on each collection (`db.collection.getIndexes()`) match your contract.
* **Validators.** Your existing documents pass the strict validators Prisma ORM 8 adds to each collection (see *Good to know* in step 4).
* **Addressing.** Every call site uses storage names like `db.orm.users`, not model names.
* **Transactions.** Every v6 `$transaction` now has a driver-session equivalent.
* **Raw calls.** Every `$runCommandRaw`, `findRaw`, and `aggregateRaw` has a pipeline-builder or `mongodb`-driver replacement.
* **Read-only trial run.** Run Prisma ORM 8 read-only alongside your v6 app for a while and compare the results. This surfaces any differences while v6 is still handling all the writes.
* **Cutover and rollback.** Switch writes over only once the trial run looks good, and keep the v6 branch deployable. Rolling back is just a code rollback since your data never moved.

Don't delete the v6 client, schema, or dependencies until this checklist passes.

## 6. Post-migration: adopting Next workflows [#6-post-migration-adopting-next-workflows]

Once you've cut over, this is the day-to-day workflow:

* **Schema changes.** Edit the contract, then run `contract emit`, `migration plan`, and `migrate` (same loop from step 4).
* **Troubleshooting.** `db verify` checks the database against your contract, and `db sign` records any fixes you make by hand.
* **Performance.** Your aggregations now compile to native MongoDB pipelines, so it's worth benchmarking them against your old v6 raw calls.

See the [Prisma ORM docs](https://www.prisma.io/docs/orm) for [pipeline builder patterns](https://www.prisma.io/docs/orm/reference/pipeline-builder), [relation loading strategies](https://www.prisma.io/docs/orm/reference/orm-client), and [advanced contract features](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax). This guide gets you across the bridge. From here on, the Prisma ORM docs are the source of truth.

## Related pages

- [`Prisma ORM 7 to 8 (PostgreSQL)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql): Migrate a PostgreSQL project from Prisma ORM 7 to Prisma ORM 8 incrementally, with both versions running side by side
- [`Upgrade to v1`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v1): Guide for upgrading from Prisma 1 to Prisma ORM
- [`Upgrade to v3`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v3): Guide for upgrading to Prisma ORM v3
- [`Upgrade to v4`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v4): Guide for upgrading to Prisma ORM v4
- [`Upgrade to v5`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v5): Guide for upgrading to Prisma ORM v5

# Prisma ORM 7 to 8 (PostgreSQL) (/docs/guides/upgrade-prisma-orm/postgresql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Migrate a PostgreSQL project from Prisma ORM 7 to Prisma ORM 8 incrementally, with both versions running side by side

Location: Guides > Upgrade Prisma ORM > Prisma ORM 7 to 8 (PostgreSQL)

This guide is for teams running a Prisma ORM 7 application on PostgreSQL who want to move to **Prisma ORM 8** without a rewrite. You will install Prisma ORM 8 next to Prisma ORM 7 in the same application, move routes over one at a time, hand migration ownership to Prisma ORM 8, and remove Prisma ORM 7 once nothing depends on it.

Both versions run against the same PostgreSQL database the whole time. The database, its data, and its connection string do not change; only application code and tooling do. Because each route stays on Prisma ORM 7 until you deliberately move it, the application remains shippable at every point in the migration.

The guide covers **PostgreSQL only**. Guidance for other databases will follow. If you are coming from v6 on MongoDB, see the [MongoDB guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb).

> [!NOTE]
> Step 2.1 installs the `latest` version of both Prisma ORM 8 packages: `prisma`, the Prisma ORM 8 CLI, and `@prisma/orm-postgres`. This guide was written with `prisma` at `8.0.0-rc.17` and `@prisma/orm-postgres` at `8.0.0-rc.13`: the CLI is released separately, so the two numbers differ. Prisma ORM 7 stays at `7.10.0`: the example app in step 1.1 starts on it, and step 1.2 installs `@prisma/prisma7@7.10.0`.

## How the incremental migration works [#how-the-incremental-migration-works]

The migration runs in five phases. The application works at the end of each one.

1. **Prepare Prisma ORM 7 for side-by-side operation.** Move Prisma ORM 7 onto its own package name, binary, and config file. No behavior changes.
2. **Add Prisma ORM 8.** Install the Prisma ORM 8 CLI and runtime with their own config, schema contract, and generated client. No application code uses them yet.
3. **Migrate one route.** One route runs on Prisma ORM 8 while the rest stay on Prisma ORM 7, all against the same database.
4. **Transfer migration ownership.** Prisma ORM 8 takes over planning and applying schema changes.
5. **Remove Prisma ORM 7** once nothing imports it.

The ownership timeline matters more than the code timeline. Prisma ORM 7 owns schema migrations through phases 1 to 3, and routes move to Prisma ORM 8 independently of that. Prisma ORM 8 takes over migrations only in phase 4, after a database signature and a `db` ref are in place; the first `migration plan` then writes the baseline migration itself. You can pause between phases for as long as you need.

The [prisma8-and-7-example](https://github.com/prisma/prisma8-and-7-example) repository shows the finished result of each phase (tags `step-0` through `step-3`).

## Prerequisites [#prerequisites]

* **Node.js 22.18 or newer (on the 24 line, 24.11 or newer)**; Node.js 24 recommended
* A working **Prisma ORM 7** application on PostgreSQL: `prisma.config.ts`, the `prisma-client` generator, and a driver adapter
* **TypeScript 5.9 or newer** with `"strict": true`. [Step 2.6](#26-set-up-tsconfigjson-for-the-prisma-orm-8-client) tells you whether to change the `module` setting in `tsconfig.json`

## 1. Prepare Prisma ORM 7 for side-by-side operation [#1-prepare-prisma-orm-7-for-side-by-side-operation]

Prisma ORM 8 expects the `prisma` package name, the `prisma` binary, and the `prisma.config.ts` file name. In this phase you move Prisma ORM 7 off those three names so Prisma ORM 8 can take them without ambiguity. Nothing migrates yet.

### 1.1. Confirm the application works [#11-confirm-the-application-works]

The guide follows a small Hono API with two routes. Map the file names to your own project. The Prisma ORM 7 pieces that matter:

```json title="package.json (excerpt)"
{
  "scripts": {
    "prisma:generate": "prisma generate",
    "db:migrate": "prisma migrate dev"
  },
  "dependencies": {
    "@prisma/adapter-pg": "^7.10.0",
    "@prisma/client": "^7.10.0"
  },
  "devDependencies": {
    "prisma": "^7.10.0"
  }
}
```

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  published Boolean @default(false)
  authorId  Int
  author    User    @relation(fields: [authorId], references: [id], onDelete: Cascade)

  @@index([authorId])
}
```

```typescript title="prisma.config.ts"
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

```typescript title="src/db.ts"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client.js";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! });

export const prisma = new PrismaClient({ adapter });
```

Two routes read and write through this client, `/users` and `/posts`:

```typescript title="src/routes/users.ts"
import { Hono } from "hono";
import { prisma } from "../db.js";

export const users = new Hono();

users.get("/", async (c) => {
  const result = await prisma.user.findMany({
    include: { posts: true },
    orderBy: { id: "asc" },
  });
  return c.json(result);
});

users.post("/", async (c) => {
  const body = await c.req.json<{ email: string; name?: string }>();
  const user = await prisma.user.create({ data: body });
  return c.json(user, 201);
});
```

`src/routes/posts.ts` follows the same pattern for `Post`.

Start the app and run a read and a write:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

```bash
curl -X POST localhost:3000/users -H 'content-type: application/json' \
  -d '{"email":"alice@prisma.io","name":"Alice"}'
curl localhost:3000/users
```

Do not continue until both requests succeed. That confirms the Prisma ORM 7 application works before you change its configuration.

### 1.2. Replace the `prisma` package with `@prisma/prisma7` [#12-replace-the-prisma-package-with-prismaprisma7]

  

#### bun

```bash
bun remove prisma
bun add --dev @prisma/prisma7@7.10.0
```

#### pnpm

```bash
pnpm remove prisma
pnpm add --save-dev @prisma/prisma7@7.10.0
```

#### yarn

```bash
yarn remove prisma
yarn add --dev @prisma/prisma7@7.10.0
```

#### npm

```bash
npm uninstall prisma
npm install --save-dev @prisma/prisma7@7.10.0
```

`@prisma/prisma7` is the same Prisma ORM 7 CLI under a version-specific name. It exposes a `prisma7` binary and keeps `prisma` 7 as a transitive dependency. Your `@prisma/client` and `@prisma/adapter-pg` dependencies stay untouched.

### 1.3. Rename the Prisma ORM 7 config [#13-rename-the-prisma-orm-7-config]

```bash
mv prisma.config.ts prisma7.config.ts
```

```typescript title="prisma7.config.ts"
import "dotenv/config";
import { defineConfig } from "prisma/config"; // [!code --]
import { defineConfig } from "@prisma/prisma7/config"; // [!code ++]

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

The `prisma7` CLI discovers `prisma7.config.ts` automatically, so no `--config` flag is needed. Renaming frees the `prisma.config.ts` name for Prisma ORM 8, which only accepts its own config format under that name.

### 1.4. Point scripts at the `prisma7` binary [#14-point-scripts-at-the-prisma7-binary]

```json title="package.json (excerpt)"
{
  "scripts": {
    "prisma:generate": "prisma generate", // [!code --]
    "db:migrate": "prisma migrate dev" // [!code --]
    "prisma7:generate": "prisma7 generate", // [!code ++]
    "prisma7:migrate": "prisma7 migrate dev" // [!code ++]
  }
}
```

After Prisma ORM 8 is installed, the `prisma` binary runs the Prisma ORM 8 CLI. Update every script, CI job, and deployment command that must continue using Prisma ORM 7 to call `prisma7` instead.

### 1.5. Check that Prisma ORM 7 still works [#15-check-that-prisma-orm-7-still-works]

  

#### bun

```bash
bunx prisma7 generate
bunx prisma7 migrate status
```

#### pnpm

```bash
pnpm dlx prisma7 generate
pnpm dlx prisma7 migrate status
```

#### yarn

```bash
yarn dlx prisma7 generate
yarn dlx prisma7 migrate status
```

#### npm

```bash
npx prisma7 generate
npx prisma7 migrate status
```

**Expected result:** `generate` writes the client to `generated/prisma` as before, and `migrate status` reports that the database schema is up to date. Start the app and query each route; behavior should be identical to step 1.1.

## 2. Add Prisma ORM 8 [#2-add-prisma-orm-8]

### 2.1. Install the Prisma ORM 8 packages [#21-install-the-prisma-orm-8-packages]

  

#### bun

```bash
bun add --dev prisma@latest
bun add @prisma/orm-postgres
```

#### pnpm

```bash
pnpm add --save-dev prisma@latest
pnpm add @prisma/orm-postgres
```

#### yarn

```bash
yarn add --dev prisma@latest
yarn add @prisma/orm-postgres
```

#### npm

```bash
npm install --save-dev prisma@latest
npm install @prisma/orm-postgres
```

`prisma@latest` is the Prisma ORM 8 CLI, and its `prisma/config` subpath provides `definePrismaConfig` for the Prisma ORM 8 config file. Installing it locally (not only running it through `npx`) is what makes that import resolve. `@prisma/orm-postgres` is the PostgreSQL ORM runtime your application code will import.

After this install, `npx prisma <command>` runs the Prisma ORM 8 CLI and `npx prisma7 <command>` runs Prisma ORM 7:

  

#### bun

```bash
bunx prisma --version
```

#### pnpm

```bash
pnpm prisma --version
```

#### yarn

```bash
yarn prisma --version
```

#### npm

```bash
npx prisma --version
```

**Expected result:** the command prints `8.0.0-rc.17` or a newer version. That number does not match the version of `@prisma/orm-postgres`, because the CLI is released separately.

### 2.2. Create the Prisma ORM 8 config [#22-create-the-prisma-orm-8-config]

```typescript title="prisma.config.ts"
import "dotenv/config";
import { definePrismaConfig } from "prisma/config";
import { defineConfig as definePostgresConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: definePostgresConfig({
    contract: "prisma8/contract.prisma",
    output: "generated/prisma8",
    db: {
      connection: process.env["DATABASE_URL"],
    },
  }),
});
```

Both configs point at the **same** `DATABASE_URL`. Everything else is separate:

|                  | Prisma ORM 7           | Prisma ORM 8              |
| ---------------- | ---------------------- | ------------------------- |
| CLI              | `prisma7`              | `prisma`                  |
| Config           | `prisma7.config.ts`    | `prisma.config.ts`        |
| Schema           | `prisma/schema.prisma` | `prisma8/contract.prisma` |
| Generated client | `generated/prisma`     | `generated/prisma8`       |

Because the config carries the connection, the Prisma ORM 8 CLI commands below don't need a `--db` flag.

> [!NOTE]
> Read the Prisma ORM 7 schema instead
> 
> Instead of generating a contract file in steps 2.3 and 2.4, Prisma ORM 8 can read `prisma/schema.prisma` directly as its contract, so you keep one schema file while Prisma ORM 7 owns migrations. `schema.prisma` does not need the `// use prisma-8` first line that a contract file written for Prisma ORM 8 starts with (step 2.4 shows one). Skip steps 2.3 and 2.4, and change two lines in the `prisma.config.ts` you just wrote:
> 
> ```typescript title="prisma.config.ts"
> import "dotenv/config";
> import { definePrismaConfig } from "prisma/config";
> import { defineConfig as definePostgresConfig } from "@prisma/orm-postgres/config"; // [!code --]
> import { defineConfig as definePostgresConfig, prisma7Schema } from "@prisma/orm-postgres/config"; // [!code ++]
>
> export default definePrismaConfig({
>   orm: definePostgresConfig({
>     contract: "prisma8/contract.prisma", // [!code --]
>     contract: prisma7Schema("prisma/schema.prisma"), // [!code ++]
>     output: "generated/prisma8",
>     db: {
>       connection: process.env["DATABASE_URL"],
>     },
>   }),
> });
> ```
>
> After step 2.5, run `npx prisma db sign`. [`db sign`](https://www.prisma.io/docs/cli/db-sign) checks that the database matches the contract Prisma ORM 8 read from `schema.prisma` and records in the database that it does. Signing does not move your migrations to Prisma ORM 8. Prisma ORM 7 keeps planning and applying them, so after each Prisma ORM 7 migration, whether you ran `prisma7 migrate dev` or `prisma7 migrate deploy`, run `npx prisma contract emit` and then `npx prisma db sign` again. If you emit without signing, the Prisma ORM 8 client still runs queries, but `npx prisma db verify` reports that the contract no longer matches the one recorded in the database. [Use a Prisma ORM 7 schema](https://www.prisma.io/docs/cli/configuration#use-a-prisma-orm-7-schema) lists the parts of a Prisma ORM 7 schema that Prisma ORM 8 cannot read.
> 
> If you have not started phase 1 yet, one command does phase 1 and this setup for you:
> 
> 
>   
> 
>   #### bun

>     ```bash title="Terminal"
>     bunx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
>     ```
>
> 
>   #### pnpm

>     ```bash title="Terminal"
>     pnpm dlx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
>     ```
>
> 
>   #### yarn

>     ```bash title="Terminal"
>     yarn dlx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
>     ```
>
> 
>   #### npm

>     ```bash title="Terminal"
>     npx prisma@latest orm init --from-prisma7-schema prisma/schema.prisma
>     ```
>
> 
> 
> Write `prisma@latest`, because in a Prisma ORM 7 project `npx prisma` runs version 7. The command moves Prisma ORM 7 to the `prisma7` command and `prisma7.config.ts`, installs the Prisma ORM 8 packages, writes `prisma.config.ts` and a Prisma ORM 8 client in `src/prisma/db.ts`, and emits the contract. [`orm init` on a Prisma ORM 7 project](https://www.prisma.io/docs/cli/orm-init#on-a-prisma-orm-7-project) lists what it changes. Then run `npx prisma db sign` and continue with phase 3, using the `db` client from `src/prisma/db.ts` instead of adding one to `src/db.ts` in step 3.1.
> 
> Prisma ORM 7 keeps owning migrations on this path until you are ready for [phase 4](#4-transfer-migration-ownership), where Prisma ORM 8 takes them over. Phase 4 needs a contract file written for Prisma ORM 8, so switch to one first. Either run `npx prisma contract print --output prisma8/contract.prisma`, which writes the contract Prisma ORM 8 read from `schema.prisma` as a Prisma ORM 8 contract file, or run steps 2.3 to 2.5. Then set `contract` in `prisma.config.ts` to `"prisma8/contract.prisma"`, the file you created. Then follow phase 4 as written. Its first step, `db sign`, checks the new contract against the database before Prisma ORM 8 takes over.

### 2.3. Infer the contract from the live database [#23-infer-the-contract-from-the-live-database]

Prisma ORM 8 describes your schema as a [contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract). Generate it from the database Prisma ORM 7 built:

  

#### bun

```bash title="Terminal"
bunx prisma contract infer --output prisma8/contract.prisma
```

#### pnpm

```bash title="Terminal"
pnpm prisma contract infer --output prisma8/contract.prisma
```

#### yarn

```bash title="Terminal"
yarn prisma contract infer --output prisma8/contract.prisma
```

#### npm

```bash title="Terminal"
npx prisma contract infer --output prisma8/contract.prisma
```

### 2.4. Edit the inferred contract [#24-edit-the-inferred-contract]

`contract infer` reads every table in the database, so it also writes a `PrismaMigrations` model for `_prisma_migrations`, the table where Prisma ORM 7 records which migrations it has applied. Delete that model from the contract, because Prisma ORM 8 must not manage the table. The table itself stays in the database, and an extra table that the contract does not describe is fine.

You do not need to add `@@map` to the other models: a model without `@@map` uses its name, exactly as written, as its table name, so `User` reads and writes the `"User"` table that Prisma ORM 7 created.

After that edit, the contract looks like this:

```prisma title="prisma8/contract.prisma"
// use prisma-8

model User {
  id    Int     @id(map: "User_pkey") @default(autoincrement())
  email String
  name  String?
  posts Post[]

  @@index([email], map: "User_email_key", unique: true)
}

model Post {
  id        Int     @id(map: "Post_pkey") @default(autoincrement())
  title     String
  published Boolean @default(false)
  authorId  Int
  author    User    @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade, map: "Post_authorId_fkey")

  @@index([authorId], map: "Post_authorId_idx")
}
```

Keep `// use prisma-8` as the first line of `prisma8/contract.prisma`. `contract emit` reads only `.prisma` files that start with this line, and this is the only file in your contract, so without it `contract emit` fails with `CONTRACT.SOURCE_LOAD_FAILED`. A `schema.prisma` that Prisma ORM 8 reads through `prisma7Schema(...)`, as in the tip at the end of step 2.2, does not need the line.

### 2.5. Emit the contract artifacts [#25-emit-the-contract-artifacts]

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

`contract emit` writes `contract.json` and `contract.d.ts` to `generated/prisma8`, the runtime and type inputs for the Prisma ORM 8 client. Re-run it after every contract change.

### 2.6. Set up tsconfig.json for the Prisma ORM 8 client [#26-set-up-tsconfigjson-for-the-prisma-orm-8-client]

Your `tsconfig.json` must allow the JSON import you will write in step 3.1: `import contractJson from "../generated/prisma8/contract.json" with { type: "json" }`. TypeScript accepts the `with { type: "json" }` part only when `module` is `esnext`, `node18`, `node20`, `nodenext`, or `preserve`, and only in a file it treats as an ES module. Any other value, such as `commonjs`, `es2022`, or `node16`, rejects it, and leaving `module` unset fails too. Take the first case below that matches how your app runs:

* **`module` is already one of the five values and your build works with it, and either `package.json` has `"type": "module"` or `module` is `esnext` or `preserve`.** Keep it. Set `moduleResolution` to `bundler` if `module` is `esnext` or `preserve`, to `nodenext` if `module` is `nodenext`, and remove it if `module` is `node18` or `node20`. A `moduleResolution` of `node` or `node10` cannot resolve the `@prisma/orm-*` packages, so do not leave that in place.

* **You compile with `tsc`, run the output with `node`, and `package.json` has no `"type": "module"` (or has `"type": "commonjs"`).** Your app runs as CommonJS, and it can stay that way. Set `"module": "nodenext"` and `"moduleResolution": "nodenext"`, and do not add `"type": "module"`. Prisma ORM 8 works from CommonJS code, and your relative imports stay as they are, without extensions. TypeScript treats `db.ts` as CommonJS here, so in step 3.1 write the JSON import without the `with` part and copy the other import lines as shown.

  ```typescript title="src/db.ts (CommonJS excerpt)"
  import contractJson from "../generated/prisma8/contract.json";
  ```

* **The app runs through `tsx`, or a bundler such as `vite`, `next`, or `esbuild` builds it, and you never run `tsc` output with plain `node`.** Set `"module": "preserve"` and `"moduleResolution": "bundler"`. You do not need file extensions on relative imports, and the import lines in step 3.1 work as shown. If you run the `.ts` files directly with `node` instead, its type stripping needs the `.ts` extension on every relative import, so add `"allowImportingTsExtensions": true` as well.

* **You compile with `tsc`, run the output with `node`, and `package.json` has `"type": "module"`, even if you use `tsx` in development.** Set `"module": "nodenext"` and `"moduleResolution": "nodenext"`. Node then requires an explicit file extension on every relative import, which for compiled TypeScript files is `.js`, so this is the one setup that makes you rewrite imports; [the TypeScript module reference](https://www.typescriptlang.org/docs/handbook/modules/reference.html#node16-node18-nodenext) explains the rule, and the [example project](https://github.com/prisma/prisma8-and-7-example) is set up this way.

Whichever case applies, add `"resolveJsonModule": true` so TypeScript can type the JSON import, and add `generated/prisma8/**/*.d.ts` to `include` so it sees the emitted `contract.d.ts`. If your `tsconfig.json` has no `include`, TypeScript already picks up every file under the project, so skip that part:

```json title="tsconfig.json (excerpt)"
{
  "compilerOptions": {
    "resolveJsonModule": true // [!code ++]
  },
  "include": [
    "src/**/*.ts",
    "generated/prisma/**/*.ts",
    "generated/prisma8/**/*.d.ts" // [!code ++]
  ]
}
```

**Check:** `npx tsc --noEmit` passes. Prisma ORM 8 is now installed and configured, but no application code uses it yet. This check does not test your `module` choice, because nothing imports `contract.json` until step 3.1; if TypeScript reports TS2823 there, the `module` value rejects the `with` part, and if it reports TS2856, the file compiles as CommonJS and the `with` part has to go, as the CommonJS case shows.

## 3. Migrate one route [#3-migrate-one-route]

Pick one small route and move only that code. The rest of the application stays on Prisma ORM 7.

### 3.1. Instantiate both clients [#31-instantiate-both-clients]

```typescript title="src/db.ts"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import postgres from "@prisma/orm-postgres/runtime"; // [!code ++]
import type { Contract } from "../generated/prisma8/contract.js"; // [!code ++]
import contractJson from "../generated/prisma8/contract.json" with { type: "json" }; // [!code ++]
import { PrismaClient } from "../generated/prisma/client.js";

const connectionString = process.env.DATABASE_URL!;

const adapter = new PrismaPg({ connectionString });

export const prisma = new PrismaClient({ adapter });

export const db = postgres<Contract>({ url: connectionString, contractJson }); // [!code ++]
```

`prisma` is the Prisma ORM 7 client and `db` is the Prisma ORM 8 client, both connected to the same database.

### 3.2. Rewrite the route [#32-rewrite-the-route]

Move the users route to the Prisma ORM 8 [ORM client](https://www.prisma.io/docs/orm/reference/orm-client). Queries start from `db.orm.<schema>.<Model>` (`public` here) and chain instead of taking one options object:

  

#### After

```typescript title="src/routes/users.ts" 
import { Hono } from "hono";
import { db } from "../db.js";

export const users = new Hono();

users.get("/", async (c) => {
  const result = await db.orm.public.User.include("posts", (posts) =>
    posts.orderBy((post) => post.id.asc()),
  )
    .orderBy((user) => user.id.asc())
    .all();
  return c.json(result);
});

users.post("/", async (c) => {
  const body = await c.req.json<{ email: string; name?: string }>();
  const user = await db.orm.public.User.create(body);
  return c.json(user, 201);
});
```

#### Before

```typescript title="src/routes/users.ts" 
import { Hono } from "hono";
import { prisma } from "../db.js";

export const users = new Hono();

users.get("/", async (c) => {
  const result = await prisma.user.findMany({
    include: { posts: true },
    orderBy: { id: "asc" },
  });
  return c.json(result);
});

users.post("/", async (c) => {
  const body = await c.req.json<{ email: string; name?: string }>();
  const user = await prisma.user.create({ data: body });
  return c.json(user, 201);
});
```

`src/routes/posts.ts` stays unchanged, on Prisma ORM 7.

### 3.3. Exercise both code paths [#33-exercise-both-code-paths]

Start the app and hit both routes:

```bash
curl localhost:3000/users
curl -X POST localhost:3000/posts -H 'content-type: application/json' \
  -d '{"title":"Written by Prisma 7","authorId":1}'
curl localhost:3000/users
```

**Expected result:** the first request runs through Prisma ORM 8. The second writes through Prisma ORM 7. The third, through Prisma ORM 8 again, includes the post Prisma ORM 7 just wrote.

Remaining routes can move over the same way, one at a time, on any schedule. Prisma ORM 7 still owns schema migrations in this phase. If the schema changes, run `prisma7 migrate dev`, then re-run `contract infer` and `contract emit` so the Prisma ORM 8 contract stays current.

## 4. Transfer migration ownership [#4-transfer-migration-ownership]

So far every schema change has gone through `prisma7 migrate dev`. In this phase Prisma ORM 8 takes over planning and applying schema changes, and `prisma/schema.prisma` is frozen.

Treat the switch as a decision, not a routine step. After it, your team and your pipelines must stop using the Prisma ORM 7 migration workflow, even though routes still on the Prisma ORM 7 client keep working. See [how migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work) for the full picture.

Prisma ORM 8 tracks schema state with four pieces, and the handoff creates each one exactly once:

* A **contract hash** identifies one version of the emitted contract.
* A **migration** is an on-disk package recording how to get from one contract hash to another. `migrate` only replays recorded migrations; it never invents one.
* The **marker** is Prisma ORM 8's record, stored in the database, of which contract hash the database currently satisfies.
* A **ref** is a named pointer at a contract hash. `migration plan` uses the `db` ref as its starting point.

Step 4.1 creates the marker and the ref with one command. The baseline migration is written by the first `migration plan` in step 4.3.

### 4.1. Sign the existing database [#41-sign-the-existing-database]

Your database already has every table the contract describes, so adopt it rather than replay anything:

  

#### bun

```bash
bunx prisma db sign
bunx prisma migration status
```

#### pnpm

```bash
pnpm prisma db sign
pnpm prisma migration status
```

#### yarn

```bash
yarn prisma db sign
yarn prisma migration status
```

#### npm

```bash
npx prisma db sign
npx prisma migration status
```

`db sign` verifies that the live schema matches the emitted contract, writes Prisma ORM 8's marker at that contract version, stores the contract snapshot under `migrations/snapshots/`, and points a [ref](https://www.prisma.io/docs/orm/migrations/the-migration-graph#name-important-states-with-refs) named `db` at it. `migration plan` starts from that ref, so plans chain from the schema Prisma ORM 7 built and contain only your own changes.

**Expected result:** `Database signed`, and `migration status` shows the current and target contract hashes match with nothing pending.

### 4.2. Retire the Prisma ORM 7 migration scripts [#42-retire-the-prisma-orm-7-migration-scripts]

Remove `prisma7 migrate` from your scripts so nobody runs it by accident. Keep `prisma7 generate`, because the legacy routes still need their client:

```json title="package.json (excerpt)"
{
  "scripts": {
    "prisma7:generate": "prisma7 generate",
    "prisma7:migrate": "prisma7 migrate dev", // [!code --]
    "prisma8:migrate": "prisma db migrate --advance-ref db" // [!code ++]
  }
}
```

### 4.3. Verify the handoff with a schema change [#43-verify-the-handoff-with-a-schema-change]

Verify the migration handoff with a small additive schema change. Add a field to the contract:

```prisma title="prisma8/contract.prisma (excerpt)"
model User {
  id    Int     @id(map: "User_pkey") @default(autoincrement())
  email String
  name  String?
  bio   String? // [!code ++]
  ...
}
```

Emit, plan, and apply:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_user_bio
bunx prisma db migrate --advance-ref db
bunx prisma db verify
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_user_bio
pnpm prisma db migrate --advance-ref db
pnpm prisma db verify
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_user_bio
yarn prisma db migrate --advance-ref db
yarn prisma db verify
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_user_bio
npx prisma db migrate --advance-ref db
npx prisma db verify
```

**Expected result:** `migration plan` reports `Planned baseline + 1 operation(s)` and writes two packages under `migrations/app/`: a baseline that records the schema you adopted in step 4.1, and `add_user_bio` with the single operation `Add column "bio" to "User"`. `db migrate` skips the baseline, because the marker already records that state, and applies `add_user_bio`. `--advance-ref db` moves the ref so the next plan chains correctly, and `db verify` reports that marker and schema match the contract.

Restart the app: the Prisma ORM 8 route returns users with `bio`, and the Prisma ORM 7 route keeps working untouched, because its client doesn't know about the new column. Additive changes like nullable columns are safe next to legacy Prisma ORM 7 code. Be careful with renames or drops of columns that Prisma ORM 7 routes still read.

## 5. Remove Prisma ORM 7 [#5-remove-prisma-orm-7]

Migrate the remaining routes as in phase 3. For `posts` here, that means swapping `prisma.post.findMany(...)` for `db.orm.public.Post.include("author").all()` and `prisma.post.create({ data })` for `db.orm.public.Post.create(data)`.

When nothing imports `generated/prisma` anymore, remove Prisma ORM 7:

  

#### bun

```bash
bun remove @prisma/prisma7 @prisma/client @prisma/adapter-pg
```

#### pnpm

```bash
pnpm remove @prisma/prisma7 @prisma/client @prisma/adapter-pg
```

#### yarn

```bash
yarn remove @prisma/prisma7 @prisma/client @prisma/adapter-pg
```

#### npm

```bash
npm uninstall @prisma/prisma7 @prisma/client @prisma/adapter-pg
```

```bash
rm prisma7.config.ts
rm -r prisma generated/prisma
```

Then delete the `prisma7:*` scripts from `package.json` and drop `generated/prisma/**/*.ts` from the `include` array in `tsconfig.json`.

Verify the end state:

  

#### bun

```bash
bunx tsc --noEmit
bunx prisma db verify
```

#### pnpm

```bash
pnpm tsc --noEmit
pnpm prisma db verify
```

#### yarn

```bash
yarn tsc --noEmit
yarn prisma db verify
```

#### npm

```bash
npx tsc --noEmit
npx prisma db verify
```

Start the app and run a query against every route. The application now runs entirely on Prisma ORM 8, with schema changes managed by `prisma migration plan` and `prisma db migrate`.

> [!NOTE]
> Prisma ORM 7's `_prisma_migrations` table remains in the database. It is inert (Prisma ORM 8 ignores it) and you can drop it whenever you like.

## Next steps [#next-steps]

* [How migrations work in Prisma ORM](https://www.prisma.io/docs/orm/migrations/how-migrations-work): the day-to-day `contract emit` → `migration plan` → `migrate` loop for schema changes
* [Contract authoring](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax): the full PSL syntax for evolving `contract.prisma`
* [Prisma ORM CLI reference](https://www.prisma.io/docs/cli): every command used in this guide

## Related pages

- [`Prisma ORM 6 to 8 (MongoDB)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb): Migrate a MongoDB project from Prisma ORM 6 to Prisma ORM 8
- [`Upgrade to v1`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v1): Guide for upgrading from Prisma 1 to Prisma ORM
- [`Upgrade to v3`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v3): Guide for upgrading to Prisma ORM v3
- [`Upgrade to v4`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v4): Guide for upgrading to Prisma ORM v4
- [`Upgrade to v5`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v5): Guide for upgrading to Prisma ORM v5

# Upgrade to v1 (/docs/guides/upgrade-prisma-orm/v1)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Guide for upgrading from Prisma 1 to Prisma ORM

Location: Guides > Upgrade Prisma ORM > Upgrade to v1

This guide covers migrating your project from Prisma 1 to Prisma ORM 7, the last release built on the `schema.prisma` workflow. Once you are on Prisma ORM 7, continue with the [Prisma ORM 7 to 8 guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql). The migration involves significant architectural changes, so plan it and test it in a separate environment before touching production.

## Before you begin [#before-you-begin]

* **Back up your database** before starting the migration
* Review the [Prisma ORM documentation](https://www.prisma.io/docs/orm/v7) to understand the new architecture
* Set up a separate development environment for testing the migration
* Document your current Prisma 1 setup, including models, relations, and any custom configurations

## Key changes [#key-changes]

### Architectural changes [#architectural-changes]

| Feature                 | Prisma 1                      | Prisma ORM                                |
| ----------------------- | ----------------------------- | ----------------------------------------- |
| **Database Connection** | Uses Prisma Server as a proxy | Direct database connection                |
| **API**                 | GraphQL API for database      | Programmatic access via Prisma Client     |
| **Schema**              | GraphQL SDL + `prisma.yml`    | Unified Prisma schema                     |
| **Modeling**            | GraphQL SDL                   | Prisma Schema Language (PSL)              |
| **Workflow**            | `prisma deploy`               | `prisma migrate` and `prisma db` commands |

### Feature changes [#feature-changes]

* **Removed**: GraphQL API for database
* **New**: Type-safe database client
* **Improved**: Database introspection and migration tools
* **Improved**: Support for more database features and types

## Migration Strategy [#migration-strategy]

### 1. Preparation [#1-preparation]

#### Install Prisma ORM [#install-prisma-orm]

  

#### bun

```bash
# Initialize a new project
bun init
bun add prisma@prev @prisma/client@7

# Initialize Prisma
bunx --bun prisma init
```

#### pnpm

```bash
# Initialize a new project
pnpm init
pnpm add prisma@prev @prisma/client@7

# Initialize Prisma
pnpm prisma init
```

#### yarn

```bash
# Initialize a new project
yarn init
yarn add prisma@prev @prisma/client@7

# Initialize Prisma
yarn prisma init
```

#### npm

```bash
# Initialize a new project
npm init
npm install prisma@prev @prisma/client@7

# Initialize Prisma
npx prisma init
```

#### Set up Database Connection [#set-up-database-connection]

Update the `DATABASE_URL` in your `.env` file to point to your existing database:

```bash
DATABASE_URL="postgresql://user:password@localhost:5432/your_database?schema=public"
```

### 2. Schema Migration [#2-schema-migration]

#### Introspect Database [#introspect-database]

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This will generate a `schema.prisma` file based on your existing database schema.

#### Update Schema [#update-schema]

After introspection, you'll need to make several adjustments to the schema:

##### Default Values [#default-values]

```prisma
// Before (Prisma 1)
model User {
  id        String   @default(cuid())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
```

##### Relations [#relations]

```prisma
// Before (Prisma 1)
type Post {
  id        ID!      @id
  title     String!
  author    User!    @relation(name: "UserPosts")
}

// After (Prisma ORM)
model Post {
  id        Int      @id @default(autoincrement())
  title     String
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}
```

### 3. Data Model Adjustments [#3-data-model-adjustments]

#### 3.1 Handling Special Types [#31-handling-special-types]

| Prisma 1 Type | Prisma ORM Equivalent         | Notes                      |
| ------------- | ----------------------------- | -------------------------- |
| `ID`          | `String @id @default(cuid())` | Add `@id` directive        |
| `DateTime`    | `DateTime`                    | No change needed           |
| `Json`        | `Json`                        | No change needed           |
| `Enum`        | `Enum`                        | Define enums in the schema |

#### 3.2 Relation Handling [#32-relation-handling]

Prisma ORM requires explicit relation fields and foreign keys:

```prisma
model User {
  id    Int     @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id])
  authorId Int
}
```

### 4. Update Application Code [#4-update-application-code]

#### 4.1 Replace Prisma 1 Client with Prisma Client [#41-replace-prisma-1-client-with-prisma-client]

```typescript
// Before (Prisma 1)
import { prisma } from './generated/prisma-client';

async function getUser(id: string) {
  return prisma.user({ id });
}

// After (Prisma ORM)
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

async function getUser(id: number) {
  return prisma.user.findUnique({
    where: { id }
  });
}
```

#### 4.2 Update Queries and Mutations [#42-update-queries-and-mutations]

##### Fetching Data [#fetching-data]

```typescript
// Before (Prisma 1)
const user = await prisma.user({ id: 1 });
const posts = await prisma.user({ id: 1 }).posts();

// After (Prisma ORM)
const user = await prisma.user.findUnique({
  where: { id: 1 },
  include: { posts: true }
});
const posts = user?.posts;
```

##### Creating Records [#creating-records]

```typescript
// Before (Prisma 1)
const newUser = await prisma.createUser({
  name: 'Alice',
  email: 'alice@example.com'
});

// After (Prisma ORM)
const newUser = await prisma.user.create({
  data: {
    name: 'Alice',
    email: 'alice@example.com'
  }
});
```

## Testing and Validation [#testing-and-validation]

### 1. Test Data Operations [#1-test-data-operations]

Test all CRUD operations to ensure data consistency:

```typescript
// Test create
const user = await prisma.user.create({
  data: { name: 'Test', email: 'test@example.com' }
});

// Test read
const foundUser = await prisma.user.findUnique({
  where: { id: user.id }
});

// Test update
const updatedUser = await prisma.user.update({
  where: { id: user.id },
  data: { name: 'Updated Name' }
});

// Test delete
await prisma.user.delete({
  where: { id: user.id }
});
```

### 2. Test Relations [#2-test-relations]

Verify that all relations work as expected:

```typescript
// Test relation queries
const userWithPosts = await prisma.user.findUnique({
  where: { id: 1 },
  include: {
    posts: true,
    profile: true
  }
});

// Test nested writes
const userWithNewPost = await prisma.user.create({
  data: {
    name: 'Bob',
    email: 'bob@example.com',
    posts: {
      create: {
        title: 'Hello World',
        content: 'This is my first post'
      }
    }
  },
  include: {
    posts: true
  }
});
```

## Handling Special Cases [#handling-special-cases]

### 1. Real-time Subscriptions [#1-real-time-subscriptions]

Prisma ORM doesn't include built-in real-time subscriptions. Consider these alternatives:

#### Option 1: Database Triggers [#option-1-database-triggers]

```sql
-- PostgreSQL example
CREATE OR REPLACE FUNCTION notify_new_post()
RETURNS TRIGGER AS $$
BEGIN
  PERFORM pg_notify('new_post', row_to_json(NEW)::text);
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER new_post_trigger
AFTER INSERT ON "Post"
FOR EACH ROW EXECUTE FUNCTION notify_new_post();
```

#### Option 2: Application-Level Events [#option-2-application-level-events]

```typescript
// Publish event when creating a post
const post = await prisma.post.create({
  data: {
    title: 'New Post',
    content: 'Content',
    author: { connect: { id: userId }}
  }
});

// Publish event to your pub/sub system
await pubsub.publish('POST_CREATED', { postCreated: post });
```

### 2. Authentication [#2-authentication]

If you were using Prisma 1's built-in authentication, you'll need to implement your own solution:

```typescript
import { compare } from 'bcryptjs';
import { sign } from 'jsonwebtoken';

export async function login(email: string, password: string) {
  const user = await prisma.user.findUnique({ where: { email } });
  if (!user) throw new Error('User not found');
  
  const valid = await compare(password, user.password);
  if (!valid) throw new Error('Invalid password');
  
  const token = sign({ userId: user.id }, process.env.APP_SECRET!);
  return { token, user };
}
```

## Migration Tools [#migration-tools]

### Prisma 1 Upgrade CLI [#prisma-1-upgrade-cli]

The [Prisma 1 Upgrade CLI](https://github.com/prisma/prisma1-upgrade) can help automate parts of the migration:

  

#### bun

```bash
# Install the upgrade CLI
bun add --global prisma1-upgrade

# Run the upgrade helper
prisma1-upgrade
```

#### pnpm

```bash
# Install the upgrade CLI
pnpm add -g prisma1-upgrade

# Run the upgrade helper
prisma1-upgrade
```

#### yarn

```bash
# Install the upgrade CLI
yarn global add prisma1-upgrade

# Run the upgrade helper
prisma1-upgrade
```

#### npm

```bash
# Install the upgrade CLI
npm install -g prisma1-upgrade

# Run the upgrade helper
prisma1-upgrade
```

This tool helps with:

* Converting your Prisma 1 datamodel to Prisma schema
* Identifying potential issues in your schema
* Providing migration recommendations

## Performance Considerations [#performance-considerations]

1. **Connection Pooling**: Configure a connection limit so the client does not exhaust your database connections:
   ```typescript
   const prisma = new PrismaClient({
     log: ['query', 'info', 'warn', 'error'],
     datasources: {
       db: {
         url: process.env.DATABASE_URL + '&connection_limit=20'
       }
     }
   });
   ```

2. **Query Optimization**: Use `select` to fetch only needed fields:
   ```typescript
   const user = await prisma.user.findUnique({
     where: { id: 1 },
     select: {
       id: true,
       name: true,
       email: true
     }
   });
   ```

## Next Steps [#next-steps]

Your project now runs on Prisma ORM 7. To move to the current release, follow the [Prisma ORM 7 to 8 guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql) (or the [MongoDB version](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb)).

* [Prisma ORM Documentation](https://www.prisma.io/docs/orm/v7)
* [Prisma Schema Reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference)
* [Prisma Client API Reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference)
* [Prisma Migrate Guide](https://www.prisma.io/docs/orm/v7/prisma-migrate)
* [Prisma Studio](https://www.prisma.io/studio)

## Getting Help [#getting-help]

If you encounter issues during migration:

1. Search the [GitHub Issues](https://github.com/prisma/orm/issues)
2. Ask for help in the [Prisma Slack](https://slack.prisma.io/)
3. Open a [GitHub Discussion](https://github.com/prisma/orm/discussions)

## Related pages

- [`Prisma ORM 6 to 8 (MongoDB)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb): Migrate a MongoDB project from Prisma ORM 6 to Prisma ORM 8
- [`Prisma ORM 7 to 8 (PostgreSQL)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql): Migrate a PostgreSQL project from Prisma ORM 7 to Prisma ORM 8 incrementally, with both versions running side by side
- [`Upgrade to v3`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v3): Guide for upgrading to Prisma ORM v3
- [`Upgrade to v4`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v4): Guide for upgrading to Prisma ORM v4
- [`Upgrade to v5`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v5): Guide for upgrading to Prisma ORM v5

# Upgrade to v3 (/docs/guides/upgrade-prisma-orm/v3)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Guide for upgrading to Prisma ORM v3

Location: Guides > Upgrade Prisma ORM > Upgrade to v3

This guide helps you upgrade your project to Prisma ORM v3. Version 3 includes several breaking changes that may affect your application, so review this guide before upgrading.

## Before you begin [#before-you-begin]

* **Backup your database** before starting the upgrade process
* Review the [release notes](https://github.com/prisma/orm/releases/tag/3.0.1) for a complete list of changes
* Test the upgrade in a development or staging environment first

## Key changes [#key-changes]

### Referential Actions [#referential-actions]

Prisma ORM 3 introduces native support for referential actions, which changes how cascading deletes are handled:

* The safety net that previously prevented cascading deletes at runtime has been removed
* You now have more control over referential actions
* You should explicitly define referential actions in your schema

#### Before (Prisma 2.x): [#before-prisma-2x]

```prisma
model User {
  id      Int      @id @default(autoincrement())
  posts   Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int
}
```

#### After (Prisma 3.x): [#after-prisma-3x]

```prisma
model User {
  id      Int      @id @default(autoincrement())
  posts   Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(
    fields: [authorId], 
    references: [id], 
    onDelete: Cascade,  // Explicit action required
    onUpdate: Cascade   // Optional: define update behavior
  )
  authorId Int
}
```

**Action Required**: Review all your relation fields and add appropriate `onDelete` and `onUpdate` actions.

### Named Constraints and Indexes [#named-constraints-and-indexes]

Prisma ORM 3 changes how constraints and indexes are named:

* New naming convention for constraints and indexes
* Clear distinction between `map` (database-level name) and `name` (Prisma Client API name)
* Primary and foreign key names are now part of the schema for supporting databases

#### Option 1: Keep Existing Constraint Names [#option-1-keep-existing-constraint-names]

If you need to maintain existing constraint names (for compatibility with other tools or conventions):

1. Run `prisma db pull` to update your schema with existing constraint names
2. The schema will include `@map` attributes for non-default constraint names

#### Option 2: Use New Default Naming Convention [#option-2-use-new-default-naming-convention]

To use Prisma ORM's new default naming convention:

1. Run `prisma migrate dev` to generate a migration updating constraint names
2. Apply the migration to all environments

**Example of constraint naming in schema**:

```prisma
model User {
  id    Int    @id(map: "Custom_Primary_Key") @default(autoincrement())
  email String @unique(map: "Custom_Unique_Constraint")
  posts Post[]
}

model Post {
  id        Int    @id @default(autoincrement())
  title     String
  author    User   @relation(fields: [authorId], references: [id], map: "Custom_Foreign_Key")
  authorId  Int
}
```

### `$queryRaw` Method Changes [#queryraw-method-changes]

The `$queryRaw` method now only supports template literals for security:

#### Before (Prisma 2.x): [#before-prisma-2x-1]

```typescript
// String syntax (no longer supported in v3)
const result = await prisma.$queryRaw('SELECT * FROM User WHERE id = 1');
```

#### After (Prisma 3.x): [#after-prisma-3x-1]

```typescript
// Template literal syntax (recommended)
const userId = 1;
const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${userId}`;

// Or use $queryRawUnsafe (use with caution)
const unsafeResult = await prisma.$queryRawUnsafe(
  'SELECT * FROM User WHERE id = $1', 
  userId
);
```

**Action Required**: Update all `$queryRaw` calls in your codebase to use template literals or switch to `$queryRawUnsafe` with proper parameterization.

### JSON Null Handling [#json-null-handling]

Prisma ORM 3 introduces more precise handling of null values in JSON fields:

* `{ equals: null }` now checks for database NULL values
* New types are available for different null representations:
  * `Prisma.JsonNull`: Represents a JSON null value
  * `Prisma.DbNull`: Represents a database NULL value
  * `Prisma.AnyNull`: Matches either JSON null or database NULL

#### Before (Prisma 2.x): [#before-prisma-2x-2]

```typescript
// Ambiguous behavior in v2
const result = await prisma.log.findMany({
  where: {
    meta: {
      equals: null // Could mean either JSON null or database NULL
    }
  }
});
```

#### After (Prisma 3.x): [#after-prisma-3x-2]

```typescript
import { Prisma } from '@prisma/client';

// Check for JSON null
const jsonNullResults = await prisma.log.findMany({
  where: {
    meta: {
      equals: Prisma.JsonNull
    }
  }
});

// Check for database NULL
const dbNullResults = await prisma.log.findMany({
  where: {
    meta: {
      equals: Prisma.DbNull
    }
  }
});

// Check for either
const anyNullResults = await prisma.log.findMany({
  where: {
    meta: {
      equals: Prisma.AnyNull
    }
  }
});

// Creating with specific null types
await prisma.log.create({
  data: {
    meta: Prisma.JsonNull // or Prisma.DbNull
  }
});
```

**Action Required**: Update all JSON field operations that involve null values to use the appropriate null type.

## Update packages [#update-packages]

To upgrade to Prisma ORM 3 from an earlier version, you need to update both the `prisma` and `@prisma/client` packages:

  

#### bun

```bash
bun add @prisma/client@3
bun add --dev prisma@3
bunx prisma generate
```

#### pnpm

```bash
pnpm add @prisma/client@3
pnpm add -D prisma@3
pnpm prisma generate
```

#### yarn

```bash
yarn add @prisma/client@3
yarn add --dev prisma@3
yarn prisma generate
```

#### npm

```bash
npm install @prisma/client@3
npm install -D prisma@3
npx prisma generate
```

> [!NOTE]
> For yarn, use `yarn up prisma@3 @prisma/client@3`. For pnpm, use `pnpm upgrade prisma@3 @prisma/client@3`.

> [!CAUTION]
> Before you upgrade, check each breaking change below to see how the upgrade might affect your application.

## Upgrade steps [#upgrade-steps]

1. **Add Referential Actions**: Update your schema to include explicit `onDelete` and `onUpdate` actions for all relations.
2. **Handle Constraint Naming**: Decide whether to keep existing constraint names or migrate to the new naming convention.
3. **Update JSON Fields**: Modify any JSON field operations that involve null values to use the new null types.

### 4. Update Application Code [#4-update-application-code]

1. **Update Raw Queries**: Convert all `$queryRaw` calls to use template literals or switch to `$queryRawUnsafe`.
2. **Test Thoroughly**: Pay special attention to:
   * Relations and cascading deletes
   * JSON field operations
   * Any raw SQL queries
   * Custom constraints and indexes

### 5. Migration Strategy for Production [#5-migration-strategy-for-production]

1. **Test in Development**: Test the upgrade in a development or staging environment first.
2. **Create a Backup**: Always create a backup of your production database before upgrading.
3. **Schedule Downtime**: Plan for a maintenance window if needed.
4. **Deploy Updates**: Update your application with the new Prisma ORM 3 packages.
5. **Monitor**: Keep an eye on your application after the upgrade.

## Troubleshooting [#troubleshooting]

### Common Issues [#common-issues]

1. **Missing Referential Actions**
   * **Symptom**: Unexpected behavior with cascading deletes
   * **Solution**: Add explicit `onDelete` and `onUpdate` actions to your relations

2. **JSON Null Handling**
   * **Symptom**: Type errors when filtering JSON fields
   * **Solution**: Use `Prisma.JsonNull`, `Prisma.DbNull`, or `Prisma.AnyNull`

3. **Raw Query Errors**
   * **Symptom**: Errors with `$queryRaw`
   * **Solution**: Convert to template literals or use `$queryRawUnsafe`

## Next Steps [#next-steps]

* [Prisma ORM 3 Release Notes](https://github.com/prisma/orm/releases/tag/3.0.1)
* [Prisma Schema Reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference)
* [Prisma Client API Reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference)
* [Raw Database Access](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries)

## Related pages

- [`Prisma ORM 6 to 8 (MongoDB)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb): Migrate a MongoDB project from Prisma ORM 6 to Prisma ORM 8
- [`Prisma ORM 7 to 8 (PostgreSQL)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql): Migrate a PostgreSQL project from Prisma ORM 7 to Prisma ORM 8 incrementally, with both versions running side by side
- [`Upgrade to v1`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v1): Guide for upgrading from Prisma 1 to Prisma ORM
- [`Upgrade to v4`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v4): Guide for upgrading to Prisma ORM v4
- [`Upgrade to v5`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v5): Guide for upgrading to Prisma ORM v5

# Upgrade to v4 (/docs/guides/upgrade-prisma-orm/v4)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Guide for upgrading to Prisma ORM v4

Location: Guides > Upgrade Prisma ORM > Upgrade to v4

This guide helps you upgrade your project to Prisma ORM 4. Version 4 includes several breaking changes that may affect your application, so review this guide before upgrading.

## Before you begin [#before-you-begin]

* **Back up your database** before starting the upgrade
* Review the [release notes](https://github.com/prisma/orm/releases/tag/4.0.0) for a complete list of changes
* Test the upgrade in a development or staging environment first
* Ensure you're using Node.js 14.17.0 or later (required for Prisma 4+)

## Key changes [#key-changes]

### System requirements [#system-requirements]

* **Minimum Node.js version**: 14.17.0 or later
* **Database versions**: Check [system requirements](https://www.prisma.io/docs/orm/v7/reference/system-requirements) for database version compatibility

### Breaking changes [#breaking-changes]

1. **Schema Changes**
   * Explicit `@unique` constraints for one-to-one relations
   * Enforced `@unique` or `@id` for one-to-one and one-to-many relations in MySQL/MongoDB
   * Scalar list defaults
   * Index configuration improvements
   * Better string literal grammar

2. **Client changes**
   * `queryRaw` return type changes
   * JSON null handling updates
   * MongoDB composite type default fields
   * Removed deprecated APIs

## Update packages [#update-packages]

To upgrade to Prisma ORM 4 from an earlier version, you need to update both the `prisma` and `@prisma/client` packages:

  

#### bun

```bash
bun add @prisma/client@4
bun add --dev prisma@4
bunx prisma generate
```

#### pnpm

```bash
pnpm add @prisma/client@4
pnpm add -D prisma@4
pnpm prisma generate
```

#### yarn

```bash
yarn add @prisma/client@4
yarn add --dev prisma@4
yarn prisma generate
```

#### npm

```bash
npm install @prisma/client@4
npm install -D prisma@4
npx prisma generate
```

> [!CAUTION]
> Before you upgrade, check each breaking change below to see how the upgrade might affect your application.

## Upgrade steps [#upgrade-steps]

1. **Update Schema**: Review and update your schema to handle breaking changes
2. **Update Application Code**: Make necessary changes to your application code
3. **Test Thoroughly**: Test all functionality, especially:
   * One-to-one relations
   * JSON field operations
   * Raw queries
   * Index configurations

### Update schema [#update-schema]

#### Handle Schema Validation Errors [#handle-schema-validation-errors]

Run the following command to check for schema validation errors:

  

#### bun

```bash
bunx prisma validate
```

#### pnpm

```bash
pnpm prisma validate
```

#### yarn

```bash
yarn prisma validate
```

#### npm

```bash
npx prisma validate
```

Address any validation errors, paying special attention to:

1. **Explicit `@unique` constraints for one-to-one relations**

   * Add `@unique` to relation scalar fields in one-to-one relations

   ```prisma
   // Before
   model User {
     id      Int      @id @default(autoincrement())
     profile Profile? @relation(fields: [profileId], references: [id])
     profileId Int?
   }

   // After
   model User {
     id        Int      @id @default(autoincrement())
     profile   Profile? @relation(fields: [profileId], references: [id])
     profileId Int?     @unique  // Added @unique
   }
   ```

2. **Enforced `@unique` or `@id` for relations in MySQL/MongoDB**

   * Ensure referenced fields in one-to-one and one-to-many relations have `@unique` or `@id`

   ```prisma
   // Before (MySQL/MongoDB)
   model User {
     id    Int    @id @default(autoincrement())
     email String  // Missing @unique
     posts Post[]
   }

   // After (MySQL/MongoDB)
   model User {
     id    Int    @id @default(autoincrement())
     email String @unique  // Added @unique
     posts Post[]
   }
   ```

3. **Update SQLite connection strings**
   * Remove the `sqlite:` protocol prefix if present
   * Change from: `sqlite:./dev.db`
   * To: `file:./dev.db`

4. **String literals**
   * Update any string literals that use the old grammar
   * Change from: `a string with \"quotes\"`
   * To: `a string with \"quotes\"` or `a string with "quotes"`

#### Pull Latest Schema Changes [#pull-latest-schema-changes]

After fixing validation errors, pull the latest schema changes:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This will update your schema with new capabilities like improved index configuration.

### Update application code [#update-application-code]

#### Handle `queryRaw` Return Type Changes [#handle-queryraw-return-type-changes]

In Prisma 4, the return types of `queryRaw` and `queryRawUnsafe` have changed:

| Data Type  | Before 4.0.0 | From 4.0.0 |
| ---------- | ------------ | ---------- |
| `DateTime` | `String`     | `Date`     |
| `BigInt`   | `String`     | `BigInt`   |
| `Bytes`    | `String`     | `Buffer`   |
| `Decimal`  | `String`     | `Decimal`  |

**Update your code** to handle these type changes, especially if you're using TypeScript or performing type checks.

#### Update JSON Handling [#update-json-handling]

Prisma 4 changes how JSON null values are handled. If you're working with JSON fields:

```typescript
// Before
const result = await prisma.model.findMany({
  where: {
    jsonField: { equals: null }
  }
});

// After
import { Prisma } from '@prisma/client';

const result = await prisma.model.findMany({
  where: {
    jsonField: { equals: Prisma.JsonNull }
  }
});
```

#### MongoDB Composite Types [#mongodb-composite-types]

For MongoDB users, Prisma 4 changes how default fields on composite types work. If you're using MongoDB with composite types, test your queries to ensure they return the expected results.

### Test application [#test-application]

After updating your schema and code, thoroughly test your application:

1. **Run your test suite** to catch any type errors or runtime issues
2. **Test database operations** including:
   * CRUD operations
   * Relations and nested queries
   * Transactions
   * Raw queries
3. **Verify performance** of common operations
4. **Check error handling** for edge cases

## New Features in Prisma 4 [#new-features-in-prisma-4]

### 1. Improved Index Configuration (GA) [#1-improved-index-configuration-ga]

The `extendedIndexes` feature is now generally available, with support for:

* **Length configuration** for MySQL indexes
* **Sort order** configuration for indexes
* **Additional index types** for PostgreSQL:
  * Hash
  * GIN
  * GiST
  * SP-GiST
  * BRIN
* **Index clustering** for SQL Server

Example usage:

```prisma
model User {
  id    Int    @id
  email String @unique(sort: Desc)
  name  String

  @@index([name(sort: Asc, length: 10)])
  @@index([email], type: Hash)  // PostgreSQL specific
}
```

### 2. Scalar List Defaults [#2-scalar-list-defaults]

You can now set default values for scalar lists in your schema:

```prisma
model User {
  id             Int      @id @default(autoincrement())
  favoriteColors String[] @default(["red", "blue", "green"])
  luckyNumbers   Int[]    @default([7, 42])
}
```

### 3. Better Type Safety [#3-better-type-safety]

Prisma 4 improves type safety with:

* Stricter validation of relation fields
* Better error messages for common mistakes
* Improved type inference for complex queries

## Migration checklist [#migration-checklist]

### Before Upgrading [#before-upgrading]

* [ ] Back up your database
* [ ] Check Node.js version (14.17.0 or later required)
* [ ] Review breaking changes in this guide
* [ ] Set up a testing environment

### During Upgrade [#during-upgrade]

* [ ] Update dependencies to Prisma 4
* [ ] Fix schema validation errors
* [ ] Update relation fields with required `@unique` constraints
* [ ] Update raw query handling for new return types
* [ ] Test JSON field operations
* [ ] Verify MongoDB composite type behavior if applicable

### After Upgrading [#after-upgrading]

* [ ] Run your full test suite
* [ ] Test all critical paths in your application
* [ ] Monitor performance in production
* [ ] Update any documentation that references Prisma versions

## Troubleshooting [#troubleshooting]

### Common Issues [#common-issues]

1. **Schema Validation Errors**
   * **Symptom**: Errors about missing `@unique` constraints
   * **Solution**: Add `@unique` to required relation fields

2. **Type Errors in `queryRaw`**
   * **Symptom**: Type errors after upgrade
   * **Solution**: Update type definitions to match new return types

3. **JSON Null Handling**
   * **Symptom**: Different behavior with JSON nulls
   * **Solution**: Use `Prisma.JsonNull`, `Prisma.DbNull`, or `Prisma.AnyNull` explicitly

## Next Steps [#next-steps]

* [Prisma 4.0.0 Release Notes](https://github.com/prisma/orm/releases/tag/4.0.0)
* [Prisma Schema Reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference)
* [Prisma Client API Reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference)
* [Raw Database Access](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries)

## Getting Help [#getting-help]

If you encounter issues during the upgrade:

1. Check the [GitHub Issues](https://github.com/prisma/orm/issues) for known problems
2. Ask for help in the [Prisma Slack](https://slack.prisma.io/)
3. Open a [GitHub Discussion](https://github.com/prisma/orm/discussions)

## Related pages

- [`Prisma ORM 6 to 8 (MongoDB)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb): Migrate a MongoDB project from Prisma ORM 6 to Prisma ORM 8
- [`Prisma ORM 7 to 8 (PostgreSQL)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql): Migrate a PostgreSQL project from Prisma ORM 7 to Prisma ORM 8 incrementally, with both versions running side by side
- [`Upgrade to v1`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v1): Guide for upgrading from Prisma 1 to Prisma ORM
- [`Upgrade to v3`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v3): Guide for upgrading to Prisma ORM v3
- [`Upgrade to v5`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v5): Guide for upgrading to Prisma ORM v5

# Upgrade to v5 (/docs/guides/upgrade-prisma-orm/v5)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Guide for upgrading to Prisma ORM v5

Location: Guides > Upgrade Prisma ORM > Upgrade to v5

Prisma ORM v5.0.0 introduces a number of changes, including the usage of our new JSON Protocol, [which makes Prisma Client faster by default](https://www.prisma.io/blog/prisma-5-f66prwkjx72s). A full list of these changes can be found [in our release notes](https://github.com/prisma/orm/releases/tag/5.0.0).

This guide explains how upgrading might affect your application and gives instructions on how to handle breaking changes within Prisma ORM 5.

## Update packages [#update-packages]

To upgrade to Prisma ORM 5 from an earlier version, you need to update both the `prisma` and `@prisma/client` packages.

  

#### bun

```bash
bun add @prisma/client@5
bun add --dev prisma@5
bunx prisma generate
```

#### pnpm

```bash
pnpm add @prisma/client@5
pnpm add -D prisma@5
pnpm prisma generate
```

#### yarn

```bash
yarn add @prisma/client@5
yarn add --dev prisma@5
yarn prisma generate
```

#### npm

```bash
npm install @prisma/client@5
npm install -D prisma@5
npx prisma generate
```

> [!CAUTION]
> Before you upgrade, check each breaking change below to see how the upgrade might affect your application.

## Prerequisites [#prerequisites]

Prisma ORM 5 includes some minimum version changes for Node.js, TypeScript, and PostgreSQL. To use Prisma version 5.0.0 and up, you will need to have at least the minimum versions below:
See our [system requirements](https://www.prisma.io/docs/orm/v7/reference/system-requirements) for all minimum version requirements.

### Node.js version [#nodejs-version]

From Prisma ORM version 5.0.0, the minimum version of Node.js supported is 16.13.0. If your project uses an earlier version of Node.js, you will need to upgrade it.

> [!WARNING]
> Node.js v16.x is reaching [end-of-life on 11 September 2023](https://nodejs.org/en/blog/announcements/nodejs16-eol) in order to coincide with the end-of-life of OpenSSL 1.1.1. For that reason, we recommend upgrading to the current Node.js LTS, v18.x. Please note that Prisma ORM 5 will be the last major version of Prisma ORM to support Node.js v16.

### TypeScript version [#typescript-version]

From Prisma ORM version 5.0.0, the minimum version of TypeScript supported is 4.7. If your project uses an earlier version of TypeScript, you will need to upgrade it.

### PostgreSQL version [#postgresql-version]

From Prisma ORM version 5.0.0, the minimum version of PostgreSQL supported is 9.6. If your project uses an earlier version of PostgreSQL, you will need to upgrade it.

> [!WARNING]
> While Prisma ORM supports PostgreSQL versions 9.6 and above, we **strongly** recommend updating to a version that is currently supported and still receiving updates. Please check [PostgreSQL's versioning policy](https://www.postgresql.org/support/versioning/) to determine which versions are currently supported.

### SQLite version [#sqlite-version]

With Prisma ORM version 5.0.0, we have upgraded the embedded version of SQLite from `3.35.4` to `3.41.2`. We did not see any breaking changes and don't anticipate any changes needed in user projects, but if you are using SQLite, especially with raw queries that might go beyond Prisma ORM's functionality, make sure to check [the SQLite changelog](https://www.sqlite.org/changes.html).

## Breaking changes [#breaking-changes]

This section gives an overview of the main breaking changes in Prisma ORM 5.

### Removed `rejectOnNotFound` [#removed-rejectonnotfound]

With Prisma ORM 5, the deprecated parameter `rejectOnNotFound` has been removed. Depending on if your project used `rejectOnNotFound` per query or globally, there will be different ways of updating your code.

If you are using the `rejectOnNotFound` parameter on a per-query basis, then follow our steps for [updating your code at the query level](#removed-rejectonnotfound).

If instead you have set up the `rejectOnNotFound` parameter at the client level, you will need to follow [the steps for updating your code at the client level](#removed-rejectonnotfound).

### JSON protocol [#json-protocol]

The `jsonProtocol` preview feature is now Generally Available. This new protocol leads to [significantly improved startup times](https://www.prisma.io/blog/prisma-5-f66prwkjx72s#improved-startup-performance-in-prisma-client) when compared to our previous GraphQL-based protocol. When upgrading to Prisma ORM 5, make sure to remove `jsonProtocol` from your preview features, if added.

Prisma ORM 4 and lower:

```prisma
generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["jsonProtocol"]
}
```

Prisma ORM 5:

```prisma
generator client {
  provider = "prisma-client-js"
}
```

### Removed Array Shortcuts [#removed-array-shortcuts]

Prisma ORM 5 drops support for a number of "array shortcuts". These shortcuts were a way to add a single element as a value to an array-based operator instead of wrapping that one element in an array. To make our typings more consistent and logical and to conform to the new JSON Protocol, we now require array values for these operators.

In most cases, the fix is to wrap the existing value in an array. The shortcuts removed in Prisma ORM 5 are:

* `OR` shortcuts
* `in` and `notIn` shortcuts
* PostgreSQL JSON `path` field shortcuts
* Scalar list shortcuts
* MongoDB Composite list shortcuts

While `OR`, `in`, and `notIn` operators are affected, `AND` and `NOT` are not affected by this change.

### `cockroachdb` provider is now required when connecting to a CockroachDB database [#cockroachdb-provider-is-now-required-when-connecting-to-a-cockroachdb-database]

With Prisma ORM version 5.0.0, we require the `cockroachdb` provider to be used when connecting to CockroachDB databases. Previously, we had accepted `postgresql` as well, but we are removing that option.

If you were using [native database types](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#postgresql) and also the `postgresql` provider, you will need to [baseline your database](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/cockroachdb#5-baseline-your-database) from PostgreSQL to CockroachDB:

1. Backup your existing `schema.prisma` file (e.g. use version control)
2. Update your `datasource` provider from `postgresql` to `cockroachdb`
3. Use `npx prisma db pull --force` in order to overwrite your existing Prisma schema (including native types) to those that are on your CockroachDB instance.
4. Review changes between your Prisma schema backup and the new Prisma schema generated by `db pull`. You can either use the new schema as is, or update it to include your preferred spacing, comments, etc.
5. Delete your existing migrations. We will be [performing a baseline](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/cockroachdb#5-baseline-your-database) in order to make your local setup agree with your existing CockroachDB instance.
6. Perform the [baselining steps](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/cockroachdb#5-baseline-your-database). After these steps, you'll have migrated successfully from the `postgresql` provider to the `cockroachdb` provider!

### Removed `runtime/index.js` [#removed-runtimeindexjs]

The `runtime/index.js` file has been removed from Prisma Client.

#### Using public APIs from `@prisma/client/runtime` [#using-public-apis-from-prismaclientruntime]

Importing from `@prisma/client/runtime` is no longer available in Prisma ORM 5. If you were using public APIs available in this namespace before, you can instead import `Prisma` and access them. For example:

```js
import { Decimal, NotFoundError } from "@prisma/client/runtime";
const num = new Decimal(24.454545);
const notFound = new NotFoundError();
```

will need to be changed to

```js
import { Prisma } from "@prisma/client";
const num = new Prisma.Decimal(24.454545);
const notFound = new Prisma.NotFoundError();
```

#### Using private APIs for a specific runtime [#using-private-apis-for-a-specific-runtime]

We highly discourage the use of internal private APIs as they can change without warning and are not guaranteed to be supported. If your usage requires a private API that was previous available [please reach out to us on GitHub.](https://github.com/prisma/orm/discussions/new?category=q-a)

### Generated type changes [#generated-type-changes]

#### Changes to `RelationFilterInput` to account for nullability [#changes-to-relationfilterinput-to-account-for-nullability]

Prior to Prisma ORM 5, there was a long-standing bug that caused nullable reverse relations to not be marked as nullable in our generated types. For example, take the following schema:

```prisma
model User {
  id Int @id

  addressId Int     @unique
  address   Address @relation(fields: [addressId], references: [id])

  post Post[]
}

model Address {
  id Int @id

  user User?
}

model Post {
  id Int @id

  userId Int
  user   User @relation(fields: [userId], references: [id])
}
```

In the generated types, `Address.user` and `Post.user` would use the same type, `UserRelationFilter`. This is obviously unintended as `Address.user` is nullable while `Post.user` is not. In Prisma ORM 5, the type of `Address.user` would be `UserNullableRelationFilter`, resolving this issue.

If you import generated types in your code, you will need to update instances like this to use the new `Nullable` types.

#### Changes to `UncheckedUpdateManyInput` to avoid name collisions [#changes-to-uncheckedupdatemanyinput-to-avoid-name-collisions]

In certain instances it was possible for name collisions to occur when one model had two foreign keys to two other models that had the same property name for the reverse relation. As an example, the following schema:

```prisma
model Invoice {
  InvoiceId Int @id @default(autoincrement())

  invoice_items InvoiceItem[]
}

model InvoiceItem {
  InvoiceLineId Int @id @default(autoincrement())

  InvoiceItemInvoiceId Int     @map("InvoiceId")
  invoices             Invoice @relation(fields: [InvoiceItemInvoiceId], references: [InvoiceId])

  TrackId Int
  tracks  Track @relation(fields: [TrackId], references: [TrackId])
}

model Track {
  TrackId Int    @id @default(autoincrement())
  Name    String

  invoice_items InvoiceItem[]
}
```

Would lead to conflicting names between the two relations on `InvoiceItem`. The reverse relations, that is `Invoice.invoice_items` and `Track.invoice_items` would both get the type `InvoiceItemUncheckedUpdateManyWithoutInvoice_itemsInput`. In Prisma ORM 5, this is resolved and Prisma Client will generate `InvoiceItemUncheckedUpdateManyWithoutInvoicesInput` and `InvoiceItemUncheckedUpdateManyWithoutTracksInput` respectively.

If you import generated types in your code, you will need to update instances like this to the corrected types.

## Other Changes [#other-changes]

### Removal of deprecated Prisma CLI flags [#removal-of-deprecated-prisma-cli-flags]

Several deprecated CLI flags have been removed. All following flags are from previous APIs and are no longer needed:

* `--preview-feature` used in `db execute`, `db seed`, and `db diff`
* `--experimental` and `--early-access-feature` used in `migrate`
* `--force`/`-f` used in `db push`
* `--experimental-reintrospection` and `--clean` used in `db pull`

The outdated use of `db push --force` can be replaced with the newer implementation `db push --accept-data-loss`.

### Removal of the `beforeExit` hook from the library engine [#removal-of-the-beforeexit-hook-from-the-library-engine]

The `beforeExit` hook has been removed from the Prisma ORM library engine. While this functionality is still required for the Prisma ORM binary engine in order to run last minute queries or perform shutdown related operations, it provides no benefit over native Node.js exit hooks in the library engine. Instead of this hook we recommend using built-in Node.js exit events.

The following code with Prisma ORM 4:

```js
const exitHandler = () => {
  // your exit handler code
};

prisma.$on("beforeExit", exitHandler);
```

Could become:

```js
const exitHandler = () => {
  // your exit handler code
};

process.on("exit", exitHandler);
process.on("beforeExit", exitHandler);
process.on("SIGINT", exitHandler);
process.on("SIGTERM", exitHandler);
process.on("SIGUSR2", exitHandler);
```

If you're using the `beforeExit` hook in NestJS, you can upgrade to Prisma ORM 5 by removing the custom `enableShutdownHooks` method in your service:

```diff title="prisma.service.ts"
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect()
  }

-  async enableShutdownHooks(app: INestApplication) {
-    this.$on('beforeExit', async () => {
-      await app.close()
-    })
-  }
}
```

Instead, use the built-in `enableShutdownHooks` method in NestJS if you need to handle lifecycle events:

```diff title="main.ts"
- prismaService.enableShutdownHooks(app)
+ app.enableShutdownHooks()
```

### Removal of deprecated `prisma2` executable [#removal-of-deprecated-prisma2-executable]

When we released Prisma ORM 2, the `prisma2` executable was used in order to differentiate from Prisma 1. In a later release, the `prisma2` cli took over the `prisma` executable name.

The `prisma2` executable has been deprecated for some time and is now removed. If your scripts use Prisma CLI as `prisma2`, replace it with `prisma`.

### Removed `experimentalFeatures` [#removed-experimentalfeatures]

The `previewFeatures` field of the [generator block](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#generator) used to be called `experimentalFeatures`. We are removing that deprecated property.

In Prisma ORM 5, you will need to update references of `experimentalFeatures` to `previewFeatures` manually or use the new code action in the Prisma VSCode extension.

### Renamed `migration-engine` to `schema-engine` [#renamed-migration-engine-to-schema-engine]

The engine responsible for commands like `prisma migrate` and `prisma db` has been renamed from `migration-engine` to `schema-engine` to better describe its use. For many users, no changes will be required. However, if you need to explicitly include or exclude this engine file, or refer to the engine name for any other reason, you will need to update your code references.

#### Example with the Serverless Framework [#example-with-the-serverless-framework]

One example we have seen is projects using the Serverless Framework. In these instances, you will need to update any patterns that reference `migration-engine` to instead reference `schema-engine`.

```yaml highlight=6;delete|7;add
package:
  patterns:
    - '!node_modules/.prisma/client/libquery_engine-*'
    - 'node_modules/.prisma/client/libquery_engine-rhel-*'
    - '!node_modules/prisma/libquery_engine-*'
    -- '!node_modules/prisma/migration-engine-*'
    -- '!node_modules/prisma/schema-engine-*'
```

**Serverless Framework pattern suggestion**

Be sure to include the `@prisma/engines` folder in your package patterns.

```yaml highlight=6;normal
package:
  patterns:
    - '!node_modules/.prisma/client/libquery_engine-*'
    - 'node_modules/.prisma/client/libquery_engine-rhel-*'
    - '!node_modules/prisma/libquery_engine-*'
    -- '!node_modules/@prisma/engines/**'
```

## Related pages

- [`Prisma ORM 6 to 8 (MongoDB)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb): Migrate a MongoDB project from Prisma ORM 6 to Prisma ORM 8
- [`Prisma ORM 7 to 8 (PostgreSQL)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql): Migrate a PostgreSQL project from Prisma ORM 7 to Prisma ORM 8 incrementally, with both versions running side by side
- [`Upgrade to v1`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v1): Guide for upgrading from Prisma 1 to Prisma ORM
- [`Upgrade to v3`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v3): Guide for upgrading to Prisma ORM v3
- [`Upgrade to v4`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v4): Guide for upgrading to Prisma ORM v4

# Upgrade to v6 (/docs/guides/upgrade-prisma-orm/v6)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Guide for upgrading to Prisma ORM v6

Location: Guides > Upgrade Prisma ORM > Upgrade to v6

Prisma ORM v6 introduces a number of **breaking changes** when you upgrade from an earlier Prisma ORM version. This guide explains how this upgrade might affect your application and gives instructions on how to handle any changes.

**Questions answered in this page**

* What changed in Prisma 6?
* How do I upgrade safely?
* Which breaking changes affect my app?

## Update packages [#update-packages]

To upgrade to Prisma ORM v6 from an earlier version, you need to update both the `prisma` and `@prisma/client` packages:

  

#### bun

```bash
bun add @prisma/client@6
bun add --dev prisma@6
```

#### pnpm

```bash
pnpm add @prisma/client@6
pnpm add -D prisma@6
```

#### yarn

```bash
yarn add @prisma/client@6
yarn add --dev prisma@6
```

#### npm

```bash
npm install @prisma/client@6
npm install -D prisma@6
```

> [!NOTE]
> For yarn, use `yarn up prisma@6 @prisma/client@6`. For pnpm, use `pnpm upgrade prisma@6 @prisma/client@6`. For bun, use `bun add @prisma/client@6` and `bun add prisma@6 --dev`.

> [!CAUTION]
> Before you upgrade, check each breaking change below to see how the upgrade might affect your application.

## Breaking changes [#breaking-changes]

This section gives an overview of breaking changes in Prisma ORM v6.

### Minimum supported Node.js versions [#minimum-supported-nodejs-versions]

The new minimum supported Node.js versions for Prisma ORM v6 are:

* for Node.js 18 the minimum supported version is **18.18.0**
* for Node.js 20 the minimum supported version is **20.9.0**
* for Node.js 22 the minimum supported version is **22.11.0**

There is *no* official support for Node.js 16, 17, 19 and 21.

### Minimum supported TypeScript version [#minimum-supported-typescript-version]

The new minimum supported TypeScript version for Prisma ORM v6 is: **5.1.0**.

> [!NOTE]
> This schema change only applies to PostgreSQL.\
> If you are using CockroachDB, you do not need to take any action; the schema for implicit m-to-n relationships remains unchanged.

### Schema change for implicit m-n relations on PostgreSQL [#schema-change-for-implicit-m-n-relations-on-postgresql]

If you're using PostgreSQL and are defining [implicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations) in your Prisma schema, Prisma ORM maintains the [relation table](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#relation-table-conventions) for you under the hood. This relation table has `A` and `B` columns to represent the tables of the models that are part of this relation.

Previous versions of Prisma ORM used to create a *unique index* on these two columns. In Prisma v6, this unique index is changing to a *primary key* in order to [simplify for the default replica identity behaviour](https://github.com/prisma/orm/issues/25196).

**Expand for an example**

As an example, consider the following Prisma schema with an implicit m-n relation between `Post` and `Tag` models:

```prisma
model Post {
  id         Int    @id @default(autoincrement())
  title      String
  categories Tag[]
}

model Tag {
  id    Int    @id @default(autoincrement())
  name  String
  posts Post[]
}
```

In this case, Prisma ORM maintains the following relation table for you under the hood:

```sql
-- CreateTable
CREATE TABLE "_PostToTag" (
    "A" INTEGER NOT NULL,
    "B" INTEGER NOT NULL
);

-- CreateIndex
CREATE UNIQUE INDEX "_PostToTag_AB_unique" ON "_PostToTag"("A", "B"); 

-- CreateIndex
CREATE INDEX "_PostToTag_B_index" ON "_PostToTag"("B");

-- AddForeignKey
ALTER TABLE "_PostToTag" ADD CONSTRAINT "_PostToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Post"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_PostToTag" ADD CONSTRAINT "_PostToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
```

In Prisma v6, the `UNIQUE INDEX` is changing into a `PRIMARY KEY`:

```sql
-- CreateTable
CREATE TABLE "_PostToTag" (
    "A" INTEGER NOT NULL,
    "B" INTEGER NOT NULL,

    CONSTRAINT "_PostToTag_AB_pkey" PRIMARY KEY ("A","B") 
);

-- CreateIndex
CREATE INDEX "_PostToTag_B_index" ON "_PostToTag"("B");

-- AddForeignKey
ALTER TABLE "_PostToTag" ADD CONSTRAINT "_PostToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Post"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_PostToTag" ADD CONSTRAINT "_PostToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
```

If you're defining implicit m-n relations in your Prisma schema, **the next migration you'll create will contain `ALTER TABLE` statements for *all* the relation tables** that belong to these relations. These will look similar to this:

```sql
-- AlterTable
ALTER TABLE "_PostToTag" ADD CONSTRAINT "_PostToTag_AB_pkey" PRIMARY KEY ("A", "B");

-- DropIndex
DROP INDEX "_PostToTag_AB_unique";
```

In order to isolate these schema changes (and not having them bundled with your next migration), **we recommend that you create a new migration *right after* having upgraded to Prisma v6**:

  

#### bun

```bash
bunx prisma migrate dev --name upgrade-to-v6
```

#### pnpm

```bash
pnpm prisma migrate dev --name upgrade-to-v6
```

#### yarn

```bash
yarn prisma migrate dev --name upgrade-to-v6
```

#### npm

```bash
npx prisma migrate dev --name upgrade-to-v6
```

That way, you have a single, dedicated migration that takes care of this schema change and otherwise keeps your migration history clean.

### Full-text search on PostgreSQL [#full-text-search-on-postgresql]

The [`fullTextSearch`](https://www.prisma.io/docs/orm/v6/prisma-client/queries/full-text-search) Preview feature is promoted to General Availability only for MySQL. This means that if you're using PostgreSQL and currently make use of this Preview feature, you now need to use the new [`fullTextSearchPostgres`](https://www.prisma.io/docs/orm/v6/prisma-client/queries/full-text-search#enabling-full-text-search-for-postgresql) Preview feature:

#### Before [#before]

```prisma title="schema.prisma"
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["fullTextSearch"] 
}
```

#### After [#after]

```prisma title="schema.prisma"
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["fullTextSearchPostgres"] 
}
```

### Usage of `Buffer` [#usage-of-buffer]

In an effort to improve compatibility between Prisma and newer JavaScript runtimes, we're gradually moving away from Node.js-specific APIs in favor of standard JavaScript.

Prisma v6 replaces the usage of [`Buffer`](https://nodejs.org/api/buffer.html) with [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) to represent fields of type `Bytes`. Make sure to replace all your occurrences of the `Buffer` type with the new `Uint8Array`.

**Expand to view how to convert between <code>Buffer</code> and <code>Uint8Array</code>**

### Conversion from `Buffer` to `Uint8Array` [#conversion-from-buffer-to-uint8array]

You can directly use the `Buffer` instance as a `Uint8Array`:

```ts
const buffer: Buffer = Buffer.from([1, 2, 3, 4]);
const uint8Array: Uint8Array = buffer; // No conversion needed
```

### Conversion from `Uint8Array` to `Buffer` [#conversion-from-uint8array-to-buffer]

You can create a `Buffer` from a `Uint8Array` using `Buffer.from`:

```ts
const uint8Array: Uint8Array = new Uint8Array([1, 2, 3, 4]);
const buffer: Buffer = Buffer.from(uint8Array.buffer);
```

#### Before [#before-1]

  

#### Code

```ts
import { PrismaClient } from "@prisma/client";

async function main() {
  const prisma = new PrismaClient();
  await prisma.user.deleteMany();

  const bytesCreated = await prisma.user.create({
    data: {
      bytes: Buffer.from([1, 2, 3, 4]),
    },
  });
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^
  // `bytesCreated` used to have type: {
  //    bytes: Buffer
  //    id: number
  // }

  for (const bytesFound of await prisma.user.findMany()) {
    bytesFound.bytes; // Buffer [ 1, 2, 3, 4 ]
  }
}

main();
```

#### Prisma schema

```prisma
model User {
  id    Int   @id @default(autoincrement())
  bytes Bytes
}
```

#### After [#after-1]

  

#### Code

```ts
import { PrismaClient } from "@prisma/client";

async function main() {
  const prisma = new PrismaClient();
  await prisma.user.deleteMany();

  const bytesCreated = await prisma.user.create({
    data: {
      bytes: Uint8Array.from([1, 2, 3, 4]),
    },
  });
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^
  // `bytesCreated` now has type: {
  //    bytes: Uint8Array
  //    id: number
  // }

  for (const bytesFound of await prisma.user.findMany()) {
    bytesFound.bytes; // Uint8Array [ 1, 2, 3, 4 ]
  }
}

main();
```

#### Prisma schema

```prisma
model User {
  id    Int   @id @default(autoincrement())
  bytes Bytes
}
```

### Removed `NotFoundError` [#removed-notfounderror]

In Prisma v6, we removed the `NotFoundError` in favor of `PrismaClientKnownRequestError` with error code [`P2025`](https://www.prisma.io/docs/orm/v7/reference/error-reference#p2025) in [`findUniqueOrThrow()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#finduniqueorthrow) and [`findFirstOrThrow()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#findfirstorthrow). If you've relied on catching `NotFoundError` instances in your code, you need to adjust the code accordingly.

#### Before [#before-2]

```ts
import { PrismaClient, NotFoundError } from "@prisma/client";

// inside an `async` function
try {
  const user = await prisma.user.findUniqueOrThrow({
    where: { id: 42 },
  });
  console.log(user);
} catch (error) {
  if (error instanceof NotFoundError) {
    // [!code highlight]
    console.error("User not found!"); // [!code highlight]
  } // [!code highlight]
  else {
    console.error("Unexpected error:", error);
  }
}
```

#### After [#after-2]

```ts
import { PrismaClient, Prisma } from "@prisma/client";

// inside an `async` function
try {
  const user = await prisma.user.findUniqueOrThrow({
    where: { id: 42 },
  });
  console.log(user);
} catch (error) {
  if (
    // [!code highlight]
    error instanceof Prisma.PrismaClientKnownRequestError && // [!code highlight]
    error.code === "P2025" // Specific code for "record not found" // [!code highlight]
  ) {
    // [!code highlight]
    console.error("User not found!"); // [!code highlight]
  } // [!code highlight]
  else {
    console.error("Unexpected error:", error);
  }
}
```

### New keywords that can't be used as model names: `async`, `await`, `using` [#new-keywords-that-cant-be-used-as-model-names-async-await-using]

With this release, you can't use `async`, `await` and `using` as model names any more.

## Preview features promoted to General Availability [#preview-features-promoted-to-general-availability]

In this release, we are promoting a number of [Preview](https://www.prisma.io/docs/orm/v7/more/releases#preview) features to [General Availability](https://www.prisma.io/docs/orm/v7/more/releases#generally-available-ga).

### `fullTextIndex` [#fulltextindex]

If you use the [full-text index](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#full-text-indexes-mysql-and-mongodb) feature in your app, you can now remove `fullTextIndex` from the `previewFeatures` in your Prisma schema:

```prisma
generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["fullTextIndex"] // [!code --]
}
```

### `fullTextSearch` [#fulltextsearch]

If you use the [full-text search](https://www.prisma.io/docs/orm/v6/prisma-client/queries/full-text-search) feature with **MySQL** in your app, you can now remove `fullTextSearch` from the `previewFeatures` in your Prisma schema:

```prisma
generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["fullTextSearch"] // [!code --]
}
```

If you are using it with **PostgreSQL**, you need to update the name of the feature flag to `fullTextSearchPostgres`:

```prisma
generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["fullTextSearchPostgres"] // [!code highlight]
}
```

## Related pages

- [`Prisma ORM 6 to 8 (MongoDB)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb): Migrate a MongoDB project from Prisma ORM 6 to Prisma ORM 8
- [`Prisma ORM 7 to 8 (PostgreSQL)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql): Migrate a PostgreSQL project from Prisma ORM 7 to Prisma ORM 8 incrementally, with both versions running side by side
- [`Upgrade to v1`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v1): Guide for upgrading from Prisma 1 to Prisma ORM
- [`Upgrade to v3`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v3): Guide for upgrading to Prisma ORM v3
- [`Upgrade to v4`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v4): Guide for upgrading to Prisma ORM v4

# Upgrade to v7 (/docs/guides/upgrade-prisma-orm/v7)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Guide for upgrading to Prisma ORM v7

Location: Guides > Upgrade Prisma ORM > Upgrade to v7

Prisma ORM v7 introduces **breaking changes** when you upgrade from an earlier Prisma ORM version. This guide explains how this upgrade might affect your application and gives instructions on how to handle any changes.

> [!NOTE]
> Upgrading to Prisma ORM 8?
> 
> Prisma ORM 8 is the current release. If you are moving a Prisma ORM 7 project to Prisma ORM 8, use the [PostgreSQL](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql) or [MongoDB](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb) upgrade guide instead.

**Questions answered in this page**

* What changed in Prisma v7?
* How do I upgrade safely?
* Which breaking changes affect my app?

For developers using AI Agents, we have a [migration prompt](https://www.prisma.io/docs/ai/prompts/prisma-7) that you can
add to your project for automatic migrations.

> [!NOTE]
> If you are using MongoDB, please note that Prisma ORM v7 does not yet support MongoDB. You should continue using Prisma ORM v6 for now. Support for MongoDB is coming soon in v7.

## Update packages [#update-packages]

To upgrade to Prisma ORM v7 from an earlier version, you need to update both the `prisma` and `@prisma/client` packages:

  

#### bun

```bash
bun add @prisma/client@7
bun add --dev prisma@7
```

#### pnpm

```bash
pnpm add @prisma/client@7
pnpm add -D prisma@7
```

#### yarn

```bash
yarn add @prisma/client@7
yarn add --dev prisma@7
```

#### npm

```bash
npm install @prisma/client@7
npm install -D prisma@7
```

> [!CAUTION]
> Before you upgrade, check each breaking change below to see how the upgrade might affect your application.

## Breaking changes [#breaking-changes]

This section gives an overview of breaking changes in Prisma ORM v7.

### Prerequisites [#prerequisites]

|            | Minimum Version | Recommended |
| ---------- | --------------- | ----------- |
| Node       | 20.19.0         | 22.x        |
| TypeScript | 5.4.0           | 5.9.x       |

### ESM support [#esm-support]

Prisma ORM now ships as an ES module, the module format supported in Bun, Deno, and Node. Set the
`type` field in your `package.json` to `module`

```json
{
  "type": "module",
  "scripts": {...},
}
```

If you are using TypeScript, you need to configure your `tsconfig.json` to be able to consume ES modules

```json
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true
  }
}
```

### Schema changes [#schema-changes]

The older `prisma-client-js` provider will be removed in future releases of Prisma ORM. Upgrade to
the new `prisma-client` provider which uses the new Rust-free client. This will give you faster
queries, smaller bundle size, and require less system resources when deployed to your server.

The `output` field is now **required** in the generator block. Prisma Client will no longer be generated in `node_modules` by default. You must specify a custom output path.

  

#### Before

```prisma
generator client {
  provider = "prisma-client-js"
  engineType = "binary"
}
```

#### After

```prisma
generator client {
  provider = "prisma-client"
  output   = "./generated/prisma"
}
```

After running `npx prisma generate`, you'll need to update your imports to use the new generated path:

```ts
// Before
import { PrismaClient } from "@prisma/client";

// After
import { PrismaClient } from "./generated/prisma/client";
```

> [!NOTE]
> The import path depends on where you place your generated client. Adjust the path based on your `output` configuration and the location of the file you're importing from.

Additionally other fields such as `url`, `directUrl`, and `shadowDatabaseUrl` in the `datasource` block are deprecated. You can configure them in the [Prisma Config](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference).

If you were previously using `directUrl` to run migrations then you need to pass the `directUrl` value in the `url` field of `prisma.config.ts` instead as the connection string defined in `url` is used by Prisma CLI for migrations.

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  datasource: {
    url: env("DATABASE_URL"),
    shadowDatabaseUrl: env("SHADOW_DATABASE_URL"),
  },
});
```

### Driver adapters [#driver-adapters]

The way to create a new Prisma Client has changed to require a driver adapter for all databases.
This change is part of the move to make the main Prisma Client as lean and open as possible. For
instance, if you are using Prisma Postgres, you now need the `@prisma/adapter-pg` adapter. This also
means the signature for creating a new Prisma Client has changed slightly:

> [!WARNING]
> Connection pools have changed.
> 
> Driver adapters use the connection pool settings from the underlying Node.js database driver, which may differ significantly from Prisma ORM v6 defaults. For example, the `pg` driver has no connection timeout by default (`0`), while Prisma ORM v6 used a 5-second timeout.
> 
> **If you experience timeout issues after upgrading**, configure your driver adapter to match v6 behavior. See the [connection pool guide](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool#prisma-orm-v7-driver-adapter-defaults) for detailed configuration examples for each database.

#### Before [#before]

```ts
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient({
  datasources: {
    db: { url: process.env.DATABASE_URL },
  },
  datasourceUrl: process.env.DATABASE_URL,
});
```

#### After [#after]

```ts
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
});
export const prisma = new PrismaClient({ adapter });
```

If you are using SQLite, you can use the `@prisma/adapter-better-sqlite3`:

```ts
import { PrismaClient } from "./generated/prisma/client";
import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";

const adapter = new PrismaBetterSqlite3({
  url: process.env.DATABASE_URL || "file:./dev.db",
});

export const prisma = new PrismaClient({ adapter });
```

### Prisma Accelerate [#prisma-accelerate]

> [!WARNING]
> Accelerate retirement
> 
> Standalone Prisma Accelerate and hosted Prisma Postgres `prisma+postgres://accelerate.prisma-data.net` connections will be retired on December 1, 2026.
> 
> * If the URL connects to Prisma Postgres, [switch to pooled TCP or the Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/switch-from-accelerate).
> * If the URL connects to another database, [keep the database and remove Accelerate](https://www.prisma.io/docs/accelerate/keep-your-database).

If you complete the Prisma ORM 7 upgrade before removing Accelerate, you can keep the Accelerate URL and extension temporarily. Do **not** pass the Accelerate URL to a driver adapter, because `PrismaPg` expects a direct database connection string and will fail with `prisma://` or `prisma+postgres://`.

1. Keep your Accelerate URL in `.env` (for example `DATABASE_URL="prisma://..."` or `prisma+postgres://...`).
2. You can point `prisma.config.ts` directly to that same Accelerate URL for CLI operations:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

* If you prefer a separate direct URL for migrations, you can still use `DIRECT_DATABASE_URL` as above, but it's optional for Accelerate users.

3. Instantiate Prisma Client with the Accelerate URL and extension (no adapter):

```ts
import { PrismaClient } from "./generated/prisma/client";
import { withAccelerate } from "@prisma/extension-accelerate";

export const prisma = new PrismaClient({
  accelerateUrl: process.env.DATABASE_URL,
}).$extends(withAccelerate());
```

Remove this temporary integration before December 1, 2026 by following the transition guide that matches your database.

### SSL certificate validation changes [#ssl-certificate-validation-changes]

Since Prisma ORM v7 uses `node-pg` instead of the Rust-based query engine, SSL certificate defaults have changed. Previously, invalid SSL certificates were ignored. In v7, you may encounter the following error:

```bash
Error: P1010: User was denied access on the database <database>
```

To fix this, either keep the previous behavior:

```ts
const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
  ssl: { rejectUnauthorized: false },
});
```

Or properly configure your database certificates using `node --use-openssl-ca` or by setting the `NODE_EXTRA_CA_CERTS` environment variable.

For more details, see [GitHub issue #28795](https://github.com/prisma/orm/issues/28795).

### Environment variables [#environment-variables]

In Prisma ORM 7.0.0, environment variables are not loaded by default. Instead developers need to
explicitly load the variables when calling the `prisma` CLI. Libraries like [`dotenv`](https://github.com/motdotla/dotenv) can be used to manage loading environment variables by reading the appropriate `.env` file.

  

#### bun

```bash
bun add dotenv
```

#### pnpm

```bash
pnpm add dotenv
```

#### yarn

```bash
yarn add dotenv
```

#### npm

```bash
npm install dotenv
```

For bun users, no action is required as bun will automatically load `.env` files.

### Prisma config [#prisma-config]

Prisma Config is now the default place for configuring how the Prisma CLI interacts with your
database. You now configure your database URL, schema location, migration output, and custom seed
scripts.

> [!NOTE]
> The `prisma.config.ts` file should be placed at the **root of your project** (where your `package.json` is located).

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  // the main entry for your schema
  schema: "prisma/schema.prisma",
  // where migrations should be generated
  // what script to run for "prisma db seed"
  migrations: {
    path: "prisma/migrations",
    seed: "tsx prisma/seed.ts",
  },
  // The database URL
  datasource: {
    // Type Safe env() helper
    // Does not replace the need for dotenv
    url: env("DATABASE_URL"),
  },
});
```

### Metrics removed [#metrics-removed]

The Metrics preview feature was deprecated in [Prisma ORM 6.14.0](https://github.com/prisma/orm/releases/tag/6.14.0) and has been removed for Prisma ORM 7.0.0.
If you need this feature, you can use the underlying driver adapter for your database, or Client Extensions to make this information available.

For example, a basic `totalQueries` counter:

```ts
let total = 0;
const prisma = new PrismaClient().$extends({
  client: {
    $log: (s: string) => console.log(s),
    async $totalQueries() {
      return total;
    },
  },
  query: {
    $allModels: {
      async $allOperations({ query, args }) {
        total += 1;
        return query(args);
      },
    },
  },
});

async function main() {
  prisma.$log("Hello world");
  const totalQueries = await prisma.$totalQueries();
  console.log(totalQueries);
}
```

### Mapped enum values in generated TypeScript [#mapped-enum-values-in-generated-typescript]

> [!NOTE]
> Reversion to Prisma 6 behavior
> 
> The mapped enum implementation that was initially planned for Prisma ORM v7 has been reverted. Mapped enum behavior now matches Prisma ORM v6 to avoid breaking changes. We plan to implement a similar feature in the future with different syntax.

In Prisma ORM v7, the generated TypeScript enum values use the **schema names**, not the mapped values. This maintains compatibility with Prisma ORM v6 behavior.

#### Prisma ORM v6 behavior [#prisma-orm-v6-behavior]

Given this Prisma schema:

```prisma
enum SuggestionStatus {
  PENDING  @map("pending")
  ACCEPTED @map("accepted")
  REJECTED @map("rejected")
}
```

In v6, the generated TypeScript enum was:

```ts
export const SuggestionStatus = {
  PENDING: "PENDING",
  ACCEPTED: "ACCEPTED",
  REJECTED: "REJECTED",
} as const;
```

#### Prisma ORM v7 (reverted behavior) [#prisma-orm-v7-reverted-behavior]

In v7, the same schema generates the same TypeScript as v6:

```ts
export const SuggestionStatus = {
  PENDING: "PENDING",
  ACCEPTED: "ACCEPTED",
  REJECTED: "REJECTED",
} as const;
```

This means that `SuggestionStatus.PENDING` evaluates to `"PENDING"`, not `"pending"`. The mapping is handled at the database level only.

#### Migration steps [#migration-steps]

No migration is required for this change. The behavior now matches Prisma ORM v6, so existing code will continue to work as expected.

### Client middleware removed [#client-middleware-removed]

The client middleware API has been removed. If possible, use [Client Extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions).

```ts
// ❌ Old (removed)
prisma.$use(async (params, next) => {
  // middleware logic
  return next(params);
});
// ✅ New (use extensions)
const prisma = new PrismaClient().$extends({
  query: {
    user: {
      async findMany({ args, query }) {
        // extension logic
        return query(args);
      },
    },
  },
});
```

### Seeding changes [#seeding-changes]

In Prisma ORM v6 and earlier, running `prisma migrate dev` or `prisma migrate reset` would automatically execute your seed script after applying migrations. This automatic seeding behavior has been removed in Prisma ORM v7.

To seed your database in v7, you must explicitly run:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

### Removed CLI flags [#removed-cli-flags]

The `--skip-generate` flag was removed from `prisma migrate dev` and `prisma db push`. The `--skip-seed` flag was removed from `prisma migrate dev`.

`migrate dev` and `db push` no longer run `prisma generate` automatically. You must run `prisma generate` explicitly to generate Prisma Client.

### Removed db execute flags [#removed-db-execute-flags]

The `--schema` and `--url` flags have been removed from the `prisma db execute` command. Previously, you could use `--schema` to specify the path to your Prisma schema file, or `--url` to specify the database URL directly. Now, the database connection must be configured in `prisma.config.ts`.

#### Before (v6) [#before-v6]

```bash
# Using --schema
prisma db execute --file ./script.sql --schema prisma/schema.prisma

# Using --url
prisma db execute --file ./script.sql --url "$DATABASE_URL"
```

#### After (v7) [#after-v7]

Configure your database connection in `prisma.config.ts` instead:

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Then run the command without `--schema` or `--url`:

```bash
prisma db execute --file ./script.sql
```

### Migrate diff changes [#migrate-diff-changes]

Several options have been removed from `prisma migrate diff` and replaced with new options that use `prisma.config.ts`:

| Removed Option             | Replacement                     |
| -------------------------- | ------------------------------- |
| `--from-url`               | `--from-config-datasource`      |
| `--to-url`                 | `--to-config-datasource`        |
| `--from-schema-datasource` | `--from-config-datasource`      |
| `--to-schema-datasource`   | `--to-config-datasource`        |
| `--shadow-database-url`    | Configure in `prisma.config.ts` |

#### Before (v6) [#before-v6-1]

```bash
prisma migrate diff \
  --from-url "$DATABASE_URL" \
  --to-schema schema.prisma \
  --script
```

#### After (v7) [#after-v7-1]

Configure your database connection in `prisma.config.ts`, then use `--from-config-datasource` or `--to-config-datasource`:

```bash
prisma migrate diff \
  --from-config-datasource \
  --to-schema schema.prisma \
  --script
```

### Various environment variables have been removed [#various-environment-variables-have-been-removed]

We've removed a small selection of Prisma-specific environment variables.

* `PRISMA_CLI_QUERY_ENGINE_TYPE`
* `PRISMA_CLIENT_ENGINE_TYPE`
* `PRISMA_QUERY_ENGINE_BINARY`
* `PRISMA_QUERY_ENGINE_LIBRARY`
* `PRISMA_GENERATE_SKIP_AUTOINSTALL`
* `PRISMA_SKIP_POSTINSTALL_GENERATE`
* `PRISMA_GENERATE_IN_POSTINSTALL`
* `PRISMA_GENERATE_DATAPROXY`
* `PRISMA_GENERATE_NO_ENGINE`
* `PRISMA_CLIENT_NO_RETRY`
* `PRISMA_MIGRATE_SKIP_GENERATE`
* `PRISMA_MIGRATE_SKIP_SEED`

## Related pages

- [`Prisma ORM 6 to 8 (MongoDB)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb): Migrate a MongoDB project from Prisma ORM 6 to Prisma ORM 8
- [`Prisma ORM 7 to 8 (PostgreSQL)`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql): Migrate a PostgreSQL project from Prisma ORM 7 to Prisma ORM 8 incrementally, with both versions running side by side
- [`Upgrade to v1`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v1): Guide for upgrading from Prisma 1 to Prisma ORM
- [`Upgrade to v3`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v3): Guide for upgrading to Prisma ORM v3
- [`Upgrade to v4`](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v4): Guide for upgrading to Prisma ORM v4

# Guides (Prisma ORM v7) (/docs/guides/v7)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A collection of guides for various tasks and workflows

Location: Guides > Guides

This section contains step-by-step guides for specific tasks with Prisma products, including Prisma ORM, Prisma Accelerate, and Prisma Postgres.

## Quick start [#quick-start]

Scaffold a new project with Prisma ORM and Prisma Postgres already set up:

  

#### bun

```bash
bunx create-prisma@stable
```

#### pnpm

```bash
pnpm create prisma@stable
```

#### yarn

```bash
yarn create prisma@stable
```

#### npm

```bash
npm create prisma@stable
```

Pick your framework and options from the prompts. To skip prompts use `--yes`, to set a framework upfront use `--template` (`next`, `hono`, `svelte`, `astro`, `nuxt`, `tanstack-start`, `nest`, `elysia`, `turborepo`).

## Getting started [#getting-started]

* [Next.js](https://www.prisma.io/docs/guides/v7/frameworks/nextjs) - Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel
* [Hono](https://www.prisma.io/docs/guides/v7/frameworks/hono) - Learn how to use Prisma ORM in a Hono app
* [SvelteKit](https://www.prisma.io/docs/guides/v7/frameworks/sveltekit) - Learn how to use Prisma ORM in a SvelteKit app
* [React Router 7](https://www.prisma.io/docs/guides/v7/frameworks/react-router-7) - Learn how to use Prisma ORM in a React Router 7 app
* [SolidStart](https://www.prisma.io/docs/guides/v7/frameworks/solid-start) - Learn how to use Prisma ORM in a SolidStart app

## Deployment [#deployment]

* [Docker](https://www.prisma.io/docs/guides/v7/deployment/docker) - Run a Prisma ORM app and its database with Docker Compose
* [Cloudflare Workers](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-workers) - Use Prisma ORM and Prisma Postgres in a Cloudflare Worker
* [Cloudflare D1](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-d1) - Use Prisma ORM with Cloudflare D1
* [Turborepo](https://www.prisma.io/docs/guides/v7/deployment/turborepo) - Share a Prisma ORM database package in a Turborepo monorepo
* [pnpm workspaces](https://www.prisma.io/docs/guides/v7/deployment/pnpm-workspaces) - Share a Prisma ORM database package in a pnpm workspace
* [Bun workspaces](https://www.prisma.io/docs/guides/v7/deployment/bun-workspaces) - Share a Prisma ORM database package in a Bun workspace

## Database [#database]

* [Multiple databases](https://www.prisma.io/docs/guides/v7/database/multiple-databases) - Use several Prisma Clients in one app
* [Expand-and-contract migrations](https://www.prisma.io/docs/guides/v7/database/data-migration) - Migrate data safely with the expand and contract pattern
* [Schema changes](https://www.prisma.io/docs/guides/v7/database/schema-changes) - Handle migrations when working as a team

## Switch to Prisma ORM [#switch-to-prisma-orm]

* [From Drizzle](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-drizzle)
* [From Sequelize or TypeORM](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-sql-orms)
* [From Mongoose](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-mongoose)

## Integrations [#integrations]

* [AI SDK](https://www.prisma.io/docs/guides/v7/integrations/ai-sdk) - Store chat sessions and messages with Prisma ORM and Next.js
* [GitHub Actions](https://www.prisma.io/docs/guides/v7/integrations/github-actions) - Provision a Prisma Postgres database per pull request

## Related pages

- [`Writing guides`](https://www.prisma.io/docs/guides/making-guides): How to write, validate, and file a Prisma ORM guide for the Prisma documentation.

# Supported database features (/docs/orm/contract-authoring/capabilities)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The contract records which database features your packages support, so Prisma ORM can reject an unsupported one early with a clear error.

Location: ORM > Contract authoring > Supported database features

Your [contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract), the `contract.prisma` file that replaced `schema.prisma`, describes your data. [`npx prisma contract emit`](https://www.prisma.io/docs/cli/contract-emit) writes `contract.json` and `contract.d.ts` beside it. The `capabilities` section of `contract.json` lists the database features you can use, under keys such as `sql.lateral`. Prisma ORM writes that section, and you never edit it. If you use a feature that is not listed, Prisma ORM raises an error instead of sending the query to the database.

## Where the `capabilities` section comes from [#where-capabilities-come-from]

The keys come from your database package (`@prisma/orm-postgres`, `@prisma/orm-sqlite`, or `@prisma/orm-mongo`) and any extension packages listed in `prisma.config.ts`. `npx prisma contract emit` never connects to your database: it reads those packages and writes what they report, in groups:

```json title="src/prisma/contract.json (excerpt)"
{
  "capabilities": {
    "postgres": { "distinctOn": true, "pgvector.cosine": true },
    "sql": { "lateral": true, "scalarList": true }
  }
}
```

Error messages and the table below name a key group first, `postgres.pgvector.cosine`. The `sql` group holds keys that more than one SQL database may support, and SQLite reports `false` for some of them. Keys under `postgres` belong to PostgreSQL only. Extension packages add keys of their own, and `pgvector.cosine` comes from the pgvector package. Install it with `npm install @prisma/orm-extension-pgvector`, list it in `prisma.config.ts`, and run `npx prisma contract emit` again:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { definePrismaConfig } from "prisma/config";
import pgvector from "@prisma/orm-extension-pgvector/control";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./src/prisma/contract.prisma",
    extensions: [pgvector],
    db: { connection: process.env['DATABASE_URL']! },
  }),
});
```

pgvector is also a PostgreSQL server extension, and the package ships a migration that installs it. Apply it with `npx prisma db migrate`, see [Using extensions](https://www.prisma.io/docs/orm/extensions/using-extensions). Run `npx prisma contract emit` after every change to the contract or to the extension list.

## What the `capabilities` section controls [#what-capabilities-gate]

**When the contract is built.** If your contract uses a feature your database package does not support, `npx prisma contract emit` fails. SQLite has no `scalarList` key, so a list field such as `tags String[]` fails on SQLite:

```text
Field "User.tags" is a scalar list, but target "sqlite" does not support
scalar lists (the adapter does not report the "scalarList" capability).
Remove the list or author it against a target that supports scalar lists.
```

In that message, both words mean your database package, and the message's `"scalarList"` is the `sql.scalarList` key. Do one of the two: remove the list field, or move to a database that supports list fields. To move to PostgreSQL, change the `@prisma/orm-sqlite/config` import and the connection string in `prisma.config.ts`, and create the new database.

**When you call a method on the [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder) or on the ORM client.** A method that needs a feature throws an error whose `code` is `ORM.CAPABILITY_MISSING`, and the message names the method and the key:

```text
distinctOn() requires capability postgres.distinctOn
```

That message means the method is not available on the database package you chose, so rewrite the query without it, or move to a database that supports the feature. If the key comes from an extension package, install that package and list it in `prisma.config.ts`. You do not have to run the query to get the error, so a test that only builds the query still fails. Your own code can read the same list through `db`, the client you create once in `src/prisma/db.ts`, which `npx prisma orm init` writes. A value such as `db.contract.capabilities.sql?.lateral` is `true` or `false`, or `undefined` if the whole group is missing. For a key with a dot in it, write `db.contract.capabilities.postgres?.["pgvector.cosine"]`:

```typescript
if (db.contract.capabilities.sql?.lateral) {
  // run the lateral join here, or fall back to a second query
}
```

## Example keys [#example-capabilities]

A few of the keys your database package and extension packages supply:

| Key                        | What it covers                            |
| -------------------------- | ----------------------------------------- |
| `sql.lateral`              | Lateral joins (`lateralJoin()`)           |
| `sql.returning`            | `RETURNING` clauses on writes             |
| `sql.scalarList`           | List fields such as `tags String[]`       |
| `postgres.distinctOn`      | `DISTINCT ON` queries (`distinctOn()`)    |
| `postgres.pgvector.cosine` | Cosine distance from the pgvector package |

PostgreSQL reports `true` for all three `sql` keys above, while SQLite reports `false` for `sql.lateral`, `true` for `sql.returning`, and has no `sql.scalarList` key at all. This table is a sample, not the full list, so open `src/prisma/contract.json` in your project to see every key you have. The MongoDB packages report no keys, so neither check applies on MongoDB. The [ORM reference](https://www.prisma.io/docs/orm/reference) lists the methods each database has.

## The `capabilities` section and `prisma db verify` [#capabilities-and-verification]

[`npx prisma db verify`](https://www.prisma.io/docs/cli/db-verify) checks the live database against the contract's tables and columns, not against this section: the keys say what your packages support, recorded when you run `npx prisma contract emit`.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. In an existing project, run `npx prisma skills sync` to add them. The `prisma-8` skill covers this material, so ask your agent to:

* "Which keys in the `capabilities` section does our code rely on, and which package provides each?"
* "Add pgvector to the project and confirm its key shows up in the emitted contract."

## Next steps [#next-steps]

* See where the `capabilities` block is, and what `contract.d.ts` holds, in [contract.json and contract.d.ts](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact).
* Add extension packages, and the keys they bring, in the [CLI configuration](https://www.prisma.io/docs/cli/configuration).

## Related pages

- [`Author in PSL`](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax): Write the Prisma ORM contract in the Prisma schema language you already know, plus the Prisma ORM 8 additions.
- [`Author in TypeScript`](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder): Define the Prisma ORM contract with a typed builder in TypeScript instead of a schema file. Same models, same `contract.json` and `contract.d.ts`, no separate language.
- [`contract.json and contract.d.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact): contract.json and contract.d.ts are the two files every other part of Prisma ORM reads. Here is what is inside them.
- [`Editor support`](https://www.prisma.io/docs/orm/contract-authoring/editor-support): What the Prisma VS Code extension does for a Prisma ORM contract, and what to do when it stops accepting the file.
- [`The data contract`](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract): The data contract is the one description of your data model and how it is stored. Prisma ORM types your queries, plans your migrations, and checks your database against it.

# Editor support (/docs/orm/contract-authoring/editor-support)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

What the Prisma VS Code extension does for a Prisma ORM contract, and what to do when it stops accepting the file.

Location: ORM > Contract authoring > Editor support

Install the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) to get error checking, formatting, and completion in your `.prisma` file.

In Prisma ORM 8 that file is the [data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract): the description of your models that Prisma ORM 7 called the schema. Its path is the `contract` setting in your `prisma.config.ts`, which is `prisma/contract.prisma` in the config [`orm init`](https://www.prisma.io/docs/cli/orm-init) writes; see [Configuration](https://www.prisma.io/docs/cli/configuration#config-file).

Coming from Prisma ORM 7? Start with [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7). This page covers VS Code only.

## The file header [#the-file-header]

The extension only works on `.prisma` files whose first non-blank line is:

```prisma title="prisma/contract.prisma"
// use prisma-8
```

A file without that line gets no error checking, no completion, and no formatting. [`prisma contract emit`](https://www.prisma.io/docs/cli/contract-emit) also skips it without a warning, and when none of the files that the `contract` setting names has the line, `contract emit` fails with `CONTRACT.SOURCE_LOAD_FAILED`. [`orm init`](https://www.prisma.io/docs/cli/orm-init) and [`contract infer`](https://www.prisma.io/docs/cli/contract-infer) write the line for you. Add it yourself when you create a contract by hand.

## What the editor does [#what-the-editor-does]

* **Errors** appear inline as you type. They are the same errors you would get from [`prisma contract emit`](https://www.prisma.io/docs/cli/contract-emit), the command that checks the contract and writes `contract.json` and `contract.d.ts`.
* **Formatting** reformats the whole file. In VS Code, run **Format Document**.
* **Completion** starts when you type `@` or `@@`. The editor lists attribute names such as `@id`, `@default`, and `@@index`, each with a short description. Inside an attribute, it lists the names of the arguments you have not filled in yet and suggests values for them. It also suggests values inside `[ ]` and `{ }`. In a MongoDB index's field list, it suggests the option and its values in the parentheses after a field name, such as `sort` and `Desc` in `@@index([createdAt(sort: Desc)])`. Where an attribute expects a field name, it suggests only scalar fields. When an attribute has required arguments, VS Code inserts them as placeholders named after each argument, which you tab through.
* **Signature help** appears when you type `(` or `,` inside an attribute. It shows the attribute's arguments and describes the one you are typing.

The list of attributes comes from your `prisma.config.ts`: the database it declares and the Prisma extension packs listed under `extensions`; see [Extension packs](https://www.prisma.io/docs/cli/configuration#extension-packs) for that config. Extension packs are add-on packages for database features such as [pgvector](https://www.prisma.io/docs/orm/extensions/using-extensions). If your config lists the pgvector pack, the editor also suggests pgvector's attributes. No database connection is needed.

## False errors after an upgrade [#false-errors-after-an-upgrade]

If the editor marks attributes as errors in a contract that `prisma contract emit` accepts, the likely cause is an old ORM package. That is the `@prisma/orm-postgres`, `@prisma/orm-mongo`, or `@prisma/orm-sqlite` package your project installs for its database. Check the installed version:

```bash title="Terminal"
npm ls @prisma/orm-postgres
```

If it prints a version below `8.0.0-rc.9`, update it to the current release:

  

#### bun

```bash title="Terminal"
bun add @prisma/orm-postgres@latest
```

#### pnpm

```bash title="Terminal"
pnpm add @prisma/orm-postgres@latest
```

#### yarn

```bash title="Terminal"
yarn add @prisma/orm-postgres@latest
```

#### npm

```bash title="Terminal"
npm install @prisma/orm-postgres@latest
```

Replace `orm-postgres` with `orm-mongo` or `orm-sqlite` to match your database. Then reload the editor window. In VS Code, run **Developer: Reload Window** from the Command Palette.

## Related pages

- [`Author in PSL`](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax): Write the Prisma ORM contract in the Prisma schema language you already know, plus the Prisma ORM 8 additions.
- [`Author in TypeScript`](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder): Define the Prisma ORM contract with a typed builder in TypeScript instead of a schema file. Same models, same `contract.json` and `contract.d.ts`, no separate language.
- [`contract.json and contract.d.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact): contract.json and contract.d.ts are the two files every other part of Prisma ORM reads. Here is what is inside them.
- [`Supported database features`](https://www.prisma.io/docs/orm/contract-authoring/capabilities): The contract records which database features your packages support, so Prisma ORM can reject an unsupported one early with a clear error.
- [`The data contract`](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract): The data contract is the one description of your data model and how it is stored. Prisma ORM types your queries, plans your migrations, and checks your database against it.

# Author in PSL (/docs/orm/contract-authoring/psl-syntax)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Write the Prisma ORM contract in the Prisma schema language you already know, plus the Prisma ORM 8 additions.

Location: ORM > Contract authoring > Author in PSL

PSL, the Prisma Schema Language, is the preferred way to author [your contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract), the `contract.prisma` file that replaced `schema.prisma`. You usually write one file, `src/prisma/contract.prisma`, or [split it into several](#split-the-contract-across-several-files), and [`npx prisma contract emit`](https://www.prisma.io/docs/cli/contract-emit) writes `contract.json` and `contract.d.ts` beside it. If you know the Prisma schema language, most of a contract file reads exactly as you expect. The five biggest additions are listed here, and the rest of the page is the full reference for every attribute and block:

* named types: give a database column type a name you can reuse on many fields.
* enums: an enum can now say how its values are stored, and what each member stores.
* value objects: a structured value stored inside its parent row, with no table of its own.
* base models and variants: one table can hold more than one kind of record. Put the shared fields in a base model, put the differences in each variant, and Prisma ORM uses one column to tell them apart.
* extension types: field types that come from an npm package, such as vectors.

The `datasource` and `generator` blocks are gone: the connection URL and the file paths are set in `prisma.config.ts` instead. [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#schema) lists every change to the schema file, including what each old `@db.` attribute becomes.

## A complete contract [#a-complete-contract]

The first non-blank line of every contract file is `// use prisma-8`, because `contract emit` reads only the `.prisma` files that start with it. When the `contract` setting in `prisma.config.ts` names one file and that file lacks the line, `contract emit` fails with `CONTRACT.SOURCE_LOAD_FAILED`, and the error's details include `PSL_NO_OPTED_IN_SCHEMA_FILES`. When `contract` is a [glob that matches several files](#split-the-contract-across-several-files), a file without the line is left out of the contract without a warning, and `contract emit` fails only when none of the files has it.

  

#### PostgreSQL

```prisma title="src/prisma/contract.prisma" 
// use prisma-8

types {
  ShortName = VarChar(35)
}

type Address {
  street  String
  city    String
  zip     String?
  country String
}

enum Priority {
  @@type("pg/text@1")
  Low    = "low"
  High   = "high"
  Urgent = "urgent"
}

model User {
  id        Uuid     @id @default(uuid())
  email     String
  createdAt DateTime @default(now())
  address   Address?
  posts     Post[]

  @@map("user")
}

model Post {
  id        Uuid      @id @default(uuid())
  title     ShortName
  userId    Uuid
  priority  Priority  @default(Low)
  createdAt DateTime  @default(now())

  user User @relation(fields: [userId], references: [id])

  @@map("post")
}
```

#### MongoDB

```prisma title="src/prisma/contract.prisma" 
// use prisma-8

type Address {
  street  String
  city    String
  zip     String?
  country String
}

enum UserRole {
  @@type("mongo/string@1")
  Admin  = "admin"
  Author = "author"
  Reader = "reader"
}

model User {
  id      ObjectId @id @map("_id")
  email   String
  role    UserRole
  address Address?
  posts   Post[]

  @@map("users")
}

model Post {
  id       ObjectId @id @map("_id")
  title    String
  authorId ObjectId

  author User @relation(fields: [authorId], references: [id])

  @@index([authorId])
  @@map("posts")
}
```

`Uuid` is PostgreSQL's `uuid` type written as a field type. Run `npx prisma contract emit` after any change to refresh `contract.json` and `contract.d.ts`, and then [`npx prisma db init`](https://www.prisma.io/docs/cli/db-init) creates the tables.

## Point the config at the schema [#point-the-config-at-the-schema]

The config's `contract` path names the file Prisma ORM reads. If the path ends in `.prisma`, Prisma ORM reads it as PSL, and if it ends in `.ts`, as TypeScript. The `db` key holds the connection URL:

```typescript title="prisma.config.ts"
import 'dotenv/config';
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./src/prisma/contract.prisma",
    db: {
      connection: process.env['DATABASE_URL']!,
    },
  }),
});
```

`npx prisma orm init` writes a config like this, `DATABASE_URL` included. The import chooses the database: `@prisma/orm-postgres/config` makes it a PostgreSQL project, and `@prisma/orm-mongo/config` a MongoDB one. [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#schema) lists the other keys.

### Split the contract across several files [#split-the-contract-across-several-files]

Set `contract` to a glob, such as `"./src/prisma/**/*.prisma"`, to write the contract in several files. Every matching file that starts with `// use prisma-8` becomes part of one contract, and a file you add later joins it on the next `contract emit`, with no change to the config. A model in one file can refer to a model in another. `contract emit` writes `contract.json` and `contract.d.ts` into the folder before the first wildcard, here `./src/prisma/`. See [Configuration](https://www.prisma.io/docs/cli/configuration#split-the-schema-across-several-files).

## Models and fields [#models-and-fields]

Models declare fields with a type, an optional `?` marker, and attributes. [Scalar fields](https://www.prisma.io/docs/orm/data-modeling#scalar-fields) lists the types a field can hold, among them `String`, `Int`, `Boolean`, `Decimal`, `DateTime`, `Json`, and `Bytes`. On PostgreSQL, plain `String` is a `text` column, `Int` is `int4`, and `DateTime` is `timestamptz`. You can also use one of these PostgreSQL types as the field type: `VarChar`, `Char`, `Numeric`, `Timestamp`, `Timestamptz`, `Time`, `Timetz`, `Date`, `Uuid`, `Inet`, `SmallInt`, or `Real`. Their arguments are optional: `VarChar(35)` and `Char(2)` set a length, `Numeric(10, 2)` sets a precision and scale, and `Timestamp(3)`, `Timestamptz(3)`, `Time(3)`, and `Timetz(3)` set how many digits of a second are kept. `Timestamptz` without an argument is the same column as `DateTime`, so use it only when you want to set that precision.

On PostgreSQL, the date and time types reach your code as `Temporal` values: `DateTime` and `Timestamptz` as a `Temporal.Instant`, `Timestamp` as a `Temporal.PlainDateTime`, `Date` as a `Temporal.PlainDate`, and `Time` as a `Temporal.PlainTime`. Your app needs a global `Temporal` to read and write them, and [Scalar fields](https://www.prisma.io/docs/orm/data-modeling#scalar-fields) says how to check for it. When you want a string instead, use `DateString`, a `date` column your code gets as a string, or `TimestampString`, `TimestamptzString`, and `TimeString`, which do the same for `timestamp`, `timestamptz`, and `time`. `TimestamptzJsDate` is a `timestamptz` column your code gets as a JavaScript `Date`, so it needs no `Temporal`, but a `Date` drops the microseconds PostgreSQL stores.

* `@id` marks the primary key. `@@id([a, b])` declares a composite key.
* `@unique` adds a unique constraint on one field. `@@unique([userId, title])` adds one across several fields.
* `@@index([...])` declares a secondary index.
* `@default(...)` sets a default the database fills in when it is a literal, `now()`, `autoincrement()`, or any other SQL expression. Write the SQL as a `sql` tagged literal, which is `sql` followed by the SQL in backticks, such as ``@default(sql`gen_random_uuid()`)``. See [Default values](#default-values) for how to write each kind of literal.
* `@default(...)` sets a default Prisma ORM generates when it is `uuid()` (a version 4 UUID, the same as `uuid(4)`), `uuid(7)`, `cuid(2)`, `ulid()`, or `nanoid()`, where `nanoid(n)` sets the length, from 2 to 255. Prisma ORM computes the value when it writes the row and the database will not fill it in for you, so a row written by raw SQL or another application gets no value. Prisma ORM 7's `cuid()` is rejected with a hint to use `cuid(2)`.
* `@map("column_name")` sets a field's column name in the database. `@@map("table_name")` sets the table or collection name when it differs from the model name. Without `@@map`, the table or collection has the model's name exactly as written, so `model UserProfile` is the table `"UserProfile"`.
* `@@check(expression: "total >= 0", name: "order_total_positive")` adds a check constraint of your own to the table. See [Check constraints](#check-constraints).
* `@@control(observed)` says how far Prisma ORM manages the table. See [Control policy](#control-policy).

A field can be a list on PostgreSQL: `tags String[]` is a `text[]` column, and the same works for `Int[]` and the other scalar types. Prisma ORM adds a check constraint to a list column so it cannot hold a `NULL` element. To leave that constraint out, for example when the column already exists without it, add `@noCheck(elementNotNull)` to the field. Lists of enums and of named types are not supported; a list of a value object is, as [Value objects](#value-objects) shows.

`@updatedAt` is gone, so write `temporal.updatedAt()` where the field's type would go:

```prisma
model Post {
  updatedAt temporal.updatedAt()
}
```

Prisma ORM sets the field to the current time on every create and update. `temporal` is a built-in group of timestamp field types, such as `temporal.createdAt()` and `temporal.updatedAt()`, so you do not import it or declare it. On PostgreSQL the column is `timestamptz`, and you can still set the field yourself on a write. `temporal.createdAt()` sets the field once, when the row is created. Both take the time from your application's clock, not from the database, so the column has no database default, and a row you insert with raw SQL must supply the value. For a value the database generates, use `DateTime @default(now())` instead. `temporal.createdAtJsDate()` and `temporal.updatedAtJsDate()` do the same with a JavaScript `Date` in place of a `Temporal` value. `temporal.createdAt()` and `temporal.updatedAt()` need a global `Temporal` for writes as well as reads, so when your runtime has none, install `temporal-polyfill` and add `import "temporal-polyfill/full/global"` to your app's entry file.

How IDs map differs by database:

  

#### PostgreSQL

```prisma
model User {
  id Uuid @id @default(uuid())
}
```

#### MongoDB

```prisma
model User {
  id ObjectId @id @map("_id")
}
```

On PostgreSQL the primary key is an ordinary column, so pick its type and default yourself. On MongoDB the primary key is the document's `_id`, so type it `ObjectId` and map it to `_id`.

### Default values [#default-values]

Write each default in a form its column can hold. A quoted string is text, for example, so it cannot be the default of a JSON, decimal, or floating-point column. When a default does not fit its column, `contract emit` fails with `PSL_DEFAULT_TYPE_INCOMPATIBLE` and names the types the column accepts. The examples below show the form for each kind of column:

```prisma title="src/prisma/contract.prisma (excerpt)"
model Account {
  id        String   @id @default(sql`gen_random_uuid()`)
  meta      Jsonb    @default(json`{ "plan": "free" }`)
  tags      Jsonb    @default(json`[1, 2]`)
  price     Decimal  @default(1.50)
  ratio     Float    @default(NaN)
  role      String   @default("member")
  active    Boolean  @default(true)
  startsOn  Date     @default("2024-01-01")
  createdAt DateTime @default(now())
  expiresAt DateTime @default(sql`(now() + '00:03:00'::interval)`)
}
```

* A JSON default is a `json` tagged literal: `json` followed by the JSON document in backticks. Write a JSON array the same way, as `tags` shows.
* A decimal default is a bare number, and it keeps every digit you write, trailing zeros included.
* `NaN`, `Infinity`, and `-Infinity` are written without quotes, and so are `true` and `false`.
* A text default is a quoted string, and so is a fixed date or time, as `startsOn` shows. A `DateTime` default is a point in time with a UTC offset, such as `"2024-01-01T00:00:00Z"`, and a `Timestamp` default has no offset, such as `"2024-01-01 00:00:00"`.
* A fixed default on a `Date`, `DateTime`, `Timestamp`, or `Time` field needs a global `Temporal` in the Node.js that runs `contract emit`, which uses it to check the value. Without one, `contract emit` fails with `PSL_INVALID_DEFAULT_LITERAL`. A polyfill imported in your app does not help here, so run the CLI on a Node.js version that has `Temporal` built in, or use `DateString`, `TimestampString`, `TimestamptzString`, or `TimeString`, which need no `Temporal`.
* On a field typed with an `enum` block, the default is the member's name without quotes, as in `@default(Low)`. On a `pg.enum(...)` field, it is the value the member stores, in quotes, as in `@default("admin")`. [Enums](#enums) covers both.
* Any other SQL expression is a `sql` tagged literal, and it goes into the column default exactly as written. Write the current time as `now()` and a sequence as `autoincrement()`, not as `` sql`now()` `` or `` sql`autoincrement()` ``, which are refused.

Prisma ORM 7's `dbgenerated("...")` is not accepted, and `contract emit` reports `PSL_UNKNOWN_DEFAULT_FUNCTION`. Write the same SQL as a `sql` tagged literal instead, so `@default(dbgenerated("gen_random_uuid()"))` becomes ``@default(sql`gen_random_uuid()`)``. [`contract infer`](https://www.prisma.io/docs/cli/contract-infer) writes every default in these forms.

### Indexes [#indexes]

`@@index([...])` takes a list of fields, and on PostgreSQL the named arguments below. Either the list or `expression:` is required, and an `expression:` index needs a `name:`:

```prisma
model User {
  @@index([name], where: "(name IS NOT NULL)", name: "user_name_active")
  @@index(expression: "lower(handle)", unique: true, name: "user_handle_lower")
  @@index([slug], type: "hash", name: "user_slug_hash")
}
```

* `expression:` is the whole index expression as SQL, in place of the field list.
* `where:` makes a partial index; it is the condition as SQL, without the `WHERE` keyword.
* `unique:` makes a unique index. `@@unique([...])` is a unique constraint, which is the usual way to say a value must be unique; use `unique:` on `@@index` when you also need `expression:` or `where:`.
* `type:` picks the index method, such as `"hash"` or `"gin"`.
* `name:` names the index. The name in the database is not exactly what you typed: it gets an eight-character hash on the end, `user_name_active_000a85d8`, and if you change `name:` later, the next `migration plan` renames the index instead of dropping and recreating it. `map:` instead sets the exact name, for an index that already exists in the database, which is what [`contract infer`](https://www.prisma.io/docs/cli/contract-infer) writes for indexes it finds. Give one or the other, not both.

The `expression:` and `where:` strings go into the SQL as written, so they use column names, not field names (they differ when a field has `@map`), and you quote the names yourself. Prisma ORM does not check the SQL until the migration runs. On MongoDB, `@@index` takes different arguments; see [MongoDB indexes](#mongodb-indexes).

### Full-text indexes [#full-text-indexes]

`@@fullTextIndex([field])` creates the GIN index that PostgreSQL [full-text search](https://www.prisma.io/docs/orm/reference/orm-client#full-text-search) uses. It takes one text field, and it needs either `name:` or `map:`, but not both:

```prisma title="src/prisma/contract.prisma (excerpt)"
model Post {
  id    Int    @id
  title String

  @@fullTextIndex([title], name: "post_title_search")
}
```

`language:` sets the text-search language, which tells PostgreSQL how to break the text into searchable words. It defaults to `english`, and you set it as in `@@fullTextIndex([title], name: "post_title_search", language: "german")`. In a query, you search with the text field's `fullTextMatches` and `fullTextRank` functions, which take the same `language` option, as in `p.title.fullTextMatches(query, { language: "german" })`, and that option also defaults to `english`. Give the index and the search the same language, because PostgreSQL does not use the index for a search in another language. `where:` makes it a partial index, as on `@@index`. A field typed `pg.enum(...)`, a PostgreSQL enum type as [Enums](#enums) describes, cannot have a full-text index. PostgreSQL only.

### Check constraints [#check-constraints]

`@@check` adds a check constraint you write yourself, on top of the ones Prisma ORM generates for enum and list columns:

```prisma
model Order {
  id    Int     @id @default(autoincrement())
  total Decimal

  @@check(expression: "total >= 0", name: "order_total_positive")
}
```

`expression:` is the condition as SQL, using column names, as on `@@index`. `name:` and `map:` work as they do on `@@index`: `name:` for a constraint you are adding, and `map:` for one that already exists in the database under that exact name. A model can carry any number of `@@check` attributes. PostgreSQL only.

Prisma ORM also adds two check constraints of its own: one on every enum column, so it accepts only the enum's values, and one on every list column, so it rejects `NULL` elements. When one of them gets in your way, `@noCheck` on the field leaves both out, `@noCheck(membership)` leaves out only the enum check, and `@noCheck(elementNotNull)` only the list check. The field's TypeScript type does not change, so the database can then hold values the type does not describe.

### Control policy [#control-policy]

`@@control(...)` says how far Prisma ORM manages the table, with one of four values:

| Value                   | `db verify`                                                             | Migrations                                    |
| ----------------------- | ----------------------------------------------------------------------- | --------------------------------------------- |
| `managed` (the default) | The table must exist and match the model exactly.                       | Create, alter, and drop it.                   |
| `tolerated`             | Declared columns must match; extra columns are accepted.                | Create it if missing; never alter or drop it. |
| `external`              | Declared columns must match; extra columns and constraints are ignored. | Never touch it.                               |
| `observed`              | Anything goes; a mismatch is a warning, not a failure.                  | Never touch it.                               |

Put it on a model whose table something else owns, such as an audit table another system writes:

```prisma
model AuditLog {
  id      Int    @id @default(autoincrement())
  message String

  @@control(observed)
}
```

## Named types [#named-types]

The `types` block gives a database column type a name you can reuse on many fields:

```prisma
types {
  ShortName = VarChar(35)
}
```

Fields then use `ShortName` like any built-in type. The name keeps the column decision in one place: a `varchar(35)` column rather than `text`. You do not have to name a type: a field can use the native PostgreSQL type directly, such as `VarChar(35)`, `Numeric(10, 2)`, `Uuid`, or `Timestamptz`.

Three types cover big integers, and they differ in what your code receives:

| Type           | Column    | In your code                                                                |
| -------------- | --------- | --------------------------------------------------------------------------- |
| `BigInt`       | `bigint`  | a JavaScript `bigint`                                                       |
| `BigIntNumber` | `bigint`  | a JavaScript `number`; a read or write outside the safe integer range fails |
| `UnboundedInt` | `numeric` | a JavaScript `bigint` of any size                                           |

In Prisma ORM 8 the native type is the field's type, so `String @db.VarChar(35)` from Prisma ORM 7 becomes `VarChar(35)`, and the `@db.` attributes are gone. The `types` block is PostgreSQL only.

## Enums [#enums]

An enum lists its members. It can also say, with `@@type`, how their values are stored, and what each member stores:

```prisma
enum Priority {
  @@type("pg/text@1")
  Low    = "low"
  High   = "high"
  Urgent = "urgent"
}
```

In `pg/text@1`, `pg` is PostgreSQL, `text` is the column type, and `@1` is the version of how the value is stored and read. Write `@@type("pg/int4@1")` to store the values as integers instead. When a member has no explicit value, the member name itself is stored.

`@@type` is optional, and when you leave it out Prisma ORM picks the type from the member values: bare member names and string values give the database's text type, and integer values give its integer type. Give every member the same kind of value, because a mix of string and integer values throws an error whose `code` is `PSL_ENUM_CANNOT_INFER_TYPE`. A `@default` names the member, as in `priority Priority @default(Low)`, even where the member stores a different value.

An `enum` block is not a PostgreSQL `enum` type: the column is text or an integer. For a PostgreSQL `enum` type, declare it in a `native_enum` block and type the field `pg.enum(Role)`:

```prisma
native_enum Role {
  admin  = "admin"
  member = "member"
}

model User {
  role pg.enum(Role)
}
```

Each member needs a value. `pg` comes with `@prisma/orm-postgres`, so there is nothing to import. You do not create the PostgreSQL type yourself: `npx prisma migration plan` includes the `CREATE TYPE`.

## Value objects [#value-objects]

A `type` block declares a value object: a structured value stored inside its parent row, with no table of its own.

```prisma
type Address {
  street  String
  city    String
  zip     String?
  country String
}

model User {
  id        Uuid     @id @default(uuid())
  address   Address?
  addresses Address[]
}
```

A value object field can be optional or a list, and a `type` block can hold a field of another `type`. Watch the two spellings: `types { ... }` declares named types, and `type X { ... }` declares a value object. Storage differs by database: on PostgreSQL a value object field is stored in a single `jsonb` column, while on MongoDB it is an embedded document. Either way, `contract.d.ts` types it as a structured object rather than untyped JSON. On MongoDB, whether to embed or reference is the central modeling decision, and [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb#embed-or-reference) covers it.

## Relations [#relations]

Relations use the `@relation` syntax you know from Prisma ORM. The side that holds the foreign key declares the scalar field and the mapping, and the other side declares a list:

```prisma
model Post {
  userId Uuid
  user   User @relation(fields: [userId], references: [id])
}

model User {
  posts Post[]
}
```

Add `onDelete` and `onUpdate` to the same `@relation`: they belong on the side that holds the foreign key, not on the list side, and each takes `Cascade`, `Restrict`, `NoAction`, `SetNull`, or `SetDefault`:

```prisma
model Post {
  authorId Uuid
  editorId Uuid?
  author   User  @relation("Authored", fields: [authorId], references: [id], onDelete: Cascade)
  editor   User? @relation("Edited", fields: [editorId], references: [id], onDelete: SetNull)
}

model User {
  posts  Post[] @relation("Authored")
  edited Post[] @relation("Edited")
}
```

When two relations join the same two models, as `Authored` and `Edited` do here, give each pair the same `@relation("Name")` on both ends so Prisma ORM can tell which list belongs to which foreign key; otherwise `npx prisma contract emit` fails with an error whose `code` is `PSL_AMBIGUOUS_BACKRELATION`. For a one-to-one, make the other side singular instead of a list, so `User` declares `profile Profile?`, and put `@unique` on the foreign-key field:

```prisma
model Profile {
  userId Uuid @unique
  user   User @relation(fields: [userId], references: [id])
}
```

Many-to-many relations need a model for the join table, and you write that model yourself: there is no implicit many-to-many. That model must follow two rules: if a side has a composite primary key, that model needs one foreign-key field for each part of it, and its `@@id([...])` must list exactly the foreign-key fields and nothing else.

```prisma
model Post {
  tags Tag[]
}

model Tag {
  posts Post[]
}

model PostTag {
  postId Uuid
  tagId  Uuid

  post Post @relation(fields: [postId], references: [id])
  tag  Tag  @relation(fields: [tagId], references: [id])

  @@id([postId, tagId])
  @@map("post_tag")
}
```

You then read `post.tags` as a list of `Tag`, without mentioning `PostTag` in the query. Break either rule and `npx prisma contract emit` reports which list field it could not match to a model. If two models qualify, `npx prisma contract emit` throws an error whose `code` is `PSL_AMBIGUOUS_BACKRELATION`: put the same `@relation("name")` on both ends of one pair, so on `PostTag.post` for `Post.tags`.

For which shape to choose and which side owns the foreign key, see [relational data modeling](https://www.prisma.io/docs/orm/data-modeling/relational-databases) and [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb).

## Namespaces [#namespaces]

A PostgreSQL schema other than `public` is a `namespace` block, and the models inside it get their tables there:

```prisma
namespace audit {
  model AuditLog {
    id      Int    @id @default(autoincrement())
    message String

    @@map("audit_log")
  }
}
```

Models outside any block are in `public`. In queries, the block name is the segment after `db.orm`, so this model is `db.orm.audit.AuditLog`. Two `namespace` blocks with the same name in one file are one namespace, so you can open a block again further down the file. A relation can also point at a model that an [extension pack](#extension-types), an npm package you add to your config, declares in a different PostgreSQL schema. Write that model as the relation field's type, in the form `<pack>:<schema>.<Model>`, where `<schema>` is the PostgreSQL schema. For example, the Supabase pack declares `AuthUser` in the `auth` schema:

```prisma title="src/prisma/contract.prisma (excerpt)"
model Profile {
  id     Uuid                   @id @default(uuid())
  userId Uuid                   @unique
  user   supabase:auth.AuthUser @relation(fields: [userId], references: [id], onDelete: Cascade)
}
```

The [Supabase extension](https://www.prisma.io/docs/orm/extensions) documents that form.

## Row-level security [#row-level-security]

Two block kinds and one attribute declare PostgreSQL row-level security, and [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) turns them into `ENABLE ROW LEVEL SECURITY` and `CREATE POLICY` statements. `@@rls` on a model turns row-level security on for its table. A `policy_select`, `policy_insert`, `policy_update`, `policy_delete`, or `policy_all` block declares one policy for one operation, and a `role` block declares a database role a policy names:

```prisma
model User {
  id Uuid @id @default(uuid())

  @@map("user")
  @@rls
}

namespace unbound {
  role authenticated {}
}

policy_select user_self_read {
  target = User
  roles  = [authenticated]
  using  = "id = current_setting('app.user_id')::uuid"
}

policy_update user_self_write {
  target     = User
  roles      = [authenticated]
  using      = "id = current_setting('app.user_id')::uuid"
  withCheck  = "id = current_setting('app.user_id')::uuid"
  permissive = false
}
```

Policy and role blocks assign their settings with `=`, unlike model attributes. `target` names the model, which must carry `@@rls`; put the policy blocks inside the same `namespace` block as the model when it has one. `roles` lists bare role names. A role Prisma ORM should create needs a `role` block, whose braces stay empty; a role that already exists in the database, such as `public`, is written bare with no block: `roles = [public]`. `using` and `withCheck` are the two conditions as SQL, using column names: `policy_select` and `policy_delete` take `using`, `policy_insert` takes `withCheck`, and `policy_update` and `policy_all` take either or both. `permissive = false` makes the policy `AS RESTRICTIVE` in PostgreSQL's terms, so a row must pass it as well as the permissive policies. The block's name becomes the policy name with a hash on the end, as index names do. A `role` block must be inside `namespace unbound { }`; `unbound` is a reserved word meaning "not in any schema", which is where a role belongs.

## MongoDB indexes [#mongodb-indexes]

On MongoDB, `@@index` and `@@unique` take a list of fields, each with an optional sort direction, plus MongoDB's own index options as named arguments, and `@@textIndex` declares a text index:

```prisma
model Post {
  @@index([authorId])
  @@index([createdAt(sort: Desc), authorId])
  @@index([expiresAt], expireAfterSeconds: 3600, sparse: true)
  @@index([title], filter: "{ \"kind\": \"article\" }")
  @@index([location], type: "2dsphere")
  @@index([wildcard(meta)], exclude: ["meta.internal"])
  @@textIndex([title, body], weights: { "title": 10, "body": 1 }, language: "english")
}

model User {
  @@unique([email], collationLocale: "en", collationStrength: 2)
}
```

`sort: Asc` or `sort: Desc` on a field sets its direction; this form is MongoDB only. The keys in `weights` are field names, quoted. The named arguments are `type` (`"text"`, `"2dsphere"`, `"2d"`, or `"hashed"`), `sparse`, `expireAfterSeconds`, `filter` (a partial filter expression, written as a JSON string), `default_language` and `languageOverride` for a `type: "text"` index, `include` or `exclude` for a wildcard index, and the collation options `collationLocale`, `collationStrength`, `collationCaseLevel`, `collationCaseFirst`, `collationNumericOrdering`, `collationAlternate`, `collationMaxVariable`, `collationBackwards`, and `collationNormalization`. `@@textIndex` takes `weights`, `language`, `languageOverride`, `filter`, and the same collation options. There is no `name:` on MongoDB; MongoDB names the index from its keys.

A wildcard index covers every field under a path, which is how you index documents whose keys you do not know in advance. Write `wildcard()` in the field list to cover the whole document, or `wildcard(meta)` to cover the fields under `meta`; the key becomes `$**` or `meta.$**`. `include` and `exclude` are lists of field names, quoted, that narrow what the index covers; give one or the other, and only with `wildcard()`. An index can hold one `wildcard()`, and it cannot be an `@@unique`, take `expireAfterSeconds`, or set a `type:` such as `"hashed"`.

## Base models and variants [#base-models-and-variants]

A base model declares a discriminator field, the field whose value says which variant a row is. Each variant names its base and its discriminator value:

```prisma
model Task {
  id     Uuid   @id @default(uuid())
  title  String
  type   String

  @@discriminator(type)
  @@map("task")
}

model Bug {
  severity     String
  stepsToRepro String?

  @@base(Task, "bug")
  @@map("bug")
}
```

Field and model names are written bare, as `type` and `Task` are, while table names and discriminator values are quoted, as `"task"` and `"bug"` are. Rows whose `type` column holds `"bug"` are `Bug` records. A variant reuses its base model's fields, so a `Bug` has `id`, `title`, and `type` as well as `severity` and `stepsToRepro`. The base model can be declared before or after its variants. A variant does not declare an `@id` of its own: it takes the base model's primary key.

You query a variant through the base model: `db.orm.public.Task.variant('Bug')` returns the `Bug` rows only, and `public` here is the PostgreSQL schema. Writing a row of a variant starts with the same `variant('Bug')` call. See [`variant()`](https://www.prisma.io/docs/orm/reference/orm-client#variant).

On a variant, `@@map` does more than rename: on PostgreSQL it chooses between two storage layouts. Give the variant its own `@@map`, as `Bug` has here, and its fields are in a table of their own that shares the base model's primary key. Leave `@@map` out and they are nullable columns in the base table. [Relational data modeling](https://www.prisma.io/docs/orm/data-modeling/relational-databases#polymorphic-relations) covers choosing between the two.

On MongoDB, a variant adds its fields to documents in the base model's collection, so it declares `@@base` but no `@@map` of its own.

## Extension types [#extension-types]

An extension pack is an npm package that adds field types Prisma ORM does not ship, such as vectors. Install the pack, add the import and the `extensions` line to the config shown above, then call its types in the `types` block:

```bash
npm install @prisma/orm-extension-pgvector
```

```typescript title="prisma.config.ts"
import pgvector from "@prisma/orm-extension-pgvector/control";

// inside ormConfig({ ... }), beside contract and db:
    extensions: [pgvector],
```

```prisma title="src/prisma/contract.prisma"
// use prisma-8

types {
  Embedding1536 = pgvector.Vector(1536)
}

model Post {
  id        Uuid           @id @default(uuid())
  embedding Embedding1536?
}
```

A field can also use the pack's type directly, with the argument named: `embedding pgvector.Vector(length: 1536)?`. The `pgvector` part of `pgvector.Vector(1536)` is a fixed name the pack declares, not the name you gave the import. List the pack before using its types, and run `npx prisma contract emit` again after changing the extension list. [Using extensions](https://www.prisma.io/docs/orm/extensions/using-extensions) covers installing a pack and names the packs you can add.

## Starting from an existing database [#starting-from-an-existing-database]

If the database already exists, don't write the contract by hand: [`contract infer`](https://www.prisma.io/docs/cli/contract-infer) reads the live schema and writes a starter `contract.prisma` for you to review and edit.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest -- my-app` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent: skills are instruction files the agent reads. In an existing project, run `npx prisma skills sync` to add them. The `prisma-8` skill covers PSL authoring, so ask your agent to:

* "Using the prisma-8 skill, add a Status enum stored as text and use it on the Order model."
* "Add a one-to-many between User and Post with the foreign key on Post."
* "Give the Post model a composite unique constraint on userId and title."

## Next steps [#next-steps]

* Run `npx prisma contract emit` and inspect [`contract.json` and `contract.d.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact). You do not import them yourself. `db`, the client that reads both, is in `src/prisma/db.ts`, and `prisma orm init` writes that file. See [transactions and runtime](https://www.prisma.io/docs/orm/reference/transactions-and-runtime).
* If you prefer defining models in code, see [authoring in TypeScript](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder).
* Plan changes to a database you have already created with [`migration plan`](https://www.prisma.io/docs/cli/migration-plan).

## Related pages

- [`Author in TypeScript`](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder): Define the Prisma ORM contract with a typed builder in TypeScript instead of a schema file. Same models, same `contract.json` and `contract.d.ts`, no separate language.
- [`contract.json and contract.d.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact): contract.json and contract.d.ts are the two files every other part of Prisma ORM reads. Here is what is inside them.
- [`Editor support`](https://www.prisma.io/docs/orm/contract-authoring/editor-support): What the Prisma VS Code extension does for a Prisma ORM contract, and what to do when it stops accepting the file.
- [`Supported database features`](https://www.prisma.io/docs/orm/contract-authoring/capabilities): The contract records which database features your packages support, so Prisma ORM can reject an unsupported one early with a clear error.
- [`The data contract`](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract): The data contract is the one description of your data model and how it is stored. Prisma ORM types your queries, plans your migrations, and checks your database against it.

# contract.json and contract.d.ts (/docs/orm/contract-authoring/the-contract-artifact)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

contract.json and contract.d.ts are the two files every other part of Prisma ORM reads. Here is what is inside them.

Location: ORM > Contract authoring > contract.json and contract.d.ts

Your contract is [a single file that describes your data and how it is stored](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract). It replaces the `schema.prisma` of Prisma ORM 7 and is either `src/prisma/contract.prisma` in Prisma Schema Language (PSL) or `src/prisma/contract.ts` in TypeScript. [`npx prisma contract emit`](https://www.prisma.io/docs/cli/contract-emit) reads that file and writes two files beside it. In the table below, `db` is your client, the object you run queries on. [`npx prisma orm init`](https://www.prisma.io/docs/cli/orm-init) creates the contract source, `src/prisma/db.ts`, and `.env.example` for you. In Prisma ORM 7 you edited `schema.prisma` and the tooling read the same file, but now you edit the contract and the tooling reads the two files it produces.

| File            | Contents                                                                                                      | Read by                                                                 |
| --------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `contract.json` | The machine-readable contract: models, how they are stored, which database features they need, and the hashes | `db`, `prisma db sign`, `prisma db verify`, and `prisma migration plan` |
| `contract.d.ts` | TypeScript declarations derived from the contract                                                             | The query APIs and your application code, for typed models and results  |

`prisma db sign` writes the current contract's hashes into the database, so later commands can tell which contract that database was built for. Both files are generated, so do not edit them: change the [PSL](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax) or [TypeScript](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder) source and run `npx prisma contract emit` again. `contract.d.ts` starts with a comment saying it is generated and must not be edited, and `contract.json` carries the same notice in a `_generated` entry. To write the two files to another directory, see [`prisma contract emit`](https://www.prisma.io/docs/cli/contract-emit).

The everyday loop on a project:

1. Edit `contract.prisma` or `contract.ts`.
2. Run `npx prisma contract emit`.
3. Create the migration with [`npx prisma migration plan`](https://www.prisma.io/docs/cli/migration-plan), read it, then apply it with [`npx prisma db migrate`](https://www.prisma.io/docs/cli/db-migrate).
4. Check the database against the contract with [`npx prisma db verify`](https://www.prisma.io/docs/cli/db-verify) in CI or in your deploy step.

`npx prisma db verify` reports whether the database has a record and whether it matches. You almost never sign a database yourself:

* Applying a migration records the match for you, and so does [`npx prisma db init`](https://www.prisma.io/docs/cli/db-init) when it creates the structures in an empty database.
* Run [`npx prisma db sign`](https://www.prisma.io/docs/cli/db-sign) by hand only after [`npx prisma contract infer`](https://www.prisma.io/docs/cli/contract-infer) has written a starter contract from a database that already matches it.

## The same source always produces the same two files [#deterministic-emission]

Run `npx prisma contract emit` on the same source on any machine and you get the same two files, byte for byte. That holds only if your contract source does not read the environment, the clock, or random values, and the [TypeScript authoring page](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder#keep-the-contract-file-pure) lists the rules.

## The content hashes [#the-content-hashes]

`npx prisma contract emit` computes a hash over each part of the contract, and you never compute or compare them yourself. `storageHash` covers the storage layout: tables, columns, primary keys, uniques, indexes, foreign keys, and the allowed values of each enum. `profileHash` covers which database the contract targets. The hashes are how Prisma ORM connects the contract to a live database: `npx prisma db sign` checks that the database satisfies the contract, then records `storageHash` and `profileHash` in the database. `npx prisma db verify` compares the contract you hold against that record and against the live schema, and fails when they disagree. To fix a mismatch, apply the pending migration, or run `npx prisma db sign` when the database already matches the contract.

## Inside `contract.json` [#inside-contractjson]

The contract keeps your application's view of the data separate from the way the database stores it. The `domain` section describes models, fields, and relations, while the `storage` section describes tables, columns, keys, and indexes. On MongoDB it describes collections and indexes instead. Each model's own `storage` block maps each field to its column. Everything is grouped by namespace, and on PostgreSQL the namespace is the schema, which is `public` unless you put the models in a `namespace` block in your [PSL source](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax).

An abridged `contract.json` for a `User` and `Post` schema:

```json title="src/prisma/contract.json (abridged)"
{
  "schemaVersion": "1",
  "targetFamily": "sql",
  "target": "postgres",
  "profileHash": "…",
  "roots": {
    "Post": { "model": "Post", "namespace": "public" },
    "User": { "model": "User", "namespace": "public" }
  },
  "domain": {
    "namespaces": {
      "public": {
        "models": {
          "User": {
            "fields": {
              "email": { "nullable": false, "type": { "codecId": "pg/text@1", "kind": "scalar" } },
              "id": { "nullable": false, "type": { "codecId": "pg/uuid@1", "kind": "scalar" } }
            },
            "storage": {
              "fields": { "email": { "column": "email" }, "id": { "column": "id" } },
              "namespaceId": "public",
              "table": "User"
            }
          }
        }
      }
    }
  },
  "storage": {
    "namespaces": {
      "public": {
        "entries": {
          "table": {
            "User": {
              "columns": {
                "email": { "codecId": "pg/text@1", "nativeType": "text", "nullable": false },
                "id": { "codecId": "pg/uuid@1", "nativeType": "uuid", "nullable": false }
              },
              "primaryKey": { "columns": ["id"] }
            }
          }
        }
      }
    },
    "storageHash": "…"
  },
  "capabilities": { "postgres": { "returning": true } }
}
```

The sections, top to bottom:

* **`schemaVersion`, `targetFamily`, `target`**: the contract format version, whether the database is SQL or MongoDB, and which database this contract targets.
* **`roots`**: one entry per table that stores a model. The key is the name of that table, so for a model `User` mapped to a table `users` the key is `users`. The value names the model. You can query the model's data in two ways. The [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder), `db.sql`, reaches the table by its table name, and the ORM API, `db.orm`, reaches the model by its model name. In this example both names are `User`, because the model sets no `@@map`, so the calls are `db.sql.public.User` and `db.orm.public.User`. For a model `User` mapped to a table `users`, they are `db.sql.public.users` and `db.orm.public.User`. The [ORM reference](https://www.prisma.io/docs/orm/reference) covers both.
* **`domain` and `storage`**: your application's view, then the database's view. Each scalar field in `domain` records whether it is nullable and its `codecId`. `nativeType` is the column type in the database. `codecId` names how Prisma ORM reads and writes the value, the PostgreSQL type plus a version. `storage` holds the tables with their columns, keys, indexes, constraints, and enum values. `prisma db verify` compares it to the live database.
* **`capabilities`**: which database features this contract can use. `npx prisma contract emit` collects them from the adapter for your database and from the packages listed in `extensions: [...]` in `prisma.config.ts`, the config file `prisma orm init` writes. The query APIs check them before building a query that needs one. See [supported database features](https://www.prisma.io/docs/orm/contract-authoring/capabilities) and [extension types](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#extension-types).

## Inside `contract.d.ts` [#inside-contractdts]

The declarations file gives the type system the same information. It exports:

* `Contract`, the type the client is built from. `db.ts` imports it.
* One type per hash, such as `StorageHash` and `ProfileHash`. Each one carries the hash of that part of the contract.
* Input and output types for each [`type` block](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#value-objects) in your contract.

```typescript title="src/prisma/contract.d.ts (excerpt)"
export type StorageHash =
  StorageHashBase<'fac9b49833c04e1ea5da153f6f7c2444520bbbc24cc5bcf7e21a80b199ca412b'>;
```

You never write these types yourself. Both files come from the one `npx prisma contract emit` run, so they only drift when someone commits one and not the other. The CI check below catches that.

## How the application consumes the artifacts [#how-the-application-consumes-the-artifacts]

`db` is built from both files: `contract.json` as the value, `contract.d.ts` as the type. `prisma orm init` writes `src/prisma/db.ts` for you.

```typescript title="src/prisma/db.ts"
import "dotenv/config";
import postgres from "@prisma/orm-postgres/runtime";
import type { Contract } from "./contract.d";
import contractJson from "./contract.json" with { type: "json" };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});
```

The connection string comes from the `DATABASE_URL` environment variable: `prisma orm init` writes `.env.example`, and you put your `DATABASE_URL` in `.env`. Keep the `.d` in the import path: it names `contract.d.ts`, so the import still finds the generated type when you author the contract in TypeScript and a `contract.ts` sits beside it. The `tsconfig.json` settings the JSON import needs are on the [transactions and runtime page](https://www.prisma.io/docs/orm/reference/transactions-and-runtime). Before its first query, `db` reads the record in the database of which contract it matches and compares it with the contract's hashes. If they do not match, it logs a warning whose `code` is `CONTRACT.MARKER_MISMATCH` and runs the query anyway. If there is no record at all, because nothing has signed the database yet, it logs a warning whose `code` is `CONTRACT.MARKER_MISSING` and again runs the query. On MongoDB the client is `mongo<Contract>(...)` from `@prisma/orm-mongo/runtime`, described under [`mongo(options)`](https://www.prisma.io/docs/orm/reference/transactions-and-runtime#mongooptions).

When `CONTRACT.MARKER_MISMATCH` shows up in production, apply the pending migration, or run `npx prisma db sign` when the database already matches the contract. The client warns by default, and you can set [`verifyMarker`](https://www.prisma.io/docs/orm/reference/transactions-and-runtime#postgresoptions) to `false` to skip the check. It cannot be made to fail, so run `prisma db verify` when you need a check that fails.

## Version control [#version-control]

Commit `contract.json` and `contract.d.ts` alongside the source: they hold structure only, no data and no credentials. Committing them lets teammates, CI, and deploys read the contract without running `npx prisma contract emit` first. Run `npx prisma contract emit` after every source change so the two files never trail the source; in a Vite project, the [Vite plugin](https://www.prisma.io/docs/cli/contract-emit#run-it-automatically) does that whenever the contract or `prisma.config.ts` changes while the dev server runs. A CI job can check this in two lines:

```bash
npx prisma contract emit
git diff --exit-code src/prisma
```

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. In an existing project, run `npx prisma skills sync` to add them. The `prisma-8` skill covers the contract, so ask your agent to:

* "Explain the difference between contract.json and contract.d.ts in this project."
* "Run prisma contract emit and show me what changed in contract.json."

## Next steps [#next-steps]

* Learn [which database features](https://www.prisma.io/docs/orm/contract-authoring/capabilities) the contract needs, and how Prisma ORM checks that your database has them.
* Apply the contract to a fresh database with [`prisma db init`](https://www.prisma.io/docs/cli/db-init).
* Check a live database against the contract with [`prisma db verify`](https://www.prisma.io/docs/cli/db-verify).
* Plan schema changes between contract versions with [`prisma migration plan`](https://www.prisma.io/docs/cli/migration-plan).

## Related pages

- [`Author in PSL`](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax): Write the Prisma ORM contract in the Prisma schema language you already know, plus the Prisma ORM 8 additions.
- [`Author in TypeScript`](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder): Define the Prisma ORM contract with a typed builder in TypeScript instead of a schema file. Same models, same `contract.json` and `contract.d.ts`, no separate language.
- [`Editor support`](https://www.prisma.io/docs/orm/contract-authoring/editor-support): What the Prisma VS Code extension does for a Prisma ORM contract, and what to do when it stops accepting the file.
- [`Supported database features`](https://www.prisma.io/docs/orm/contract-authoring/capabilities): The contract records which database features your packages support, so Prisma ORM can reject an unsupported one early with a clear error.
- [`The data contract`](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract): The data contract is the one description of your data model and how it is stored. Prisma ORM types your queries, plans your migrations, and checks your database against it.

# The data contract (/docs/orm/contract-authoring/the-data-contract)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The data contract is the one description of your data model and how it is stored. Prisma ORM types your queries, plans your migrations, and checks your database against it.

Location: ORM > Contract authoring > The data contract

Every Prisma ORM project has one description of its data: the models, their fields, and how they map to database tables. That description is the data contract, the `contract.prisma` file that replaced `schema.prisma`. For example, a blog's contract declares a `User` and a `Post`, the fields each one has, and how they relate. You author it in PSL, the Prisma Schema Language, the same language as `schema.prisma`:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  posts Post[]
}

model Post {
  id     Int    @id @default(autoincrement())
  title  String
  userId Int
  user   User   @relation(fields: [userId], references: [id])
}
```

The first line, `// use prisma-8`, marks the file as a Prisma ORM 8 contract rather than a Prisma ORM 7 schema, and `npx prisma orm init` writes it into the `contract.prisma` file it creates. The first non-blank line of every `.prisma` contract file must be `// use prisma-8`, because `contract emit` reads only the files that have it and skips any other file without a warning. When no file has the line, `contract emit` fails with `CONTRACT.SOURCE_LOAD_FAILED`. The editor extension also looks for the line before it checks, completes, or formats the file. A `contract.ts` file needs no header line. See [Editor support](https://www.prisma.io/docs/orm/contract-authoring/editor-support).

`npx prisma contract emit` turns this file into two files that the CLI and your application read: `contract.json` and `contract.d.ts`. Your queries are type-checked against the contract, migrations are planned as changes to it, and `npx prisma db verify` checks a live database against it.

> [!NOTE]
> Contract vs. schema
> 
> In Prisma ORM, the **contract** is what you write in your code. The **schema** is your database's actual structure.

## Why a contract [#why-a-contract]

Your contract compiles to two plain files you can open and read: `contract.json` describes your models, how they are stored, and the [database features they need](https://www.prisma.io/docs/orm/contract-authoring/capabilities), and `contract.d.ts` holds the TypeScript types derived from it. You can read both files in a code review and hand them to tools and coding agents.

`npx prisma db migrate` records in your database which contract it applied, and the first time `db` runs a query it checks that record and logs a warning on a mismatch. To fail instead, run [`npx prisma db verify`](https://www.prisma.io/docs/cli/db-verify) in a deploy check.

## How it works [#how-it-works]

A Prisma ORM project declares one contract file in `prisma.config.ts`:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./src/prisma/contract.prisma",
    db: {
      connection: process.env["DATABASE_URL"]!,
    },
  }),
});
```

`definePrismaConfig` holds the whole config: which contract file to use and how to reach your database. Your connection string is in `prisma.config.ts` now, and the contract has no `datasource` block. `npx prisma orm init` writes `.env.example`, and your `DATABASE_URL` goes in `.env`. `@prisma/orm-postgres/config` exports `defineConfig`, which the example renames to `ormConfig` on import. The packages are `@prisma/orm-postgres` for PostgreSQL, `@prisma/orm-sqlite` for SQLite, and `@prisma/orm-mongo` for MongoDB. The examples here use PostgreSQL.

To start a new project, run `npm create prisma@latest -- my-app`. To add Prisma ORM 8 to a project that has no Prisma ORM at all, run `npx prisma orm init`. If you already have a Prisma ORM 7 `schema.prisma`, follow the [PostgreSQL upgrade guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql) instead, and [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) lists what changed. Both `npm create prisma@latest` and `npx prisma orm init` write `prisma.config.ts`, the contract file, and `src/prisma/db.ts`, and install the database package.

The contract file is either a PSL file (`contract.prisma`) or a TypeScript file (`contract.ts`). The file extension selects the authoring mode, so to author in TypeScript you point `contract` at `./src/prisma/contract.ts`. You can also split a PSL contract across several files by setting `contract` to a glob such as `./src/prisma/**/*.prisma`, as [Configuration](https://www.prisma.io/docs/cli/configuration#split-the-schema-across-several-files) shows. Both modes describe the same things: models with fields and relations, the tables and columns they map to, named types, enums, and any types that [extension packages](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#extension-types) add. Extension packages are npm packages that add field types and database features. For example, `@prisma/orm-extension-pgvector` adds vector columns, which it stores with pgvector, a PostgreSQL extension.

After every change to the contract, run these three commands:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan
bunx prisma db migrate
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan
pnpm prisma db migrate
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan
yarn prisma db migrate
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan
npx prisma db migrate
```

`npx prisma contract emit` writes `contract.json` and `contract.d.ts` beside the contract file, so `src/prisma/`. [`npx prisma migration plan`](https://www.prisma.io/docs/orm/migrations/generating-a-migration) compares your contract against the last one and writes a migration. [`npx prisma db migrate`](https://www.prisma.io/docs/orm/migrations/applying-a-migration) applies it and records the match for you. When the database already matches the contract, run [`npx prisma db sign`](https://www.prisma.io/docs/cli/db-sign), which records the match without applying anything, for example after [`npx prisma contract infer`](https://www.prisma.io/docs/cli/contract-infer), which writes a contract from an existing database.

`db` is the client you create once in `src/prisma/db.ts`, and `npx prisma orm init` writes that file for you. From a file directly inside `src/`, import it with `import { db } from "./prisma/db"` and query a model: `await db.orm.public.User.all()` returns every user row. From a deeper file, adjust the relative path. `db.orm` is the ORM client, one of the [three query APIs](https://www.prisma.io/docs/orm/reference), and `public` is the PostgreSQL schema, the namespace your tables are in, unless you configured a different one. [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data) covers queries.

## Two authoring modes, one `contract.json` [#two-authoring-modes-one-artifact]

**[PSL](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax)**, a compact language for describing data, is the usual way to write the contract: it is what `npm create prisma@latest` scaffolds, and what [`npx prisma contract infer`](https://www.prisma.io/docs/cli/contract-infer) writes when you start from an existing database.

Define models with the &#x2A;*[TypeScript builder](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder)** instead when you want to build them with code: reach for it when model definitions must be composed, generated, or shared as ordinary TypeScript modules. That page shows what a `contract.ts` file looks like.

Both modes produce the same contract, so migrations, database checks, and `db` behave the same no matter which mode you write. The config names either PSL files or one TypeScript file, never both, and Prisma ORM reads only the files it names. So do not keep both a `contract.prisma` and a `contract.ts`, because edits to the one the config does not name do nothing. To switch modes, change the path in `contract` and delete the old file.

## What the contract contains [#what-the-contract-contains]

The contract describes structure, not data:

* models, fields, and relations, plus how they map to tables and columns
* how the data is stored: primary keys, unique constraints, indexes, and foreign keys
* [named types](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#named-types), which are reusable aliases for a database column type, and enums
* [`type` blocks](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#value-objects), also called value objects, each a reusable group of fields such as an address, stored inside its parent row with no table of its own
* the types and database features that extension packages add, such as pgvector's `Vector` type

It contains no rows, no credentials, and no connection details, so committing the source, `contract.json`, and `contract.d.ts` to version control is safe and expected.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. In an existing project, run `npx prisma skills sync` to add them. The `prisma-8` skill covers the contract, so ask your agent to:

* "Using the prisma-8 skill, explain what our contract.json currently declares."
* "Add an Invoice model to the contract and run prisma contract emit."
* "Check whether our database still satisfies the contract."

## Next steps [#next-steps]

* [Model your data](https://www.prisma.io/docs/orm/data-modeling) before writing the contract: models, keys, and relations.

- [Author in PSL](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax): Write the contract as a PSL file.

- [Author in TypeScript](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder): Define the same models with the TypeScript builder.

- [contract.json and contract.d.ts](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact): What is inside contract.json and contract.d.ts, and how the hashes work.

- [Supported database features](https://www.prisma.io/docs/orm/contract-authoring/capabilities): How Prisma ORM checks that your database supports what the contract needs.

## Related pages

- [`Author in PSL`](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax): Write the Prisma ORM contract in the Prisma schema language you already know, plus the Prisma ORM 8 additions.
- [`Author in TypeScript`](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder): Define the Prisma ORM contract with a typed builder in TypeScript instead of a schema file. Same models, same `contract.json` and `contract.d.ts`, no separate language.
- [`contract.json and contract.d.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact): contract.json and contract.d.ts are the two files every other part of Prisma ORM reads. Here is what is inside them.
- [`Editor support`](https://www.prisma.io/docs/orm/contract-authoring/editor-support): What the Prisma VS Code extension does for a Prisma ORM contract, and what to do when it stops accepting the file.
- [`Supported database features`](https://www.prisma.io/docs/orm/contract-authoring/capabilities): The contract records which database features your packages support, so Prisma ORM can reject an unsupported one early with a clear error.

# Author in TypeScript (/docs/orm/contract-authoring/typescript-schema-builder)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Define the Prisma ORM contract with a typed builder in TypeScript instead of a schema file. Same models, same `contract.json` and `contract.d.ts`, no separate language.

Location: ORM > Contract authoring > Author in TypeScript

In Prisma ORM 8, `schema.prisma` is replaced by a file called [the contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract), which holds the model definitions you used to write in `schema.prisma`. You can write it in two forms: one is a `.prisma` file written in PSL, short for Prisma Schema Language, and the other is TypeScript, in `src/prisma/contract.ts`, built with the `defineContract` builder. Both forms produce the same two files: [`npx prisma contract emit`](https://www.prisma.io/docs/cli/contract-emit) writes `contract.json` and `contract.d.ts` into the folder that holds your contract file.

## When to choose TypeScript over PSL [#when-to-choose-typescript-over-psl]

[PSL](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax) is the preferred way to write the contract, and both forms produce the same two files, so you give up nothing by staying with PSL. Use the TypeScript builder for the cases PSL does not cover, and reach for it when:

* model definitions must be split, composed, or reused across ordinary TypeScript modules or packages
* you want to build models in a loop from data you already keep in TypeScript, such as one model per entry in a list of table names

If neither applies, write PSL, which is more compact and is what [`contract infer`](https://www.prisma.io/docs/cli/contract-infer) writes.

## Point the config at the contract file [#point-the-config-at-the-contract-file]

For a new project, run [`npx prisma orm init`](https://www.prisma.io/docs/cli/orm-init), which asks how you want to write your schema, and choosing TypeScript creates the contract file and the config together.

The config's `contract` path names the one file Prisma ORM reads, and a `.ts` extension selects TypeScript authoring. An optional `output` names a directory for `contract.json` and `contract.d.ts`, which otherwise land next to the contract file; `npm create prisma@latest` sets it to `./src/prisma/generated` for TypeScript projects:

  

#### PostgreSQL

```typescript title="prisma.config.ts" 
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./src/prisma/contract.ts",
    output: "./src/prisma/generated",
  }),
});
```

#### MongoDB

```typescript title="prisma.config.ts" 
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-mongo/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./src/prisma/contract.ts",
  }),
});
```

## A complete contract [#a-complete-contract]

The builder comes from your database's package: `@prisma/orm-postgres/contract-builder` for PostgreSQL, `@prisma/orm-mongo/contract-builder` for MongoDB.

Export the contract under the name `contract`, as below, or as the file's default export, because those are the only two names `prisma contract emit` looks for. Run `npx prisma contract emit` again after every edit to the contract, and commit the contract file together with [`contract.json` and `contract.d.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact).

  

#### PostgreSQL

```typescript title="src/prisma/contract.ts" 
import { defineContract, enumType, member } from "@prisma/orm-postgres/contract-builder";

// nativeType is the column type the database gets. codecId picks how Prisma ORM converts the value between TypeScript and that column, and its @1 is the version of that conversion.
const pgText = { codecId: "pg/text@1", nativeType: "text" } as const;

const Priority = enumType("Priority", pgText, member("Low", "low"), member("High", "high"));

export const contract = defineContract({}, ({ field, model, rel }) => {
  const User = model("User", {
    fields: {
      id: field.id.uuidv4String(),
      email: field.text(),
      createdAt: field.temporal.createdAt(),
      address: field.json().optional(),
    },
  });

  const Post = model("Post", {
    fields: {
      id: field.id.uuidv4String(),
      title: field.text(),
      userId: field.uuidString(),
      priority: field.namedType(Priority).default(Priority.members.Low),
      createdAt: field.temporal.createdAt(),
      updatedAt: field.temporal.updatedAt(),
    },
  });

  return {
    enums: { Priority },
    models: {
      User: User.relations({ posts: rel.hasMany(Post, { by: "userId" }) }).sql({ table: "user" }),
      Post: Post.relations({
        user: rel.belongsTo(User, { from: "userId", to: "id" }).sql({ fk: { name: "post_userId_fkey" } }),
      }).sql({ table: "post" }),
    },
  };
});
```

#### MongoDB

```typescript title="src/prisma/contract.ts" 
import { defineContract, field, model, rel } from "@prisma/orm-mongo/contract-builder";

const User = model("User", {
  collection: "users",
  fields: {
    _id: field.objectId(),
    email: field.string(),
  },
  relations: {
    posts: rel.hasMany("Post", { from: "_id", to: "authorId" }),
  },
});

const Post = model("Post", {
  collection: "posts",
  fields: {
    _id: field.objectId(),
    authorId: field.objectId(),
    title: field.string(),
    publishedAt: field.date().optional(),
  },
  relations: {
    author: rel.belongsTo(User, { from: "authorId", to: User.ref("_id") }),
  },
});

export const contract = defineContract({ models: { User, Post } });
```

## How `defineContract` works [#how-definecontract-works]

On PostgreSQL, `defineContract` takes an options object and then a function. You do not set a `provider` anywhere: importing `@prisma/orm-postgres/contract-builder` is what selects PostgreSQL. The options object lists the extension packs you use, and you write `{}` when you use none. The function returns the contract's content: `models`, plus `enums`, `types`, and `entities` if you have them.

The options object takes four more keys, all optional:

| Option                                                    | What it does                                                                                                                                                                                    |
| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `naming: { tables: "snake_case", columns: "snake_case" }` | Derives table and column names from model and field names, so `createdAt` becomes `created_at` without a `.column(...)` call on every field. Set either key or both.                            |
| `foreignKeyDefaults: { constraint: true, index: true }`   | Gives every `rel.belongsTo` a foreign key constraint and an index in the database. Without this option a relation gets neither unless its own `.sql({ fk })` asks; see [Relations](#relations). |
| `defaultControlPolicy: "managed"`                         | The [control policy](#control-policy) for every model that does not set its own.                                                                                                                |
| `namespaces: ["audit"]`                                   | The PostgreSQL schemas other than `public` that models may use; see [Namespaces](#namespaces).                                                                                                  |

Take `field`, `model`, `rel`, and `type` from the function's one argument, and import `defineContract`, `enumType`, and `member` from the package. The package also exports `model` and `rel` for use outside the function, plus a `field` that has only `column`, `generated`, and `namedType`.

On MongoDB, `defineContract` also accepts a single object holding `models`, as above, and you import `field`, `model`, and `rel` from the package instead. The MongoDB builder differs from the PostgreSQL one in five ways:

* Every model declares an `_id` field built with `field.objectId()`. That field is always the primary key, so you never mark it with `.id()` and there is no `.attributes(...)` on MongoDB.
* The scalar helpers are `field.objectId()`, `field.string()`, `field.int32()`, `field.double()`, `field.bool()`, and `field.date()`.
* The collection name is an inline option on the model rather than a chained call, and relations are inline as well.
* Relations name the field on each side. `rel.hasMany` takes `{ from, to }` on MongoDB and `{ by }` on PostgreSQL. `to` accepts either the field name as a string or a typed reference such as `User.ref("_id")`, and both forms mean the same thing. PostgreSQL writes that reference as `User.refs.id`.
* Indexes are an `indexes` option on the model, built with the `index` helper the same package exports, as in `indexes: [index({ email: 1 }, { unique: true })]`. The `1` is ascending, MongoDB's own index syntax.

Enums and extension packs work on MongoDB too: `enumType` and `member` come from `@prisma/orm-mongo/contract-builder`. Pass the enums in the same object as the models, as `defineContract({ models, enums })`, and extension packs go in the same `extensions` option.

The MongoDB builder also has, on the model object:

* `indexes`, a list of `index(keys, options?)` calls. `keys` maps each field to `1`, `-1`, `"text"`, `"2dsphere"`, `"2d"`, or `"hashed"`, and `options` takes MongoDB's own index options: `unique`, `sparse`, `name`, `expireAfterSeconds`, `partialFilterExpression`, `collation`, `weights`, and `wildcardProjection`. For example, `index({ expiresAt: 1 }, { expireAfterSeconds: 3600, sparse: true })`.
* `collectionOptions`, for options on the collection itself, such as `{ collation: { locale: "en", strength: 2 } }`.
* `discriminator` and `base`, for one collection that holds more than one kind of document. The base model declares `discriminator: { field: "kind", variants: { Article: { value: "article" } } }`, and each variant model declares `base: Post` and the same `collection` as its base, plus its own fields. [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb#polymorphic-collections) covers when to use it.

And two more field helpers: `field.vector()` for a vector, which takes no dimension count, and `field.valueObject(Address)` for an embedded document, where `Address` is declared with `valueObject("Address", { fields: { ... } })` from the package and returned in `defineContract`'s `valueObjects` map:

```typescript
import { defineContract, field, index, model, valueObject } from "@prisma/orm-mongo/contract-builder";

const Address = valueObject("Address", {
  fields: { street: field.string(), zip: field.string().optional() },
});

const User = model("User", {
  collection: "users",
  fields: {
    _id: field.objectId(),
    email: field.string(),
    address: field.valueObject(Address).optional(),
    embedding: field.vector().optional(),
  },
  indexes: [index({ email: 1 }, { unique: true, collation: { locale: "en", strength: 2 } })],
});

export const contract = defineContract({ models: { User }, valueObjects: { Address } });
```

The examples below use the PostgreSQL builder.

## Fields [#fields]

`field` has a helper for each column type. On PostgreSQL:

| Column                                  | Helper               |
| --------------------------------------- | -------------------- |
| text                                    | `field.text()`       |
| integer                                 | `field.int()`        |
| big integer                             | `field.bigint()`     |
| float                                   | `field.float()`      |
| decimal                                 | `field.decimal()`    |
| boolean                                 | `field.boolean()`    |
| date and time                           | `field.dateTime()`   |
| bytes                                   | `field.bytes()`      |
| JSON                                    | `field.json()`       |
| UUID stored in a `character(36)` column | `field.uuidString()` |
| UUID stored in a `uuid` column          | `field.uuidNative()` |

There is no helper for a date without a time, or a time without a date. For a date-only column, name the type yourself: `field.column({ codecId: "pg/date-temporal@1", nativeType: "date" } as const)`. `field.column(...)` and the chained `.column(...)` below are different calls: `field.column(descriptor)` builds a field from a type description, and `.column(name)` on an existing field sets its column name. Extension packs add more helpers of their own.

For a primary key your app generates, use a `field.id.*` helper. Each one marks the field as the primary key and generates the ID in your app when you create a row. `field.id.uuidv4String()` is the common choice, and the others are `field.id.uuidv7String()`, `field.id.ulid()`, `field.id.nanoid()`, `field.id.cuid2()`, and `field.id.ksuid()`. To store a UUID in a `uuid` column instead of a `character(36)` column, use `field.id.uuidv4Native()` or `field.id.uuidv7Native()`.

For a key the database generates, chain `.default(...)` and `.id()` on a field. An integer that counts up is `field.int().default(autoincrement()).id()`, and a UUID is ``field.uuidNative().default(sql`gen_random_uuid()`).id()``. Import `autoincrement` and `sql` from `@prisma/orm-postgres/contract-builder`.

`field.temporal.createdAt()` sets the column to the current time when the row is created, and `field.temporal.updatedAt()` sets it on every create and every update. Prisma ORM sets both in the client, from your application's clock, so the column has no database default. If you insert a row with raw SQL, you must supply the value yourself. For a time the database sets instead, use `field.dateTime().default(now())`, with `now` imported from `@prisma/orm-postgres/contract-builder`.

`field.dateTime()`, `field.temporal.createdAt()`, and `field.temporal.updatedAt()` give your code a `Temporal.Instant`, so your app needs a global `Temporal` to read and write them; [Scalar fields](https://www.prisma.io/docs/orm/data-modeling#scalar-fields) says how to check for it and which polyfill to load when it is missing. To get a JavaScript `Date` instead, and need no `Temporal`, use `field.temporal.timestamptzJsDate()` for a `timestamptz` column, and `field.temporal.createdAtJsDate()` and `field.temporal.updatedAtJsDate()` for creation and update times.

`field.namedType(x)` takes an enum or a type from an extension pack.

Every field builder supports chained modifiers:

* `.optional()` makes the field nullable.
* `.default(value)` sets a fixed default. A decimal default is a string, as in `.default("1.50")`, and a JSON default is the object or array itself, as in `.default({ plan: "free" })`. The value has the type your code writes to that field, because the field's codec encodes it: a `field.dateTime()` default is a `Temporal.Instant`, as in `.default(Temporal.Instant.from("2024-01-01T00:00:00Z"))`, and a `field.bigint()` default is a `bigint`, as in `.default(1n)`. To write the time as a string, use `field.temporal.timestamptzString().default("2024-01-01T00:00:00Z")`. A value of the wrong type is a type error, and a value the codec refuses makes `contract emit` fail with [`CONTRACT.DEFAULT_INVALID`](https://www.prisma.io/docs/orm/reference/error-reference#CONTRACT.DEFAULT_INVALID). Do not write `.default(null)`: an `.optional()` field without a default is already `NULL` in the database when you leave it out.
* `.default(...)` also takes a default the database computes: `.default(now())`, `.default(autoincrement())`, or any other SQL expression as a `sql` template, such as ``.default(sql`gen_random_uuid()`)``. Import `now`, `autoincrement`, and `sql` from `@prisma/orm-postgres/contract-builder`. `` sql`now()` `` and `` sql`autoincrement()` `` are refused, so use the named helpers. `.defaultSql(expression)` still works but is deprecated, and it will be removed in the stable `8.0.0` release.
* `.unique()` adds a unique constraint. `.id()` marks the primary key, for a key that is not generated, such as an integer you set yourself.
* `.column("column_name")` sets the column name in the database when it differs from the field name.
* `.many()` makes the field a list, stored as a PostgreSQL array column such as `text[]`. A list column gets a check constraint that rejects `NULL` elements.
* `.noCheck()` leaves out the check constraints Prisma ORM generates for the column: the one that keeps an enum column to the enum's values, and the one that keeps `NULL` out of a list. `.noCheck("membership")` and `.noCheck("elementNotNull")` leave out one or the other. The field's TypeScript type does not change.

## Enums [#enums]

`enumType` declares an enum, the type its values are stored as, and its members, as `Priority` does in the full example above.

The second argument says how each member is stored, as the same `codecId` and `nativeType` pair the full example above explains. Write `as const` after the object, so TypeScript keeps the exact strings. To store the members as integers, pass `{ codecId: "pg/int4@1", nativeType: "int4" } as const`. More type ids are listed with the [raw query `param` helper](https://www.prisma.io/docs/orm/reference/raw-queries#binding-a-bare-value-with-param), which names types the same way.

Each `member(name, storedValue)` pairs the TypeScript-visible name with the value stored in the column. Fields reference the enum with `field.namedType(Priority)`, and defaults reference a member as `Priority.members.Low`. Include the enum in the returned `enums` map so it reaches the two files.

Members are stored in whatever column type you name here, `text` above. For a real PostgreSQL `enum` type, declare it with `nativeEnum` and type the field with `pg.enum`, both exported by `@prisma/orm-postgres/contract-builder`. The type is created in the database under the name you give it:

```typescript
import { defineContract, nativeEnum, pg } from "@prisma/orm-postgres/contract-builder";

const Role = nativeEnum("Role", "user", "admin");

export const contract = defineContract({}, ({ field, model }) => {
  const Account = model("Account", { fields: { role: field.column(pg.enum(Role)) } });
  return { models: { Account: Account.sql({ table: "account" }) } };
});
```

`Role` does not go in the returned `enums` map: using it on a field is enough to create the type in the database.

## Relations [#relations]

Relations are declared on the model builder with `.relations(...)` and the `rel` helpers, as the full example above shows.

`rel.hasMany(Model, { by })` names the foreign key field on the other model, and `rel.hasOne(Model, { by })` is the same with at most one row on the other side. `rel.belongsTo(Model, { from, to })` maps the local foreign key field to the field it points at.

`rel.manyToMany(Model, { through, from, to })` goes through a join table: you declare the model for the join table yourself and pass it as `through`. Below, `PostTag` is that model, holding the two foreign key fields `postId` and `tagId`:

```typescript
Post.relations({
  tags: rel.manyToMany(Tag, { through: PostTag, from: "postId", to: "tagId" }),
});
```

`rel.belongsTo` on its own does not create a foreign key constraint in the database, so ask for one by chaining `.sql(...)` on the relation itself, inside the `.relations({ ... })` object, as the full example above does:

```typescript
Post.relations({
  user: rel.belongsTo(User, { from: "userId", to: "id" }).sql({ fk: { name: "post_userId_fkey" } }),
});
```

`fk` takes `name`, `onDelete`, and `onUpdate`. `onDelete` and `onUpdate` each take `'noAction'`, `'restrict'`, `'cascade'`, `'setNull'`, or `'setDefault'`.

Prisma ORM does not check that the column types on the two sides of a relation match, so choose a field helper that produces the same column type as the key you point at.

`rel.hasMany`, `rel.hasOne`, `rel.belongsTo`, and `rel.manyToMany` also accept the model name as a string. Pass the model object, as above, and a typo is a compile error, but pass a string and the typo is reported when `prisma contract emit` builds the contract.

## Storage mapping [#storage-mapping]

`.sql(...)` maps a model to its table, and the object form covers the common case: `User.sql({ table: "user" })`. Without a `table`, and without the `naming` option, the table has the model's name exactly as written, so `User` is the table `"User"`.

You can chain `.relations(...)`, `.attributes(...)`, and `.sql(...)` in any order, and you can skip any of them, so a model with no relations calls `.sql({ table })` straight after `model(...)`.

The callback form gives you the model's columns as `cols` and the constraint builders as `constraints`. Use it for indexes:

```typescript
Post.relations({ ... }).sql(({ cols, constraints }) => ({
  table: "post",
  indexes: [
    constraints.index([cols.userId]),
    constraints.index([cols.userId, cols.createdAt], { name: "post_user_created_idx" }),
  ],
}));
```

`constraints.index` takes a list of columns, even when the list has one entry, or an object with `expression`, the whole index expression as SQL. The options are `unique`, `where` (a partial-index condition as SQL, without the `WHERE` keyword), `type` with `options` (the index method and its parameters; `options: {}` when there are none), and `name` or `map`. `name: "user_handle_active"` creates an index called `user_handle_active_2a0c4277`, with a hash on the end; `map` sets the exact name, which is what you want when the index already exists. An `expression` index needs one of the two:

```typescript
indexes: [
  constraints.index([cols.handle], { where: "(handle IS NOT NULL)", name: "user_handle_active" }),
  constraints.index({ expression: "lower(handle)", unique: true, name: "user_handle_lower" }),
  constraints.index([cols.tags], { type: "gin", options: {}, name: "user_tags_gin" }),
],
```

The `where` and `expression` strings go into the SQL as written, so they use column names, and you quote them yourself.

The primary key, unique constraints, indexes, and foreign keys of one model must all have different names. A `name` used twice is a type error that your editor and `tsc` report, but `npx prisma contract emit` does not type-check the file, and it accepts the repeated `name` because each name gets a different hash on the end in the database. A `map` used twice makes `contract emit` fail with `CONTRACT.SOURCE_LOAD_FAILED`.

For PostgreSQL [full-text search](https://www.prisma.io/docs/orm/reference/orm-client#full-text-search), `fullTextIndex` from `@prisma/orm-postgres/contract-builder` creates the GIN index that a text field's `fullTextMatches` and `fullTextRank` query functions use. It takes one text column and a `name` or `map`, plus optional `language` and `where`:

```typescript title="src/prisma/contract.ts (excerpt)"
import { fullTextIndex } from "@prisma/orm-postgres/contract-builder";

Post.sql(({ cols }) => ({
  table: "post",
  indexes: [fullTextIndex(cols.title, { name: "post_title_search" })],
}));
```

`language` defaults to `english` on both the index and the query functions, and PostgreSQL uses the index only when the two match, so change both or neither. To search German text, for example, write `fullTextIndex(cols.title, { name: "post_title_search", language: "german" })` on the index and `p.title.fullTextMatches(query, { language: "german" })` in the query.

Two more keys go in the same object, in either the object form or the callback form: `checks`, a list of check constraints you write yourself, built with `check` from the package, and `control`, the model's [control policy](#control-policy):

```typescript
import { check } from "@prisma/orm-postgres/contract-builder";

Order.sql({
  table: "order",
  checks: [check({ expression: "total >= 0", name: "order_total_positive" })],
});
```

`expression` is the condition as SQL, using column names, and `name` and `map` work as they do on an index.

`Model.refs` provides typed references to another model's fields, for the constraint builders inside `.sql(...)`. Write `constraints.foreignKey(cols.userId, User.refs.id)` and TypeScript checks `id` against the actual `User` definition.

For a primary key made of two fields, use `.attributes(...)` instead of `.sql(...)`, and build it from the field references:

```typescript
PostTag.attributes(({ fields, constraints }) => ({
  id: constraints.id([fields.postId, fields.tagId]),
}));
```

That object accepts exactly two keys, `id` and `uniques`. `id` takes one constraint, and `uniques` takes a list, so `uniques: [constraints.unique([fields.postId, fields.tagId])]` makes a unique constraint across two fields. For a key made of one field, `.id()` on the field is enough, and the `field.id.*` helpers already do it.

## Namespaces [#namespaces]

A model can go in a PostgreSQL schema other than `public`: declare the schema in `defineContract`'s `namespaces` option, then name it on the model. Without the declaration, `npx prisma contract emit` fails and names the missing entry.

```typescript
export const contract = defineContract({ namespaces: ["audit"] }, ({ field, model }) => {
  const AuditLog = model("AuditLog", {
    namespace: "audit",
    fields: { id: field.id.uuidv4String(), message: field.text() },
  });
  return { models: { AuditLog: AuditLog.sql({ table: "audit_log" }) } };
});
```

## Control policy [#control-policy]

`control` on `.sql(...)` says how far Prisma ORM manages the table, with one of four values:

| Value                     | `db verify`                                                             | Migrations                                    |
| ------------------------- | ----------------------------------------------------------------------- | --------------------------------------------- |
| `"managed"` (the default) | The table must exist and match the model exactly.                       | Create, alter, and drop it.                   |
| `"tolerated"`             | Declared columns must match; extra columns are accepted.                | Create it if missing; never alter or drop it. |
| `"external"`              | Declared columns must match; extra columns and constraints are ignored. | Never touch it.                               |
| `"observed"`              | Anything goes; a mismatch is a warning, not a failure.                  | Never touch it.                               |

Put it on a model whose table something else owns:

```typescript
AuditLog.sql({ table: "audit_log", control: "observed" })
```

`defaultControlPolicy` in `defineContract`'s options sets the policy for every model that does not set its own.

## Row-level security [#row-level-security]

The package exports the pieces of PostgreSQL row-level security, and [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) turns them into `ENABLE ROW LEVEL SECURITY` and `CREATE POLICY` statements. `rlsEnabled(Model)` turns row-level security on for the model's table. `policySelect`, `policyInsert`, `policyUpdate`, `policyDelete`, and `policyAll` each declare one policy for one operation, and `role("name")` declares a database role a policy names. Return them all in the `entities` list:

```typescript
import { defineContract, policySelect, policyUpdate, rlsEnabled, role } from "@prisma/orm-postgres/contract-builder";

export const contract = defineContract({}, ({ field, model }) => {
  const User = model("User", { fields: { id: field.id.uuidv4String() } });
  const authenticated = role("authenticated");

  return {
    models: { User: User.sql({ table: "user" }) },
    entities: [
      authenticated,
      rlsEnabled(User),
      policySelect(User, { name: "user_self_read", roles: [authenticated], using: "id = current_setting('app.user_id')::uuid" }),
      policyUpdate(User, { name: "user_self_write", roles: [authenticated], using: "id = current_setting('app.user_id')::uuid", withCheck: "id = current_setting('app.user_id')::uuid" }),
    ],
  };
});
```

`roles` lists role handles, and a role Prisma ORM should create goes in `entities` as well, as `authenticated` does above, while a role that already exists in the database, such as `public`, is `role("public")` in `roles` and left out of `entities`. `using` and `withCheck` are the two conditions as SQL, using column names: `policySelect` and `policyDelete` take `using`, `policyInsert` takes `withCheck`, and `policyUpdate` and `policyAll` take either or both. The policy `name` gets an eight-character hash on the end in the database.

## Extension types [#extension-types]

An extension pack is an npm package that adds column types to the builder. List packs in `defineContract`'s options object, and the `type` helper exposes their constructors:

```typescript title="src/prisma/contract.ts"
import pgvector from "@prisma/orm-extension-pgvector/pack";
import { defineContract } from "@prisma/orm-postgres/contract-builder";

export const contract = defineContract({ extensions: { pgvector } }, ({ field, model, type }) => {
  const types = { Embedding1536: type.pgvector.Vector(1536) } as const;
  const Post = model("Post", {
    fields: { id: field.id.uuidv4String(), embedding: field.namedType(types.Embedding1536) },
  });
  return { types, models: { Post: Post.sql({ table: "post" }) } };
});
```

The key on `type.pgvector` is the pack's own name, not the name you gave the import. The name is in the pack's documentation, and pgvector's is `pgvector`. `Embedding1536` is a name you choose, and it appears under that name in `contract.d.ts`. Return the `types` map so the name reaches the two files.

Add the same pack to `prisma.config.ts`: it goes inside `ormConfig({ ... })`, beside `contract`, and the config imports the pack's `/control` export while the contract file imports its `/pack` export:

```typescript title="prisma.config.ts"
import { definePrismaConfig } from "prisma/config";
import pgvector from "@prisma/orm-extension-pgvector/control";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./src/prisma/contract.ts",
    extensions: [pgvector],
  }),
});
```

## Keep the contract file free of changing values [#keep-the-contract-file-pure]

The contract file describes structure, and these rules keep it usable:

* Do not read `process.env`, the current time, or random values into the contract. A contract built from those values makes `npx prisma contract emit` produce a different `contract.json` on each run.
* Keep field values plain: strings, numbers, booleans, and the builder's own objects. Functions, class instances, and `Date` objects do not serialize.
* Keep the file free of side effects. `npx prisma contract emit` loads the file with Node.js, so anything it does while loading, such as writing a file or calling a service, happens every time you run the command. The file is ordinary TypeScript, so `import` model definitions from other files as usual.
* `npx prisma contract emit` runs the file but does not type-check it. Type errors show in your editor and when you run `tsc`.

Configuration that legitimately varies per environment, such as the database URL, belongs in `prisma.config.ts`, not in the contract.

## Parity with PSL [#parity-with-psl]

TypeScript and [PSL](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax) authoring produce the same `contract.json` and `contract.d.ts` for an equivalent contract, so you can move between the two forms without changing anything downstream. A project names exactly one contract file in its config.

No command converts a `.prisma` contract into TypeScript, so to move an existing project, write the TypeScript file by hand, point `contract` in `prisma.config.ts` at it, and delete the `.prisma` file so the two can never disagree.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. In an existing project, run `npx prisma skills sync` to add them. The `prisma-8` skill covers TypeScript authoring, so ask your agent to:

* "Convert this contract.prisma to the TypeScript schema builder."
* "Using the prisma-8 skill, add a unique constraint to the email field in our TypeScript schema."

## Next steps [#next-steps]

* Inspect [`contract.json` and `contract.d.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact), the two files the contract produces.
* Apply the contract to a database with [`db init`](https://www.prisma.io/docs/cli/db-init) or plan changes with [`migration plan`](https://www.prisma.io/docs/cli/migration-plan).

## Related pages

- [`Author in PSL`](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax): Write the Prisma ORM contract in the Prisma schema language you already know, plus the Prisma ORM 8 additions.
- [`contract.json and contract.d.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact): contract.json and contract.d.ts are the two files every other part of Prisma ORM reads. Here is what is inside them.
- [`Editor support`](https://www.prisma.io/docs/orm/contract-authoring/editor-support): What the Prisma VS Code extension does for a Prisma ORM contract, and what to do when it stops accepting the file.
- [`Supported database features`](https://www.prisma.io/docs/orm/contract-authoring/capabilities): The contract records which database features your packages support, so Prisma ORM can reject an unsupported one early with a clear error.
- [`The data contract`](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract): The data contract is the one description of your data model and how it is stored. Prisma ORM types your queries, plans your migrations, and checks your database against it.

# Overview (/docs/orm/data-modeling)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Describe the data your application needs with models, primary keys, scalar fields, and relations.

Location: ORM > Overview

Data modeling is the process of describing the data your application needs and how that data is connected.

For example, a blog has users, posts, and comments. A user has fields like an email and a name. A post has fields like a title and content. These models also relate to each other: a user can write many posts, and a post can have many comments.

In Prisma ORM, you define this structure in your contract, the `contract.prisma` file that replaced `schema.prisma`. It holds your models the way `schema.prisma` did, and Prisma ORM derives both your TypeScript types and your migrations from it.

There is no `datasource` or `generator` block any more, because the connection string has moved to `prisma.config.ts`. [A complete contract](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#a-complete-contract) shows a whole file together with the config file, and if you are [coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7), that page covers the rename and the rest of the differences.

Prisma ORM 8 supports PostgreSQL and MongoDB today, and [Supported databases](https://www.prisma.io/docs/orm/supported-databases) lists the ones that are coming. Whichever you use, a contract is built from the same four building blocks:

* [Models](#models): the things your application works with
* [Primary keys](#primary-keys): how each record is identified
* [Scalar fields](#scalar-fields): the values a model stores
* [Relations](#relations): how models connect to each other

All four blocks apply to both databases. How you model relations is where the two differ, so continue with [relational data modeling](https://www.prisma.io/docs/orm/data-modeling/relational-databases) or [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb).

## Models [#models]

A model describes one kind of record: a user, an order, a blog post. Declare a model with the `model` keyword and give it fields:

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

On a relational database, a model becomes a table. On MongoDB, it becomes a collection.

## Primary keys [#primary-keys]

A primary key is the field that uniquely identifies each record. Give every model one and mark it with `@id`, because `update` and `delete` fail at runtime on a model that has neither a primary key nor a unique field:

  

#### PostgreSQL

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

#### MongoDB

```prisma
model User {
  id    ObjectId @id @map("_id")
  email String
  @@map("users")
}
```

On MongoDB, the primary key is the document's mandatory `_id` field, and it must be an `ObjectId`. `@map("_id")` gives the field that name in the database. The field takes no `@default`, because MongoDB assigns the id itself when you create a document without one. `@@map("users")` names the collection and is optional: without it, the collection is the model name exactly as written, `User`.

### Natural keys [#natural-keys]

A natural key is a value that already identifies the record in the real world. Use one when the value is stable, unique, and assigned outside your application, such as a standardized code you receive rather than invent.

Natural keys fit reference tables best, the tables that hold a fixed set of values other records point at. A country, for example, is identified by its ISO code, and that code never changes:

```prisma
model Country {
  code String @id
  name String
}
```

Records that point at `Country` now store a readable value (`US`, `DE`) instead of a meaningless number. Currencies (`USD`, `EUR`) and other reference tables work the same way.

### Surrogate keys [#surrogate-keys]

A surrogate key is a generated value with no business meaning: an auto-incrementing integer, a UUID, an ObjectId. It is the better default for records your application creates, because it is stable. Values you might be tempted to use as a key, like an email address or a product SKU, change in practice, and changing a primary key is expensive because every record that points at the old value must be updated too. A surrogate key never changes.

Keep the natural value as a regular field and enforce its uniqueness with `@unique`, so you get a stable key and the uniqueness guarantee at the same time:

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

### Which surrogate type to pick [#which-surrogate-type-to-pick]

Pick by how the record is created and where its id travels:

```prisma
// Auto-incrementing integer: smallest and fastest to index.
// Good for internal records whose id never leaves your system.
model Invoice {
  id Int @id @default(autoincrement())
}
```

The database assigns the value, so you only know it after the insert. It is also sequential, so it leaks row counts and invites guessing if you expose it in URLs.

```prisma
// UUID: globally unique, generated before the insert.
// Good for ids that appear in URLs or are created across services.
model ApiToken {
  id String @id @default(uuid())
}
```

A UUID takes more space than an integer, but independent services never produce the same one. `@default(uuid())` generates a random UUID, and `@default(uuid(7))` generates one that sorts by creation time. On MongoDB there is no choice to make, because the key is always the `ObjectId` shown above.

### Composite keys [#composite-keys]

A composite key spans several fields, declared with `@@id`. Use one when the identity really is the combination, which usually means a model that links two others:

```prisma
model UserTag {
  userId Int
  tagId  Int

  @@id([userId, tagId])
}
```

A duplicate `(userId, tagId)` pair would be meaningless, so the pair itself is the key. [Many-to-many](https://www.prisma.io/docs/orm/data-modeling/relational-databases#many-to-many) writes a model like this one out with its relation fields. Avoid composite keys for ordinary models, though, because everything that points at the model then has to store all of the key's fields.

## Scalar fields [#scalar-fields]

A scalar field holds a single value. The common types:

| Type                                                      | Stores                                           |
| --------------------------------------------------------- | ------------------------------------------------ |
| `String`                                                  | Text                                             |
| `Int`                                                     | 32-bit integer                                   |
| `BigInt`                                                  | 64-bit integer                                   |
| `Float`                                                   | Floating-point number                            |
| `Decimal`, or `Numeric(10, 2)` with a precision and scale | Exact decimal, PostgreSQL `numeric`              |
| `Boolean`                                                 | `true` / `false`                                 |
| `DateTime`                                                | Timestamp, PostgreSQL `timestamptz`              |
| `Bytes`                                                   | Binary data, PostgreSQL `bytea`                  |
| `Json`                                                    | Arbitrary JSON value, PostgreSQL's native `json` |
| `Jsonb`                                                   | Arbitrary JSON value, PostgreSQL's `jsonb`       |
| `ObjectId`                                                | MongoDB document identifier                      |

The PostgreSQL names in the table are the column types Prisma ORM creates. `ObjectId` is a MongoDB-only type, and MongoDB names its other scalar types after the BSON types they store, such as `Int32` and `Bool`; [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb#field-types) lists them.

A `Decimal` reaches your code as a string, so nothing is rounded through a JavaScript number, and a `Bytes` value reaches you as a `Uint8Array`. On PostgreSQL, a `DateTime` reaches you as a `Temporal.Instant`, the standard JavaScript type for a point in time. `Temporal` is built into Node.js 26.8.2 and later, but Homebrew's build of Node.js 26 leaves it out, so check with `node -p "typeof Temporal"`. If that prints `undefined`, install the `temporal-polyfill` package and add `import "temporal-polyfill/full/global"` to your app's entry file, before any query runs. That import covers your app only, and `contract emit` needs its own `Temporal` when a date or time field has a fixed default, as [Default values](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#default-values) explains. To work with a JavaScript `Date` on PostgreSQL instead, and need no polyfill, type the field `TimestamptzJsDate`, but a `Date` drops the microseconds PostgreSQL stores.

`Json` and `Jsonb` are two separate types, and they differ in how you can filter on them. On a `Jsonb` field, `.where()` compares the whole value, so you can ask whether the column equals a given document but not whether a key inside it matches. A `Json` field cannot be compared in `.where()` at all, so use `Jsonb` unless you specifically need PostgreSQL's plain `json` column. When you need a path query into the document, reach for [raw SQL](https://www.prisma.io/docs/orm/reference/raw-queries). [Extensions](https://www.prisma.io/docs/orm/extensions) add more types, such as vectors or geometry.

A trailing `?` makes a field optional: `name String?`. A trailing `[]` makes it a list: `tags String[]`. A `@default(...)` must be written in a form the field's type accepts, such as the `json` literal ``@default(json`{}`)`` on a `Jsonb` field and `@default(1.50)` on a `Decimal` field; [Default values](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#default-values) lists them.

A field can also hold one of a fixed set of values. Declare them in an `enum` block:

```prisma
enum Priority {
  @@type("pg/text@1")
  Low  = "low"
  High = "high"
}
```

`@@type` says how the values are stored, here as PostgreSQL `text`, written as the database type plus a version that is always `@1` today. On MongoDB, write `@@type("mongo/string@1")`. You can also leave `@@type` out, in which case Prisma ORM infers the storage from the members: text for string values and an integer for whole numbers. [Enums](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#enums) has the rest of the syntax.

### How to pick a data type [#how-to-pick-a-data-type]

Match the type to what the value means, not to what it looks like.

An identifier is a `String`, even when it looks numeric. You never add zip codes or phone numbers together, they can have leading zeros, and they do not sort numerically:

```prisma
model Address {
  id  Int    @id @default(autoincrement())
  zip String
}
```

Money is not a `Float`, because floating-point numbers cannot represent decimal amounts exactly and sums drift by fractions of a cent. For ordinary money, use `Int` and store the amount in the currency's smallest unit, such as cents, which also gives you a plain JavaScript number to work with. Reserve `Decimal` for values that need more decimal places than the currency has, such as a per-unit rate:

```prisma
model Product {
  id         Int @id @default(autoincrement())
  priceCents Int
}
```

A point in time is a `DateTime`, not a `String`, because a real timestamp type gives you correct comparison, sorting, and range queries:

```prisma
model Post {
  id          Int      @id @default(autoincrement())
  publishedAt DateTime
}
```

When you are unsure between two sizes, lean toward the wider one. For a counter that could grow past two billion, that means `BigInt` over `Int`, since changing `Int` to `BigInt` later needs a migration that picking `BigInt` now lets you skip. `BigInt` does cost you something in your code, though: the value reaches you as a JavaScript `bigint`, which `JSON.stringify` refuses to serialize until you call `.toString()` on it.

Mark a field optional (`?`) only when "absent" means something different from a sensible default, such as `publishedAt DateTime?` where no value means unpublished. A required field with a default is often the clearer model.

## Relations [#relations]

A relation connects two models: a user has many posts, a post belongs to one user.

A relation uses two kinds of field. The model that holds the link needs both of them, while the model on the other end needs only a relation field:

* The link field stores the other record's primary key, like `authorId`. Prisma ORM 7 called this the relation scalar field. On a relational database it is the foreign key column, and on MongoDB it is the field holding the other document's `_id`.
* The relation field is typed as the other model, like `author User`. It creates no column of its own and only tells Prisma ORM how to follow the connection in a query.

The `@relation` attribute ties them together: `fields` names the link field, and `references` names the field it points at on the other model. On the other model, `posts Post[]` is the other end of the same relation.

```prisma
model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  authorId Int
  author   User @relation(fields: [authorId], references: [id])
}
```

Relations come in three kinds:

* One-to-one: a user has at most one profile. The model that holds the link gets `@unique` on its link field, and the field on `User` is `profile Profile?`, not a list. [One-to-one](https://www.prisma.io/docs/orm/data-modeling/relational-databases#one-to-one) has both models written out.
* One-to-many: a user has many posts, as in the example above.
* Many-to-many: a post has many tags, and a tag appears on many posts. This needs a model for the join table, with one record per connected pair. Prisma ORM 7 let you write a list field on both sides with no such model, but that form is gone and `npx prisma contract emit` rejects it, so write the model out as [many-to-many](https://www.prisma.io/docs/orm/data-modeling/relational-databases#many-to-many) shows.

How each kind is stored, and which model should hold the link field, is where relational and document databases differ. Continue with the guide for your database:

* [Relational data modeling](https://www.prisma.io/docs/orm/data-modeling/relational-databases) for PostgreSQL: foreign keys, the model for the join table, and which side owns the key.
* [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb): embedding versus referencing, and polymorphic collections.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent, instruction files that tell it how Prisma ORM 8 works. In an existing project, run `npx prisma skills sync` to add them, then try prompts that map to each section:

* "Using the prisma-8 skill, add a Product model with a surrogate id and a unique sku field."
* "Add a Country reference table keyed by its ISO code."
* "Review my contract for fields that should be an enum or a DateTime instead of a String."
* "Connect Post to User with a foreign key and a relation field."

## Next steps [#next-steps]

* [Model relational data](https://www.prisma.io/docs/orm/data-modeling/relational-databases): one-to-one, one-to-many, many-to-many, and polymorphic relations on PostgreSQL.
* [Model MongoDB data](https://www.prisma.io/docs/orm/data-modeling/mongodb): embed or reference, and polymorphic collections.
* [Generate a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration) to get the models you wrote into the database. The loop is: edit the contract, run `npx prisma contract emit` to check it and regenerate your types (it replaces `prisma generate`), run `npx prisma migration plan` to write the migration files, then run `npx prisma db migrate` to apply them. That page has the flags and explains how the next plan finds its starting point.
* [Query your models](https://www.prisma.io/docs/orm/fundamentals/reading-data) once your contract is in place.

## Related pages

- [`Coming from Prisma ORM 7`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7): What each Prisma ORM 7 schema attribute, command, and query is called in Prisma ORM 8, and what is not available.
- [`Core concepts`](https://www.prisma.io/docs/orm/core-concepts): The ideas every Prisma ORM command and API builds on: contracts, emitting, plans, the database signature, codecs, and the migration graph.
- [`Extensions`](https://www.prisma.io/docs/orm/extensions): Every package that plugs into Prisma ORM: database packages, column types, indexes, query operations, and middleware, by Prisma and the community.
- [`Prisma 7`](https://www.prisma.io/docs/orm/v7): Prisma ORM is a next-generation Node.js and TypeScript ORM that provides type-safe database access, migrations, and a visual data editor.
- [`Prisma ORM`](https://www.prisma.io/docs/orm/v6): Learn about Prisma ORM

# MongoDB data modeling (/docs/orm/data-modeling/mongodb)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Model documents, embedded documents, and references for MongoDB, and decide when to embed and when to reference.

Location: ORM > Data modeling > MongoDB data modeling

MongoDB stores data as documents grouped into collections. A document can nest objects and arrays directly, which gives you a real choice for related data: keep it inside the document (embed it) or store it in its own collection and link to it (reference it). Making that choice well is the core of MongoDB data modeling. If you are new to models and keys, start with the [data modeling overview](https://www.prisma.io/docs/orm/data-modeling).

## Documents, collections, and the _id key [#documents-collections-and-the-_id-key]

Your models go in your contract, the `contract.prisma` file that replaced `schema.prisma`. A model maps to a collection, each record is a document, and every document has an `_id` field as its primary key. There is no `datasource` block on MongoDB: your connection string goes in `prisma.config.ts` instead, passed to `defineConfig` from `@prisma/orm-mongo/config`, and [the data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) page shows that config file.

```prisma
model User {
  id    ObjectId @id @map("_id")
  name  String
  email String   @unique
  @@map("users")
}
```

In the contract you call the field `id`, but in TypeScript it is always `_id`, never `id`, because `@map("_id")` sets the name in the database and in your code alike. So you write `user._id` and `where({ _id })`. `@@map("users")` names the collection and is optional: without it the collection takes the model name exactly as written, so `User`. `@unique` on `email` becomes a unique index when you migrate.

Write `ObjectId` for the key type. That is the contract type only: in TypeScript a document's own `_id` is a plain string, so there is no `ObjectId` to construct. The old `String @db.ObjectId` and `@default(auto())` are no longer allowed.

Leave the id out of the values you pass to `create`, and MongoDB assigns it. In the examples below, `db` is the client created in `src/prisma/db.ts`, and `db.orm` is the ORM client, one of the query APIs on `db` that [the ORM reference](https://www.prisma.io/docs/orm/reference) covers.

```ts
import { db } from "./prisma/db";
const user = await db.orm.users.create({ name: "Ada", email: "ada@example.com" });
const found = await db.orm.users.where({ _id: user._id }).first();
```

The name after `db.orm.` is the collection name, so with `@@map("users")` you write `db.orm.users`, not `db.orm.user`. The values go straight into `create`, without the `data:` wrapper Prisma ORM 7 used. You `await` the whole chain, and the last call says what you want back: `.first()` for one document or `null`, `.all()` for every matching document.

## Field types [#field-types]

On MongoDB, each scalar type is named after the BSON type it stores:

| Type         | Stored as                                          | In your code                         |
| ------------ | -------------------------------------------------- | ------------------------------------ |
| `String`     | BSON string                                        | `string`                             |
| `Int32`      | BSON int                                           | `number`                             |
| `Int64`      | BSON long                                          | `bigint`                             |
| `Double`     | BSON double                                        | `number`                             |
| `Decimal128` | BSON decimal                                       | a string, so that no digit is lost   |
| `Bool`       | BSON bool                                          | `boolean`                            |
| `Date`       | BSON date                                          | a JavaScript `Date`                  |
| `Binary`     | BSON binary                                        | `Uint8Array`                         |
| `Json`       | a BSON object, array, string, number, bool or null | a JSON value                         |
| `Bson`       | any BSON value                                     | the value the MongoDB driver returns |
| `ObjectId`   | BSON ObjectId                                      | `string`                             |

A `Json` field holds only JSON values. A read fails with `RUNTIME.DECODE_FAILED`, and a write with `RUNTIME.ENCODE_FAILED`, when the field holds a `Date`, an `ObjectId`, a `Decimal128`, a `Binary` or another value that is not JSON, at any depth. Type the field `Bson` when it holds such values. A contract whose source is a Prisma ORM 6 schema cannot declare `Bson`.

The names `Int`, `Float`, `Boolean` and `DateTime` from earlier releases are deprecated. They still work and give the same contract, but `contract emit` reports a `PSL_DEPRECATED_SCALAR_NAME` warning for each use, and a later release removes them. Rename them to `Int32`, `Double`, `Bool` and `Date`.

For a timestamp that Prisma ORM fills in, type the field `temporal.createdAt()` or `temporal.updatedAt()`:

```prisma
model Post {
  id        ObjectId             @id @map("_id")
  title     String
  createdAt temporal.createdAt()
  updatedAt temporal.updatedAt()
  @@map("posts")
}
```

With a client created by `mongo()`, `create` sets both fields, and every `update` that changes something sets `updatedAt` again. Both fields are optional in the values you pass to `create`.

## Embed or reference [#embed-or-reference]

Two pieces of related data can live together in one document (embedded) or in separate collections linked by an id (referenced). Embedding nests the data inside its parent: an order and its line items in one document. One read returns everything, and a write updates parent and children together, atomically. The trade-off is that you cannot read embedded data without its parent, and it comes back on every read of the parent.

Referencing keeps the data in its own collection and stores the linked document's `_id`. Loading both takes a second read, but each record stands on its own: it can be queried, listed, and updated independently, and it is not duplicated when several parents point at it. A quick way to decide:

| Signal                        | Example                     | Lean toward |
| ----------------------------- | --------------------------- | ----------- |
| Always loaded with the parent | An order's line items       | Embed       |
| Small and bounded in size     | A user's mailing address    | Embed       |
| No meaning outside the parent | A post's SEO metadata       | Embed       |
| Grows without limit           | A user's activity events    | Reference   |
| Queried or updated on its own | Products in a catalog       | Reference   |
| Shared by many parents        | A tag on thousands of posts | Reference   |

A blog post's comments make it concrete. If you always render them with the post and their count stays modest, embed them. If comments can grow into the thousands, or you need "every comment by this author across posts", reference them.

## Embedded documents [#embedded-documents]

Describe the shape of embedded data with a `type` block, then use it as a field. An embedded value has no `_id` and no collection of its own, so it is created, loaded, updated, and deleted with the document that holds it.

```prisma
type Address {
  street  String
  city    String
  country String
}
model User {
  id      ObjectId @id @map("_id")
  name    String
  tags    String[]
  address Address?
  @@map("users")
}
```

A single embedded value models a one-to-one relation. A list of embedded values models a one-to-many relation: `addresses Address[]` stores every address inside the user document, with no second collection and no join to load them. Pass an embedded value to `create` as a plain nested object:

```ts
const address = { street: "1 Main St", city: "Berlin", country: "DE" };
await db.orm.users.create({ name: "Ada", tags: [], address });
```

In an `update`, the callback argument `u` builds the changes you want, and because the callback returns an array, several changes go in one call. Use `u.fieldName` to change a top-level field, or `u("path.to.field")` for a field inside an embedded document, written as a string because a dotted path is not a property name. On a list of scalars, `.push(...)` adds values and `.pull(...)` removes them:

```ts
await db.orm.users.where({ _id: user._id }).update((u) => [u("address.city").set("Hamburg")]);
await db.orm.users.where({ _id: user._id }).update((u) => [u.tags.push("admin"), u.tags.pull("new")]);
```

Replace a whole embedded value with `u.address.set({ ... })`, remove it with `u.address.unset()`, and replace a list of embedded values as a whole with `u.addresses.set([ ... ])`. Filtering is more limited: the object form of `.where()` filters on top-level model fields only, so to match on a field inside an embedded document you use the pipeline builder, a chained builder for MongoDB aggregation pipelines:

```ts
const query = db.query.from("users").match((f) => f("address.city").eq("Berlin")).build();
```

`build()` returns the query rather than the rows, and [the pipeline builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#mongodb-pipeline-builder) page explains how to run it and what comes back.

Embedded arrays are only a good idea while they stay bounded. An array that grows forever slows every read of the parent and pushes the document toward MongoDB's 16 MB limit, where a write that exceeds it fails, so when a list has no natural cap, reference it instead.

## References across collections [#references-across-collections]

When related records need their own collection, store one document's `_id` on the other and declare the relation with the same `@relation(fields:, references:)` used everywhere in Prisma ORM:

```prisma
model User {
  id    ObjectId @id @map("_id")
  name  String
  posts Post[]
  @@map("users")
}
model Post {
  id       ObjectId @id @map("_id")
  title    String
  authorId ObjectId
  author   User     @relation(fields: [authorId], references: [id])
  @@map("posts")
}
```

This is a one-to-many by reference: many posts point at one user, and each post is queryable on its own. Note that in `references: [id]` you write the field's contract-side name, `id`, not `_id`. There are no nested writes on MongoDB, so create the user first and then the post with its `authorId`. To load a post together with its author, chain `.include("author")`, which adds the related record to every row you get back:

```ts
await db.orm.posts.create({ title: "Hello", authorId: user._id });
const posts = await db.orm.posts.include("author").all();
```

`.include("posts")` on `db.orm.users` works the other way and gives each user an array of their posts. See [relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins) for the rest of the query API.

Resolving a reference means a lookup into the other collection on every read. If a read is frequent, you can copy the few fields it needs into the parent document, such as a comment storing its author's name, but the copy does not follow the original when it changes, so you update it yourself.

## Polymorphic collections [#polymorphic-collections]

One collection can hold more than one kind of document. You declare a base model for the shared fields and a variant model for each kind, and a discriminator field on the base model records which kind each document is.

```prisma
model Post {
  id       ObjectId @id @map("_id")
  title    String
  kind     String
  @@discriminator(kind)
  @@map("posts")
}
model Article {
  summary String
  @@base(Post, "article")
}
model Tutorial {
  difficulty String
  duration   Int32
  @@base(Post, "tutorial")
}
```

`@@discriminator(kind)` takes the name of the field that records each document's variant, so write `kind` and not `"kind"`. `@@base(Post, "article")` declares `Article` as the `"article"` variant of `Post`. A variant declares only its own fields, since `id`, `title`, and `kind` come from `Post`, and it uses its base's collection, so it needs no `@@map` of its own.

A query for posts returns articles and tutorials together. To reach a single variant, go through the base model: `db.orm.posts.variant("Article")` limits the query to one variant, and it takes the variant's model name, `"Article"`, not the discriminator value `"article"`. Creating through a variant fills in `kind` for you:

```ts
const article = await db.orm.posts.variant("Article").create({ title: "Hello", summary: "A short post" });
```

Use one collection when you almost always query the variants together, for example email, SMS, and push notifications that you read as a single feed. Prefer separate collections when the types rarely appear in the same query or need very different indexes.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8), instruction files for coding agents. In an existing project, run `npx prisma skills sync` to add them. The `prisma-8` skill covers document modeling, so try prompts that map to each section:

* "Using the prisma-8 skill, add an embedded Address type to the User model."
* "Cart items are always read with the cart. Model them as an embedded list."
* "Comments can grow without limit. Move them from an embedded array to a referenced collection."
* "Split the posts collection into Article and Tutorial variants with a discriminator."

## Next steps [#next-steps]

* Start a new project with `npm create prisma@latest -- my-app`, or run `npx prisma orm init` in an existing one. After every change to your contract, run `npx prisma contract emit` to check it and regenerate your types, then `npx prisma migration plan` to write a migration and `npx prisma db migrate` to apply it, which creates the collections and indexes. [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration) has the flags and explains how the next plan finds its starting point.
* [Query documents](https://www.prisma.io/docs/orm/fundamentals/reading-data) and [resolve references](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins) with `.include(...)`.
* Aggregate and reshape documents with the [pipeline builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#mongodb-pipeline-builder).
* To model relational data, see the [relational data modeling guide](https://www.prisma.io/docs/orm/data-modeling/relational-databases).

## Related pages

- [`Relational data modeling`](https://www.prisma.io/docs/orm/data-modeling/relational-databases): Model one-to-one, one-to-many, many-to-many, and polymorphic relations for PostgreSQL.

# Relational data modeling (/docs/orm/data-modeling/relational-databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Model one-to-one, one-to-many, many-to-many, and polymorphic relations for PostgreSQL.

Location: ORM > Data modeling > Relational data modeling

In a relational database, each model becomes a table and each scalar field becomes a column. Models connect through foreign keys: a column in one table that holds the primary key of a row in another table. If you are new to models and keys, start with the [data modeling overview](https://www.prisma.io/docs/orm/data-modeling).

You write your models in your contract, the `contract.prisma` file that replaced `schema.prisma`. After every change to it, run `npx prisma contract emit`, which checks the contract and regenerates your TypeScript types without touching the database. The query examples below use `db`, the client you create once in `src/prisma/db.ts`, the file `npx prisma orm init` writes. On it, `db.orm` holds your models by model name, and `public` is the PostgreSQL schema your tables are in.

## How relations are declared [#how-relations-are-declared]

The model whose table gets the foreign key column declares two fields: a scalar field for the foreign key column, and a relation field typed as the other model. `@relation(fields:, references:)` ties them together:

```prisma
model Post {
  id       Int  @id @default(autoincrement())
  authorId Int
  author   User @relation(fields: [authorId], references: [id])
}
```

The side that declares the `fields` argument owns the foreign key, and deciding which side that should be is the main choice in each relation kind below.

To let a post have no author, make the foreign key field and the relation field both optional: `authorId Int?` and `author User?`. The two fields have to agree, so if one is optional and the other is required, `npx prisma contract emit` reports an error.

When a `User` row is deleted or its `id` changes, referential actions decide what happens to the `Post` rows that point at it. Add `onDelete` and `onUpdate` to `@relation`, as in `@relation(fields: [userId], references: [id], onDelete: Cascade)`, and they become the foreign key's `ON DELETE` and `ON UPDATE` clauses. If you write neither, the foreign key gets neither clause and the database decides what happens. The five actions are:

* `Cascade` deletes or updates the matching rows.
* `Restrict` blocks the change.
* `SetNull` clears the foreign key, so the foreign key field has to be optional.
* `SetDefault` writes the foreign key's default value, which has to point at a row that exists.
* `NoAction` is the same as writing nothing.

Two relations between the same pair of models need a name on both sides, such as `@relation("Authored", fields: [authorId], references: [id])` on one side and `@relation("Authored")` on the other. Without the name, `npx prisma contract emit` reports an error.

## One-to-many [#one-to-many]

A one-to-many relation (`1:n`) connects one record to many: one user writes many posts, and each post belongs to one user. This is the most common relation kind.

```prisma
model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  posts Post[]
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  authorId Int
  author   User   @relation(fields: [authorId], references: [id])
}
```

The foreign key is on the "many" side, `Post.authorId`, because each post points at exactly one user, while a user points at an open-ended list of posts. Use a one-to-many whenever a record belongs to one parent and a parent has many children: comments on a post, line items on an order, employees in a department. A model can also point at itself: a category with a parent category is an ordinary one-to-many whose relation field is typed as the same model, and a single self-relation like this needs no relation name.

`posts Post[]` on `User` is the mirror field, the field on the other side of the relation, which stores nothing in the database. You can leave it out, and the relation still works: you then read it from the foreign key side with `db.orm.public.Post.where({ authorId: user.id }).all()`, where `.all()` is the call that runs the query and returns every matching row.

To connect a post to a user, set the foreign key when you create the post. Here `user` is a user record you read earlier:

```typescript
import { db } from "./prisma/db";

const post = await db.orm.public.Post.create({
  title: "Hello",
  authorId: user.id,
});
```

Reading back the other way, `db.orm.public.Post.include("author").all()` returns each post with its user nested on it. [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins#one-to-many) covers querying in both directions.

## One-to-one [#one-to-one]

A one-to-one relation (`1:1`) connects at most one record on each side: a user has at most one profile, and a profile belongs to exactly one user.

Model it like a one-to-many, then add `@unique` to the foreign key. The unique constraint is what turns "many" into "at most one": no two profiles can reference the same user.

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

model Profile {
  id     Int    @id @default(autoincrement())
  bio    String
  userId Int    @unique
  user   User   @relation(fields: [userId], references: [id])
}
```

Declare the relation on the side that holds the foreign key, `Profile` here. You can also add the mirror field `profile Profile?` to `User`, with a type and nothing else, because it needs no `@relation` of its own. It is a single `Profile?` rather than a list because `userId` is unique, and it has to be optional because nothing in the database guarantees a matching profile row. With it in place you can [read the relation from either side](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins#one-to-one), as in `db.orm.public.User.include("profile").all()`.

### Which side owns the foreign key [#which-side-owns-the-foreign-key]

Put the foreign key on the dependent side, meaning the record that cannot exist on its own. A profile needs a user, but a user does not need a profile, so `Profile` holds `userId`.

The other signals all point at the same side. The dependent record is:

* The one you create second. Insert the `User`, then its `Profile`.
* The one you would delete when the parent goes away.
* The one whose absence is normal. A user without a profile is fine, and a profile without a user is broken data.

## Many-to-many [#many-to-many]

A many-to-many relation (`m:n`) connects many records on each side: a post has many tags, and a tag applies to many posts.

One foreign key column cannot hold many values, so you add a third model, the model for the join table, which holds one record per connected pair.

```prisma
model Post {
  id    Int       @id @default(autoincrement())
  title String
  tags  Tag[]
}

model Tag {
  id    Int       @id @default(autoincrement())
  label String    @unique
  posts Post[]
}

model PostTag {
  postId Int
  tagId  Int
  post   Post @relation(fields: [postId], references: [id])
  tag    Tag  @relation(fields: [tagId], references: [id])

  @@id([postId, tagId])
}
```

The composite primary key on `PostTag`, `@@id([postId, tagId])`, allows one record per pair. Note that `Post.tags` is typed `Tag[]`, not `PostTag[]`, and the same goes for `Tag.posts`: you name the model at the other end, not the join table. If a second join table connects the same two models, the relation name goes on both sides again, which here means the list field `Post.tags` and the field that points back at `Post`, `PostTag.post`.

Connect a post to a tag with a nested write on the mirror field:

```typescript
await db.orm.public.Post.where({ id: post.id }).update({
  tags: (t) => t.connect([{ id: tag.id }]),
});
```

`t` is the argument of the nested write callback: `t.create([...])` makes new related records and links them, `t.connect([...])` links existing ones, and `t.disconnect([...])` removes the link. The nested write goes through the mirror fields, `Post.tags` and `Tag.posts`, so if you leave them out you write the `PostTag` rows yourself with `db.orm.public.PostTag.create({ postId: post.id, tagId: tag.id })`. Because `PostTag` is an ordinary model, the join table can also hold data about the pairing itself: to record when a tag was added, add `addedAt DateTime @default(now())` to `PostTag`.

An implicit many-to-many, with list fields on both sides and no join table as in Prisma ORM 7, is not supported, so declare `PostTag` yourself. If you skip it, `npx prisma contract emit` reports an error whose `code` is `PSL_ORPHANED_BACKRELATION`. [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins#many-to-many) shows how to read across the join table in one query.

## Polymorphic relations [#polymorphic-relations]

Sometimes several kinds of record share a common core but each has its own extra fields: every `Task` has a title, but a `Bug` also has a severity and a `Feature` has a target release. Prisma ORM models this with a base model plus variant models. One field on the base model, the discriminator, records which variant each row is:

```prisma
model Task {
  id    Int    @id @default(autoincrement())
  title String
  type  String

  @@discriminator(type)
}

model Bug {
  severity String

  @@base(Task, "bug")
}

model Feature {
  targetRelease String?

  @@base(Task, "feature")

  @@map("features")
}
```

`@@discriminator(type)` marks the field that records the variant, and `@@base(Task, "bug")` declares that `Bug` is the `"bug"` variant of `Task`. Both take a field or model name without quotes, while the variant value is a string. A variant has every field of its base plus the ones it declares, and it needs no `@id` of its own because it uses the base model's primary key.

Read and write variants through the base model, where `.variant(...)` limits the query to one variant. It takes the model name, `"Bug"`, with a capital letter, and passing the discriminator value `"bug"` instead is a type error. On a create, the discriminator value is filled in for you:

```typescript
await db.orm.public.Task.variant("Bug").create({ title: "Crash on save", severity: "high" });
```

A query on `Task` with no `.variant(...)` returns every variant. Each row carries the base fields plus only its own variant's fields, and the discriminator field holds that variant's value, such as `"bug"`. Switch on `task.type` to reach a variant's own fields:

```typescript
switch (task.type) {
  case "bug":
    return task.severity;
  case "feature":
    return task.targetRelease;
}
```

`@@map` decides how a variant is stored, which is a new job for it: in Prisma ORM 7, `@@map` only renamed a table. A variant with no `@@map`, like `Bug`, is stored in the base model's table, and its extra columns are added there as nullable columns, because a `Feature` row has no severity. A variant with its own `@@map`, like `Feature`, is split into its own table, named by the string you pass, and its columns there can be `NOT NULL`, though reading a full variant then costs a join.

Start with the shared table, and give a variant its own table only when its columns have to be `NOT NULL` in the database or when the variant has many columns of its own. The pattern as a whole fits when you query the variants together (one feed of tasks, one stream of events) and each variant has real structure of its own. If you never query them together, separate models are simpler, and if the variants differ by one nullable field, a single model is simpler still.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. In an existing project, run `npx prisma skills sync` to add them. The `prisma-8` skill covers relation modeling, so try prompts that map to each section:

* "Using the prisma-8 skill, add a one-to-many between User and Post with the foreign key on Post."
* "Make the Profile relation one-to-one by adding a unique constraint to its foreign key."
* "Model a many-to-many between Post and Tag with an explicit model for the join table and an addedAt timestamp."
* "Split Task into Bug and Feature variants with a discriminator field."

## Next steps [#next-steps]

* [Query relations](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins) with `.include(...)`, filters on relation data, and reads across the join table.
* To change the database to match the contract, edit `contract.prisma`, run `npx prisma contract emit`, then run `npx prisma migration plan` to write the migration files and `npx prisma db migrate` to apply them. [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration) has the flags and explains how the next plan finds its starting point.
* To model for MongoDB, see the [MongoDB data modeling guide](https://www.prisma.io/docs/orm/data-modeling/mongodb).

## Related pages

- [`MongoDB data modeling`](https://www.prisma.io/docs/orm/data-modeling/mongodb): Model documents, embedded documents, and references for MongoDB, and decide when to embed and when to reference.

# Extensions (/docs/orm/extensions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Every package that plugs into Prisma ORM: database packages, column types, indexes, query operations, and middleware, by Prisma and the community.

Location: ORM > Extensions

An extension is an npm package that adds something Prisma ORM does not do on its own: a column type such as a vector or a geometry, an index type, query operations (new functions you can call in a query, such as pgvector's `cosineDistance`), or middleware, which runs your own code before and after every query. To use PostgreSQL you install `@prisma/orm-postgres`, and to use MongoDB you install `@prisma/orm-mongo`, because support for a database comes from an extension too.

Installing the package is not the whole job, because you register an extension in two places. It goes in `prisma.config.ts`, so that the command line tools know about it, and in `db.ts`, the file where you create the client, so that your queries can use what it adds. `@prisma/orm-postgres` is the package you call directly: `ormConfig(...)` in `prisma.config.ts` and `postgres(...)` in `db.ts`. Other extensions are listed in the `extensions` array passed to those two calls. [Using extensions](https://www.prisma.io/docs/orm/extensions/using-extensions) shows both registrations, with the install command, for pgvector. Middleware is the exception, because you register it on the client only, and [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works) covers that.

Your contract is what Prisma ORM 8 calls your schema: [`contract.prisma`](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) in place of `schema.prisma`. If you have a Prisma ORM 7 project, [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) says what replaced `schema.prisma`, `@prisma/client`, and `$use`.

## Catalog [#catalog]

The [extension directory](https://www.prisma.io/extensions) has the install command and the registration snippet for each entry below. There is no MySQL package, and [Supported databases](https://www.prisma.io/docs/orm/supported-databases) says what is planned. An entry marked experimental works today, but its API can change between releases.

| Name                                                                   | What it adds                                                                                                     | Package                                  | Databases           | By                                              |
| ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ------------------- | ----------------------------------------------- |
| [arktype-json](https://www.prisma.io/extensions/arktype-json)          | JSON columns validated by an arktype schema and typed end to end.                                                | `@prisma/orm-extension-arktype-json`     | PostgreSQL          | Prisma                                          |
| [Cache middleware](https://www.prisma.io/extensions/middleware-cache)  | Serve repeated reads from an in-memory or pluggable cache, opted in per query.                                   | `@prisma/orm-extension-middleware-cache` | PostgreSQL, MongoDB | Prisma                                          |
| [MongoDB](https://www.prisma.io/extensions/mongodb)                    | MongoDB support for Prisma ORM: config, runtime, contract authoring, BSON values, and migrations in one package. | `@prisma/orm-mongo`                      | MongoDB             | Prisma                                          |
| [ParadeDB](https://www.prisma.io/extensions/paradedb) (experimental)   | BM25 full-text search indexes.                                                                                   | `@prisma/orm-extension-paradedb`         | PostgreSQL          | Prisma                                          |
| [pgvector](https://www.prisma.io/extensions/pgvector)                  | Vector columns and similarity search for embeddings.                                                             | `@prisma/orm-extension-pgvector`         | PostgreSQL          | Prisma                                          |
| [PostGIS](https://www.prisma.io/extensions/postgis)                    | Geometry columns and geospatial queries such as distance and containment.                                        | `@prisma/orm-extension-postgis`          | PostgreSQL          | Prisma                                          |
| [PostgreSQL](https://www.prisma.io/extensions/postgresql)              | PostgreSQL support for Prisma ORM: config, runtime, contract authoring, and migrations in one package.           | `@prisma/orm-postgres`                   | PostgreSQL          | Prisma                                          |
| [SQLite](https://www.prisma.io/extensions/sqlite) (experimental)       | SQLite support for Prisma ORM: config, runtime, contract authoring, and migrations in one package.               | `@prisma/orm-sqlite`                     | SQLite              | Prisma                                          |
| [Supabase](https://www.prisma.io/extensions/supabase) (experimental)   | Supabase auth and storage tables plus role-bound clients for row-level security.                                 | `@prisma/orm-extension-supabase`         | PostgreSQL          | Prisma                                          |
| [IndexedDB](https://www.prisma.io/extensions/indexeddb) (experimental) | Prisma 8 for IndexedDB: a browser database from your PSL schema, with typed accessors and explicit migrations.   | `@prisma-idb/client-idb`                 | IndexedDB           | [Yash Kolekar](https://whyash5114.com)          |
| [typed-json](https://www.prisma.io/extensions/typed-json)              | Typed JSON and text columns with no validator dependency.                                                        | `prisma-orm-extension-typed-json`        | PostgreSQL          | [Omar Dulaimi](https://github.com/omar-dulaimi) |
| [zod-json](https://www.prisma.io/extensions/zod-json)                  | Typed JSON columns described and enforced by a zod schema.                                                       | `prisma-orm-extension-zod-json`          | PostgreSQL          | [Omar Dulaimi](https://github.com/omar-dulaimi) |

In the Supabase row, role-bound clients are client instances pinned to a particular PostgreSQL role, so the database applies that role's row-level security policies to whatever you query through them.

## Publish your own [#publish-your-own]

An extension you write yourself is an npm package with one entry point for the command line tools and one for your application. Name your two entry points `control` and `runtime`, as pgvector does and as the [call for extension authors](https://www.prisma.io/blog/prisma-next-call-for-extension-authors) describes. Middleware ships a single entry point instead, because it is only ever registered on the client.

To write middleware, follow [Authoring custom middleware](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware). If you are adding a whole database, `@prisma/orm-postgres` is the one to copy for a SQL database and `@prisma/orm-mongo` for a document database. Once your package is on npm, [submit it to the directory](https://www.prisma.io/extensions/submit), and a maintainer reviews your entry before it appears in the catalog.

## See also [#see-also]

* [Using extensions](https://www.prisma.io/docs/orm/extensions/using-extensions): install an extension and run your first query with it
* [Supported databases](https://www.prisma.io/docs/orm/supported-databases): which databases Prisma ORM ships and what is planned
* [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7): what changes in a project that already uses `@prisma/client` and `schema.prisma`

## Related pages

- [`Coming from Prisma ORM 7`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7): What each Prisma ORM 7 schema attribute, command, and query is called in Prisma ORM 8, and what is not available.
- [`Core concepts`](https://www.prisma.io/docs/orm/core-concepts): The ideas every Prisma ORM command and API builds on: contracts, emitting, plans, the database signature, codecs, and the migration graph.
- [`Overview`](https://www.prisma.io/docs/orm/data-modeling): Describe the data your application needs with models, primary keys, scalar fields, and relations.
- [`Prisma 7`](https://www.prisma.io/docs/orm/v7): Prisma ORM is a next-generation Node.js and TypeScript ORM that provides type-safe database access, migrations, and a visual data editor.
- [`Prisma ORM`](https://www.prisma.io/docs/orm/v6): Learn about Prisma ORM

# Using extensions (/docs/orm/extensions/using-extensions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Extensions add database features like vector search, geospatial data, and full-text search to a Prisma ORM project.

Location: ORM > Extensions > Using extensions

An extension is a package that teaches Prisma ORM a database feature it does not know out of the box. Installing one gives you new column types to declare and new query operations to call, along with the migrations that install the feature in the database itself. Vector search, geospatial data, full-text search, typed JSON, and provider-specific integrations all reach your project this way.

Reach for an extension when your application needs one of those database features and you still want everything Prisma ORM gives you for the rest of your data: typed schema declarations, generated TypeScript, migration support, and query helpers.

Your contract is what Prisma ORM 8 calls your schema: `contract.prisma` in place of `schema.prisma`. In a project made with `npm create prisma@latest` it is at `src/prisma/contract.prisma`.

Adding an extension means installing its package and then registering it in two places, your config file and your client. These steps use pgvector, the vector search extension, as the example, and they assume a PostgreSQL project from the [quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql), so `@prisma/orm-postgres` is already installed and the extension package is added next to it. Supabase is set up differently, so if that is the extension you are adding, read [the note under the catalog](#available-extensions) first.

## 1. Install the package [#1-install-the-package]

  

#### bun

```bash title="Terminal"
bun add @prisma/orm-extension-pgvector
```

#### pnpm

```bash title="Terminal"
pnpm add @prisma/orm-extension-pgvector
```

#### yarn

```bash title="Terminal"
yarn add @prisma/orm-extension-pgvector
```

#### npm

```bash title="Terminal"
npm install @prisma/orm-extension-pgvector
```

## 2. Register it in the config [#2-register-it-in-the-config]

A project made with `npm create prisma@latest` already has `prisma.config.ts`, so open it and add the extension to the `extensions` array.

```ts title="prisma.config.ts"
import { definePrismaConfig } from 'prisma/config';
import pgvector from '@prisma/orm-extension-pgvector/control';
import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';

export default definePrismaConfig({
  orm: ormConfig({
    contract: './src/prisma/contract.prisma',
    extensions: [pgvector],
    db: {
      connection: process.env['DATABASE_URL']!,
    },
  }),
});
```

`@prisma/orm-postgres` is the package you call directly: `ormConfig(...)` in `prisma.config.ts` and `postgres(...)` in `db.ts`. Other extensions are listed in the `extensions` array passed to those two calls. The example renames `defineConfig` to `ormConfig` so it is not confused with `definePrismaConfig`, and you can keep the original name.

Import the paths the extension's page in the [extension directory](https://www.prisma.io/extensions) gives you. For pgvector they are `/control` in `prisma.config.ts` and `/runtime` in `db.ts`.

## 3. Register it on the client [#3-register-it-on-the-client]

Add the extension to the `extensions` array on the client as well, which is what gives the `db` object you write queries against the extension's query operations and value types.

```ts title="src/prisma/db.ts"
import pgvector from '@prisma/orm-extension-pgvector/runtime';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
  extensions: [pgvector],
});
```

The `'./contract.d'` in that import is not a typo: it is how you import `contract.d.ts`, one of the two files `npx prisma contract emit` writes.

## 4. Use the new type in your contract [#4-use-the-new-type-in-your-schema]

Now that pgvector is in `prisma.config.ts`, `npx prisma contract emit` accepts `pgvector.Vector(1536)` in your contract. A vector column needs an explicit number of dimensions, so declare that dimension once as a named type in a `types` block, and then every column that uses the name gets the same dimension. The trailing `?` on `Embedding1536?` makes the column optional, exactly as `?` did in Prisma ORM 7. The `types` block is part of [PSL syntax](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax).

The `pgvector` in `pgvector.Vector(1536)` is the name the extension registers its types under, and its page in the extension directory lists them. PostGIS, for example, gives you `postgis.Geometry(4326)`.

The first line of the file, `// use prisma-8`, is required. `npx prisma contract emit` reads only `.prisma` files whose first line is `// use prisma-8` and skips any other file without a warning, so keep that line at the top when you add the `types` block.

```prisma title="src/prisma/contract.prisma"
// use prisma-8

types {
  Embedding1536 = pgvector.Vector(1536)
}

model Post {
  id        String         @id @default(uuid())
  title     String
  embedding Embedding1536?
}
```

## 5. Apply and query [#5-apply-and-query]

Getting the new column from your contract into your database takes these commands, in this order:

1. `npx prisma contract emit`, so that `contract.json` and `contract.d.ts` pick up the new column. Run it again after every later change to `contract.prisma`.
2. `npx prisma migration plan`, which writes the extension's own migration into `migrations/`, so commit it along with your other migrations. Skip this and the next command stops with an error whose `code` is `MIGRATION.CONTRACT_SPACE_LAYOUT_VIOLATION`.
3. `npx prisma db init` on a new database, or `npx prisma db update` on one that already has tables, which [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration) covers. This runs the extension's migration and makes the database match your contract: it creates the `Post` table, or adds the `embedding` column when the `Post` table already exists.

The extension's migration is the `CREATE EXTENSION IF NOT EXISTS vector` statement, so you never write that statement yourself, but the PostgreSQL server has to have pgvector available for it to succeed. Both databases the quickstart offers have it: the local Prisma Postgres database that Composer starts, and a Prisma Postgres database from `npx create-db@latest`. A stock PostgreSQL image may not, and then the migration fails on that statement, so install pgvector on the server first, following [pgvector's own instructions](https://github.com/pgvector/pgvector).

With the column in your database, write an embedding into it. A vector value is a plain `number[]` with as many entries as the column's dimension, so a column typed `Embedding1536` takes an array of 1536 numbers, which is what an embedding model gives you. Prisma ORM does not produce the numbers, and `embed` in this example stands for whichever model you call:

```ts title="src/prisma/write-post.ts"
import { db } from './db';

const embedding: number[] = await embed('about cats');
await db.orm.public.Post.create({ title: 'about cats', embedding });
```

In Prisma ORM 8 `create` takes the fields directly, with no `data` wrapper. [Create a record](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#create-a-record) shows the two side by side. `public` is the PostgreSQL schema your tables are in.

Searching for the rows closest to a query vector uses the operations the extension adds, and you write that search with the SQL query builder rather than with `db.orm`. In that block:

* `db.orm` is the ORM API, and under it you address a model by the name in your contract, so the model `Post` is `db.orm.public.Post`.
* `db.sql` is the [SQL query builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries), and under it you address a table by the name it has in the database, so the same data is `db.sql.public.Post`. The two names are the same because the model sets no `@@map`.
* `db.runtime()` is what runs a built query.
* `f`, in the callback of each builder method, holds the row's columns.
* `fns` holds the functions you can call on those columns, including the ones pgvector adds.
* `queryVector` is a `number[]` of the same length as the stored embeddings.

```ts title="src/prisma/similarity-search.ts"
import { db } from './db';

export async function similaritySearch(queryVector: number[]) {
  const plan = db.sql.public.Post
    .select('id', 'title')
    .select('distance', (f, fns) => fns.cosineDistance(f.embedding, queryVector))
    .orderBy((f, fns) => fns.cosineDistance(f.embedding, queryVector), { direction: 'asc' })
    .limit(10)
    .build();

  return db.runtime().query(plan);
}
```

`.select('distance', ...)` names the computed column `distance`, and `.build()` returns a plain object that `db.runtime().query(...)` runs. Each row that comes back has `id`, `title`, and `distance`, a `number` that is `null` when the row has no embedding.

Alongside `fns.cosineDistance`, pgvector gives you `fns.cosineSimilarity`. Both take two vectors and return a PostgreSQL `float8`, which you get as a `number`. The difference is which way you sort: order ascending when you sort by distance, because the closest row has the smallest distance, and descending when you sort by similarity.

## How the pieces fit [#how-the-pieces-fit]

One installed package supplies both registrations, the one in `prisma.config.ts` and the one in `db.ts`:

<ConceptAnimation name="extension-planes" />

## When a registration is missing [#capabilities]

When your contract uses an extension and `db.ts` does not list it in `extensions`, `postgres(...)` throws an error whose `code` is `RUNTIME.MISSING_EXTENSION_PACK` before any query runs. Add the extension's `runtime` import to `db.ts` to fix it. If the database cannot install the extension, `db init` or `db update` reports it.

## Available extensions [#available-extensions]

Every extension, whether Prisma wrote it or someone in the community did, is listed in the [extension directory](https://www.prisma.io/extensions) with its install command and the registration snippets to copy.

| Name                                                                   | What it adds                                                                                                     | Package                              | Databases  | By                                              |
| ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------ | ---------- | ----------------------------------------------- |
| [arktype-json](https://www.prisma.io/extensions/arktype-json)          | JSON columns validated by an arktype schema and typed end to end.                                                | `@prisma/orm-extension-arktype-json` | PostgreSQL | Prisma                                          |
| [MongoDB](https://www.prisma.io/extensions/mongodb)                    | MongoDB support for Prisma ORM: config, runtime, contract authoring, BSON values, and migrations in one package. | `@prisma/orm-mongo`                  | MongoDB    | Prisma                                          |
| [ParadeDB](https://www.prisma.io/extensions/paradedb) (experimental)   | BM25 full-text search indexes.                                                                                   | `@prisma/orm-extension-paradedb`     | PostgreSQL | Prisma                                          |
| [pgvector](https://www.prisma.io/extensions/pgvector)                  | Vector columns and similarity search for embeddings.                                                             | `@prisma/orm-extension-pgvector`     | PostgreSQL | Prisma                                          |
| [PostGIS](https://www.prisma.io/extensions/postgis)                    | Geometry columns and geospatial queries such as distance and containment.                                        | `@prisma/orm-extension-postgis`      | PostgreSQL | Prisma                                          |
| [PostgreSQL](https://www.prisma.io/extensions/postgresql)              | PostgreSQL support for Prisma ORM: config, runtime, contract authoring, and migrations in one package.           | `@prisma/orm-postgres`               | PostgreSQL | Prisma                                          |
| [SQLite](https://www.prisma.io/extensions/sqlite) (experimental)       | SQLite support for Prisma ORM: config, runtime, contract authoring, and migrations in one package.               | `@prisma/orm-sqlite`                 | SQLite     | Prisma                                          |
| [Supabase](https://www.prisma.io/extensions/supabase) (experimental)   | Supabase auth and storage tables plus role-bound clients for row-level security.                                 | `@prisma/orm-extension-supabase`     | PostgreSQL | Prisma                                          |
| [IndexedDB](https://www.prisma.io/extensions/indexeddb) (experimental) | Prisma 8 for IndexedDB: a browser database from your PSL schema, with typed accessors and explicit migrations.   | `@prisma-idb/client-idb`             | IndexedDB  | [Yash Kolekar](https://whyash5114.com)          |
| [typed-json](https://www.prisma.io/extensions/typed-json)              | Typed JSON and text columns with no validator dependency.                                                        | `prisma-orm-extension-typed-json`    | PostgreSQL | [Omar Dulaimi](https://github.com/omar-dulaimi) |
| [zod-json](https://www.prisma.io/extensions/zod-json)                  | Typed JSON columns described and enforced by a zod schema.                                                       | `prisma-orm-extension-zod-json`      | PostgreSQL | [Omar Dulaimi](https://github.com/omar-dulaimi) |

The database packages are in the table too.

The ones marked experimental work today, but their methods and options are still changing between releases. Each name in the table links to that extension's directory page, and from there to the package README. Middleware wraps queries rather than adding a database feature, so it is listed on [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works) instead.

> [!NOTE]
> Supabase does not follow the recipe above
> 
> Supabase publishes no `control` entry point. What the command line tools read is published at `@prisma/orm-extension-supabase/pack` instead, so the config imports that and passes it to the same `ormConfig(...)` call step 2 uses:
> 
> ```ts title="prisma.config.ts"
> import { definePrismaConfig } from 'prisma/config';
> import supabasePack from '@prisma/orm-extension-supabase/pack';
> import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';
>
> export default definePrismaConfig({
>   orm: ormConfig({
>     contract: './src/prisma/contract.prisma',
>     extensions: [supabasePack],
>     db: {
>       connection: process.env['DATABASE_URL']!,
>     },
>   }),
> });
> ```
>
> The client is where the real difference is, because you build it with `supabase()` from `@prisma/orm-extension-supabase/runtime` rather than with `postgres()`, and it needs a way to check the JWTs your users send:
> 
> ```ts title="src/prisma/db.ts"
> import { supabase } from '@prisma/orm-extension-supabase/runtime';
> import type { Contract } from './contract.d';
> import contractJson from './contract.json' with { type: 'json' };
>
> export const db = await supabase<Contract>({
>   contractJson,
>   url: process.env['DATABASE_URL']!,
>   jwksUrl: process.env['SUPABASE_JWKS_URL']!,
> });
> ```
>
> `jwksUrl` is your project's JWKS endpoint, `https://<project-ref>.supabase.co/auth/v1/.well-known/jwks.json`, and it is the right option for a current Supabase project, because those sign their JWTs with ES256 keys. An older project that still signs with the shared HS256 secret passes `jwtSecret` instead of `jwksUrl`, and never both. `supabase status` prints a `JWT_SECRET` even for an ES256 project, so its presence does not tell you which one yours uses. A token signed the other way is rejected with an error whose `code` is `SUPABASE.JWT_INVALID`, and the message names the fix.
> 
> `supabase(...)` takes the same `extensions` array as `postgres(...)`, so pgvector or another extension goes there in the same way.
> 
> `await db.asUser(jwt)` takes the user's Supabase JWT and gives you a client that runs as that user. `db.asAnon()` gives you one that runs as the anonymous role, and `db.asServiceRole()` one that bypasses row-level security. `db` itself has no `orm` or `sql`: those live on the three role-bound clients. The [runnable example](https://github.com/prisma/orm/tree/main/examples/supabase) shows the whole setup in one project.
> 
> `@prisma/orm-extension-supabase` has a contract of its own, which describes Supabase's `auth` and `storage` tables, check constraints included. Prisma read those tables from one Supabase version, supabase/postgres 17.6.1.106, and a Supabase project on another version can have a different set of check constraints. [`npx prisma db verify`](https://www.prisma.io/docs/cli/db-verify) compares your database with the extension's contract as well as with yours, and when a check constraint the extension describes is missing from your database, `db verify` lists it and fails. You cannot fix that with a migration, because Prisma ORM never changes Supabase's own tables. Instead, [open an issue on prisma/orm](https://github.com/prisma/orm/issues) with the output of `db verify` and your Supabase version, so the extension can be updated to match.
> 
> [`npx prisma db sign`](https://www.prisma.io/docs/cli/db-sign) checks that a database matches your contract and then records in the database which contract it matches, and it records the extension's contract the same way. When an update to `@prisma/orm-extension-supabase` changes the extension's contract, that record no longer matches, and `npx prisma db verify` fails with `MIGRATION.CONTRACT_SPACE_VIOLATION` until you run `npx prisma db sign` again against every database you signed with the earlier version. The Prisma ORM release notes say when an update changes the extension's contract, for example for the change introduced in 8.0.0-rc.12. If you are also re-emitting your own contract with `npx prisma contract emit`, run that before `db sign`.

If you would rather read a whole working project than a set of snippets, there is a runnable example for each of these extensions: [pgvector](https://github.com/prisma/orm/tree/main/examples/prisma-8-demo), [PostGIS](https://github.com/prisma/orm/tree/main/examples/prisma-8-postgis-demo), [ParadeDB](https://github.com/prisma/orm/tree/main/examples/paradedb-demo), and [Supabase](https://github.com/prisma/orm/tree/main/examples/supabase).

If the extension you need does not exist yet, you can build it. An extension is an npm package with a documented layout, and the [call for extension authors](https://www.prisma.io/blog/prisma-next-call-for-extension-authors) explains how to write and publish one. Once yours is on npm, [submit it to the directory](https://www.prisma.io/extensions/submit), where the form validates your entry and opens the pull request for you.

## See also [#see-also]

* [Advanced queries](https://www.prisma.io/docs/orm/fundamentals/advanced-queries): the SQL query builder, where extension operations like `cosineDistance` appear
* [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works) for wrapping queries rather than adding database features
* [Quickstart with PostgreSQL](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql) to set up a project to add extensions to
* [Extensions overview](https://www.prisma.io/docs/orm/extensions) for the full catalog, including middleware
* [Prisma ORM overview](https://www.prisma.io/docs/orm) for how your contract, your migrations, and your client fit together

# Advanced queries (/docs/orm/fundamentals/advanced-queries)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Use the SQL query builder on PostgreSQL and the pipeline builder on MongoDB for queries the ORM API can't express.

Location: ORM > Fundamentals > Advanced queries

Most queries fit the ORM API, and when one doesn't, there is a query builder. Prisma ORM 8 supports PostgreSQL, SQLite, and MongoDB; the SQL query builder is for PostgreSQL and SQLite, the pipeline builder for MongoDB. Neither builder asks you to write SQL as a string. When the builder cannot express a query, `db.raw.sql` lets you write one, with values still sent as parameters. Both builders come with `@prisma/orm-postgres` and `@prisma/orm-mongo`, so there is nothing extra to install.

The schema file is now `contract.prisma`; it is the same schema language as Prisma ORM 7 (with the type changes on [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#schema)). The docs call it your contract, and TypeScript checks both builders against it.

You choose per query, not per app, so using the ORM API everywhere and a builder in the three places that need it is normal.

Every example here imports `db`, the client you create once in `src/prisma/db.ts`, and `prisma orm init` writes that file for you. The examples run from a file directly inside `src/`.

Every example on this page queries these four models:

```prisma
model User {
  id    String  @id @default(cuid(2))
  email String  @unique
  name  String?
  posts Post[]

  @@map("user")
}

model Post {
  id        String   @id @default(cuid(2))
  title     String
  published Boolean  @default(false)
  createdAt DateTime @default(now())
  authorId  String
  author    User     @relation(fields: [authorId], references: [id])
  tags      Tag[]

  @@map("post")
}

model Tag {
  id    String @id @default(cuid(2))
  name  String @unique
  posts Post[]

  @@map("tag")
}

model PostTag {
  postId String
  tagId  String
  post   Post   @relation(fields: [postId], references: [id])
  tag    Tag    @relation(fields: [tagId], references: [id])

  @@id([postId, tagId])
  @@map("post_tag")
}
```

In Prisma ORM 8 a many-to-many relation is the two list fields plus a model for the join table, as `PostTag` here; see [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins). The MongoDB examples use the same models, except that each id is declared as `id ObjectId @id @map("_id")`, so the property is `_id`.

## PostgreSQL: SQL query builder [#postgresql-sql-query-builder]

A SQL builder query takes two steps: first you build it, then you run it. You decide the exact SQL: the joins, the grouping, and the columns that come back.

**Use it when:**

* The query is easier to say in SQL: joins with conditions, computed columns, one row per group.
* You need PostgreSQL behavior the ORM API doesn't offer, such as `RETURNING` on a bulk insert.
* An aggregation needs precise control, such as ordering and limiting by a count in the database.
* A query is performance-sensitive and you want to decide its exact SQL.

**Prefer the ORM API when** the query is CRUD, filtered reads, or relation traversal. The [reading](https://www.prisma.io/docs/orm/fundamentals/reading-data), [writing](https://www.prisma.io/docs/orm/fundamentals/writing-data), and [relations](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins) pages cover those methods, with less code and the same type safety.

### Build a query and run it [#build-a-query-and-run-it]

Start from a table with `db.sql.public.<table>`. `db.sql` is the SQL query builder, keyed by table name. A table's name is the model's `@@map` value, or the model name exactly as written when the model has no `@@map`, and column names are the field names unless a field sets `@map`. `public` is the PostgreSQL schema your tables are in. If you put a model inside a `namespace` block in your contract, the block's name is the PostgreSQL schema instead, so for a model inside `namespace billing { ... }` you write `billing` in place of `public`: `db.sql.billing.<table>`.

`db.runtime()` is the database connection; call it whenever you run a query. `query()` always resolves to an array of rows, even when the query matches one row.

Chain the clauses you want, call `.build()`, and pass the result to `db.runtime().query(...)`:

```typescript
import { db } from "./prisma/db";

const publishedPosts = db.sql.public.post
  .select("id", "title", "authorId")
  .where((f, fns) => fns.eq(f.published, true))
  .limit(10).offset(20)
  .build();

const rows = await db.runtime().query(publishedPosts);
```

The `.where(...)` callback receives two arguments. The first, `f`, holds the column references, and the second, `fns`, holds the operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`, `and`, `or`, and `ilike` for text columns on PostgreSQL. There are more; the [SQL query builder reference](https://www.prisma.io/docs/orm/reference/sql-query-builder#built-in-functions) has the full list.

Pass a value from your own code straight into an operator. Here `authorId` is a variable, such as one you read from a request:

```typescript
const postsByAuthor = db.sql.public.post
  .select("id", "title")
  .where((f, fns) => fns.eq(f.authorId, authorId)).build();
```

The builder sends every value you pass this way to the database as a query parameter, never as text pasted into the SQL, so it is safe against SQL injection.

`ResultType` names the type of one row of a built query, so you can use that type in your own function signatures:

```typescript
import type { ResultType } from "@prisma/orm-postgres/components/runtime";

type PublishedPost = ResultType<typeof publishedPosts>;

function titles(posts: PublishedPost[]) {
  return posts.map((post) => post.title);
}
```

`ResultType<...>` is one row, not the array, so `await db.runtime().query(publishedPosts)` resolves to `PublishedPost[]`. See [`ResultType`](https://www.prisma.io/docs/orm/reference/sql-query-builder#resulttype) in the reference.

### Join tables with precise control [#join-tables-with-precise-control]

Alias each side with `.as(...)`, join on any condition, and project columns from both sides into a flat result. `.select(...)` takes column names, or a callback that builds the row from the aliases, or a name plus an expression for a computed column:

```typescript
const postsWithAuthors = db.sql.public.post
  .as("p")
  .innerJoin(db.sql.public.user.as("u"), (f, fns) => fns.eq(f.p.authorId, f.u.id))
  .select((f) => ({ postId: f.p.id, title: f.p.title, authorEmail: f.u.email }))
  .where((f, fns) => fns.eq(f.p.published, true))
  .limit(10)
  .build();

const rows = await db.runtime().query(postsWithAuthors);
// Array<{ postId, title, authorEmail }>
```

After a join, `f` is keyed by the alias you gave each side, so a column is `f.p.authorId` rather than `f.authorId`.

Chain more joins for multi-hop traversals. This is how you get a flat post-tag list through a [many-to-many join table](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins#many-to-many), one row per pair:

```typescript
const postTagPairs = db.sql.public.post_tag
  .as("pt")
  .innerJoin(db.sql.public.tag.as("t"), (f, fns) => fns.eq(f.pt.tagId, f.t.id))
  .innerJoin(db.sql.public.post.as("p"), (f, fns) => fns.eq(f.pt.postId, f.p.id))
  .select((f) => ({ postTitle: f.p.title, tagName: f.t.name }))
  .build();

const rows = await db.runtime().query(postTagPairs);
```

```js no-copy
[
  { postTitle: 'Hello Prisma 8', tagName: 'databases' },
  { postTitle: 'Typed queries', tagName: 'typescript' }
]
```

The table here is `post_tag` because the model for the join table sets `@@map("post_tag")`.

### Group and rank results [#group-and-rank-results]

Answer "top N groups" questions, such as the authors with the most posts, by ordering and limiting on an aggregate directly in the database:

```typescript
const topAuthors = db.sql.public.post
  .select((f, fns) => ({ authorId: f.authorId, posts: fns.count() }))
  .groupBy((f) => f.authorId)
  .orderBy((f, fns) => fns.count(), { direction: "desc" })
  .limit(5)
  .build();

const rows = await db.runtime().query(topAuthors);
```

```js no-copy
[
  { authorId: 'cuid20000000000000000001', posts: 2 },
  { authorId: 'cuid20000000000000000002', posts: 1 }
]
```

Pass the same aggregate to `.orderBy(...)` that you passed to `.select(...)`, and the database does the sorting and the limiting.

Use `fns.countBigInt()` when a count can grow past `Number.MAX_SAFE_INTEGER`, because it returns a `bigint` while `fns.count()` returns a JavaScript `number`. A count larger than `Number.MAX_SAFE_INTEGER` throws an error with code `RUNTIME.DECODE_FAILED` rather than rounding.

### Write with RETURNING [#write-with-returning]

SQL builder writes take an array of rows. Use `.returning(...)` to choose which columns come back from the same statement:

```typescript
const insertUser = db.sql.public.user
  .insert([{ email: "sql@prisma.io" }])
  .returning("id", "email").build();

const [insertedUser] = await db.runtime().query(insertUser);
// insertedUser is { id, email }. The id comes from the @default(cuid(2)) in the contract.
```

Drop the `.returning(...)` call and the insert returns no rows, so run it with `db.runtime().execute(...)`, which resolves to `{ affectedRows }`.

The builder writes updates and deletes too. Choose the rows with `.where(...)`, and add `.returning(...)` when you want columns back. `postId` and `tagId` here are values from your own code:

```typescript
const publishPost = db.sql.public.post
  .update({ published: true })
  .where((f, fns) => fns.eq(f.id, postId)).build();
const deleteTag = db.sql.public.tag.delete().where((f, fns) => fns.eq(f.id, tagId)).build();

const { affectedRows } = await db.runtime().execute(publishPost);
await db.runtime().execute(deleteTag);
```

Neither of those two returns rows, so both go to `execute()`. Add `.returning(...)` to either one and you run it with `query()` instead.

### Raw SQL [#raw-sql]

Raw SQL comes in two sizes. When the operators don't cover a single expression you need, write that expression with `fns.raw` and declare what type it returns with `.returns(...)`, and the rest of the query stays typed.

Calling `.select` a second time adds columns rather than replacing the ones already chosen. The second call takes a name for the new column, then the expression:

```typescript
const users = db.sql.public.user
  .select("id", "email")
  .select("upperEmail", (f, fns) => fns.raw`UPPER(${f.email})`.returns("pg/text@1"))
  .limit(10).build();

const rows = await db.runtime().query(users);
// [{ id: 'cuid20000000000000000001', email: 'alice@prisma.io', upperEmail: 'ALICE@PRISMA.IO' }, ...]
```

`.returns(...)` takes a type name as a string: `"pg/text@1"` is the PostgreSQL type `text`, and type names always end in `@1`. The [raw queries reference](https://www.prisma.io/docs/orm/reference/raw-queries) covers how a bare value picks its type name.

A raw fragment is as safe as an operator, and you can interpolate columns and other typed expressions the same way.

When the whole statement has to be raw, write it with `db.raw.sql` and end it with one of two calls. Use `.returnsRow(...)` when the statement returns rows, then run the built query with `query()`:

```typescript
const limit = 10;
const user = db.sql.public.user; // alias, to shorten user.columns.id

const authorPostCounts = db.raw.sql`
  SELECT u.id, u.email, count(p.id) AS "postCount"
  FROM "user" u
  LEFT JOIN "post" p ON p."authorId" = u.id
  GROUP BY u.id, u.email
  LIMIT ${limit}
`
  .returnsRow({ id: user.columns.id, email: user.columns.email, postCount: "pg/int8@1" })
  .build();

const rows = await db.runtime().query(authorPostCounts);
```

Quote identifiers as PostgreSQL requires; `"authorId"` keeps the camel case. Each entry in the `.returnsRow(...)` object says how to read one result column. An entry is either a column from the contract, as in `user.columns.id`, or a type name as a string for a result column the contract has no counterpart for. `"pg/int8@1"` is a 64-bit integer, so `postCount` comes back as a `bigint`.

Use `.affectedCount()` when the statement returns no rows, then run the built query with `execute()`, which resolves to `{ affectedRows }`:

```typescript
const publishDrafts = db.raw.sql`
  UPDATE "post" SET "published" = true WHERE "published" = false
`.affectedCount().build();

const { affectedRows } = await db.runtime().execute(publishDrafts);
```

To use one raw statement inside another, interpolate it with `${...}`. End the inner statement at `.returnsRow(...)` without `.build()`; call `.build()` only on the outer one. Every un-built raw statement exposes its declared columns as `.returns`, so the outer statement can reuse them:

```typescript
const minPosts = 5;

const authorsWithPosts = db.raw.sql`
  SELECT p."authorId" AS "authorId", count(*) AS "postCount"
  FROM "post" p
  GROUP BY p."authorId"
  HAVING count(*) >= ${minPosts}
`.returnsRow({
  authorId: db.sql.public.post.columns.authorId,
  postCount: "pg/int8@1",
});

const activeAuthors = db.raw.sql`
  WITH active AS (${authorsWithPosts})
  SELECT u.email, active."postCount"
  FROM active
  JOIN "user" u ON u.id = active."authorId"
`.returnsRow({
  email: db.sql.public.user.columns.email,
  postCount: authorsWithPosts.returns.postCount,
}).build();

const rows = await db.runtime().query(activeAuthors);
```

A column the inner statement already declared can be reused in the outer row object, as `authorsWithPosts.returns.postCount` is here. The [raw queries reference](https://www.prisma.io/docs/orm/reference/raw-queries#the-client-level-dbrawsql-tag) documents every raw query method.

## MongoDB: Pipeline builder [#mongodb-pipeline-builder]

On MongoDB the builder is at `db.query`, and it builds a typed MongoDB aggregation pipeline: a sequence of stages such as `$match`, `$group`, `$sort`, and `$lookup`, checked against your contract. There is no `db.sql` on MongoDB.

All MongoDB aggregation happens here: the ORM API has no `.aggregate(...)` on MongoDB, so counts, sums, and grouping are pipeline builder work.

**Use it when:**

* You need an aggregation: counts, grouping, or summaries per key.
* You want to join and reshape documents across collections with `$lookup`.
* A query needs MongoDB pipeline stages that don't map to the ORM API, such as multi-stage filtering and projection.
* You want to filter with an operator such as `gt` or `ne`. On MongoDB the ORM API's `.where(...)` matches exact values only, and `.match(...)` here takes the operators.

**Prefer the ORM API when** the query is document create, read, update, or delete, and for reading a reference relation. A reference relation is a relation stored as an id in the document rather than as an embedded document, and `.include(...)` already covers the common `$lookup` case.

### Build a pipeline and run it [#build-a-pipeline-and-run-it]

Start from a collection with `db.query.from(...)`, which takes the collection name as a string: the model's `@@map` value, or the model name exactly as written when the model has no `@@map`. Every model above sets `@@map`, so the collections are `user`, `post`, `tag`, and `post_tag`. On MongoDB the ORM API uses the same name, as in `db.orm.post`.

`acc` holds the aggregate functions you can use inside `.group(...)`, such as `acc.count()` and `acc.max(f.createdAt)`. In the pipeline builder, fields use their stored names, so the id is `_id` (see the note under the contract above), and `_id` is also the grouping key in `.group(...)`. On MongoDB `db.runtime()` returns a promise, so await it before you run anything. Chain stages, call `.build()`, and run the result:

```typescript
import { acc } from "@prisma/orm-mongo/query-builder";
import { db } from "./prisma/db";

const runtime = await db.runtime();

// Post count per author, most prolific first
const postsByAuthor = db.query
  .from("post")
  .group((f) => ({ _id: f.authorId, postCount: acc.count() }))
  .sort({ postCount: -1 }) // -1 is descending
  .build();

const rows = await runtime.query(postsByAuthor);
```

```js no-copy
[
  { _id: "clx3n9x4v0000abc123def456", postCount: 3 },
  { _id: "clx3n9x4v0001abc123def457", postCount: 2 }
]
```

The rows are typed by the stages you built.

### Filter and group in stages [#filter-and-group-in-stages]

Chain `.match(...)` before `.group(...)` to aggregate over a subset, the pipeline equivalent of `WHERE` before `GROUP BY`:

```typescript
const draftsByAuthor = db.query
  .from("post")
  .match((f) => f.published.eq(false))
  .group((f) => ({ _id: f.authorId, draftCount: acc.count() })).build();

const rows = await runtime.query(draftsByAuthor);
```

In a `.match(...)` callback the operators are on the field itself, as in `f.published.eq(false)`, while the SQL query builder puts them on `fns` instead. The [pipeline builder reference](https://www.prisma.io/docs/orm/reference/pipeline-builder#match) lists the operators you can use here.

### Join collections with $lookup [#join-collections-with-lookup]

Use `.lookup(...)` for a type-checked join against another collection. The joined documents arrive under the name you give `.as(...)`:

```typescript
const postsWithAuthors = db.query
  .from("post")
  .match((f) => f.published.eq(true))
  .lookup((from) =>
    from("user").on((local, foreign) => ({ local: local.authorId, foreign: foreign._id })).as("author"),
  )
  .build();

const rows = await runtime.query(postsWithAuthors);
const authorId = "68e1f0c2a4b9d3e5f7a1b2c3";
const mine = rows.filter((row) => String(row.author[0]?._id) === authorId);
```

Each row is a post document with an extra `author` field, and that field is an array of the matching user documents. `row.author` is empty when the author is missing. A document pulled in by `.lookup(...)` keeps MongoDB's own `ObjectId` for `_id`, so wrap it in `String(...)` before you compare it with an id from your own code. The [pipeline builder reference](https://www.prisma.io/docs/orm/reference/pipeline-builder#lookup) has the rest of the stages.

## Choose the right query API [#choose-the-right-query-api]

| You need                                                       | Use                                         |
| -------------------------------------------------------------- | ------------------------------------------- |
| CRUD, filters, relations, simple aggregates                    | ORM API (`db.orm`)                          |
| Explicit join, computed projection, grouped top-N, `RETURNING` | SQL query builder (`db.sql.public.<table>`) |
| A whole SQL statement of your own, such as a CTE               | Raw SQL (`db.raw.sql`)                      |
| `$group`, `$lookup` with reshaping, any MongoDB aggregation    | Pipeline builder (`db.query.from(...)`)     |

`db.orm` holds your models by model name, as in `db.orm.public.User` on PostgreSQL. On MongoDB there is no schema segment, and the name is the collection: `db.orm.post`.

A built query that returns rows runs through `db.runtime().query(builtQuery)` on PostgreSQL. On MongoDB, await the connection first: `(await db.runtime()).query(builtQuery)`. A write that returns no rows goes to `execute(builtQuery)` instead, which resolves to `{ affectedRows }`.

Inside a transaction, `tx` is the argument your callback receives, and you run the built query on it: `await db.transaction(async (tx) => tx.query(builtQuery))`. `tx.query(...)` and `tx.execute(...)` run built queries inside a transaction; see [Transactions](https://www.prisma.io/docs/orm/fundamentals/transactions).

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. The `prisma-8` skill covers both builders and the choice between them and the ORM API, so try prompts that map to each section:

* "Using the prisma-8 skill, write a SQL builder query for the top 10 authors by post count."
* "This report needs post and author columns in one flat result. Build the join with the SQL query builder."
* "On MongoDB, group posts per author with the pipeline builder and sort by the count."
* "Review this file and tell me which queries should stay on the ORM API and which need a builder."

## Next [#next]

* [Read data](https://www.prisma.io/docs/orm/fundamentals/reading-data): the ORM API these builders extend.
* [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins): understand relationships before reaching for explicit joins.
* [Transactions](https://www.prisma.io/docs/orm/fundamentals/transactions): run built queries inside one.

## Related pages

- [`Reading data`](https://www.prisma.io/docs/orm/fundamentals/reading-data): Fetch one record or many with Prisma ORM, then filter, select, sort, paginate, and iterate the results.
- [`Relations and joins`](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins): Read related records in one query with .include(), and understand how one-to-one, one-to-many, and many-to-many relationships work.
- [`Transactions`](https://www.prisma.io/docs/orm/fundamentals/transactions): Run several writes so they all succeed or all fail together with db.transaction().
- [`Writing data`](https://www.prisma.io/docs/orm/fundamentals/writing-data): Create, update, delete, and upsert records with Prisma ORM, one at a time or in bulk.

# Reading data (/docs/orm/fundamentals/reading-data)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Fetch one record or many with Prisma ORM, then filter, select, sort, paginate, and iterate the results.

Location: ORM > Fundamentals > Reading data

This page shows how to read data with Prisma ORM: fetching [many records or one](#fetch-many-records-or-one), [filtering](#filter-records), [selecting fields](#select-fields), [sorting and paginating](#sort-and-paginate), [counting](#count-records), and [iterating large results](#iterate-a-large-result).

Every query chains methods on a model, and the last call in the chain says what you want back and runs the query, usually `.all()` or `.first()`:

  

#### PostgreSQL

```typescript
import { db } from "./prisma/db";

// Every published post
const posts = await db.orm.public.Post.where({ published: true }).all();

// One user, or null
const user = await db.orm.public.User.where({ email: "alice@prisma.io" }).first();
```

#### MongoDB

```typescript
import { db } from "./prisma/db";

// Every published post
const posts = await db.orm.posts.where({ published: true }).all();

// One user, or null
const user = await db.orm.users.where({ email: "alice@prisma.io" }).first();
```

`npm create prisma@latest` scaffolds a new project, while `npx prisma orm init` adds Prisma ORM to a project you already have.

Your contract is the `contract.prisma` file that replaced `schema.prisma`: it is where you declare your models, and every result on this page is typed from it. See [Core concepts](https://www.prisma.io/docs/orm/core-concepts) for how the contract and the client fit together.

`db` is the client you create once in `src/prisma/db.ts`, and `npx prisma orm init` writes that file for you. Commit it; unlike Prisma ORM 7's generated client, it is your code. `db.ts` reads two generated files that `npx prisma contract emit` writes next to it; you do not edit those. These examples are written from a file in `src/`, so the import is `./prisma/db`; from elsewhere, change the relative path.

`db.orm` holds your models. On PostgreSQL you reach a model through the database schema it is in: in `db.orm.public.User`, `User` is the model name and `public` is the PostgreSQL schema. It is `public` unless the model sits in a `namespace` block in your contract; see [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#schema). On MongoDB there is no schema segment, and the name is the collection: `db.orm.users`.

You can write `.where`, `.select`, `.orderBy`, `.limit`, and `.offset` in any order, but `.cursor(...)` must come after `.orderBy(...)`.

For Prisma ORM 7 users, `findMany` and `findFirst` / `findUnique` map directly onto `.all()` and `.first()` ([Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) maps the rest of the API):

```diff
- const posts = await prisma.post.findMany({ where: { published: true } });
+ const posts = await db.orm.public.Post.where({ published: true }).all();

- const user = await prisma.user.findUnique({ where: { email } });
+ const user = await db.orm.public.User.where({ email }).first();

- const page = await prisma.post.findMany({ take: 20, skip: 20 });
+ const page = await db.orm.public.Post.limit(20).offset(20).all();
```

`.first()` asks the database for one row. `findUnique` and `findFirst` both become `.first()`, so if several records match you get one of them, in no guaranteed order; add `.orderBy(...)` to choose.

## Example schema [#example-schema]

All examples on this page are based on the contract below. The file is `contract.prisma`, and it is still written in the Prisma schema language, so it looks like the `schema.prisma` you already know. `@default(cuid(2))` generates a CUID version 2 id.

**Expand for sample schema**

#### PostgreSQL

```prisma
model User {
  id        String   @id @default(cuid(2))
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  posts     Post[]
}

model Post {
  id        String   @id @default(cuid(2))
  title     String
  content   String?
  published Boolean
  authorId  String
  author    User     @relation(fields: [authorId], references: [id])
  createdAt DateTime @default(now())
}
```

#### MongoDB

```prisma
model User {
  id        ObjectId @id @map("_id")
  email     String   @unique
  name      String?
  createdAt Date
  posts     Post[]
  @@map("users")
}

model Post {
  id        ObjectId @id @map("_id")
  title     String
  content   String?
  published Bool
  author    User     @relation(fields: [authorId], references: [id])
  authorId  ObjectId
  createdAt Date
  @@map("posts")
}
```

> [!NOTE]
> On MongoDB, `@map("_id")` renames the field to `_id` everywhere: you filter on `_id`, you select `_id`, and the returned document has an `_id` key. That is why the MongoDB examples below never say `id`.

## Fetch many records or one [#fetch-many-records-or-one]

Use `.all()` when you want every matching record. It returns an array:

```typescript
const users = await db.orm.public.User.all();
```

```js no-copy
[
  { id: 'cuid20000000000000000001', email: 'alice@prisma.io', name: 'Alice', createdAt: 2026-07-06T09:03:13.808Z },
  { id: 'cuid20000000000000000002', email: 'bob@prisma.io', name: 'Bob', createdAt: 2026-07-06T09:03:14.112Z }
]
```

`.all()` takes no filter of its own, so put the filter in `.where(...)` before it. `.all()` also applies no limit, so combine it with [`limit`](#sort-and-paginate) on tables that can grow.

Use `.first()` when you want a single record. It returns the record, or `null` when nothing matches, and on both databases it asks for at most one row:

```typescript
const user = await db.orm.public.User.where({ email: "alice@prisma.io" }).first();
```

```js no-copy
{ id: 'cuid20000000000000000001', email: 'alice@prisma.io', name: 'Alice', createdAt: 2026-07-06T09:03:13.808Z }
```

On PostgreSQL you can skip `.where(...)` and pass the filter straight to `.first(...)`, which takes anything `.where(...)` takes, not just the primary key. On MongoDB, `.first()` takes no argument, so filter with `.where(...)`:

  

#### PostgreSQL

```typescript
const user = await db.orm.public.User.first({ id: userId });
```

#### MongoDB

```typescript
const user = await db.orm.users.where({ _id: userId }).first();
```

If you want an error instead of `null` when nothing matches, call `.firstOrThrow()`, the replacement for `findUniqueOrThrow` and `findFirstOrThrow`:

```typescript
const user = await db.orm.public.User.where({ email }).limit(1).all().firstOrThrow();
```

`.limit(1)` keeps it to one row, and `.firstOrThrow()` throws an error with code `RUNTIME.NO_ROWS` when nothing matches. There is no `.firstOrThrow()` on `.first()`. The error is an `Error` with a `code` property, so check `"code" in error` before you read it. The same form works on MongoDB, with `db.orm.users`.

## Filter records [#filter-records]

Use `.where(...)` to narrow a query, and pass an object to match fields by equality:

```typescript
const drafts = await db.orm.public.Post.where({ published: false }).all();
```

Chain several `.where(...)` calls to combine conditions with AND, which is also how you express a range:

```typescript
const recentPosts = await db.orm.public.Post
  .where((p) => p.createdAt.gte(start))
  .where((p) => p.createdAt.lte(end))
  .all();
```

### Filter operators on PostgreSQL [#filter-operators-on-postgresql]

On PostgreSQL, `.where(...)` also accepts a callback for richer comparisons, as in the range example above. The callback receives one object, written `p` here, with a property per field of your model. Each of those fields has `.eq`, `.neq`, `.lt`, `.lte`, `.gt`, `.gte`, `.like`, `.ilike`, `.in([...])`, `.notIn([...])`, `.isNull()`, and `.isNotNull()`, as far as its type supports them: a native enum field (`pg.enum(...)`), for example, has no `.like` or `.ilike`. `.like` and `.ilike` take SQL `LIKE` patterns, where `%` matches any run of characters. For search over words rather than patterns, text fields also have PostgreSQL [full-text search](https://www.prisma.io/docs/orm/reference/orm-client#full-text-search):

```typescript
// Case-insensitive text search
const matchingPosts = await db.orm.public.Post
  .where((p) => p.title.ilike("%prisma%"))
  .all();

// One of several values
const team = await db.orm.public.User
  .where((u) => u.email.in(["alice@prisma.io", "bob@prisma.io"]))
  .all();
```

To combine conditions with OR, AND, or NOT, use the `or`, `and`, and `not` helpers from `@prisma/orm-postgres/orm-client`. `@prisma/orm-postgres` is already installed; it is the package `db.ts` imports from:

```typescript
import { and, not, or } from "@prisma/orm-postgres/orm-client";

const highlighted = await db.orm.public.Post
  .where((p) => or(p.title.ilike("%hello%"), p.title.ilike("%prisma%")))
  .all();

const publishedPrismaPosts = await db.orm.public.Post
  .where((p) => and(p.published.eq(true), p.title.ilike("%prisma%")))
  .all();

const notHello = await db.orm.public.Post
  .where((p) => not(p.title.eq("Hello")))
  .all();
```

### Filter operators on MongoDB [#filter-operators-on-mongodb]

On MongoDB, `.where(...)` does not take a callback, but the object form covers equality:

```typescript
const drafts = await db.orm.posts.where({ published: false }).all();
```

For anything else, pass `.where(...)` a filter built with `MongoFieldFilter`, imported from `@prisma/orm-mongo/query-ast/execution`. `@prisma/orm-mongo` is the package `db.ts` imports from. `MongoFieldFilter` has one static method per operator: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `nin` (not in), `isNull`, and `isNotNull`, and each one takes the field name first:

```typescript
import { MongoFieldFilter } from "@prisma/orm-mongo/query-ast/execution";

const junePosts = await db.orm.posts
  .where(MongoFieldFilter.gte("createdAt", new Date("2026-06-01")))
  .where(MongoFieldFilter.lt("createdAt", new Date("2026-07-01")))
  .all();
```

Chained `.where(...)` calls combine with AND, the same as on PostgreSQL. Call `.not()` on a filter to invert it, and use `MongoOrExpr.of([...])` from the same import to combine filters with OR:

```typescript
import { MongoFieldFilter, MongoOrExpr } from "@prisma/orm-mongo/query-ast/execution";

const notAlice = await db.orm.users
  .where(MongoFieldFilter.eq("name", "Alice").not())
  .all();

const oldOrNew = await db.orm.posts
  .where(
    MongoOrExpr.of([
      MongoFieldFilter.eq("title", "Old"),
      MongoFieldFilter.eq("title", "New"),
    ]),
  )
  .all();
```

`MongoFieldFilter` has no case-insensitive or partial-match operator. For those, use the [pipeline builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#mongodb-pipeline-builder), which has a `regexMatch` expression.

The full operator list is in [Filter conditions and operators](https://www.prisma.io/docs/orm/reference/orm-client#filter-conditions-and-operators).

## Select fields [#select-fields]

Use `.select(...)` to fetch only the fields you need. On PostgreSQL the result type narrows to match, while on MongoDB only the fetched document narrows; the type keeps every field, so a field you left out is `undefined` at runtime. On both, you can filter on fields you did not select:

  

#### PostgreSQL

```typescript
const users = await db.orm.public.User.select("id", "email").all();
```

#### MongoDB

```typescript
const users = await db.orm.users.select("_id", "email").all();
```

```js no-copy
[
  { id: 'cuid20000000000000000001', email: 'alice@prisma.io' },
  { id: 'cuid20000000000000000002', email: 'bob@prisma.io' }
]
```

## Sort and paginate [#sort-and-paginate]

Use `.orderBy(...)` to sort, `.limit(n)` to limit, and `.offset(n)` to offset.

On PostgreSQL, sort with a callback that calls `.asc()` or `.desc()` on a field, and on MongoDB, sort with MongoDB's own direction numbers: `1` for ascending and `-1` for descending.

  

#### PostgreSQL

```typescript
// Second page of posts, newest first
const page = await db.orm.public.Post
  .orderBy((p) => p.createdAt.desc())
  .limit(20)
  .offset(20)
  .all();
```

#### MongoDB

```typescript
// Second page of posts, newest first
const page = await db.orm.posts
  .orderBy({ createdAt: -1 })
  .limit(20)
  .offset(20)
  .all();
```

For a composite sort on PostgreSQL, pass an array of callbacks, and records are sorted by the first field, with the second as tiebreaker:

```typescript
const posts = await db.orm.public.Post
  .orderBy([(p) => p.createdAt.desc(), (p) => p.id.desc()])
  .all();
```

On PostgreSQL, a sort can also use a related record, a count, and a placement for nulls:

```typescript
// Posts by their author's name
const byAuthor = await db.orm.public.Post
  .orderBy([(p) => p.author.name.asc(), (p) => p.id.asc()])
  .all();

// Users by how many posts they have
const mostPosts = await db.orm.public.User
  .orderBy((u) => u.posts.count().desc())
  .all();

// Posts without content go last
const titled = await db.orm.public.Post
  .orderBy((p) => p.content.desc({ nulls: "last" }))
  .all();
```

A relation to one record gives you that record's fields, one relation deep. A relation to many records gives you `count()`, which takes an optional filter, as in `u.posts.count((p) => p.published.eq(true))`. The [`orderBy()` reference](https://www.prisma.io/docs/orm/reference/orm-client#orderby) has the details.

### Cursor pagination [#cursor-pagination]

Offset gets slower on deep pages, so for stable pagination over a large table, follow `.orderBy(...)` with `.cursor(...)` and resume from the last record you returned. `.cursor(...)` is PostgreSQL only.

The cursor record is excluded from the next page, so pages pick up strictly after it.

Pass `.cursor(...)` a value for every field you sorted by, as in the example below. Keep the `id` tiebreaker in both the sort and the cursor, because `createdAt` is not unique, and a cursor on a non-unique field alone can skip or repeat records that share the boundary value. With `id` in the cursor, pages never overlap even when timestamps tie:

```typescript
const page1 = await db.orm.public.Post
  .orderBy([(p) => p.createdAt.desc(), (p) => p.id.desc()])
  .limit(20)
  .all();

const last = page1[page1.length - 1]!;
const page2 = await db.orm.public.Post
  .orderBy([(p) => p.createdAt.desc(), (p) => p.id.desc()])
  .cursor({ createdAt: last.createdAt, id: last.id })
  .limit(20)
  .all();
```

A cursor works only when every sort is a plain field of the model. With a sort by a related record, a count, an extension operation such as a vector distance, or a `nulls` placement, `.cursor(...)` throws an error whose `code` is `ORM.ARGUMENT_INVALID`, so page those queries with `.limit(n)` and `.offset(n)`.

On MongoDB, page with `.limit(n)` and `.offset(n)`.

## Count records [#count-records]

On PostgreSQL, count with `.aggregate(...)`. Like `.all()` and `.first()`, it is the last call in the chain: it says what you want back and runs the query. It takes a callback, written `a` here, and returns an object with the keys you named:

```typescript
const result = await db.orm.public.Post
  .where({ published: true })
  .aggregate((a) => ({ total: a.count() }));
```

```js no-copy
{ total: 2 }
```

The callback offers `a.count()`, `a.sum(...)`, `a.avg(...)`, `a.min(...)`, and `a.max(...)`, plus `countBigInt()`, `sumBigInt(...)`, and `avgDecimal(...)` for values beyond a JavaScript `number`. All but `a.count()` take a field name as a string, such as `a.max("createdAt")`. Ask for as many as you like in one call, one key each:

```typescript
const stats = await db.orm.public.Post
  .where({ published: true })
  .aggregate((a) => ({ total: a.count(), newest: a.max("createdAt") }));
```

There is no `.count()` method on the query chain, on either database.

MongoDB has no `.count()` and no `.aggregate(...)`. Count with the [pipeline builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#mongodb-pipeline-builder), `db.query`: `.from("posts")` names the collection, `.count("total")` counts, `.build()` finishes the query, and `(await db.runtime()).query(...)` runs it (on MongoDB `db.runtime()` returns a promise).

```typescript
import { db } from "./prisma/db";

const built = db.query
  .from("posts")
  // .match((f) => f.published.eq(true)) counts only a subset
  .count("total")
  .build();

const [result] = await (await db.runtime()).query(built);
```

```js no-copy
{ total: 2 }
```

## Iterate a large result [#iterate-a-large-result]

You can `await` a read for an array, or loop over it with `for await`. Pick one; once you iterate a result with `for await` it is used up (see below).

`await` runs the query and gives you an array, which is the right default: you get the whole result in memory and can read the array as often as you like.

```typescript
const posts = await db.orm.public.Post.all();

console.log(posts.length);
console.log(posts[0]);
```

Use `for await` to handle records one at a time, as your loop asks for them, for example to write each one to a file:

```typescript
for await (const post of db.orm.public.Post.all()) {
  await exportToSearchIndex(post);
}
```

It does not fetch less: on the standard client (`postgres({...})` in `src/prisma/db.ts`) every row is loaded first. For large tables page with `.limit()` and `.cursor()` (see [Sort and paginate](#sort-and-paginate)).

The serverless client, `postgresServerless(...)`, does fetch rows as you iterate, but it has no `db.orm`, so none of the queries on this page run on it: see [Transactions and runtime](https://www.prisma.io/docs/orm/reference/transactions-and-runtime).

### An iterated result can only be read once [#an-iterated-result-can-only-be-read-once]

Once a `for await` loop has touched a result, that result is finished, even if the loop exited early. Iterating it again, or `await`ing it afterwards, throws:

```typescript
const result = db.orm.public.Post.all();

for await (const post of result) {
  // ...
}

await result;
```

```text no-copy
RuntimeError: AsyncIterableResult iterator has already been consumed via for-await loop.
Each AsyncIterableResult can only be iterated once.
```

`AsyncIterableResult` is the type a query returns before you await it; the error means you read it twice. The error has the code `RUNTIME.ITERATOR_CONSUMED`.

If you need the data more than once, `await` the query into an array and reuse the array:

```typescript
const posts = await db.orm.public.Post.all();

const published = posts.filter((p) => p.published);
const titles = posts.map((p) => p.title);
```

The read-once rule is the same on PostgreSQL and MongoDB.

## Common mistakes [#common-mistakes]

### Fetching everything to use one record [#fetching-everything-to-use-one-record]

You wanted one record, so you queried and took the first element:

```typescript
const users = await db.orm.public.User.where({ email }).all();
const user = users[0];
```

This fetches every matching record and throws away the rest. Use `.first()` instead: it returns one record or `null`, and it asks the database for at most one row:

```typescript
const user = await db.orm.public.User.where({ email }).first();
```

### Forgetting that .all() has no limit [#forgetting-that-all-has-no-limit]

`.all()` returns every match, so on a table that grows, yesterday's fast query becomes today's slow one. Add `.limit(n)` when you don't genuinely need every record, and when you do need every record, page through the table: `.cursor(...)` on PostgreSQL, `.offset(n)` on MongoDB.

### Reusing an iterated result [#reusing-an-iterated-result]

You read a result with `for await`, then tried to read it again. The second read throws, because a result is used up as it is iterated. Store the data if you need it twice:

```typescript
const posts = await db.orm.public.Post.all();
// posts is a plain array now; read it as often as you like
```

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the Prisma ORM skills for your coding agent, and in an existing project you run `npx prisma skills sync` to add them. Skills are instruction files a coding agent reads, and the [`prisma-8` skill](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) covers everything on this page, so try prompts that map to each section:

* "Using the prisma-8 skill, write a query that returns the 20 newest published posts."
* "Add a case-insensitive title search to the posts query, using the .ilike operator."
* "Convert this offset pagination to cursor pagination with the .cursor() API."
* "This export loops over a huge table. Rewrite it to page through the rows with .limit() and .cursor()."

## Next [#next]

* [Write data](https://www.prisma.io/docs/orm/fundamentals/writing-data): create, update, delete, and upsert records.
* [Read related records](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins) in the same query with `.include(...)`.
* [Use advanced queries](https://www.prisma.io/docs/orm/fundamentals/advanced-queries) when a shape needs the SQL query builder or a MongoDB pipeline.

## Related pages

- [`Advanced queries`](https://www.prisma.io/docs/orm/fundamentals/advanced-queries): Use the SQL query builder on PostgreSQL and the pipeline builder on MongoDB for queries the ORM API can't express.
- [`Relations and joins`](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins): Read related records in one query with .include(), and understand how one-to-one, one-to-many, and many-to-many relationships work.
- [`Transactions`](https://www.prisma.io/docs/orm/fundamentals/transactions): Run several writes so they all succeed or all fail together with db.transaction().
- [`Writing data`](https://www.prisma.io/docs/orm/fundamentals/writing-data): Create, update, delete, and upsert records with Prisma ORM, one at a time or in bulk.

# Relations and joins (/docs/orm/fundamentals/relations-and-joins)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Read related records in one query with .include(), and understand how one-to-one, one-to-many, and many-to-many relationships work.

Location: ORM > Fundamentals > Relations and joins

Read related records in the same query by adding `.include(...)`. The related records come back nested on the parent record, and their types match your models.

  

#### PostgreSQL

```typescript
import { db } from "./prisma/db";

const posts = await db.orm.public.Post
  .where({ published: true })
  .include("author")
  .all();
// posts[0].author is the full User record
```

#### MongoDB

```typescript
import { db } from "./prisma/db";

const posts = await db.orm.posts
  .where({ published: true })
  .include("author")
  .all();
// posts[0].author is the referenced user document
```

If this is your first Prisma ORM 8 query, start with the two files it needs. Your models live in `src/prisma/contract.prisma`, the same file Prisma ORM 7 called `schema.prisma`; the docs call it your contract. Both commands below write `src/prisma/db.ts`, which creates the client and exports it as `db`, and it reads `DATABASE_URL` from `.env`.

```bash
npm create prisma@latest -- my-app --no-deploy   # a new project
npx prisma orm init                              # a project you already have
```

That is the file the examples above import as `./prisma/db`, from a file directly inside `src/`. Here is what the rest of those lines are made of:

* On PostgreSQL the path is `db.orm.<schema>.<ModelName>`. `db.orm` is the model API; `db.sql` and `db.raw.sql` are for SQL. The PostgreSQL schema (not the contract file) is `public` unless you wrap the model in a `namespace` block. Write `namespace billing { model Invoice { ... } }` in your contract and the path becomes `db.orm.billing.Invoice`.
* On MongoDB there is no schema segment. The path is `db.orm.<collectionName>`. The collection name is the `@@map(...)` on the model, or the model name exactly as written. The models behind the MongoDB query above are [further down this page](#postgresql-and-mongodb-differences).
* You `await` the whole chain, and the last call says what you want back. `.all()` returns every matching record as an array. `.first()` returns one record, or `null` when nothing matches.
* `.where(...)` takes two forms. Pass an object, like `.where({ published: true })`, to match fields to exact values. Pass a callback for a comparison, like `.where((p) => p.title.like("Hello%"))`. Chaining `.where(...)` twice requires both to match.

The name you pass to `.include(...)` is the relation field name you declared in your contract, not a table name. `.include(...)` fetches the relation in the same query as the parent: one SQL statement, which reads the relation with a correlated subquery. `.include("author")` replaces Prisma ORM 7's `include: { author: true }`; see [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#queries) for the rest of the query API side by side. Use `.include(...)` when the caller needs the related data in the same response, and skip it when the foreign key already on the record is enough. This page walks through the three kinds of relationship, from the data model to the query and the result. If you already know how relational data is modeled, jump to [filtering by relation data](#filter-parent-records-by-relation-data) or the [limitations](#current-limitations).

## One-to-one [#one-to-one]

One record is linked to at most one other record: for example, every profile belongs to exactly one user.

<ConceptAnimation name="relation-one-to-one" />

The model that holds the foreign key declares the relation, and the `@unique` on the foreign key is what makes it one-to-one:

```prisma
model Profile {
  id     String @id @default(cuid(2))
  bio    String
  userId String @unique
  user   User   @relation(fields: [userId], references: [id])
}
```

Write `@default(cuid(2))` and you never pass `id` yourself: `cuid(2)` generates the id (the `2` is the CUID version). To read a profile with its user, query from the profile and include the relation:

```typescript
const profileWithUser = await db.orm.public.Profile
  .where({ userId: "cuid20000000000000000001" })
  .include("user")
  .first();
// { id, bio, userId, user: { id, email } }
```

`.first()` returns `null` when the profile doesn't exist, so a user without a profile is a `null` check, not an error. You can also declare the matching field on the other side and start from users: an optional field typed as the other model is enough, and it needs no `@relation` of its own:

```prisma
model User {
  id      String   @id @default(cuid(2))
  email   String   @unique
  profile Profile?
}
```

This works as long as the foreign key on the other side is unique, so `Profile.userId` must carry `@unique`. Without it, `npx prisma contract emit` fails with the error code `PSL_NON_UNIQUE_BACKRELATION`.

Then run `npx prisma contract emit`, the command that regenerates the client types from your contract. Run it after every change you make to the contract. Then apply the change to the database with `npx prisma db update` (the replacement for `prisma db push`) during development, or with a migration: run `npx prisma migration plan` then `npx prisma db migrate`; see [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration). With the field in place, `include("profile")` returns one record or `null`:

```typescript
const usersWithProfiles = await db.orm.public.User
  .select("id", "email")
  .include("profile")
  .all();
// Array<{ id, email, profile: { id, bio, userId } | null }>
```

`.select(...)` narrows the parent's own fields only, while an included relation still comes back with all of its fields, which is why `profile` above has `bio` and `userId`. To narrow the included relation's fields, use the callback form shown in the next section.

## One-to-many [#one-to-many]

One parent record is linked to any number of child records: one user has many posts. This is the relationship you'll query most.

<ConceptAnimation name="relation-one-to-many" />

The child stores the parent's id, and the parent declares a list field:

```prisma
model User {
  id    String @id @default(cuid(2))
  email String @unique
  posts Post[]
}

model Post {
  id        String   @id @default(cuid(2))
  title     String
  published Boolean  @default(false)
  createdAt DateTime @default(now())
  authorId  String
  author    User     @relation(fields: [authorId], references: [id])
}
```

Query it in either direction: from the parent, the children arrive as an array, and from the child, the parent arrives as one object:

```typescript
// Each user with their posts
const usersWithPosts = await db.orm.public.User.include("posts").all();
// Array<{ id, email, posts: Post[] }>

// Each post with its author
const postsWithAuthors = await db.orm.public.Post.include("author").all();
// Array<{ id, title, published, createdAt, authorId, author: User }>
```

To choose what each relation returns, pass a callback as the second argument, and inside it, chain `.where`, `.select`, `.orderBy`, and `.limit` exactly like a top-level query. `.desc()` sorts newest first, and `.asc()` sorts the other way. This is how you fetch "each user with their five newest posts" in one query:

```typescript
const usersWithRecentPosts = await db.orm.public.User
  .select("id", "email")
  .include("posts", (post) =>
    post
      .select("id", "title", "createdAt")
      .orderBy((post) => post.createdAt.desc())
      .limit(5),
  )
  .limit(10)
  .all();
// Array<{ id, email, posts: Array<{ id, title, createdAt }> }>
```

The callback also takes `.include(...)`, so you can go two levels deep in one query. If `Post` also declares a `comments Comment[]` list field:

```typescript
const usersWithPostsAndComments = await db.orm.public.User
  .include("posts", (post) => post.include("comments"))
  .all();
// Array<{ id, email, posts: Array<{ id, title, published, createdAt, authorId, comments: Comment[] }> }>
```

To write a parent and its children in one call, pass a callback for the list field and Prisma ORM fills in the foreign key on each child: `db.orm.public.User.create({ email: "jane@prisma.io", posts: (p) => p.create([{ title: "Hello", published: false }]) })` writes the user and the post together. The common mistake here is the N+1 loop: fetching users, then querying posts inside a `for` loop over them, which runs one query per user. One `.include("posts")` on the user query returns the same data in a single query.

## Many-to-many [#many-to-many]

Records on both sides connect to many on the other: a post has many tags, and a tag appears on many posts. Neither table can hold the other's foreign key, so a separate table holds one link per pair.

<ConceptAnimation name="relation-many-to-many" />

Write three models: on each side, declare a list field typed as the other model, then write a third model for the join table, and give it a primary key made of exactly two foreign keys, one to each side:

```prisma
model Post {
  id        String  @id @default(cuid(2))
  title     String
  published Boolean @default(false)
  tags      Tag[]
}

model Tag {
  id    String @id @default(cuid(2))
  name  String @unique
  posts Post[]
}

model PostTag {
  postId String
  tagId  String
  post   Post   @relation(fields: [postId], references: [id])
  tag    Tag    @relation(fields: [tagId], references: [id])

  @@id([postId, tagId])
}
```

Prisma ORM finds the model for the join table by that shape: the one model whose primary key is exactly a foreign key to `Post` and a foreign key to `Tag`, and there is no other way to name it. If two models have that shape, `npx prisma contract emit` fails with `PSL_AMBIGUOUS_BACKRELATION`, and you pick one by adding the same `@relation("...")` name to the list field and to the foreign key pointing back at it. You do not add a `PostTag[]` field to `Post` or `Tag`. `.include(...)` then reads a post's tags in one query, and returns the tags themselves, not the link records. The callback that filters and narrows a relation works here like anywhere else:

```typescript
const postsWithTags = await db.orm.public.Post
  .where({ published: true })
  .include("tags", (tag) => tag.select("id", "name").orderBy((tag) => tag.name.asc()))
  .all();
```

```js no-copy
[{ title: 'Hello Prisma 8', tags: [{ id: 't2…', name: 'databases' }] }]
```

Writes reach the join table the same way: pass a callback for the relation and use `create`, `connect`, or `disconnect`:

```typescript
// Create a post and two new tags in one call
const post = await db.orm.public.Post.create({
  title: "Hello Prisma 8",
  tags: (t) => t.create([{ name: "typescript" }, { name: "databases" }]),
});

// Link an existing tag
const updated = await db.orm.public.Post.where({ id: post.id }).update({
  tags: (t) => t.connect([{ name: "typescript" }]),
});

// Unlink it again
await db.orm.public.Post.where({ id: post.id }).update({
  tags: (t) => t.disconnect([{ name: "typescript" }]),
});
```

`connect` and `disconnect` identify the tag by any primary key or `@unique` field, so `{ name: "typescript" }` works here because `Tag.name` is `@unique`. When that key is made of several columns, pass every one of them in the object. `update(...)` returns the updated post, or `null` when no post matched the filter. `create` always inserts a new tag record, so creating a tag whose name already exists fails on that same unique constraint. Use `connect` for tags that already exist.

There is no `connectOrCreate` in Prisma ORM 8, so upsert the tag first, which creates it or leaves an existing one alone, then connect it:

```typescript
const tag = await db.orm.public.Tag.upsert({
  create: { name: "typescript" },
  update: {},
  conflictOn: { name: "typescript" },
});
await db.orm.public.Post.where({ id: post.id }).update({
  tags: (t) => t.connect([{ id: tag.id }]),
});
```

The upsert is safe when two requests create the same tag at once, but the `connect` is not: if both requests also link that tag to the same post, the second fails with an error whose code is `ORM.RELATION_LINK_DUPLICATE`. Catch that code and treat it as done.

See [what is not available yet](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#not-available-yet) for the rest of the gaps, and [Upsert a record](https://www.prisma.io/docs/orm/fundamentals/writing-data#upsert-a-record) for the top-level `.upsert(...)` call. These nested writes are for relational databases, so on MongoDB, write the parent document and the child document in two calls, and set the reference field yourself:

```typescript
const user = await db.orm.users.create({ email: "jane@prisma.io" });
const post = await db.orm.posts.create({ title: "Hello", published: false, authorId: user._id });
```

If you need the link records themselves, for example because the join table has columns of its own, query its model directly:

```typescript
const links = await db.orm.public.PostTag.include("tag").all();
// Array<{ postId, tagId, tag: { id, name } }>
```

A join table may carry columns beyond the two foreign keys, but those extra columns must not be part of the primary key. Nested `create` and `connect` are rejected when one of them is required, because neither can supply a value for it, so insert the link records yourself:

```typescript
const tag = await db.orm.public.Tag.first({ name: "typescript" });
await db.orm.public.PostTag.create({ postId: post.id, tagId: tag!.id, addedBy: "me" });
```

## Filter parent records by relation data [#filter-parent-records-by-relation-data]

On PostgreSQL, `.where(...)` can reach into a relation: `.some(...)` matches parents with at least one matching child, `.none(...)` matches parents with none, and `.every(...)` matches parents whose children all match. A parent with no children also matches.

```typescript
// Users who have at least one published post
const activeAuthors = await db.orm.public.User
  .where((u) => u.posts.some((p) => p.published.eq(true)))
  .all();

// Posts that carry a specific tag
const taggedPosts = await db.orm.public.Post
  .where((p) => p.tags.some((t) => t.id.eq("cuid20000000000000000007")))
  .all();
```

Chaining `.where(...)` combines conditions with AND, so for OR, call the `or` helper inside a single callback. It comes from `@prisma/orm-postgres/orm-client`, already installed with `@prisma/orm-postgres`:

```typescript
import { or } from "@prisma/orm-postgres/orm-client";

const posts = await db.orm.public.Post
  .where((p) => or(p.published.eq(true), p.title.eq("Hello Prisma 8")))
  .all();
```

See [filter operators](https://www.prisma.io/docs/orm/fundamentals/reading-data#filter-operators-on-postgresql) for the comparisons you can pass to `.where(...)`. On MongoDB, relation filters are not available, so query the child collection directly instead, and include the parent:

```typescript
// MongoDB: the published posts, each with its author
const publishedPosts = await db.orm.posts
  .where({ published: true })
  .include("author")
  .all();
// Every author that appears here has at least one published post
```

To group or reshape the result, use the [pipeline builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#mongodb-pipeline-builder), which has `$lookup` and `$match`.

## PostgreSQL and MongoDB differences [#postgresql-and-mongodb-differences]

MongoDB calls a related document that lives in its own collection, linked by id, a reference relation. Declare it as you would on PostgreSQL, and the three kinds of relationship above all apply:

```prisma
type Address {
  street String
  city   String
}

model User {
  id      ObjectId @id @map("_id") // the property is _id, because of @map("_id")
  email   String
  address Address?
  posts   Post[]

  @@map("users")
}

model Post {
  id        ObjectId @id @map("_id")
  title     String
  published Bool
  authorId  ObjectId
  author    User     @relation(fields: [authorId], references: [id])

  @@map("posts")
}
```

`Post.author` is a reference: the user is a separate document in the `users` collection, and `.include("author")` reads it. `User.address` is an embedded document, and you can tell by the declaration: `Address` is written with `type`, not `model`, so its fields are stored inside the user document itself. Embedded documents come back with every read, so you never include them. Calling `.include(...)` on an embedded relation throws an error with code `ORM.INCLUDE_UNSUPPORTED`, so use `.include(...)` only for documents stored in their own collection. [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb#embed-or-reference) covers which to choose.

## Current limitations [#current-limitations]

* A many-to-many needs the model for the join table. List fields on both sides with no such model are rejected. Write the model as shown [above](#many-to-many), with its primary key made of the two foreign keys.
* On PostgreSQL, `.include(...)` takes an optional callback to filter and narrow the relation. On MongoDB it takes the relation name only. Reshape joined documents with the [pipeline builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#mongodb-pipeline-builder) instead.
* Relation filters (`.some(...)`, `.none(...)`, `.every(...)`) and nested writes on relations are for relational databases. They are not available on MongoDB.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest -- my-app` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8), instruction files for your coding agent. The `prisma-8` skill covers both relation queries and the relation fields in your contract, so try prompts that map to each section:

* "Using the prisma-8 skill, add a one-to-one Profile model with a unique foreign key to User."
* "Using the prisma-8 skill, fetch each user with their five newest posts in one query."
* "Model a many-to-many between Post and Tag with a model for the join table, and write the nested include that reads a post's tag names."
* "Find users that have at least one published post, using `.some(...)` in the where clause instead of a loop."

## Next [#next]

* [Use advanced queries](https://www.prisma.io/docs/orm/fundamentals/advanced-queries) for the SQL query builder, explicit joins, and `$lookup` pipelines.
* [Read data](https://www.prisma.io/docs/orm/fundamentals/reading-data) to filter, sort, paginate, and select fields from your models.
* [Run writes that span several models atomically](https://www.prisma.io/docs/orm/fundamentals/transactions) with a transaction.

## Related pages

- [`Advanced queries`](https://www.prisma.io/docs/orm/fundamentals/advanced-queries): Use the SQL query builder on PostgreSQL and the pipeline builder on MongoDB for queries the ORM API can't express.
- [`Reading data`](https://www.prisma.io/docs/orm/fundamentals/reading-data): Fetch one record or many with Prisma ORM, then filter, select, sort, paginate, and iterate the results.
- [`Transactions`](https://www.prisma.io/docs/orm/fundamentals/transactions): Run several writes so they all succeed or all fail together with db.transaction().
- [`Writing data`](https://www.prisma.io/docs/orm/fundamentals/writing-data): Create, update, delete, and upsert records with Prisma ORM, one at a time or in bulk.

# Transactions (/docs/orm/fundamentals/transactions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Run several writes so they all succeed or all fail together with db.transaction().

Location: ORM > Fundamentals > Transactions

Run several writes as one unit with `db.transaction(...)`: they all commit together, or they all roll back.

Prisma ORM 8 runs on PostgreSQL, SQLite, and MongoDB, but there is no MySQL support. The examples on this page are PostgreSQL; `db.transaction(...)` works the same way on SQLite, and MongoDB is covered in [Transactions on MongoDB](#transactions-on-mongodb).

## Run writes in a transaction [#run-writes-in-a-transaction]

Use a transaction whenever one business operation spans more than one write: creating a user with their first records, moving a value between two rows, or deleting a parent after its children. Pass a callback to `db.transaction(...)`, and inside it, query through `tx` instead of `db`. `tx.orm` is the model API, what `prisma.user` was in Prisma ORM 7; `tx.sql` is the SQL query builder, and both work the same as `db.orm` and `db.sql`. Every query you make on `tx` runs inside the transaction, and `db.transaction(...)` returns whatever your callback returns:

```typescript
import { db } from "./prisma/db";
const result = await db.transaction(async (tx) => {
  const user = await tx.orm.public.User.create({ email: "jane@prisma.io", name: "Jane" });
  const post = await tx.orm.public.Post.create({ title: "Hello", published: false, authorId: user.id });
  return { userId: user.id, postId: post.id }; // both records exist once this returns
});
```

`db` is the client you create once in `src/prisma/db.ts`, and `prisma orm init` writes that file for you. It writes the file once; it is your code, so edit it freely. Under `tx.orm.public`, the property name is the model name, so `User` and `Post` are spelled exactly as you spelled them in your contract.

`public` is the PostgreSQL schema, the namespace your tables live in, which is `public` unless you set one. `create(...)` takes the fields of the record directly, with no `data:` wrapper: pass a field if it is required and has no default, while everything else is optional, and [Write data](https://www.prisma.io/docs/orm/fundamentals/writing-data) has the full rules. You don't need a transaction for a single write; every mutation is already atomic on its own.

### Read inside a transaction [#read-inside-a-transaction]

Reads work the same way as writes: query through `tx.orm` and you see the rows the transaction has already written. `.first()` returns `null` when nothing matches.

```typescript
await db.transaction(async (tx) => {
  await tx.orm.public.User.create({ email: "jane@prisma.io", name: "Jane" });
  const jane = await tx.orm.public.User.where({ email: "jane@prisma.io" }).first();
  // jane is the record created a line earlier, before the transaction commits
});
```

### Pass tx to your helper functions [#pass-tx-to-your-helper-functions]

A helper that runs inside the caller's transaction takes `tx` as a parameter:

```typescript
import { db, type Tx } from "./prisma/db";
async function createWelcomePost(tx: Tx, authorId: string) {
  return tx.orm.public.Post.create({ title: "Welcome", published: false, authorId });
}
await db.transaction(async (tx) => {
  const user = await tx.orm.public.User.create({ email: "jane@prisma.io", name: "Jane" });
  await createWelcomePost(tx, user.id);
});
```

Prisma ORM does not export a type for `tx`, so add this line to `src/prisma/db.ts`: `export type Tx = Parameters<Parameters<typeof db.transaction>[0]>[0];`, then import `Tx` wherever a helper needs it.
Do not open a second transaction inside the helper, because calling `db.transaction(...)` again inside a callback does not nest: the inner call is a separate transaction that commits or rolls back on its own, and the outer one cannot roll it back. Pass `tx` down instead.

### Options and isolation level [#options-and-isolation-level]

`db.transaction(...)` takes the callback and nothing else. There are no `isolationLevel`, `timeout`, or `maxWait` options; see [what is not available yet](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#not-available-yet). Every transaction runs at the database's default isolation level, `READ COMMITTED` on PostgreSQL, and you cannot ask for another level yet. If you need one, set it yourself as the first statement in the callback:

```typescript
await db.transaction(async (tx) => {
  await tx.execute(db.raw.sql`SET TRANSACTION ISOLATION LEVEL SERIALIZABLE`.affectedCount().build());
  // your writes
});
```

There is no transaction timeout either, so a transaction stays open for as long as your callback runs. If you need a limit, set PostgreSQL's `idle_in_transaction_session_timeout` on the connection (`transaction_timeout` on PostgreSQL 17 and later).

## Roll back on errors [#roll-back-on-errors]

The transaction commits when the callback returns and rolls back when it throws, so nothing inside the callback survives an error:

```typescript
try {
  await db.transaction(async (tx) => {
    await tx.orm.public.User.create({ email: "ghost@prisma.io", name: "Ghost" });
    throw new Error("boom");
  });
} catch {
  // The user record was rolled back and does not exist
}
```

### Write conflicts [#write-conflicts]

When PostgreSQL cannot commit your transaction because another transaction touched the same rows, it aborts yours. Errors from the database arrive with a `sqlState` property holding the PostgreSQL error code (`40001` for a serialization failure, when two transactions changed the same rows and one had to give way; `40P01` for a deadlock). When the conflict surfaces at commit, the error you catch has the code `RUNTIME.TRANSACTION_COMMIT_FAILED` and the database error sits on its `cause`. There is no exported error class to check with `instanceof`, so test for the property, on the error and on its `cause`. Prisma ORM does not retry write conflicts for you, so write the retry yourself around the `db.transaction(...)` call:

```typescript
async function withRetry<T>(run: () => Promise<T>, attempts = 3): Promise<T> {
  for (let attempt = 1; ; attempt++) {
    try {
      return await run();
    } catch (error) {
      const source = error instanceof Error && error.cause ? error.cause : error;
      const code = typeof source === "object" && source && "sqlState" in source ? source.sqlState : null;
      if ((code !== "40001" && code !== "40P01") || attempt === attempts) throw error;
    }
  }
}
await withRetry(() => db.transaction(async (tx) => { /* your writes */ }));
```

## Use the SQL builder in a transaction [#use-the-sql-builder-in-a-transaction]

The [SQL query builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries) works the same way inside a transaction. `tx.sql` has the methods `db.sql` has, and you run the finished query with `tx.execute(...)`:

```typescript
const cutoff = Temporal.Instant.from("2026-01-01T00:00:00Z");
await db.transaction(async (tx) => {
  const query = tx.sql.public.Post
    .update({ published: false })
    .where((f, fns) => fns.lt(f.createdAt, cutoff))
    .build();
  await tx.execute(query);
});
```

`tx.orm` takes the model name and `tx.sql` takes the table name, which is the model's `@@map` value, or the model name exactly as written when the model has no `@@map`. So the model `Post` is `tx.sql.public.Post`, and a model with `@@map("post")` is `tx.sql.public.post`.

The other difference from `tx.orm` is that you chain clauses and then call `.build()` to finish the query: `.build()` returns the query without running it, and `tx.execute(...)` runs it and returns `{ affectedRows }`, the number of rows it changed. The `.where(...)` callback receives two arguments: `f` holds the columns, and `fns` holds the operators (`lt` is less-than). [Advanced queries](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#build-a-query-and-run-it) covers both.

To read rows, build a `SELECT` on `tx.sql` the same way and run it with `tx.query(...)`, which resolves to an array of rows:

```typescript title="src/read-posts.ts"
await db.transaction(async (tx) => {
  const query = tx.sql.public.Post
    .select("id", "title")
    .where((f, fns) => fns.eq(f.published, false))
    .limit(10)
    .build();
  const drafts = await tx.query(query);
});
```

## Transactions on MongoDB [#transactions-on-mongodb]

Prisma ORM does not support MongoDB transactions yet: there is no `db.transaction(...)` on the MongoDB client. To run a multi-document transaction today, use the MongoDB driver directly: share one `MongoClient` between Prisma ORM and your code, and group the writes in a driver session.
MongoDB only runs transactions on a replica set, and a standalone server rejects them. To turn a standalone server into a single-member replica set, follow the MongoDB guide on [converting a standalone to a replica set](https://www.mongodb.com/docs/manual/tutorial/convert-standalone-to-replica-set/).
Install `@prisma/orm-mongo`, which a MongoDB project already has, together with version 7 of the `mongodb` driver:

  

#### bun

```bash
bun add @prisma/orm-mongo mongodb@7
```

#### pnpm

```bash
pnpm add @prisma/orm-mongo mongodb@7
```

#### yarn

```bash
yarn add @prisma/orm-mongo mongodb@7
```

#### npm

```bash
npm install @prisma/orm-mongo mongodb@7
```

`prisma orm init` writes `src/prisma/db.ts` with a `url` option. Replace that option with a `MongoClient` you create and export yourself, so your driver code and Prisma ORM use the same connection:

Run `npx prisma contract emit` once first; `db.ts` imports the two files it writes.

```typescript title="src/prisma/db.ts"
import "dotenv/config";
import mongo from "@prisma/orm-mongo/runtime";
import { MongoClient } from "mongodb";
import type { Contract } from "./contract.d"; // the two files `prisma contract emit` writes
import contractJson from "./contract.json" with { type: "json" };

export const client = new MongoClient(process.env["DATABASE_URL"]!);
export const db = mongo<Contract>({
  contractJson,
  mongoClient: client,
  dbName: "app",
});
```

Keep the `contractJson` import and the `Contract` type, and run `prisma contract emit` after every change to your contract, on PostgreSQL and on MongoDB alike.
`dbName` is now the only thing that picks the database, so set it to the database your driver code reads, and `client.db("app")` and Prisma ORM stay on the same one. An empty `dbName` is an error.

```typescript
import { client, db } from "./prisma/db";
const session = client.startSession();
try {
  await session.withTransaction(async () => {
    const database = client.db("app");
    const users = database.collection("users");
    const user = await users.insertOne({ email: "jane@prisma.io", name: "Jane" }, { session });
    const post = { title: "Hello", published: false, authorId: user.insertedId };
    await database.collection("posts").insertOne(post, { session });
  });
} finally {
  await session.endSession();
}
// Prisma ORM reads see the committed result
const jane = await db.orm.users.where({ email: "jane@prisma.io" }).first();
```

On MongoDB there is no schema segment in the path, and the property name is the collection name: the model's `@@map` value, or the model name exactly as written when the model has no `@@map`. The example above assumes a `User` model mapped to the `users` collection, like the one below, so Prisma ORM reads it as `db.orm.users` and the driver code as `database.collection("users")`. Without the `@@map` line it would be `db.orm.User`.

```prisma title="src/prisma/contract.prisma (excerpt)"
model User {
  id    ObjectId @id @map("_id")
  email String   @unique
  name  String?
  @@map("users")
}
```

The `id` field has no `@default` because you never pass it: when you insert a document without an `_id`, MongoDB assigns one, and `insertOne` returns it as `insertedId`, which the example uses as the post's `authorId`.

Writes you make through the driver skip the type-checking that Prisma ORM queries get, so put each driver transaction in its own small function, and write everything around it as Prisma ORM queries.

## Coming from Prisma ORM 7 [#coming-from-prisma-orm-7]

Prisma ORM 8 has no `$transaction`, so both of the Prisma ORM 7 forms become `db.transaction(async (tx) => ...)`. The interactive form maps one for one: rename the method and query through `tx`.

```diff
- const result = await prisma.$transaction(async (prisma) => {
-   const user = await prisma.user.create({ data: { email, name } });
-   return prisma.post.create({ data: { title, authorId: user.id } });
- });
+ const result = await db.transaction(async (tx) => {
+   const user = await tx.orm.public.User.create({ email, name });
+   // published is required and has no default, so you pass it
+   return tx.orm.public.Post.create({ title, published: false, authorId: user.id });
+ });
```

The array form has no replacement of its own, so write the queries out in the callback, one after another:

```diff
- const [user, post] = await prisma.$transaction([
-   prisma.user.create({ data: { email, name } }),
-   prisma.post.create({ data: { title, authorId } }),
- ]);
+ const { user, post } = await db.transaction(async (tx) => {
+   const user = await tx.orm.public.User.create({ email, name });
+   const post = await tx.orm.public.Post.create({ title, published: false, authorId: user.id });
+   return { user, post };
+ });
```

You get the same atomicity, and you also get what the array form never allowed: one query's result (here `user.id`) can feed the next query in the same transaction.

## Common mistakes [#common-mistakes]

### Side effects inside the callback [#side-effects-inside-the-callback]

Sending an email or queueing a job inside the callback looks natural, because it is right next to the write it belongs to:

```typescript
await db.transaction(async (tx) => {
  const user = await tx.orm.public.User.create({ email, name });
  await sendWelcomeEmail(user.email); // runs even if the transaction rolls back
});
```

Database writes roll back; emails don't. If a later statement throws, the record disappears but the email was already sent. Return what you need from the callback, and run the side effect after the transaction has committed:

```typescript
const user = await db.transaction(async (tx) => {
  return tx.orm.public.User.create({ email, name });
});
await sendWelcomeEmail(user.email);
```

Now the email can only go out for a user that actually exists.

### Querying through db instead of tx [#querying-through-db-instead-of-tx]

If you open a transaction but keep writing `db.orm` inside the callback:

```typescript
await db.transaction(async (tx) => {
  await db.orm.public.User.create({ email, name }); // outside the transaction
});
```

Queries on `db` run on their own connection, outside the open transaction, so they commit immediately and won't roll back with the rest of the callback. Use `tx` for every query inside the callback: `tx.orm` for models, `tx.sql` and `tx.execute` for the SQL query builder.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8), instruction files for coding agents, and in an existing project you run `npx prisma skills sync` to add them. The `prisma-8` skill covers transactions, so try prompts that map to each section:

* "Using the prisma-8 skill, wrap this signup flow (create user, create welcome post) in a db.transaction so both writes commit together."
* "Check this transaction callback for queries that use db instead of tx, and move the email send after the commit."
* "Refactor these two service functions so the helper takes tx as a parameter instead of opening its own transaction."
* "This project is on MongoDB. Show me the driver-session pattern for an atomic two-collection write with a shared MongoClient."

## Next [#next]

* [Write data](https://www.prisma.io/docs/orm/fundamentals/writing-data): the single-record and bulk mutations you group in a transaction.
* [Use advanced queries](https://www.prisma.io/docs/orm/fundamentals/advanced-queries) to run SQL query builder statements inside or outside transactions.

## Related pages

- [`Advanced queries`](https://www.prisma.io/docs/orm/fundamentals/advanced-queries): Use the SQL query builder on PostgreSQL and the pipeline builder on MongoDB for queries the ORM API can't express.
- [`Reading data`](https://www.prisma.io/docs/orm/fundamentals/reading-data): Fetch one record or many with Prisma ORM, then filter, select, sort, paginate, and iterate the results.
- [`Relations and joins`](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins): Read related records in one query with .include(), and understand how one-to-one, one-to-many, and many-to-many relationships work.
- [`Writing data`](https://www.prisma.io/docs/orm/fundamentals/writing-data): Create, update, delete, and upsert records with Prisma ORM, one at a time or in bulk.

# Writing data (/docs/orm/fundamentals/writing-data)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create, update, delete, and upsert records with Prisma ORM, one at a time or in bulk.

Location: ORM > Fundamentals > Writing data

This page shows how to write data with Prisma ORM: [creating](#create-one-record), [updating](#update-one-record), [deleting](#delete-one-record), and [upserting](#upsert-a-record) single records, and [writing many records at once](#write-many-records).

Every example imports `db`. In a new project run `npm create prisma@latest -- my-app`, and in an existing project run `npx prisma orm init`. Either way you get `src/prisma/db.ts`, which exports `db`, and the import is `./prisma/db` from a file in `src/`.

This page uses `db.orm`, which holds your models. The rest of `db` is `db.sql` for the SQL query builder, `db.raw.sql` for raw SQL, and `db.transaction` for running several writes together.

On PostgreSQL the path to a model is `db.orm.<schema>.<ModelName>`, so the `User` model is `db.orm.public.User`. `public` is the PostgreSQL schema that holds the model's table, and the path always includes the schema name. The schema is `public` unless you put the model inside a `namespace` block, as [Example schema](#example-schema) shows. On MongoDB there is no schema segment, and the path is `db.orm.<collectionName>`, where the collection name is the model's `@@map(...)` value, or the model name when there is no `@@map`. The MongoDB `User` model in the example schema maps to `users`, so it is `db.orm.users`.

## Example schema [#example-schema]

Examples use this contract. In Prisma ORM 8 the schema file is `contract.prisma` instead of `schema.prisma`; the docs call it your contract. `@default(cuid(2))` means Prisma ORM generates the `id` for you, so you never pass one:

**Expand for sample schema**

#### PostgreSQL

```prisma
model User {
  id        String   @id @default(cuid(2))
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  posts     Post[]
}

model Post {
  id        String   @id @default(cuid(2))
  title     String
  content   String?
  published Boolean
  authorId  String
  author    User     @relation(fields: [authorId], references: [id])
  createdAt DateTime @default(now())
}
```

#### MongoDB

```prisma
model User {
  id        ObjectId @id @map("_id")
  email     String   @unique
  name      String?
  createdAt Date
  posts     Post[]
  @@map("users")
}

model Post {
  id        ObjectId @id @map("_id")
  title     String
  content   String?
  published Bool
  tags      String[]
  author    User     @relation(fields: [authorId], references: [id])
  authorId  ObjectId
  createdAt Date
  @@map("posts")
}
```

To put models in another PostgreSQL schema, wrap them in a `namespace` block:

```prisma
namespace billing {
  model Invoice {
    id     String @id @default(cuid(2))
    amount Int
  }
}
```

The model is then only at `db.orm.billing.Invoice`, and the block name is the PostgreSQL schema name.

## Create one record [#create-one-record]

Use `.create(...)` to insert one record, and pass the fields directly. Prisma ORM returns the inserted record, including generated values such as IDs and database defaults:

  

#### PostgreSQL

```typescript
import { db } from "./prisma/db";

const user = await db.orm.public.User.create({
  email: "jane@prisma.io",
  name: "Jane",
});
// user.id and user.createdAt are filled in
```

#### MongoDB

```typescript
import { db } from "./prisma/db";

const user = await db.orm.users.create({
  email: "jane@prisma.io",
  name: "Jane",
  createdAt: new Date(),
});
// user._id is filled in by the server
```

The returned record is complete, so you can use the generated values right away (PostgreSQL shown; on MongoDB the key is `_id`):

```js no-copy
{ id: 'cuid20000000000000000003', email: 'jane@prisma.io', name: 'Jane', createdAt: 2026-07-06T09:09:56.119Z }
```

To get back only some fields, chain `.select(...)` before `.create(...)`: the record is still inserted in full, but you only get back the fields you listed:

```typescript
const account = await db.orm.public.User
  .select("id", "email")
  .create({ email: "jane@prisma.io", name: "Jane" });
```

```js no-copy
{ id: 'cuid20000000000000000003', email: 'jane@prisma.io' }
```

`.select(...)` works the same before `update`, `delete`, `upsert`, `createAll`, `updateAll`, and `deleteAll`. The `AndCount` methods give you back a number, so `.select(...)` has no effect on them.

When a write breaks a unique constraint, the call throws, and errors have no shared class: a PostgreSQL database error carries `sqlState` (a five-character SQL state code), a MongoDB driver error carries a numeric `code`, and a Prisma ORM error carries a string `code` such as `RUNTIME.ITERATOR_CONSUMED`. On PostgreSQL, `23505` is the SQL state code for a unique violation. The [error reference](https://www.prisma.io/docs/orm/reference/error-reference) lists Prisma ORM's own codes:

```typescript
try {
  await db.orm.public.User.create({ email: "jane@prisma.io", name: "Jane" });
} catch (error) {
  if ((error as { sqlState?: string }).sqlState === "23505") {
    // that email is already taken
  }
}
```

On MongoDB the driver throws its own error, and a duplicate key gives you an error whose `error.code` is `11000`.

> [!NOTE]
> MongoDB contracts do not support `@default`. For a timestamp, type the field `temporal.createdAt()` or `temporal.updatedAt()` and a client created by `mongo()` fills it in, as [Field types](https://www.prisma.io/docs/orm/data-modeling/mongodb#field-types) shows. Pass any other value yourself.
> 
> `@map("_id")` renames the id field to `_id` everywhere, so the returned document has an `_id` key and not an `id` key.

## Create a record and its related records [#create-a-record-and-its-related-records]

To write related records in the same call, pass a callback for the relation field. The callback's argument, named `p` below, is the relation builder, which holds the methods that link or insert related records:

```typescript
const user = await db.orm.public.User.create({
  email: "jane@prisma.io",
  name: "Jane",
  posts: (p) =>
    p.create([{ title: "First post", content: null, published: false }]),
});
```

You do not pass `authorId` on the nested posts, because Prisma ORM fills it in from the user it just inserted.

`connect` links a record that already exists, and works in `.update(...)` too:

```typescript
await db.orm.public.User
  .where({ email: "jane@prisma.io" })
  .update({ posts: (p) => p.connect([{ id: existingPostId }]) });
```

`p.disconnect(...)` unlinks a related record, but it applies on `.update(...)` only, not on `.create(...)`.

`connectOrCreate`, the relation `set`, and nested updates, upserts, and deletes do not exist: see [Not available](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#not-available-yet). For the full picture of relations, see [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins).

## Update one record [#update-one-record]

Use `.where(...)` to pick the record, then `.update(...)` with the fields to change, which updates **one** matching record and returns it:

  

#### PostgreSQL

```typescript
const updatedUser = await db.orm.public.User
  .where({ email: "jane@prisma.io" })
  .update({ name: "Jane Doe" });
```

#### MongoDB

```typescript
const updatedUser = await db.orm.users
  .where({ email: "jane@prisma.io" })
  .update({ name: "Jane Doe" });
```

```js no-copy
{ id: 'cuid20000000000000000003', email: 'jane@prisma.io', name: 'Jane Doe', createdAt: 2026-07-06T09:09:56.119Z }
```

When nothing matches the filter, `.update(...)` returns `null` rather than throwing.

When the filter matches more than one record, `.update(...)` still changes only one of the matching records, with no guaranteed order. Use [`updateAll` or `updateAndCount`](#write-many-records) if you mean all of them.

On MongoDB you can also pass a callback instead of an object, and change a field with an operation rather than a value. The callback's argument, named `p` here, gives you one entry per field, and each field carries the operations you can apply to it:

```typescript
await db.orm.posts
  .where({ title: "Draft thoughts" })
  .update((p) => [p.content.set("Now filled in"), p.published.set(true)]);
```

The callback returns an array, so you can apply several operations in one update.

`set` and `unset` work on any field, while `inc` and `mul` are on number fields only. `push`, `pull`, `addToSet`, and `pop` are for array fields, and you call them the same way: `p.tags.push("news")`. These field operations are MongoDB only: PostgreSQL has no callback form of `update`, so on PostgreSQL you pass an object. See [Field update operations](https://www.prisma.io/docs/orm/reference/orm-client#field-update-operations) in the reference.

There is no `increment` on PostgreSQL, so to add to a number in place, write the update as raw SQL. For a `views Int` column added to `Post`, `db.raw.sql` writes a raw statement, `.affectedCount()` says you want the row count back as `{ affectedRows }`, `.build()` finishes it, and `db.runtime().execute(...)` runs it; [Advanced queries](https://www.prisma.io/docs/orm/fundamentals/advanced-queries) explains raw SQL:

```typescript
const query = db.raw.sql`UPDATE post SET views = views + 1 WHERE id = ${postId}`
  .affectedCount()
  .build();
const { affectedRows } = await db.runtime().execute(query);
```

## Delete one record [#delete-one-record]

Use `.where(...)` then `.delete()`, which deletes **one** matching record and returns it:

  

#### PostgreSQL

```typescript
const deletedUser = await db.orm.public.User
  .where({ email: "jane@prisma.io" })
  .delete();
```

#### MongoDB

```typescript
const deletedUser = await db.orm.users
  .where({ email: "jane@prisma.io" })
  .delete();
```

`.delete()` returns `null` when nothing matches, and deletes only one record when several match. See [Update one record](#update-one-record). To delete every match, use [`deleteAll` or `deleteAndCount`](#write-many-records).

## Upsert a record [#upsert-a-record]

Use `.upsert(...)` to update a record if it exists and create it otherwise, and pass the two branches separately:

  

#### PostgreSQL

```typescript
await db.orm.public.User.upsert({
  create: { email: "eve@prisma.io", name: "Eve" },
  update: { name: "Eve Exists" },
  conflictOn: { email: "eve@prisma.io" },
});
```

#### MongoDB

```typescript
await db.orm.users.where({ email: "eve@prisma.io" }).upsert({
  create: { email: "eve@prisma.io", name: "Eve", createdAt: new Date() },
  update: { name: "Eve Exists" },
});
```

`conflictOn` repeats the unique field and its value from `create`; Prisma ORM uses it to look for an existing row. For a unique constraint over several columns, pass them all in one object: `conflictOn: { tenantId, email }`. Without `conflictOn` on PostgreSQL, the upsert looks for a row by primary key, which a new record does not have, so the insert runs and fails on the unique constraint. Always pass `conflictOn`.

On MongoDB, there is no `conflictOn`, so put the match in `.where(...)` before `.upsert(...)`.

## Write many records [#write-many-records]

Use the `All` and `AndCount` methods when you intend to write every record you pass, or change every record the filter matches:

```typescript
const user = await db.orm.public.User.first({ email: "jane@prisma.io" });
if (!user) throw new Error("no such user");
// Insert many records
const newPosts = await db.orm.public.Post.createAll([
  { title: "One", content: null, published: false, authorId: user.id },
  { title: "Two", content: null, published: false, authorId: user.id },
]);

// Insert many, get back only the number inserted
const insertedCount = await db.orm.public.Post.createAndCount([
  { title: "Three", content: null, published: false, authorId: user.id },
]);

// Update every match, get back only the number updated
const updatedCount = await db.orm.public.Post.where({ published: false }).updateAndCount({ published: true });

// Delete every match, get back the deleted records
const deletedPosts = await db.orm.public.Post.where({ published: false }).deleteAll();

// Delete every match, get back only the number deleted
const deletedCount = await db.orm.public.Post.where((p) => p.title.ilike("draft%")).deleteAndCount();
```

`createAll` gives you back the inserted records, with their generated IDs:

```js no-copy
[{ id: 'cuid20000000000000000101', title: 'One', published: false, /* ... */ }, { id: 'cuid20000000000000000102', title: 'Two', published: false, /* ... */ }]
```

The `AndCount` methods return a plain number, so if three posts match, `updatedCount` is `3`, not an object.

To insert many records and skip the ones that would break a unique constraint, pass `{ onConflict: "skip" }` as the second argument to `createAll` or `createAndCount`. That skips a record that breaks any unique constraint on the table. To skip only the records that clash on one constraint, add `conflictOn` to the same object with the names of that constraint's fields, as in `createAll(users, { onConflict: "skip", conflictOn: ["email"] })`. A record that clashes on any other unique constraint is not skipped, so the database rejects the insert and the call throws a unique-constraint error. Here `conflictOn` takes field names, while in [`.upsert(...)`](#upsert-a-record) it takes the fields and their values. This replaces Prisma ORM 7's `skipDuplicates`, and it works on PostgreSQL and SQLite. On MongoDB, `createAll` and `createAndCount` take only the records, with no second argument. `createAll` returns only the records the database wrote, and `createAndCount` counts only those. [`createAll()`](https://www.prisma.io/docs/orm/reference/orm-client#createall) in the reference covers the details.

`.where((p) => p.title.ilike("draft%"))` is the callback form of a filter, for conditions an object cannot express. Its argument gives you one entry per field, and each field carries the comparisons you can apply to it. [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data) covers the filters you can write.

The bulk methods work the same on MongoDB, on the collection: `db.orm.posts`. Pass `createdAt` in every object you give `createAll`, as with `create`.

## Return rows or counts [#return-rows-or-counts]

Each write comes in three forms, and you pick by what you need back:

| Form                                                 | What it writes                        | What you get back             |
| ---------------------------------------------------- | ------------------------------------- | ----------------------------- |
| `create`, `update`, `delete`                         | one record                            | that record                   |
| `createAll`, `updateAll`, `deleteAll`                | every record you pass, or every match | those records                 |
| `createAndCount`, `updateAndCount`, `deleteAndCount` | every record you pass, or every match | the number of records written |

`update` and `delete` return `null` when nothing matches. Use the `AndCount` forms when the number is all you need, because they do not send the records back.

The `All` forms return a result you can use two ways. Nothing is sent to the database until you `await` the result or loop over it, so an `updateAll` you never await changes nothing. `await` it for an array of records:

```typescript
const publishedPosts = await db.orm.public.Post
  .where({ published: false })
  .updateAll({ published: true });
```

```js no-copy
[{ id: 'cuid20000000000000000101', title: 'One', published: true, /* ... */ }, { id: 'cuid20000000000000000102', title: 'Two', published: true, /* ... */ }]
```

Or [iterate it with `for await`](https://www.prisma.io/docs/orm/fundamentals/reading-data#iterate-a-large-result) to handle records as they arrive:

```typescript
const updated = db.orm.public.Post.where({ published: false }).updateAll({ published: true });

for await (const post of updated) {
  console.log(post.id);
}
```

Pick one: `await` it or loop it with `for await`. Mixing the two throws an error whose `error.code` is `RUNTIME.ITERATOR_CONSUMED`.

## Common mistakes [#common-mistakes]

### Updating or deleting more than one record [#updating-or-deleting-more-than-one-record]

You filtered on a non-unique field and expected every match to change:

```typescript
await db.orm.public.Post.where({ published: false }).update({ published: true });
```

`.update(...)` and `.delete()` only change one record, even when the filter matches many. See [Update one record](#update-one-record).

When you intend to affect every match, say so with the bulk methods:

```typescript
const updatedCount = await db.orm.public.Post
  .where({ published: false })
  .updateAndCount({ published: true });
```

Use `updateAll` or `deleteAll` when you also need the changed records back, and `updateAndCount` or `deleteAndCount` when the number is enough. `update` and `delete` never change more than one record, so they stay safe for the one-record case.

### Wrapping create fields in a data object [#wrapping-create-fields-in-a-data-object]

You wrote the Prisma ORM 7 shape, which fails type-checking because there is no field named `data` on your models:

```diff
- await db.orm.public.User.create({ data: { email, name } });
+ await db.orm.public.User.create({ email, name });
```

You pass the record's own fields, and you get the record back.

### Updating or deleting without a filter [#updating-or-deleting-without-a-filter]

You called `.update(...)` or `.delete()` straight on the model:

```typescript
await db.orm.public.User.delete();
```

Both need a `.where(...)` first, and the call does not type-check without one. If you truly mean every record, pass an empty filter, which adds no condition and so matches everything. `.delete()` needs a `.where(...)` for the same reason, and `.where({})` satisfies it there too:

```typescript
await db.orm.public.User.where({}).deleteAll();
```

### Running related writes back to back [#running-related-writes-back-to-back]

You created a user, then created their first post as a second await:

```typescript
const user = await db.orm.public.User.create({ email, name });
const post = await db.orm.public.Post.create({ title, published: false, authorId: user.id });
```

If the second write fails, the first has already committed, and you're left with half the operation. When writes must succeed together, run them in a [transaction](https://www.prisma.io/docs/orm/fundamentals/transactions), and inside the callback, query through `tx` instead of `db`:

```typescript
await db.transaction(async (tx) => {
  const user = await tx.orm.public.User.create({ email, name });
  await tx.orm.public.Post.create({ title, published: false, authorId: user.id });
});
```

### Passing an array of queries to a transaction [#passing-an-array-of-queries-to-a-transaction]

Prisma ORM 7 supported `$transaction([query1, query2])`, but Prisma ORM 8 does not: there is no `$transaction`, and queries don't queue up in arrays. Put the calls inside one `db.transaction(...)` callback instead, and the [Transactions page](https://www.prisma.io/docs/orm/fundamentals/transactions) shows the pattern.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent, and in an existing project you run `npx prisma skills sync` to add them. Skills are instruction files that tell the agent how Prisma ORM 8 works, and the `prisma-8` skill covers everything on this page, so try prompts that map to each section:

* "Using the prisma-8 skill, add a signup function that creates a User and returns only its id and email."
* "Write an upsert that creates a user by email or updates their name if they exist."
* "This cleanup script must delete every draft older than 30 days. Use the bulk delete method and log how many records were removed."
* "Review my mutations for places where .update() should be updateAll or updateAndCount."

## Next [#next]

* [Run several writes atomically](https://www.prisma.io/docs/orm/fundamentals/transactions) with `db.transaction(...)`.
* [Read data](https://www.prisma.io/docs/orm/fundamentals/reading-data) to filter, sort, paginate, and select fields from your models.
* [Use the SQL builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#postgresql-sql-query-builder) for inserts and updates with explicit `RETURNING` clauses.

## Related pages

- [`Advanced queries`](https://www.prisma.io/docs/orm/fundamentals/advanced-queries): Use the SQL query builder on PostgreSQL and the pipeline builder on MongoDB for queries the ORM API can't express.
- [`Reading data`](https://www.prisma.io/docs/orm/fundamentals/reading-data): Fetch one record or many with Prisma ORM, then filter, select, sort, paginate, and iterate the results.
- [`Relations and joins`](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins): Read related records in one query with .include(), and understand how one-to-one, one-to-many, and many-to-many relationships work.
- [`Transactions`](https://www.prisma.io/docs/orm/fundamentals/transactions): Run several writes so they all succeed or all fail together with db.transaction().

# Authoring custom middleware (/docs/orm/middleware/authoring-custom-middleware)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Build, register, and run your own Prisma ORM middleware, step by step, starting with a query logger.

Location: ORM > Middleware > Authoring custom middleware

## Introduction [#introduction]

A middleware you write yourself is a plain object: a `name`, plus the hook functions you want Prisma ORM to call around your queries. You do not extend a base class, and you do not call a function to install it. You put the object in the `middleware` array where you create your client, and Prisma ORM calls its hooks from then on. The examples here wrap that object in a function so the middleware can take options, but the object is the middleware, and an object literal typed as `SqlMiddleware` works just as well.

If you used `$use` in Prisma ORM 7, the `middleware` array is its replacement. There is no `next()` to wrap the query in, so where you used to write one function that ran before the query, called it, and then ran after it, you now write one hook for the moment before and another for the moment after. Because the before-hook can no longer hold a variable open across the query, [carry state from a before-hook to an after-hook](#carry-state-from-a-before-hook-to-an-after-hook) shows how the after-hook gets what the before-hook worked out. [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#not-available-yet) has a table of what each Prisma ORM 7 feature became.

The steps that follow build a query logger that prints every query with its row count and how long it took. You create one file, register it in one place, run a query, and see the output.

## Prerequisites [#prerequisites]

* A Prisma ORM project with a working `src/prisma/db.ts`, the file where the client is created, because that is where middleware is registered. If you already have a project, you can use the `db.ts` you have. You also need a PostgreSQL database to run against, because `db.ts` reads its connection string from the `DATABASE_URL` environment variable, which you export in the shell you run the commands from. The [PostgreSQL quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql) sets both up in a few minutes:

  

#### bun

```bash
bun create prisma@latest --provider postgres --no-deploy
cd my-app
bun run db:init
```

#### pnpm

```bash
pnpm create prisma@latest --provider postgres --no-deploy
cd my-app
pnpm run db:init
```

#### yarn

```bash
yarn create prisma@latest --provider postgres --no-deploy
cd my-app
yarn db:init
```

#### npm

```bash
npm create prisma@latest -- --provider postgres --no-deploy
cd my-app
npm run db:init
```

## 1. Create the middleware [#1-create-the-middleware]

Create a new file next to your database setup. The logger needs one hook, `afterQuery`, which Prisma ORM calls once after every query that returns rows. Its first argument, `plan`, is the query that was sent, as a plain object, and `plan.sql` is its SQL text. Its second argument, `result`, is where the numbers come from: `result.rowCount` is how many rows came back, and `result.latencyMs` is how long the query took in milliseconds. The `familyId: "sql"` field says the middleware works with SQL databases only, and [step 5](#5-know-which-family-to-declare) covers when to set it.

```ts title="src/prisma/query-logger.ts"
import type { SqlMiddleware } from "@prisma/orm-postgres/family-runtime";

export function queryLogger(): SqlMiddleware {
  return {
    name: "query-logger",
    familyId: "sql",

    async afterQuery(plan, result) {
      console.log(
        `[query-logger] ${result.rowCount} rows in ${Math.round(result.latencyMs)}ms · ${plan.sql}`,
      );
    },
  };
}
```

The built-in middleware and the `SqlMiddleware` type are imported from `@prisma/orm-postgres/family-runtime`, which works with any SQL database. Typing the object you return as `SqlMiddleware` is what gives `plan` and `result` their types in your editor.

The `name` is the label Prisma ORM uses when it talks about your middleware, so it turns up in messages such as `RUNTIME.MIDDLEWARE_FAMILY_MISMATCH` ("Middleware 'query-logger' requires family 'sql' ..."). Nothing checks that names are unique, so pick a name that will mean something to you when you read it in a message.

If a call gives you back a count instead of rows, `afterQuery` is not called for it and `afterExecute` is called instead. On the ORM API the calls that return a count are `createAndCount`, `updateAndCount`, and `deleteAndCount`. Every other call returns rows and reaches `afterQuery`, including `create`, `update`, `delete`, `updateAll`, and `deleteAll`.

The SQL query builder is the other way to write a query on the same client, `db.sql.public.User...` in place of `db.orm.public.User...`. With it you build a query and run it in two steps: `.build()` gives you the query as a plain object, the plan, and a method on `db.runtime()` runs it. `db.runtime().query(plan)` returns rows and calls `afterQuery`, while `db.runtime().execute(plan)` reports how many rows the statement changed and calls `afterExecute`.

To have the logger cover the counting calls as well, add a second hook to the object `queryLogger()` returns in `src/prisma/query-logger.ts`, next to `afterQuery`:

```ts title="src/prisma/query-logger.ts (excerpt)"
    async afterExecute(plan, result) {
      const affected = result.completed ? result.stats.affectedRows : 0;
      console.log(
        `[query-logger] ${affected} affected in ${Math.round(result.latencyMs)}ms · ${plan.sql}`,
      );
    },
```

`result.stats.affectedRows` is how many rows that statement changed, and it is the only field on `result.stats`. It is there only when the statement finished, which is what `result.completed` tells you, so read the count through the check above rather than on its own. A statement that failed logs `0 affected` too, so check `result.completed` when you need to tell the two apart.

## 2. Register it [#2-register-it]

You register a middleware by adding it to the `middleware` array where you create your client. Two of the imports in the file below come from your contract, which is the Prisma ORM 8 name for your schema: `contract.prisma` in a generated project, in place of `schema.prisma`. `npx prisma contract emit` writes `contract.json` and `contract.d.ts` from it, and a project created with `npm create prisma@latest` already has all three in `src/prisma/`. This is the smallest `db.ts` that works, with the logger registered:

```ts title="src/prisma/db.ts"
import postgres from '@prisma/orm-postgres/runtime';
import { queryLogger } from './query-logger';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
  middleware: [queryLogger()],
});
```

The only line added here is the `middleware` option. The `src/prisma/db.ts` that `npm create prisma@latest` generates has more in it than this, including a `connectDatabase` export that the generated `seed.ts` imports, so keep that file and add the `middleware` option to the `postgres<Contract>({ ... })` calls in it rather than replacing it with the file above. Those calls only run when the app is started with `DATABASE_URL` exported, as `npm run dev` does. With `npm run dev:composer`, the generated file takes its client from Composer through `service.load()` instead, and the `middleware` option in `db.ts` is never used, so run the app with `DATABASE_URL` exported while you follow this guide. If you set your project up by hand, [The data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) covers where `contract.json` and `contract.d.ts` come from.

That one line is all the setup there is, and every query on this client now passes through the logger, whether you wrote it with the ORM API (`db.orm.public.User...`) or with the SQL query builder.

## 3. Run a query and see the output [#3-run-a-query-and-see-the-output]

To see the logger work, put a small script in `src/index.ts` that writes a row and then reads some back:

```ts title="src/index.ts"
import { db } from "./prisma/db";

await db.orm.public.User.create({
  email: `mia+${Date.now()}@prisma.io`,
  name: "Mia",
});

const users = await db.orm.public.User.select("id", "email").limit(5).all();
console.log(`fetched ${users.length} users`);

await db.close();
```

In a project from the quickstart, the `dev` script is `tsx watch src/index.ts`, so running it runs your script and then keeps watching the file:

```bash
npm run dev
```

The logger reports both queries, and prints the SQL that actually ran:

```text no-copy
[query-logger] 1 rows in 18ms · INSERT INTO "public"."User" ("email", "name", "updatedAt") VALUES ($1, $2, $3) RETURNING "User"."createdAt", "User"."email", "User"."id", "User"."name", "User"."updatedAt", "User"."username"
[query-logger] 1 rows in 17ms · SELECT "User"."id" AS "id", "User"."email" AS "email" FROM "public"."User" LIMIT 5
fetched 1 users
```

Both lines came through `afterQuery`, the `create` included, because `create` gives you back the row it inserted rather than a count.

The `dev` script keeps running after the output appears, so stop it with Ctrl+C when you are done. If you see the query result but no `[query-logger]` lines, then the query ran on a client that does not have the middleware registered, so check that your script imports `db` from the file you edited in step 2.

## 4. Add an option [#4-add-an-option]

Middleware you write for real work usually takes options, so give the logger a threshold in milliseconds and it reports only the queries that took longer than that. The file below shows `afterQuery` on its own to keep the change easy to see. If you added `afterExecute` in step 1, keep it where it is:

```ts title="src/prisma/query-logger.ts"
import type { SqlMiddleware } from "@prisma/orm-postgres/family-runtime";

export interface QueryLoggerOptions {
  /** Only log queries slower than this many milliseconds. Default: 0, log everything. */
  readonly thresholdMs?: number;
}

export function queryLogger(options?: QueryLoggerOptions): SqlMiddleware {
  const thresholdMs = options?.thresholdMs ?? 0;

  return {
    name: "query-logger",
    familyId: "sql",

    async afterQuery(plan, result) {
      if (result.latencyMs < thresholdMs) return;
      console.log(
        `[query-logger] ${result.rowCount} rows in ${Math.round(result.latencyMs)}ms · ${plan.sql}`,
      );
    },
  };
}
```

Pass the threshold where you register it, replacing the `middleware: [queryLogger()],` line of the `src/prisma/db.ts` from step 2:

```ts title="src/prisma/db.ts (excerpt)"
middleware: [queryLogger({ thresholdMs: 250 })],
```

Run the script again and the logger goes quiet, because both queries finish in under 250ms. To see the lines again, register it with no options: `middleware: [queryLogger()]`.

Prisma ORM calls your hooks in the order you listed the middleware in the array, and that order decides what each middleware sees and whether it runs at all:

* Prisma ORM waits for each hook to finish before the query moves on, so a slow `afterQuery` delays the `await` in your own code.
* If a middleware throws, the ones listed after it do not run for that hook. A query that a before-hook rejects, as `budgets` rejects a `SELECT` with no `LIMIT`, never reaches any `afterQuery`, so the logger cannot see it wherever you list it. Put the logger first and its `afterQuery` has already run when a later middleware throws from its own `afterQuery`, as the `budgets` time check does, so those queries are still logged.
* When a middleware changes the query, the middleware listed after it sees the changed version.

A built-in middleware goes into the same array, imported from the same package as `SqlMiddleware`. To run the logger ahead of [budgets](https://www.prisma.io/docs/orm/middleware/built-in-budgets), add the import to the top of `src/prisma/db.ts` and replace its `middleware:` line:

```ts title="src/prisma/db.ts (excerpt)"
import { budgets } from '@prisma/orm-postgres/family-runtime';

middleware: [queryLogger({ thresholdMs: 250 }), budgets()],
```

## 5. Know which family to declare [#5-know-which-family-to-declare]

Prisma ORM sorts the databases it supports into two families, SQL and MongoDB, and a middleware can say which family it is written for. Set `familyId: 'sql'` when your middleware reads or writes something only a SQL database has, such as `plan.sql` in the logger above.

If a middleware that declares `familyId: 'sql'` is registered on a MongoDB client, that client throws at its first query (or at `connect()`, if you call it), before anything reaches the database. The error's `code` is `RUNTIME.MIDDLEWARE_FAMILY_MISMATCH` and the message names the middleware, so you find out straight away rather than from a failure inside your hook much later.

Leave `familyId` out when your middleware stays away from everything specific to one kind of database. It stays that way as long as you:

* Use any hook except `beforeCompile`, which only SQL databases have.
* Read what your hook is handed on `result` rather than `plan.sql` or `plan.ast`, which a SQL query has and a MongoDB query does not. `result` gives you `rowCount`, `latencyMs`, `completed`, `stats.affectedRows`, and `source`, which is `'driver'` when the database answered the query and `'middleware'` when a middleware answered it instead.

A middleware written that way runs on PostgreSQL and on MongoDB, which is how the built-in [cache](https://www.prisma.io/docs/orm/middleware/built-in-cache) works.

If the middleware only ever goes into a `postgres(...)` client, keep `SqlMiddleware`. If you want one object you can put in both a `postgres(...)` client and a `mongo(...)` client, type it as `CrossFamilyMiddleware` instead:

```ts
import type { CrossFamilyMiddleware } from '@prisma/orm-postgres/components/runtime';
```

On the MongoDB side, the client is `mongo(...)` from `@prisma/orm-mongo/runtime`, and it takes the same `middleware` array in the same place. A middleware written for MongoDB alone is typed as `MongoMiddleware` from `@prisma/orm-mongo/family-runtime`.

## The hooks [#the-hooks]

Which hooks Prisma ORM calls depends on what your call gives back. A call that returns rows runs one set of hooks, a call that returns only a count runs a shorter set, and `beforeCompile` is the only hook that runs for both. Implement whichever hooks you need:

| Hook                                | Runs for        | Runs                                                                  | Use it to                                                                                |
| ----------------------------------- | --------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `beforeCompile(draft, ctx)`         | both            | Before Prisma ORM turns the query into SQL text                       | Rewrite the query, for example add a tenant filter                                       |
| `beforeQuery(plan, ctx, params?)`   | returns rows    | After the SQL text has been built, before the database driver runs it | Validate, throw to block, or change parameter values                                     |
| `interceptQuery(plan, ctx)`         | returns rows    | Just before the database driver runs it                               | Return `{ rows }` to answer the query yourself                                           |
| `onRow(row, plan, ctx)`             | returns rows    | Once per row                                                          | Count or sample rows, or throw to stop the query                                         |
| `afterQuery(plan, result, ctx)`     | returns rows    | After the query finishes                                              | Log `result.rowCount`, `result.latencyMs`, `result.completed`, `result.source`           |
| `beforeExecute(plan, ctx, params?)` | returns a count | After the SQL text has been built, before the database driver runs it | Validate, throw to block, or change parameter values                                     |
| `interceptExecute(plan, ctx)`       | returns a count | Just before the database driver runs it                               | Return `{ stats }` to answer the statement yourself                                      |
| `afterExecute(plan, result, ctx)`   | returns a count | After the statement finishes                                          | Log `result.stats.affectedRows`, `result.latencyMs`, `result.completed`, `result.source` |

Every hook also receives `ctx`, written last above, which the logger leaves out of its parameter list because it does not use it. Throwing from `onRow` fails the call with your error, and the rows still to come are not passed on to your code.

A hook you implement for one kind of call is never called for the other kind, so a middleware that needs to cover both implements a hook on each. `beforeQuery` and `beforeExecute` take the same arguments and return nothing, which is why you can write one function and assign it to both, and anything you do return from them is ignored. The intercept hooks cannot share a function that way, because `interceptQuery` returns `{ rows }` and `interceptExecute` returns `{ stats }`.

[How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works#the-two-lifecycles) walks through the order with an animation.

### Rewrite queries with beforeCompile [#rewrite-queries-with-beforecompile]

`beforeCompile` is where you change a query before it runs. It gives you the query as an AST, the abstract syntax tree, which is the query as a tree of typed objects rather than as text. A `SELECT` is one object whose `kind` is `'select'`, whose `from` is the table it reads, and whose `where` is its condition. The hook runs before Prisma ORM turns that tree into SQL text, so a changed tree changes the SQL that reaches the database.

Its argument, the draft, is the query before Prisma ORM writes its SQL. A draft has `ast`, the tree you change, and `meta`, which you pass through unchanged. `meta.lane` says which API built the query: `'orm-client'` for the ORM API, and `'dsl'` for the SQL query builder. You return a copy of the draft with a new `ast`, or `undefined` when there is nothing to change.

The middleware below adds a condition to every `SELECT` whose own `FROM` clause names the `User` table:

```ts title="src/prisma/scope-user-selects.ts"
import type { SqlMiddleware } from '@prisma/orm-postgres/family-runtime';
import { AndExpr, type BinaryExpr } from '@prisma/orm-postgres/relational-core/ast';

export function scopeUserSelects(condition: () => BinaryExpr | undefined): SqlMiddleware {
  return {
    name: 'scope-user-selects',
    familyId: 'sql',

    async beforeCompile(draft) {
      if (draft.ast.kind !== 'select') return undefined;
      if (draft.ast.from?.kind !== 'table-source') return undefined;
      if (draft.ast.from.name !== 'User') return undefined;
      const predicate = condition();
      if (predicate === undefined) return undefined;
      const where = draft.ast.where ? AndExpr.of([draft.ast.where, predicate]) : predicate;
      return { ...draft, ast: draft.ast.withWhere(where) };
    },
  };
}
```

The `kind` check on `from` keeps the middleware to plain tables: a `SELECT` that reads from a subquery has a `from` whose `kind` is `'derived-table-source'`, and one that reads from a function has `'function-source'`. The name it checks, `'User'`, is the table name in your database rather than the model name in your contract, because by this point the query is expressed in tables and columns. The two are the same unless the model sets `@@map`. `draft.ast.withWhere(where)` gives back a new tree with that `WHERE` and leaves the original alone.

These checks read only the table in the query's own `FROM` clause, so `User` rows that a query reaches any other way do not get the condition. Users you load with `.include(...)` from another model, such as the author of each post, are not filtered, and neither is a SQL query builder query that joins `User` onto another table.

The middleware calls `condition` for each `SELECT` whose `FROM` clause names `User`, after the checks above, so the condition can change from one request to the next. You build it from the same classes. Put values through `ParamRef.of` rather than `LiteralExpr.of`, because a `ParamRef` becomes a bound parameter such as `$1` while a literal is pasted into the SQL text itself, so a value that came from one of your users could inject SQL of its own. A `ParamRef` you build by hand has to name the PostgreSQL type of the value with `codec: { codecId: ... }`, and the ids start with `pg/` and end with `@1`, so the `text` column `name` takes `pg/text@1`. Leave that out and the query fails with an error whose `code` is `RUNTIME.PARAM_REF_MISSING_CODEC`.

Prisma ORM does not know which request a query belongs to, so the value has to come from a place your condition function can read. The example below keeps it in an `AsyncLocalStorage` from Node.js, which holds one value per request while that request's code runs:

```ts title="src/prisma/db.ts"
import { AsyncLocalStorage } from 'node:async_hooks';
import postgres from '@prisma/orm-postgres/runtime';
import { BinaryExpr, ColumnRef, ParamRef } from '@prisma/orm-postgres/relational-core/ast';
import { scopeUserSelects } from './scope-user-selects';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const currentName = new AsyncLocalStorage<string>();

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
  middleware: [
    scopeUserSelects(() => {
      const name = currentName.getStore();
      if (name === undefined) return undefined;
      return BinaryExpr.eq(
        ColumnRef.of('User', 'name'),
        ParamRef.of(name, { codec: { codecId: 'pg/text@1' } }),
      );
    }),
  ],
});
```

This file imports `BinaryExpr` without `type`, because it calls `BinaryExpr.eq(...)`. Keep the `type` on the `BinaryExpr` import in `scope-user-selects.ts`.

Run each request's queries inside `currentName.run(...)`, and `await` them inside its callback. In a web server, that means wrapping the code of each request handler:

```ts title="src/routes/users.ts"
import { currentName, db } from '../prisma/db';

const users = await currentName.run('Mia', async () => {
  return await db.orm.public.User.select('id', 'name').all();
});
```

Every `SELECT` whose `FROM` clause names `User` then runs with `WHERE "User"."name" = $1` added, and a query that already had a `WHERE` clause keeps it, joined to yours with `AND`. The `await` inside the callback matters: `.all()` returns the query without running it, and the query runs when you `await` it. With `currentName.run('Mia', () => db.orm.public.User.select('id', 'name').all())`, the `await` is outside the callback, so the query runs after `run(...)` has returned, `getStore()` gives `undefined`, and the query gets no condition. The same goes for any query that runs outside `currentName.run(...)`. If every query must have one, throw in the function instead of returning `undefined`.

> [!WARNING]
> Do not rely on this middleware alone to keep one tenant's rows away from another. If you swap `name` for a tenant column, a query that reads `User` in its own `FROM` clause returns only that tenant's rows, but `User` rows loaded with `.include(...)` or joined onto another table are not filtered, so they can belong to any tenant.

The `codecId` depends on the field's type in your contract:

| Type in your contract | `codecId`                   |
| --------------------- | --------------------------- |
| `String`              | `pg/text@1`                 |
| `Int`                 | `pg/int4@1`                 |
| `BigInt`              | `pg/int8@1`                 |
| `Float`               | `pg/float8@1`               |
| `Boolean`             | `pg/bool@1`                 |
| `DateTime`            | `pg/timestamptz-temporal@1` |
| `Uuid`                | `pg/uuid@1`                 |

The `temporal` in the `DateTime` id means the value reaches your code as a JavaScript `Temporal.Instant` rather than a `Date`.

For a field whose type is not in the table, read the `codecId` off your own client: `db.sql.public.User.columns.name.codecId` is the id for the `name` column of the `User` table, so print it from any script that imports `db`. The SQL query builder reference lists every id, in its section on [`fns.raw` and `.returns()`](https://www.prisma.io/docs/orm/reference/sql-query-builder#fnsraw-and-returns).

`BinaryExpr` has one method per comparison (`eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `like`, `in`, `notIn`), and `AndExpr.of` and `OrExpr.of` combine conditions. They all come from `@prisma/orm-postgres/relational-core/ast`, so your editor lists them once you import from there.

### Answer queries with interceptQuery [#answer-queries-with-interceptquery]

`interceptQuery` lets your middleware answer a query itself: return `{ rows }` from it and the database driver never runs. Caches, test fixtures, and circuit breakers all work this way.

The rows you return are raw row objects, keyed by the column aliases in the SQL, holding the values as they come off the wire: numbers for integers, strings for text and timestamps. To see a real one, add `onRow` to the object `queryLogger()` returns in `src/prisma/query-logger.ts`, run your script once, and take it out again, because `onRow` gets rows in exactly the shape `interceptQuery` has to return:

```ts title="src/prisma/query-logger.ts (excerpt)"
async onRow(row) {
  console.log(row);
},
```

For the `SELECT` in step 3, whose SQL is `SELECT "User"."id" AS "id", "User"."email" AS "email" FROM "public"."User" LIMIT 5`, a row object has an `id` key holding a number and an `email` key holding a string. The middleware below is a test fixture: it returns one made-up row of that shape in place of the database's answer, so a test can run that query without data in the table. Add it to the same `middleware` array as the logger, either on its own as `middleware: [userFixture()]` or next to the logger as `middleware: [queryLogger(), userFixture()]`:

```ts title="src/prisma/user-fixture.ts"
import type { SqlMiddleware } from '@prisma/orm-postgres/family-runtime';

export function userFixture(): SqlMiddleware {
  return {
    name: 'user-fixture',
    familyId: 'sql',

    async interceptQuery(plan, ctx) {
      if (ctx.scope !== 'runtime') return undefined;
      if (plan.ast.kind !== 'select') return undefined;
      if (plan.ast.from?.kind !== 'table-source') return undefined;
      if (plan.ast.from.name !== 'User') return undefined;
      return { rows: [{ id: 1, email: 'mia@prisma.io' }] };
    },
  };
}
```

Prisma ORM decodes the rows you return the same way it decodes rows that came from the database, so your caller gets the types the contract gives those columns, even though you handed back plain driver values.

The last three checks make the fixture answer only a `SELECT` that reads the `User` table directly, in the same way the `beforeCompile` example picks its queries. Matching on the SQL text instead, such as `plan.sql.includes('FROM "public"."User"')`, also catches `DELETE FROM "public"."User"`, so an ORM `.deleteAll()` would get a made-up row back and delete nothing. On an `UPDATE` or a `DELETE` the table name is at `plan.ast.table.name`.

`plan.meta.lane` tells you which API built a query, but nothing on the plan says which model or which ORM call it came from, so the table name in the tree is the only thing you have to match on.

The first check, on `ctx.scope`, lets every query inside a transaction, or on a connection you took from the pool, go on to the database, so the fixture answers only queries sent on `db` directly. Keep it, because an ORM `.update()` or `.delete()` reads its row inside a transaction before it writes, and a made-up row there would send the write to the wrong row.

Return `undefined` and the query carries on to the database as usual. When several middleware implement `interceptQuery`, the first one in the array that returns rows answers the query and the rest are not called at all. `afterQuery` still runs either way, with `result.source` set to `'middleware'`, so your logging can tell which queries were answered without a trip to the database. For a call that returns a count, `interceptExecute` does the same job and returns `{ stats }`, which only ever holds `affectedRows`, as in `{ stats: { affectedRows: 0 } }`. The [cache middleware](https://www.prisma.io/docs/orm/middleware/built-in-cache) is the implementation to copy from.

## The context object [#the-context-object]

Every hook receives a context object called `ctx`, holding the following:

| Field                   | What it gives you                                                                                                      |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `ctx.planExecutionId`   | The same unique ID in every hook that runs for one query                                                               |
| `ctx.now()`             | The current time in milliseconds, the same value `Date.now()` gives                                                    |
| `ctx.scope`             | Where the query is running: `'runtime'`, `'connection'`, or `'transaction'`                                            |
| `ctx.mode`              | Whether a failed check blocks the query. Always `'strict'` on PostgreSQL, because `postgres(...)` has no way to set it |
| `ctx.contentHash(plan)` | A promise of a string that is the same for the same statement and parameters, so `await` it                            |
| `ctx.contract`          | Your contract, for when a hook needs to know what your database looks like                                             |
| `ctx.log`               | Has nowhere to go on PostgreSQL today, so use your own logger                                                          |

`ctx.scope` is `'runtime'` for a query you sent on `db` directly, `'transaction'` inside `db.transaction(...)`, and `'connection'` for a query you sent on a connection you took out of the pool yourself with `db.runtime().connection()`. The cache reads it to leave queries inside a transaction alone.

`beforeQuery` and `beforeExecute` take one more argument after `ctx`, called `params`, which lets you read and replace the values that will be sent as `$1`, `$2`, and so on. `params.entries()` gives you one entry per value, each with the `value` itself, the `codecId` naming its PostgreSQL type, and a `ref` that identifies which value it is, and you change one by handing that `ref` back to `params.replaceValue`. The hook below goes inside the object your middleware returns, next to `name` and `familyId`, and it opens with `if (!params) return;` because the argument is typed as optional even though Prisma ORM always passes it:

```ts title="src/prisma/redact-params.ts (excerpt)"
async beforeQuery(plan, ctx, params) {
  if (!params) return;
  for (const entry of params.entries()) {
    if (entry.codecId === 'pg/text@1' && entry.value === 'secret') {
      params.replaceValue(entry.ref, 'redacted');
    }
  }
},
```

You cannot add or remove values this way, only replace the ones the query already has.

### Carry state from a before-hook to an after-hook [#carry-state-from-a-before-hook-to-an-after-hook]

Every hook that runs for one query gets the same `ctx.planExecutionId`, so a middleware that has to remember something between two hooks keeps it in a `Map` under that ID and takes it out again on the other side. This is what replaces wrapping a query in `next()`. Copy the pattern whenever the after-hook needs something only the before-hook could work out. `afterQuery` runs after a success and after a driver failure, but not when a before-hook throws, so in that case the entry stays in the `Map`. Register `timing()` after any middleware that can throw, and a query one of them rejects never reaches its `beforeQuery`, so nothing is left behind:

```ts title="src/prisma/timing.ts"
import type { SqlMiddleware } from '@prisma/orm-postgres/family-runtime';

const startedAt = new Map<string, number>();

export function timing(): SqlMiddleware {
  return {
    name: 'timing',
    familyId: 'sql',

    async beforeQuery(plan, ctx) {
      startedAt.set(ctx.planExecutionId, ctx.now());
    },

    async afterQuery(plan, result, ctx) {
      const started = startedAt.get(ctx.planExecutionId);
      startedAt.delete(ctx.planExecutionId);
      console.log(`${ctx.now() - (started ?? ctx.now())}ms · ${plan.sql}`);
    },
  };
}
```

Timing itself does not need any of this, because `result.latencyMs` already tells you how long the query took.

## Common gotchas [#common-gotchas]

> [!WARNING]
> * If you throw from `afterQuery` after a query has succeeded, the call fails even though the database has already done the work, so keep that for cases where failing loudly is the point, the way the [budgets](https://www.prisma.io/docs/orm/middleware/built-in-budgets) latency check does.
> * `afterQuery` and `afterExecute` also run when the database driver fails, and they get `result.completed` set to `false`. A failed write has no `result.stats`, so read it only when `result.completed` is true.
> * If your hook throws while it is handling a failure like that, Prisma ORM discards your error and your caller still sees the failure the driver reported.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` install [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent, so you can ask it for the middleware built in the steps above:

* "Write a Prisma ORM middleware that logs every query slower than 250ms, and register it before budgets."
* "Add a beforeCompile middleware that adds an `orgId` condition, read per request from an AsyncLocalStorage, to every SELECT that reads the User table in its FROM clause."
* "Write an interceptQuery middleware that returns fixture rows for the products table in tests."

## Next steps [#next-steps]

* [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works): the order Prisma ORM runs your hooks in
* [Built-in: budgets](https://www.prisma.io/docs/orm/middleware/built-in-budgets), [Built-in: lints](https://www.prisma.io/docs/orm/middleware/built-in-lints), and [Built-in: cache](https://www.prisma.io/docs/orm/middleware/built-in-cache): middleware Prisma ORM ships, as production examples of these hooks

## Related pages

- [`Built-in: budgets`](https://www.prisma.io/docs/orm/middleware/built-in-budgets): The budgets middleware caps row counts and reports queries that took too long.
- [`Built-in: cache`](https://www.prisma.io/docs/orm/middleware/built-in-cache): The cache middleware serves repeated reads from an in-memory store, opted in per query with a cache annotation.
- [`Built-in: lints`](https://www.prisma.io/docs/orm/middleware/built-in-lints): The lints middleware inspects each query's structure before it runs and blocks or warns on risky shapes.
- [`How middleware works`](https://www.prisma.io/docs/orm/middleware/how-middleware-works): Middleware runs your code before and after every query, so one policy can cover your whole app.

# Built-in: budgets (/docs/orm/middleware/built-in-budgets)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The budgets middleware caps row counts and reports queries that took too long.

Location: ORM > Middleware > Built-in: budgets

The `budgets` middleware stops one careless query from reading far more of your data, or taking far more time, than you meant to give it. You give it a row limit and a time limit, and it checks the queries you send against both. When a query goes over either limit, your call fails with an error and you get no rows back.

Before you register it, know that `budgets` rejects any `SELECT` from the ORM API or the SQL query builder that has no `LIMIT` on it, however few rows the table holds. A statement you wrote yourself with `db.raw.sql` is not checked this way. On the [ORM API](https://www.prisma.io/docs/orm/fundamentals/reading-data), the call that runs a query and gives you every matching row is `.all()`, so that means every `.all()` call with no `.limit(...)` earlier in the chain. A `.where(...).first()` call is fine, because `.first()` asks the database for one row.

Those `.all()` calls start throwing the moment you add `budgets` to your client, and there is no warn-only setting to ease the change in. The `severities` options in the table below look like one, but they do nothing on a client you build with `postgres(...)`. So find your `.all()` calls and give them limits before you turn `budgets` on, and searching your source for the call is a good starting point:

```bash
grep -rn "\.all()" src scripts
```

The fix is a `.limit(...)` in the chain. A query that counts rows is never a problem, because a count that is not split into groups comes back as a single row. In the calls below, `db.orm` is the ORM API and `public` is the PostgreSQL schema your tables are in:

```ts
// Throws an error whose code is BUDGET.ROWS_EXCEEDED, because there is no limit.
await db.orm.public.User.select('id').all();

// Runs, because the query asks for at most 20 rows.
await db.orm.public.User.limit(20).all();

// Runs, because a count that is not split into groups returns one row.
await db.orm.public.User.aggregate((a) => ({ total: a.count() }));
```

Register `budgets` in the `postgres(...)` call that creates your client, with the row and time limits you want to enforce. The file below is the smallest `src/prisma/db.ts` that works, and the `middleware` option is the only part specific to `budgets`. The `db.ts` that `create-prisma` generates has more in it, including a `connectDatabase` export that the generated `seed.ts` imports, so add the `middleware` option to that file rather than replacing it. Its `postgres(...)` calls only run when the app is started with `DATABASE_URL` exported, as `npm run dev` does. With `npm run dev:composer`, the generated file takes its client from Composer through `service.load()` instead, and the `middleware` option in `db.ts` is never used, so `budgets` is not on. Your contract is the Prisma ORM 8 name for your schema, `contract.prisma` in place of `schema.prisma`, and `npx prisma contract emit` writes from it the `contract.json` and `contract.d.ts` that this file imports. [The data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) covers them in full.

```ts title="src/prisma/db.ts"
import postgres from '@prisma/orm-postgres/runtime';
import { budgets } from '@prisma/orm-postgres/family-runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
  middleware: [
    budgets({
      maxRows: 10_000,
      defaultTableRows: 10_000,
      tableRows: { User: 10_000, Post: 10_000 },
      maxLatencyMs: 1_000,
    }),
  ],
});
```

The built-in middleware is imported from `@prisma/orm-postgres/family-runtime`, which works with any SQL database. It arrives with `@prisma/orm-postgres`, so there is nothing extra to install.

The example sets `maxRows`, `defaultTableRows`, and `maxLatencyMs` to the values they already take by default, so that you can see where each one goes, and you can leave all three out. Set `maxRows` and `maxLatencyMs` to the largest number of rows and the longest time any single query in your app should ever need, because they are there to catch mistakes rather than to tune anything.

Every `SELECT` needs a `LIMIT` anyway, but a limit can still be larger than `maxRows`. The check before the query knows how big a table is only from the number you give it in `tableRows`, so with a real number there, a query like that on a big table fails before it runs rather than part way through reading its rows, as [Common gotchas](#common-gotchas) shows. The two numbers in the example are placeholders for how many rows your own tables really hold, so a `Post` table with two million rows in it is written `tableRows: { Post: 2_000_000 }`. A `count` from the database is enough to get each number, such as `select count(*) from "public"."User";` for the `User` table, and you can leave `tableRows` out altogether, in which case every table is assumed to hold `defaultTableRows` rows.

Each key is the table name as it is in the database: the model's `@@map` value, or the model name exactly as written when the model has no `@@map`. So the model `User` is keyed `User`, not `public.User`. `budgets` looks a table up by its name alone, so two tables with the same name in different PostgreSQL schemas share one key and one number. If you misspell a table name, `budgets` silently uses `defaultTableRows` for that table and never warns you.

Passing `budgets` to a MongoDB client throws an error whose `code` is `RUNTIME.MIDDLEWARE_FAMILY_MISMATCH` the first time that client is used, before any query of yours runs, and there is no MongoDB version of `budgets` to use instead.

## Options [#options]

Every option is optional, and the default in the table applies when you leave one out.

| Option                | Type                     | Default   | What it controls                                                                                   |
| --------------------- | ------------------------ | --------- | -------------------------------------------------------------------------------------------------- |
| `maxRows`             | `number`                 | `10_000`  | The most rows one query may produce                                                                |
| `defaultTableRows`    | `number`                 | `10_000`  | How many rows to assume a table has when it is not listed in `tableRows`                           |
| `tableRows`           | `Record<string, number>` | `{}`      | How many rows to assume each table has, keyed by table name                                        |
| `maxLatencyMs`        | `number`                 | `1_000`   | The longest one query may take, in milliseconds                                                    |
| `severities.rowCount` | `'warn' \| 'error'`      | `'error'` | Nothing on a client you build with `postgres(...)`, where going over the row budget always throws  |
| `severities.latency`  | `'warn' \| 'error'`      | `'warn'`  | Nothing on a client you build with `postgres(...)`, where going over the time budget always throws |

`severities` has no effect on a client you build with `postgres(...)`, where both budgets always throw. You can leave it out.

## How it enforces the budget [#how-it-enforces-the-budget]

A query is checked before it is sent, again as its rows arrive, and once more when it is done:

1. **Before the query runs**, `budgets` estimates how many rows the query could return, and when the estimate is over `maxRows` you get an error whose `code` is `BUDGET.ROWS_EXCEEDED` before the database is asked to do anything. A `SELECT` with no `LIMIT` on it is over budget on its own, whatever `maxRows` says and however small the table is. The exception is a query that can only ever produce one row, such as the count above.
2. **While the rows come back**, `budgets` counts the rows the database really returns, so a query that got past the estimate is still caught. As soon as that count passes `maxRows` you get an error whose `code` is `BUDGET.ROWS_EXCEEDED`, and the rows read up to that point are dropped rather than returned to you.
3. **After the query finishes**, `budgets` compares how long the query took against `maxLatencyMs` and throws an error whose `code` is `BUDGET.TIME_EXCEEDED` when it ran too long. The database has already done the work by then, so the check cannot make the query faster, but your `await` still rejects and you get no rows.

A query that joins another table is estimated from the table in its `FROM` clause alone, because that is the only name `budgets` looks up in `tableRows`, so do not count on the first check to catch a join. Writes are not estimated at all: the check before the query reads `SELECT` queries only, so a write that returns a count, such as an `updateAndCount` that reports how many rows it changed, can only ever be caught by the time check. A read with `.include(...)`, which loads related records alongside the rows you asked for, is one query, checked once like any other read.

## What you see when a budget trips [#what-you-see-when-a-budget-trips]

When `budgets` blocks a query, the call you were awaiting rejects with an ordinary `Error` that has a `code` property saying which budget was exceeded and a `details` property with the numbers it measured. If you do not catch it, a `SELECT` with no `LIMIT` and `maxRows` at `10_000` prints this, where "unbounded" in the message is the error's own word for a query with no `LIMIT`:

```text title="Row budget error" no-copy
Error [RuntimeError]: Unbounded SELECT query exceeds budget
    ... {
  code: 'BUDGET.ROWS_EXCEEDED',
  category: 'BUDGET',
  severity: 'error',
  details: { source: 'ast', estimatedRows: 10000, maxRows: 10000 }
}
```

The `source` field tells you which of the two row checks stopped the query. `'ast'` is the check before the query ran, and `'observed'` means the database really returned that many rows. What you do about it is the same either way, which is to give the query a limit, but `'observed'` also tells you the table is much bigger than the number you gave for it in `tableRows`.

When a query runs longer than `maxLatencyMs`, the error gives you both numbers, the time the query took and the time you allowed:

```text title="Latency budget error" no-copy
Error [RuntimeError]: Query latency exceeds budget
    ... {
  code: 'BUDGET.TIME_EXCEEDED',
  category: 'BUDGET',
  severity: 'error',
  details: { latencyMs: 1501, maxLatencyMs: 1000 }
}
```

Both errors are plain `Error` objects, so you catch them the way you catch anything else and read the `code` to tell which budget was exceeded:

```ts
try {
  await db.orm.public.User.select('id').all();
} catch (error) {
  if ((error as { code?: string }).code === 'BUDGET.ROWS_EXCEEDED') {
    // add a limit, or raise the budget
  }
  throw error;
}
```

Most of the time the fix is a limit, with [`limit(...)` on the ORM API](https://www.prisma.io/docs/orm/fundamentals/reading-data#sort-and-paginate) or `.limit(...)` on the [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder). When the query is right and the budget is too low, raise `maxRows`, but that raises it for every query on that client, because `budgets` is an option of the client and no query can opt out of it.

So for a job that genuinely has to read millions of rows, such as a nightly export, build a second client from the same contract and leave `budgets` out of it:

```ts title="scripts/export/db.ts"
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from '../../src/prisma/contract.d';
import contractJson from '../../src/prisma/contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});
```

Import that `db` in your export script and nowhere else, so the rest of your app keeps importing `src/prisma/db.ts` and keeps its budgets. Each `postgres(...)` call opens its own connection pool, so while the job runs you have a second pool open alongside your app's.

## Common gotchas [#common-gotchas]

> [!WARNING]
> The check that runs before your query never asks the database how big your tables are. It only knows the numbers you gave it in `tableRows` and `defaultTableRows`, so when your real tables are much larger than those numbers, a query can get past that first check and then fail part way through reading rows, once the rows the database returns pass `maxRows`.
> 
> Say `maxRows` is `10_000` and you listed `User` at 5,000 rows, but the table really holds 5 million. A query with `.limit(50_000)` on it is estimated at 5,000 rows, because `budgets` takes the smaller of your limit and the size you gave for the table, so it passes the first check. The database then starts sending 50,000 rows and the count check throws at row 10,001, part way through your read.
> 
> When a query that used to work starts failing with `source: 'observed'`, the table has grown past the number you gave for it in `tableRows`. Put a fresh count there, and the check before the query then stops that query with `source: 'ast'` before the database does any work, rather than part way through the read. The query is still over budget either way, because its limit is larger than `maxRows`. To make it run, raise `maxRows`, or lower its `.limit(...)` to `maxRows` or less and read the rest a page at a time with `.offset(...)`, as [Sort and paginate](https://www.prisma.io/docs/orm/fundamentals/reading-data#sort-and-paginate) describes:
> 
> ```ts title="scripts/export/read-users.ts"
> const pageSize = 10_000;
> for (let offset = 0; ; offset += pageSize) {
>   const page = await db.orm.public.User
>     .orderBy((u) => u.id.asc())
>     .limit(pageSize)
>     .offset(offset)
>     .all();
>   // handle this page of rows
>   if (page.length < pageSize) break;
> }
> ```

## See also [#see-also]

* [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works)
* [Built-in: lints](https://www.prisma.io/docs/orm/middleware/built-in-lints) for structural query checks that complement budgets
* [Authoring custom middleware](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware)

## Related pages

- [`Authoring custom middleware`](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware): Build, register, and run your own Prisma ORM middleware, step by step, starting with a query logger.
- [`Built-in: cache`](https://www.prisma.io/docs/orm/middleware/built-in-cache): The cache middleware serves repeated reads from an in-memory store, opted in per query with a cache annotation.
- [`Built-in: lints`](https://www.prisma.io/docs/orm/middleware/built-in-lints): The lints middleware inspects each query's structure before it runs and blocks or warns on risky shapes.
- [`How middleware works`](https://www.prisma.io/docs/orm/middleware/how-middleware-works): Middleware runs your code before and after every query, so one policy can cover your whole app.

# Built-in: cache (/docs/orm/middleware/built-in-cache)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The cache middleware serves repeated reads from an in-memory store, opted in per query with a cache annotation.

Location: ORM > Middleware > Built-in: cache

A middleware is an object you register on your client that Prisma ORM calls around every query your app runs. The cache middleware keeps the rows a read returned in memory, so when your app runs that same read again it gets the stored rows back instead of going to the database. Nothing is cached unless you ask for it: you mark a query with a TTL, meaning how long its stored rows stay usable, and every query you do not mark runs against the database exactly as it did before.

Reach for it when the same read runs over and over and you can live with an answer that is a little out of date, such as a dashboard, a lookup table, feature flags, navigation data, or a search result that is expensive to run.

Install the package and register the middleware:

  

#### bun

```bash title="Terminal"
bun add @prisma/orm-extension-middleware-cache
```

#### pnpm

```bash title="Terminal"
pnpm add @prisma/orm-extension-middleware-cache
```

#### yarn

```bash title="Terminal"
yarn add @prisma/orm-extension-middleware-cache
```

#### npm

```bash title="Terminal"
npm install @prisma/orm-extension-middleware-cache
```

Your contract is the Prisma ORM 8 name for your schema: `contract.prisma` in a generated project, in place of `schema.prisma`. `npx prisma contract emit` writes `contract.json` and `contract.d.ts` from it, and those are the two files `db.ts` imports.

```ts title="src/prisma/db.ts"
import { createCacheMiddleware } from '@prisma/orm-extension-middleware-cache';
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
  middleware: [createCacheMiddleware()],
});
```

This is a cut-down `src/prisma/db.ts` from a generated project, with `middleware` added. A project created with `npm create prisma@latest` already has `contract.json` and `contract.d.ts` in `src/prisma/`, so you do not have to run `npx prisma contract emit` yourself to get started. If you set your project up by hand, [The data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) covers where they come from.

Writes are never cached, and the `*AndCount` methods return a count rather than rows, so there is nothing to cache in their case either.

The cache works on PostgreSQL and on MongoDB. You register it on MongoDB the same way: pass `createCacheMiddleware()` in the `middleware` option of `mongo(...)`, which comes from `@prisma/orm-mongo/runtime`.

## Opt a query in [#opt-a-query-in]

You tell Prisma ORM that a read may be cached by attaching a cache annotation to it. An annotation is a note attached to a query that middleware can read, and the one the cache looks for is `cacheAnnotation({ ttl })`, where `ttl` is how long the rows stay usable, in milliseconds. There is no option that caches every read for you, so a read is cached only when it has an annotation of its own.

Prisma ORM gives you two ways to write the same read, the SQL query builder and the ORM API, and both of them can be cached. Use whichever one the rest of your code already uses, because the annotation attaches differently in each.

With the SQL query builder you build the query yourself, call `.build()`, and run the result with `db.runtime().query(...)` for rows or `db.runtime().execute(...)` for a count. Only rows can be cached, so nothing you run with `db.runtime().execute(...)` ever is. To cache a read, chain `.annotate(cacheAnnotation({ ttl: 60_000 }))` onto the query before you call `.build()`. `db.sql.public.User` names the `User` table in the PostgreSQL schema `public`.

```ts title="src/prisma/get-users-cached.ts"
import { cacheAnnotation } from '@prisma/orm-extension-middleware-cache';
import { db } from './db';

export async function getUsersCached() {
  const plan = db.sql.public.User
    .select('id', 'email')
    .annotate(cacheAnnotation({ ttl: 60_000 }))
    .limit(10)
    .build();

  return db.runtime().query(plan);
}
```

The ORM API does both steps inside the one call, and `db.orm.public.User` is the `User` model in the PostgreSQL schema `public`, rather than the table it is stored in. Its reads take an optional callback after the arguments, and the `meta` object that callback receives is where annotations go:

```ts title="src/prisma/get-user-cached.ts"
import { cacheAnnotation } from '@prisma/orm-extension-middleware-cache';
import { db } from './db';

export async function getUserCached(id: number) {
  return db.orm.public.User.first({ id }, (meta) =>
    meta.annotate(cacheAnnotation({ ttl: 60_000 })),
  );
}
```

The first call goes to the database as usual, and the cache keeps the rows it got back, exactly as they came. If the same query with the same parameter values runs again before the `ttl` has run out, Prisma ORM answers it from those stored rows and never calls the database driver.

You can set the following fields on the annotation:

| Field  | Type      | What it does                                                                     |
| ------ | --------- | -------------------------------------------------------------------------------- |
| `ttl`  | `number`  | How long the stored rows stay usable, in milliseconds                            |
| `skip` | `boolean` | Set it to `true` to send this one call to the database, ignoring anything stored |
| `key`  | `string`  | Your own string to store the rows under, instead of the one the cache works out  |

Leave `ttl` out and the annotation does nothing, so the query is not cached.

`skip` and `key` go in the same object as `ttl`, in either API. `skip: true` sends that one call to the database and leaves the stored rows untouched, so everyone else keeps getting the stored rows until the `ttl` runs out. The `ttl` in the same object is ignored on a call with `skip: true`, which is why you can leave the annotation as it is and flip `skip` on the one call that has to see current rows. With the SQL query builder it goes in the same object you pass to `.annotate(...)`:

```ts
const plan = db.sql.public.User
  .select('id', 'email')
  .annotate(cacheAnnotation({ ttl: 60_000, skip: true }))
  .limit(10)
  .build();

return db.runtime().query(plan);
```

A `key` is used exactly as you wrote it, and the cache adds nothing to it, so any two reads that pick the same `key` share one entry even when their parameter values or their models differ: the rows stored for `id: 1` come back for `id: 2` as well. Either use `key` only on a query whose parameter values never change, or put the parameter values into the string yourself, behind a prefix no other read in your app uses:

```ts
return db.orm.public.User.first({ id }, (meta) =>
  meta.annotate(cacheAnnotation({ ttl: 60_000, key: `user:${id}` })),
);
```

Attaching `cacheAnnotation` to a write such as `create`, `update`, or `delete` does not compile: TypeScript rejects it as you write the code, and forcing it through throws when the query runs. You cannot cache a write by accident.

## When a read is served from the cache [#how-keys-and-hits-work]

Unless you give it a `key`, the cache stores a read under a key built from the query, its parameter values, and a hash of your contract, and it serves a read from the cache only when all three match. The same read with a different parameter value is therefore a separate entry and does not get the first one's rows.

That contract hash changes with any migration, whichever table the migration touched, so after a migration every entry the cache keyed for itself stops matching and none of them are served again. An entry you stored under your own `key` is not affected, because your `key` is used exactly as you wrote it and has nothing about your contract in it.

Your own calling code cannot see the difference, because `db.runtime().query(plan)` and `db.orm.public.User.first(...)` give you the same rows whether the cache answered or the database did.

A read inside `db.transaction(...)`, or on a connection you took out of the pool yourself with [`db.runtime().connection()`](https://www.prisma.io/docs/orm/reference/transactions-and-runtime#manual-connection-and-transaction-control), always goes to the database, and its rows are not stored. Code that holds a transaction or a connection expects to read back what it has just written, so the cache stays out of the way and you always see your own writes.

## Check that caching is working [#check-that-caching-is-working]

Prisma ORM has no counter or log option that reports cache hits, so to see them, register a small middleware of your own after the cache. A read the cache answers still reaches the middleware after it, so your own logging and metrics keep recording it and a hook like the one below runs either way. That hook is `afterQuery`, and the `result` argument it gets says who answered: `result.source` is `'middleware'` when the cache answered and `'driver'` when the database did.

```ts title="src/prisma/cache-watch.ts"
import type { SqlMiddleware } from '@prisma/orm-postgres/family-runtime';

export function cacheWatch(): SqlMiddleware {
  return {
    name: 'cache-watch',
    async afterQuery(plan, result) {
      console.log(`[cache-watch] ${result.source} · ${plan.sql}`);
    },
  };
}
```

The other built-in middleware and the `SqlMiddleware` type are imported from `@prisma/orm-postgres/family-runtime`, which works with any SQL database. On MongoDB the same middleware is typed `MongoMiddleware`, from `@prisma/orm-mongo/family-runtime`, and a MongoDB query has no `sql` field, so log `plan.command` there instead.

Register `cacheWatch()` after the cache, by replacing the `middleware` line in `src/prisma/db.ts` and adding the import above it. Order matters for a middleware that returns rows itself instead of letting the query reach the database, because the first one to do that wins and the ones after it are never asked. `cacheWatch()` only logs, and a middleware of your own that can return rows goes after the cache as well, so that the cache is asked first.

```ts title="src/prisma/db.ts (excerpt)"
import { cacheWatch } from './cache-watch';

middleware: [createCacheMiddleware(), cacheWatch()],
```

Now call the same annotated read twice. The first call prints `driver`, because it went to the database, and the second prints `middleware`, because the cache answered it. If you register other middleware of your own that can return rows itself, `result.source` is `'middleware'` for all of them, so it tells you that a middleware answered and not which one.

## When entries go away [#when-entries-go-away]

There is no call that clears the cache or removes one entry. An entry stops being served when its `ttl` runs out, or when the built-in store drops its least recently used entry to stay under `maxEntries`.

Writes do not clear anything either. A `create`, `update`, or `delete` leaves every stored entry exactly where it was, so a read with a `ttl` of 60 seconds can keep returning the old rows for up to a minute after you have changed them. You have two ways to live with that, and no third: pick a `ttl` you can afford to be wrong for that long, and send the calls that have to see the change straight away with `skip: true`. A read that can never be even a second out of date is a read you should not annotate at all.

## Options [#options]

These are the options you pass to `createCacheMiddleware`:

| Option       | Type           | Default                      | What it controls                                                                        |
| ------------ | -------------- | ---------------------------- | --------------------------------------------------------------------------------------- |
| `maxEntries` | `number`       | `1000`                       | How many entries the built-in store holds before it drops its least recently used entry |
| `store`      | `CacheStore`   | the built-in in-memory store | Where the cached rows are kept, for example in Redis                                    |
| `clock`      | `() => number` | `Date.now`                   | The function the cache calls for the current time, recorded on each entry               |

`maxEntries` applies to the built-in store only. When you pass your own `store`, the cache ignores `maxEntries` and your store decides for itself how much it holds.

## Common gotchas [#common-gotchas]

> [!WARNING]
> The built-in store holds the rows in the memory of one process, so if you run two instances of your app each one keeps its own copy of the rows and fills it at its own pace, and every deploy starts both of them empty again. Two requests that run the same read can therefore get different rows depending on which instance served them, so never let a decision that has to be right rest on a cached read, such as a permission check or an account balance. Send those reads with `skip: true`, or leave them unannotated.

## Share one cache between instances [#share-one-cache-between-instances]

To have every instance read from the same cache, pass your own `store`. A store is an object with two methods, both async, so it can talk to Redis or to anything else your instances can all reach. `get(key)` takes a string and returns the entry stored under it, or `undefined` when there is nothing for that key. `set(key, entry, ttlMs)` keeps an entry under that key for `ttlMs` milliseconds.

Working out that an entry has expired is your store's job, so your `get` must not return an entry whose `ttlMs` has passed. A store backed by Redis can let Redis's own expiry do that for you, by setting it when `set` is called.

An entry is an object with two fields, `{ rows, storedAt }`. `storedAt` is the time the cache recorded when it stored the rows, taken from the `clock` option. `rows` is the rows as the database driver returned them, so integers are numbers and both text and timestamps are strings. A `createdAt` column reaches your store as a string and not a `Date`, as a row from `select('id', 'email', 'createdAt')` shows:

```ts
{ id: 3, email: 'mia@prisma.io', createdAt: '2026-09-17 08:00:08.775+00' }
```

Your store gets those objects as they are and has to hand back the same thing from `get`, so turning them into something Redis can hold, and back again, is yours to write. Log a row before you write the store, so you can see the values for your own columns.

```ts title="src/prisma/cache-store.ts"
import type { CacheStore } from '@prisma/orm-extension-middleware-cache';

export const store: CacheStore = {
  async get(key) {
    // return { rows, storedAt } when you have unexpired rows for this key, otherwise undefined
    return undefined;
  },
  async set(key, entry, ttlMs) {
    // keep entry under key for ttlMs milliseconds
  },
};
```

Register the middleware with your store instead of `maxEntries`, again by replacing the `middleware` line in `src/prisma/db.ts`:

```ts title="src/prisma/db.ts (excerpt)"
import { store } from './cache-store';

middleware: [createCacheMiddleware({ store })],
```

## See also [#see-also]

* [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works)
* [Authoring custom middleware](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware), including how a middleware answers a query itself instead of letting it reach the database
* [Built-in: budgets](https://www.prisma.io/docs/orm/middleware/built-in-budgets)

## Related pages

- [`Authoring custom middleware`](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware): Build, register, and run your own Prisma ORM middleware, step by step, starting with a query logger.
- [`Built-in: budgets`](https://www.prisma.io/docs/orm/middleware/built-in-budgets): The budgets middleware caps row counts and reports queries that took too long.
- [`Built-in: lints`](https://www.prisma.io/docs/orm/middleware/built-in-lints): The lints middleware inspects each query's structure before it runs and blocks or warns on risky shapes.
- [`How middleware works`](https://www.prisma.io/docs/orm/middleware/how-middleware-works): Middleware runs your code before and after every query, so one policy can cover your whole app.

# Built-in: lints (/docs/orm/middleware/built-in-lints)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The lints middleware inspects each query's structure before it runs and blocks or warns on risky shapes.

Location: ORM > Middleware > Built-in: lints

The `lints` middleware catches queries that are almost certainly a mistake before they reach your database. A `DELETE` with no `WHERE` clause removes every row in the table, which is rarely what anyone meant to write, so `lints` looks at the structure of each query first and either blocks it or logs a warning.

You turn it on by adding it to the `middleware` list when you create your `db` client. The default rules are useful as they are, so there is nothing to configure to get started:

```ts title="src/prisma/db.ts"
import postgres from '@prisma/orm-postgres/runtime';
import { lints } from '@prisma/orm-postgres/family-runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
  middleware: [lints()],
});
```

The built-in middleware is imported from `@prisma/orm-postgres/family-runtime`, which works with any SQL database. There is nothing extra to install, because it is part of the `@prisma/orm-postgres` package you already have.

This is the smallest `src/prisma/db.ts` that works, and the `middleware` option is the only part specific to `lints`. The `db.ts` that `create-prisma` generates has more in it, including a `connectDatabase` export that the generated `seed.ts` imports, so add the `middleware` option to that file rather than replacing it. Its `postgres(...)` calls only run when the app is started with `DATABASE_URL` exported, as `npm run dev` does. With `npm run dev:composer`, the generated file takes its client from Composer through `service.load()` instead, and the `middleware` option in `db.ts` is never used, so `lints` is not on. `contract.json` and `contract.d.ts` are the two files `npx prisma contract emit` writes from your contract, which is the Prisma ORM 8 name for your schema. If you set your project up by hand, [The data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) covers where those two files come from.

You register `lints` on a client you created with `postgres(...)`. Putting `lints()` in the `middleware` array of a MongoDB client is a TypeScript error. If you register other middleware alongside it, Prisma ORM runs them in the order you list them in the array, which [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works) covers.

## The rules [#the-rules]

Every query you make is checked, reads and writes alike, and a query that a rule blocks never reaches your database. The rules work on queries you build with the ORM API or the SQL query builder. Raw SQL that you wrote yourself is checked a different way, described under [Raw SQL](#raw-sql).

Every rule has a severity, which is `warn` or `error` and nothing else. A rule set to `error` throws, and the query is blocked before it reaches the database. A rule set to `warn` logs a warning and lets the query run. There is no third value that switches a rule off, so the quietest you can make a rule is `warn`.

| Rule                 | Code                        | `severities` key     | Default severity | Fires when                                         |
| -------------------- | --------------------------- | -------------------- | ---------------- | -------------------------------------------------- |
| DELETE without WHERE | `LINT.DELETE_WITHOUT_WHERE` | `deleteWithoutWhere` | `error`          | A `DELETE` has no `WHERE` clause                   |
| UPDATE without WHERE | `LINT.UPDATE_WITHOUT_WHERE` | `updateWithoutWhere` | `error`          | An `UPDATE` has no `WHERE` clause                  |
| No LIMIT             | `LINT.NO_LIMIT`             | `noLimit`            | `warn`           | A `SELECT` has no `LIMIT` clause                   |
| SELECT star          | `LINT.SELECT_STAR`          | `selectStar`         | `warn`           | A query selects all columns instead of naming them |

> [!NOTE]
> You cannot yet give the `postgres(...)` client a logger of your own, so a rule set to `warn` produces nothing you can see: nothing is printed, and there is no callback of yours for it to reach. That makes `LINT.DELETE_WITHOUT_WHERE` and `LINT.UPDATE_WITHOUT_WHERE` the two rules you can act on today, because a blocked query is something you notice, and it leaves the other two as rules to plan for until the client accepts a logger.

The rules are named after the SQL they are about, and you write your queries in the ORM API, so here is which of your own calls sets off which rule.

| Your call                                                                                                            | Rule it sets off                                           |
| -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| `.all()` with no `.limit(...)` before it                                                                             | `LINT.NO_LIMIT`                                            |
| `.first(...)`                                                                                                        | none, because it adds `LIMIT 1` for you                    |
| a query where you never called `.select(...)`                                                                        | `LINT.SELECT_STAR`                                         |
| `deleteAll()`, `deleteAndCount()`, `updateAll()`, or `updateAndCount()` after a `.where(...)` with a condition in it | none                                                       |
| `deleteAll()`, `deleteAndCount()`, `updateAll()`, or `updateAndCount()` after `.where({})`                           | `LINT.DELETE_WITHOUT_WHERE` or `LINT.UPDATE_WITHOUT_WHERE` |
| the query builder's `delete()` or `update()` with no `where()`                                                       | `LINT.DELETE_WITHOUT_WHERE` or `LINT.UPDATE_WITHOUT_WHERE` |

So `await db.orm.public.User.limit(50).all()` sets off `LINT.SELECT_STAR`, while `await db.orm.public.User.select('id', 'email').limit(50).all()` does not. In `db.orm.public.User`, `public` is the PostgreSQL schema and `User` is your model name. The SQL query builder reaches the same table by its name in the database, as `db.sql.public.User`. These examples assume a `User` model with no `@@map`, so the table has the same name as the model.

Today a `warn` rule has no visible effect. `lints` builds a record like the one below, with the code of the rule, a message, and the table the query touched, and passes it to the client's logger, but the `postgres(...)` client has no logger you can set yet, as the note above says, so the record is thrown away.

```text title="Lint warning"
warn {
  code: 'LINT.NO_LIMIT',
  message: 'Unbounded SELECT may return large result sets',
  details: { table: 'User' }
}
```

## What a blocked query looks like [#what-a-blocked-query-looks-like]

A rule set to `error` throws before the database sees anything, so the call you were awaiting rejects. It throws an ordinary `Error` with four extra properties beside its `message`: `code`, `category`, `severity`, and `details`. Use the `isRuntimeError` type guard, exported from `@prisma/orm-postgres/components/runtime`, so that TypeScript knows those properties are there and you can read `code` off the error.

The blocked `DELETE` below comes from the SQL query builder, where you build the query yourself, call `.build()`, and run the result with `db.runtime().query(...)` for rows or `db.runtime().execute(...)` for a count:

```ts
import { isRuntimeError } from '@prisma/orm-postgres/components/runtime';

try {
  const plan = db.sql.public.User.delete().build();
  await db.runtime().execute(plan);
} catch (error) {
  if (isRuntimeError(error) && error.code === 'LINT.DELETE_WITHOUT_WHERE') {
    // add a where() clause, or use a client with the rule set to warn
  }
  throw error;
}
```

Those properties hold this for a `DELETE` with no `WHERE` on the `User` table:

```text title="Blocked DELETE" no-copy
{
  code: 'LINT.DELETE_WITHOUT_WHERE',
  category: 'LINT',
  severity: 'error',
  message: 'DELETE without WHERE clause blocks execution to prevent accidental full-table deletion',
  details: { table: 'User' }
}
```

## Configure severities [#configure-severities]

When a default does not suit your project, `severities` lets you make any rule stricter or gentler. You name only the rules you want to change, using the key from the table of rules, and every rule you leave out keeps its default. Each key takes `'warn'` or `'error'`. In a service where every list endpoint has to paginate, for example, you can make a `SELECT` without a `LIMIT` fail rather than warn, and fail a query that names no columns as well. This is the `middleware` line of the `db.ts` above, with the bare `lints()` replaced:

```ts title="src/prisma/db.ts (excerpt)"
middleware: [
  lints({
    severities: {
      noLimit: 'error',
      selectStar: 'error',
    },
  }),
],
```

With `selectStar` set to `error`, a plain `.all()` in the ORM API throws, and you catch it the same way you catch a blocked `DELETE`:

```ts
import { isRuntimeError } from '@prisma/orm-postgres/components/runtime';

try {
  await db.orm.public.User.limit(50).all();
} catch (error) {
  if (isRuntimeError(error) && error.code === 'LINT.SELECT_STAR') {
    // name the columns you want with .select(...)
  }
  throw error;
}
```

## Raw SQL [#raw-sql]

A whole statement you wrote yourself with [`db.raw.sql`](https://www.prisma.io/docs/orm/reference/raw-queries) is SQL text rather than a query Prisma ORM assembled, so the four rules above are skipped for it. `lints` searches the SQL text instead, every time a raw statement runs, and it starts from its own defaults, which are not the defaults in the table of rules:

| What it searches the text for                             | Code                      | Default severity in raw SQL |
| --------------------------------------------------------- | ------------------------- | --------------------------- |
| a `select` statement containing `select *`                | `LINT.SELECT_STAR`        | `error`                     |
| a `select` statement with no `limit` anywhere in it       | `LINT.NO_LIMIT`           | `warn`                      |
| a statement that changes data in a query marked read-only | `LINT.READ_ONLY_MUTATION` | `error`                     |

So a `select *` you wrote by hand is blocked:

```ts
const plan = db.raw.sql`select * from "User"`
  .returnsRow({ id: 'pg/int4@1' })
  .build();
await db.runtime().query(plan);
```

It throws an error whose `code` is `LINT.SELECT_STAR` and whose `message` is `Raw SQL plan selects all columns via *`. `returnsRow` tells Prisma ORM the type of each column the statement gives back, written as `pg/` plus the PostgreSQL type name plus `@1`, and [`fns.raw` and `.returns()`](https://www.prisma.io/docs/orm/reference/sql-query-builder#fnsraw-and-returns) lists the ids you can use. The `severities` key for the last rule is `readOnlyMutation`, and there is no documented way to mark a query read-only, so you are unlikely to see that one.

Because these are searches through the text rather than checks on the structure of the query, they can be wrong in both directions. The word `limit` anywhere in the statement counts as a `LIMIT`, including inside a string or a column name, and a `select *` inside a subquery counts for the whole statement. So when a raw statement sets off one of these checks, go and read the query yourself before you change anything.

> [!WARNING]
> One `severities` key sets both the rule for the ORM API and the SQL query builder and the raw SQL check that has the same code, so it changes the raw defaults as well. `selectStar` is `warn` by default for the ORM API and the SQL query builder, but `error` for raw SQL. So setting `selectStar: 'warn'` changes nothing for the ORM API, which is already at `warn`: its only effect is that raw SQL's `select *` drops from `error` to `warn`, and `select * from "User"` starts running instead of being blocked. Setting `selectStar: 'error'`, as under [Configure severities](#configure-severities), keeps a raw `select *` blocked. No setting makes the ORM-API rule `error` and lets a raw `select *` run, so if you need both, give the code that runs the raw `select *` a `db` client of its own, in the way [Common gotchas](#common-gotchas) does for a backfill script.

You will not need `fallbackWhenAstMissing`, because every query from the ORM API, the SQL query builder, and `db.raw.sql` already has the structure the rules read. Leave it at its default of `'raw'`. The only other value it takes turns the checks off for a query that arrives without that structure:

```ts title="src/prisma/db.ts (excerpt)"
middleware: [lints({ fallbackWhenAstMissing: 'skip' })],
```

## Common gotchas [#common-gotchas]

> [!WARNING]
> Sometimes you do mean to change every row, in a backfill script for example. `LINT.DELETE_WITHOUT_WHERE` and `LINT.UPDATE_WITHOUT_WHERE` are `error` by default, so `lints` blocks that write, and a script like that needs one of the two ways through.

The first way is to write a `WHERE` clause that is true for every row, which states the intent in the query itself. On a table whose primary key is `id`, `id IS NOT NULL` is true for every row, and in the ORM API you write it with `isNotNull()`:

```ts title="scripts/backfill/delete-users.ts"
await db.orm.public.User.where((u) => u.id.isNotNull()).deleteAndCount();
```

An empty filter does not work for this. `.where({})` adds no condition, so `db.orm.public.User.where({}).deleteAll()` sends a `DELETE` with no `WHERE`, and `lints` blocks it with `LINT.DELETE_WITHOUT_WHERE`.

With the SQL query builder, the callback's first argument, `f`, has one property for each column, and the second, `fns`, holds the comparison helpers. Comparing a column to `null` gives you a null check rather than a comparison, so `fns.ne(f.id, null)` gives `id IS NOT NULL` and `fns.eq(f.id, null)` gives `id IS NULL`:

```ts
const plan = db.sql.public.User
  .delete()
  .where((f, fns) => fns.ne(f.id, null))
  .build();
await db.runtime().execute(plan);
```

Both deletes pass the rule and run, because each query has a `WHERE` clause and that is all `LINT.DELETE_WITHOUT_WHERE` looks for, so you can leave `lints` on its defaults in the script that runs them. An `UPDATE` takes the same shape, as in `db.orm.public.User.where((u) => u.id.isNotNull()).updateAndCount({ name: 'x' })` or `db.sql.public.User.update({ name: 'x' }).where((f, fns) => fns.ne(f.id, null)).build()`.

The second way is to build that script its own `db` client with the rule set to `warn`:

```ts title="scripts/backfill/db.ts"
import postgres from '@prisma/orm-postgres/runtime';
import { lints } from '@prisma/orm-postgres/family-runtime';
import type { Contract } from '../../src/prisma/contract.d';
import contractJson from '../../src/prisma/contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
  middleware: [lints({ severities: { deleteWithoutWhere: 'warn' } })],
});
```

Keep that client inside the script and import your usual `db` everywhere else, because setting the rule to `warn` for your whole application gives up the protection everywhere.

## See also [#see-also]

* [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works)
* [Built-in: budgets](https://www.prisma.io/docs/orm/middleware/built-in-budgets) for row-count and latency ceilings
* [Authoring custom middleware](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware)

## Related pages

- [`Authoring custom middleware`](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware): Build, register, and run your own Prisma ORM middleware, step by step, starting with a query logger.
- [`Built-in: budgets`](https://www.prisma.io/docs/orm/middleware/built-in-budgets): The budgets middleware caps row counts and reports queries that took too long.
- [`Built-in: cache`](https://www.prisma.io/docs/orm/middleware/built-in-cache): The cache middleware serves repeated reads from an in-memory store, opted in per query with a cache annotation.
- [`How middleware works`](https://www.prisma.io/docs/orm/middleware/how-middleware-works): Middleware runs your code before and after every query, so one policy can cover your whole app.

# How middleware works (/docs/orm/middleware/how-middleware-works)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Middleware runs your code before and after every query, so one policy can cover your whole app.

Location: ORM > Middleware > How middleware works

Middleware lets you run your own code around every query your app sends through Prisma ORM.

For example, you can log every query with its latency, block a `DELETE` that has no `WHERE` clause before it reaches the database, or serve a repeated read from memory instead of running it again. You write the policy once, register it once, and every query follows it, with no call sites to update.

If you used `$use` in Prisma ORM 7, the `middleware` array is its replacement. There is no `next()`: you pick the hook that runs at the moment you care about. [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) lists Prisma ORM 7 features next to the Prisma ORM 8 form each one takes.

A middleware is a plain object with a name and one or more hooks, and a hook is a function that Prisma ORM calls at a fixed moment around a query. You register the whole object once, in the `middleware` option of your client setup.

The setup below registers all three middleware Prisma ships. `lints` and `budgets` are already inside `@prisma/orm-postgres`, but the cache ships as its own package, so install that one first:

  

#### bun

```bash title="Terminal"
bun add @prisma/orm-extension-middleware-cache
```

#### pnpm

```bash title="Terminal"
pnpm add @prisma/orm-extension-middleware-cache
```

#### yarn

```bash title="Terminal"
yarn add @prisma/orm-extension-middleware-cache
```

#### npm

```bash title="Terminal"
npm install @prisma/orm-extension-middleware-cache
```

The `src/prisma/db.ts` below imports two files from your own project, `contract.json` and `contract.d.ts`. Both come from your contract, which is the Prisma ORM 8 name for your schema: `contract.prisma` in a generated project, in place of `schema.prisma`. `npx prisma contract emit` writes the two files from it. If you set your project up by hand, [The data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) covers where they come from.

```ts title="src/prisma/db.ts"
import { createCacheMiddleware } from '@prisma/orm-extension-middleware-cache';
import postgres from '@prisma/orm-postgres/runtime';
import { budgets, lints } from '@prisma/orm-postgres/family-runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
  middleware: [
    createCacheMiddleware({ maxEntries: 1_000 }),
    lints(),
    budgets({ maxRows: 10_000, maxLatencyMs: 1_000 }),
  ],
});
```

`npm create prisma@latest` generates a `src/prisma/db.ts` that already builds this client, and the `middleware` option is what you add to it. The generated file builds the client itself only when the app is started with `DATABASE_URL` exported, as `npm run dev` does. With `npm run dev:composer` it takes its client from Composer through `service.load()` instead, and the `middleware` option in `db.ts` is never used.

The client itself, `postgres(...)`, comes from `@prisma/orm-postgres/runtime`. The built-in middleware and the `SqlMiddleware` type are imported from `@prisma/orm-postgres/family-runtime`, which works with any SQL database. `lints()` and `budgets()` both take an options object, and [lints](https://www.prisma.io/docs/orm/middleware/built-in-lints) and [budgets](https://www.prisma.io/docs/orm/middleware/built-in-budgets) list what goes in it.

Writing your own middleware means writing that same kind of object: a `name`, a `familyId` saying which kind of database it works with, and the hooks you want. Here is a complete one that prints every query it sees:

```ts title="src/prisma/query-logger.ts"
import type { SqlMiddleware } from '@prisma/orm-postgres/family-runtime';

export function queryLogger(): SqlMiddleware {
  return {
    name: 'query-logger',
    familyId: 'sql',

    async afterQuery(plan, result) {
      console.log(`${result.rowCount} rows in ${Math.round(result.latencyMs)}ms · ${plan.sql}`);
    },
  };
}
```

The `name` is the label Prisma ORM uses when it has to say which middleware it means in an error message, and nothing requires it to be unique. `familyId: 'sql'` means this middleware works with SQL databases only, so Prisma ORM rejects it on a MongoDB client.

Add `queryLogger()` to the `middleware` array in `src/prisma/db.ts`, alongside the built-in middleware or on its own, and every query on that client runs through it. The [authoring guide](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware) builds this logger step by step, with the options and the other hooks.

Every query goes through that list, whichever of the two APIs you wrote it with. With the ORM API you write `db.orm.public.User...`, where `public` is the PostgreSQL schema and `User` is the model in your contract.

With the [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder) you build a query and run it in two steps. `.build()` returns a plan, which is the query as a plain object, not yet run. `db.runtime().query(plan)` runs it and returns rows, and `db.runtime().execute(plan)` runs it and returns how many rows it changed.

Both APIs send their queries on the same `db` object, so both see the same middleware. If your database is MongoDB, pass the same `middleware` option to `mongo(...)` from `@prisma/orm-mongo/runtime` and type your own middleware as `MongoMiddleware` from `@prisma/orm-mongo/family-runtime`.

<ConceptAnimation name="middleware-pipeline" />

## When your hooks run [#the-two-lifecycles]

You write only the hooks you care about, and Prisma ORM skips the ones you leave out. Which hooks it calls depends on what your query gives back: if the query returns rows, one set of hooks runs, and if it only reports how many rows it changed, a shorter set runs instead.

**A row query** is anything that returns rows. On the ORM API that is every call except `createAndCount`, `updateAndCount`, and `deleteAndCount`, so `create`, `update`, and `delete` are row queries too. It is also what you get from `db.runtime().query(plan)`. If those names are new, the [queries table](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#queries) puts each of them next to the Prisma ORM 7 call it replaces. A row query calls your hooks in this order:

`beforeCompile` → `beforeQuery` → `interceptQuery` → `onRow` (once per row) → `afterQuery`

**A non-returning write** is a statement that reports how many rows it affected rather than returning them. On the ORM API those are `createAndCount`, `updateAndCount`, and `deleteAndCount`, and with the SQL query builder it is whatever you hand to `db.runtime().execute(plan)`. These run a shorter sequence:

`beforeCompile` → `beforeExecute` → `interceptExecute` → `afterExecute`

`beforeQuery` never runs for a non-returning write, and `beforeExecute` never runs for a row query, so a middleware that has to cover reads and writes both needs a hook in each sequence. In practice that means writing the check once and calling it from `beforeQuery` and from `beforeExecute`:

```ts title="src/prisma/no-delete-all.ts"
import type { SqlMiddleware } from '@prisma/orm-postgres/family-runtime';

export function noDeleteAll(): SqlMiddleware {
  const check = (sql: string) => {
    if (sql.startsWith('DELETE ') && !sql.includes(' WHERE ')) {
      throw new Error('blocked by policy');
    }
  };

  return {
    name: 'no-delete-all',
    familyId: 'sql',

    async beforeQuery(plan) {
      check(plan.sql);
    },
    async beforeExecute(plan) {
      check(plan.sql);
    },
  };
}
```

`lints` and `budgets` are built exactly that way.

<ConceptAnimation name="middleware-lifecycle" />

At each step Prisma ORM calls that hook on every middleware you registered, and it waits for each one to finish before the query moves on, so a hook can be `async` and a slow `afterQuery` delays the `await` in your own code.

### The order your middleware runs in [#the-order-your-middleware-runs-in]

Prisma ORM calls your middleware in the order you listed them in the `middleware` array, at every hook, so the middleware at index 0 goes first. If one middleware rewrites the query in `beforeCompile`, the one after it sees the rewritten version. The after-hooks follow that same order rather than unwinding in reverse, so the middleware at index 0 is also the first to log. Order decides who answers a query as well: when several middleware implement `interceptQuery`, the first one that returns rows wins and the rest are not called at all, and the same holds for `interceptExecute`.

### beforeCompile: rewrite the query [#beforecompile-rewrite-the-query]

Reach for `beforeCompile` when you want to change what a query asks for rather than only look at it. It runs on both kinds of query, and it hands you a draft with two fields: `meta`, facts about the query that you read but do not change, such as which API built it, and `ast`, the query as a tree of typed objects. The tree is the part you can change, because the SQL text has not been written yet. Return a copy of the draft with a changed `ast` and Prisma ORM runs your version instead, which is how you add a condition to queries without editing a single call site. Return `undefined` and the query goes through as written.

The middleware below adds a condition to every `SELECT` whose own `FROM` clause names the `User` table:

```ts title="src/prisma/scope-user-selects.ts"
import type { SqlMiddleware } from '@prisma/orm-postgres/family-runtime';
import { AndExpr, type BinaryExpr } from '@prisma/orm-postgres/relational-core/ast';

export function scopeUserSelects(condition: () => BinaryExpr | undefined): SqlMiddleware {
  return {
    name: 'scope-user-selects',
    familyId: 'sql',

    async beforeCompile(draft) {
      if (draft.ast.kind !== 'select') return undefined;
      if (draft.ast.from?.kind !== 'table-source') return undefined;
      if (draft.ast.from.name !== 'User') return undefined;
      const predicate = condition();
      if (predicate === undefined) return undefined;
      const where = draft.ast.where ? AndExpr.of([draft.ast.where, predicate]) : predicate;
      return { ...draft, ast: draft.ast.withWhere(where) };
    },
  };
}
```

The three checks above are how you say "only `SELECT`s, and only ones over the `User` table". `draft.ast.kind` is `'select'`, `'insert'`, `'update'`, `'delete'`, or `'raw-query'`, and `draft.ast.from.kind` is `'table-source'` when a `SELECT` reads a plain table rather than a subquery or a function. Use the table name as it is in your database rather than the model name in your contract. They are the same, `User`, unless the model sets `@@map`, in which case use the name it maps to. `withWhere` returns a new `SELECT` with that `WHERE` on it and leaves the original alone, which is why the hook returns a copy of the draft.

These checks read only the table in the query's own `FROM` clause, so `User` rows that a query loads with `.include(...)` or through a join are not filtered. Do not rely on a middleware like this alone to keep one tenant's rows away from another.

The function you pass in returns the comparison to add, or `undefined` to add none, and the middleware calls it for each `SELECT` whose `FROM` clause names `User`, after the three checks. You build the comparison yourself, and the types for building one come from `@prisma/orm-postgres/relational-core/ast`. A value you compare against needs its `codecId`, an id that says how the value is stored, such as `pg/text@1` for text and `pg/int4@1` for a 32-bit integer. [Authoring custom middleware](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware#rewrite-queries-with-beforecompile) lists the id for each field type:

```ts title="src/prisma/db.ts (excerpt)"
import { BinaryExpr, ColumnRef, ParamRef } from '@prisma/orm-postgres/relational-core/ast';
import { scopeUserSelects } from './scope-user-selects';

const onlyMia = BinaryExpr.eq(
  ColumnRef.of('User', 'name'),
  ParamRef.of('Mia', { codec: { codecId: 'pg/text@1' } }),
);
```

Then `scopeUserSelects(() => onlyMia)` goes in the `middleware` array of your `postgres(...)` client, like any other entry. [Rewrite queries with beforeCompile](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware#rewrite-queries-with-beforecompile) shows how the function can return a different value for each request, and covers the other comparisons and why a value has to go through `ParamRef.of`. `beforeCompile` is not available on MongoDB, because the tree it works on is made of SQL objects.

### beforeQuery and beforeExecute: validate or block [#beforequery-and-beforeexecute-validate-or-block]

These two hooks are where you inspect a query and refuse it. `beforeQuery` runs on a row query and `beforeExecute` on a non-returning write, both after the SQL text has been written out and before anything reaches the database. Your hook receives the plan, so you can read the SQL text in `plan.sql` and read the same query as objects in `plan.ast`, which is the tree `beforeCompile` works on. Throwing from the hook blocks the query, and returning normally lets it carry on to the database. The hook itself goes in the object your middleware returns, next to `name` and `familyId`:

```ts
async beforeQuery(plan) {
  if (isForbidden(plan)) throw new Error("blocked by policy");
}
```

This is where `lints` stops a `DELETE` without `WHERE`, and where `budgets` rejects a query that would read too many rows. Both of them assign one check to `beforeQuery` and to `beforeExecute`, the way `noDeleteAll` above does, so the check applies to reads and writes alike.

Every hook also receives a context object, `ctx`, which tells it about the query it is running inside. `ctx` is the argument after `plan`, or after `result` in the after-hooks. `ctx.planExecutionId` is the same string in every hook that runs for one query, so you can match a line your `beforeQuery` logged to the line your `afterQuery` logged. `ctx.scope` is `'transaction'` for a query inside `db.transaction(...)` and `'runtime'` for one you sent on `db` directly, so your middleware does see the queries you run in a transaction. [The context object](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware#the-context-object) lists every field it holds.

Either hook can also change the values the query sends to the database, and it does that through a third argument, `params`, which you declare as `beforeQuery(plan, ctx, params)` when you want it. `params.entries()` walks those values one at a time, and each entry has three fields:

* `entry.value` is the value itself.
* `entry.codecId` is the stored type, an id such as `pg/text@1`, `pg/int4@1`, or `pg/timestamptz-temporal@1`.
* `entry.ref` identifies that one value in the query, and it is what you pass to `replaceValue`.

Call `params.replaceValue(entry.ref, newValue)` and the database receives your value instead of the original. `params` is typed as optional and Prisma ORM always passes it, so the guard on the first line is there to satisfy TypeScript:

```ts
async beforeQuery(plan, ctx, params) {
  if (!params) return;
  for (const entry of params.entries()) {
    if (entry.codecId === 'pg/text@1' && typeof entry.value === 'string') {
      params.replaceValue(entry.ref, entry.value.trim());
    }
  }
},
```

Check `entry.codecId` before you call `replaceValue`, as the example does. Write the hook as `beforeQuery(plan)` instead and nothing about the values changes.

### interceptQuery and interceptExecute: answer without the database [#interceptquery-and-interceptexecute-answer-without-the-database]

These hooks let you answer a query yourself, so the database never sees it. Return `{ rows }` from `interceptQuery`, or `{ stats }` from `interceptExecute`, and that is what your caller gets back, but return `undefined` and the query carries on to the database as usual. The `stats` you return is the count that statement reports, for example `{ stats: { affectedRows: 0 } }`.

The rows you return are plain objects, keyed by the column aliases in the SQL, holding the values in the form the database driver hands them over: numbers for integers, strings for text and timestamps. A read that selects `id`, `email`, and `createdAt` produces rows like this one:

```ts
{ id: 3, email: 'mia+1@prisma.io', createdAt: '2026-09-17 08:00:08.775+00' }
```

So for a query whose SQL is `SELECT "User"."id" AS "id", "User"."email" AS "email" FROM "public"."User" LIMIT 5`, `return { rows: [{ id: 1, email: 'mia@prisma.io' }] }` is a complete answer to it. Prisma ORM converts the rows you return the same way it converts rows from the database. So if you return a `createdAt` as a string, a caller on the ORM API gets a `Temporal.Instant`, which is the type of a `DateTime` field.

Before-hooks still run on a query that an intercept hook answers, because every middleware's before-hooks run before any intercept hook, whatever order you list the middleware in. So in the setup at the top of this page, where the cache comes first in the array, `lints` still checks every query before the cache answers it.

### onRow: watch rows arrive [#onrow-watch-rows-arrive]

`onRow(row, plan, ctx)` lets you see each row of a result on its way to your code, and `row` is one of those plain row objects. Prisma ORM calls it once for every row as it reads the result, before your `await` on `.all()` or `.first()` resolves, so you can count rows, sample them, or throw to stop the query part way through. If you throw, your `await` rejects with that error and you get no rows at all, not the rows read so far. That is what `budgets` does when a query returns more rows than its `maxRows` budget allows. `onRow` does not run on a non-returning write, and it does not run for rows that an `interceptQuery` hook answered.

### afterQuery and afterExecute: observe the finished operation [#afterquery-and-afterexecute-observe-the-finished-operation]

These two hooks are for recording what happened once the work is over. Prisma ORM calls them once at the end of the operation, whether it succeeded or failed.

After a row query, `afterQuery` receives `result.rowCount`, how many rows came back, and `result.latencyMs`, how long the query took. `result.completed` is `true` when the query finished and `false` when it failed, and `result.source` is `'driver'` for a query the database answered and `'middleware'` when an `interceptQuery` answered it, so you can tell where the rows came from.

After a non-returning write, `afterExecute` receives the same `result.completed`, `result.latencyMs`, and `result.source`, and on a run that completed it also gets the number of rows the statement changed, in `result.stats.affectedRows`. There is no `result.rowCount` on this one, and there is no `result.stats` on a write that failed, so read the count only when `result.completed` is `true`.

Timing, logging, and latency budgets all belong in these two hooks.

## What ships built in [#what-ships-built-in]

`@prisma/orm-postgres` already contains [lints](https://www.prisma.io/docs/orm/middleware/built-in-lints), which blocks risky query shapes, and [budgets](https://www.prisma.io/docs/orm/middleware/built-in-budgets), which caps row counts and reports slow queries, so you can register either one without installing anything else. Middleware that ships as its own package is an extension like any other, and the [extension directory](https://www.prisma.io/extensions) lists those, including middleware written by the community:

| Name                                                                  | What it adds                                                                   | Package                                  | Databases           | By     |
| --------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ---------------------------------------- | ------------------- | ------ |
| [Cache middleware](https://www.prisma.io/extensions/middleware-cache) | Serve repeated reads from an in-memory or pluggable cache, opted in per query. | `@prisma/orm-extension-middleware-cache` | PostgreSQL, MongoDB | Prisma |

"Opted in per query" in that row means nothing is cached until you say so on one particular read, which you do by attaching `cacheAnnotation({ ttl: 60_000 })` to it, where `ttl` is how many milliseconds its rows stay usable. On the ORM API the annotation goes in a callback you pass after the arguments. That callback receives a `meta` object whose `annotate` method attaches the annotation to that one call:

```ts title="src/prisma/get-user-cached.ts"
import { cacheAnnotation } from '@prisma/orm-extension-middleware-cache';
import { db } from './db';

export async function getUserCached(id: number) {
  return db.orm.public.User.first({ id }, (meta) =>
    meta.annotate(cacheAnnotation({ ttl: 60_000 })),
  );
}
```

[Opt a query in](https://www.prisma.io/docs/orm/middleware/built-in-cache#opt-a-query-in) shows the same annotation on a query you built with the SQL query builder.

If none of them do what you need, the [authoring guide](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware) builds a working query logger step by step. Once your own middleware is on npm, [submit it to the directory](https://www.prisma.io/extensions/submit) so other Prisma ORM users can find it.

## Which databases a middleware runs on [#which-databases-a-middleware-runs-on]

Prisma ORM sorts the databases it supports into two families, SQL and MongoDB, and a middleware cannot always work on both. The `familyId` key next to `name` is where a middleware says which family it was written for, and a middleware that leaves `familyId` out runs on either.

* `budgets` and `lints` declare `familyId: 'sql'`. They register on PostgreSQL and are rejected on MongoDB.
* The cache declares no `familyId`. It never reads SQL, so it runs on PostgreSQL and on MongoDB.

If you register a middleware against a database it was not written for, that client throws at its first query (or at `connect()`, if you call it), before anything reaches the database. The error's `code` is `RUNTIME.MIDDLEWARE_FAMILY_MISMATCH`.

A middleware of your own that leaves `familyId` out can still be typed as `SqlMiddleware`, as long as you only ever register it on `postgres(...)`. To write one object that you register on a `postgres(...)` client and a `mongo(...)` client both, type it as `CrossFamilyMiddleware` instead, which you import from `@prisma/orm-postgres/components/runtime`.

## When a middleware or the driver throws [#when-a-middleware-or-the-driver-throws]

When your hook throws from `beforeCompile`, `beforeQuery`, `beforeExecute`, `interceptQuery`, or `interceptExecute`, the whole operation fails before anything reaches the database, and your caller gets the error you threw. A throw from `onRow` also fails the operation, but by then the query has run: your caller gets your error and none of the rows, including the ones already read. Your own middleware can throw whatever error you like, as `noDeleteAll` throws a plain `Error`. `lints` and `budgets` throw an ordinary `Error` with a `code` property on it, so you catch them like any other error and read `code` to tell them apart. `budgets` throws two codes, `BUDGET.ROWS_EXCEEDED` and `BUDGET.TIME_EXCEEDED`, and the [lints](https://www.prisma.io/docs/orm/middleware/built-in-lints) page lists the codes `lints` throws.

When the database driver is the thing that fails, Prisma ORM still calls `afterQuery` on every middleware, or `afterExecute` after a non-returning write, with `result.completed` set to `false`, so your logging sees failed queries as well as successful ones. A throw from `afterQuery` or `afterExecute` while it is handling a failure cannot hide the real error: your caller still gets the failure the driver reported.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` install [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. Prompts that work for middleware:

* "Register the lints and budgets middleware on our Prisma ORM client with a 10k row budget."
* "Add the cache middleware and opt the dashboard queries in with a 60 second time to live."
* "Write a middleware that logs every query slower than 250ms."

## See also [#see-also]

* [Authoring custom middleware](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware): build and test a query logger step by step
* [Writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data): the mutations that lints and budgets guard
* [Built-in: budgets](https://www.prisma.io/docs/orm/middleware/built-in-budgets), [Built-in: lints](https://www.prisma.io/docs/orm/middleware/built-in-lints), [Built-in: cache](https://www.prisma.io/docs/orm/middleware/built-in-cache)
* [Using extensions](https://www.prisma.io/docs/orm/extensions/using-extensions) for adding database features rather than wrapping queries

## Related pages

- [`Authoring custom middleware`](https://www.prisma.io/docs/orm/middleware/authoring-custom-middleware): Build, register, and run your own Prisma ORM middleware, step by step, starting with a query logger.
- [`Built-in: budgets`](https://www.prisma.io/docs/orm/middleware/built-in-budgets): The budgets middleware caps row counts and reports queries that took too long.
- [`Built-in: cache`](https://www.prisma.io/docs/orm/middleware/built-in-cache): The cache middleware serves repeated reads from an in-memory store, opted in per query with a cache annotation.
- [`Built-in: lints`](https://www.prisma.io/docs/orm/middleware/built-in-lints): The lints middleware inspects each query's structure before it runs and blocks or warns on risky shapes.

# Applying a migration (/docs/orm/migrations/applying-a-migration)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The db migrate command applies the migrations you planned, until your database matches your contract, with a preview, checks on every operation, and safe re-runs.

Location: ORM > Migrations > Applying a migration

Once you have planned migrations with `npx prisma migration plan`, `npx prisma db migrate` is the command that runs them against a database, until that database matches your contract. It replaces Prisma ORM 7's [`prisma migrate deploy`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#commands), and works on the [supported databases](https://www.prisma.io/docs/orm/supported-databases), PostgreSQL and MongoDB, with SQLite still experimental.

  

#### bun

```bash
bunx prisma db migrate
```

#### pnpm

```bash
pnpm prisma db migrate
```

#### yarn

```bash
yarn prisma db migrate
```

#### npm

```bash
npx prisma db migrate
```

Prisma ORM decides what to run by comparing two records: the contract you want, and the contract state the database has. Each version of your contract, the `contract.prisma` file, is a **contract state**, and the database itself stores a [**marker**](https://www.prisma.io/docs/orm/migrations/the-migration-graph#terms-used-on-this-page), which is the record of which contract state that database matches. So when you run `db migrate`, it reads the marker to find the contract state the database already matches, and then runs the migrations from that state to the contract you last emitted with [`npx prisma contract emit`](https://www.prisma.io/docs/cli/contract-emit).

`migration status`, `migration log`, and the `db` commands connect to a database using `db.connection` in `prisma.config.ts`, as [The data contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) shows. When you want to work against a different database, production rather than your own machine for example, pass `--db` with that database's connection string, as in `--db "$PRODUCTION_DATABASE_URL"`.

When a run succeeds, it shows you what it did: each migration's operations, and then the marker it wrote:

```text
✔ Applied 1 migration(s) (3 operation(s)) across 1 contract space(s)

App space
├─ Add column "displayName" to "user"
├─ Data transform: backfill-user-displayName
├─ ⚠ Set NOT NULL on "user"."displayName"
└─ marker 866ab885a8a4bd8d9f5adc47784c068be7895a7182c55cc29f9f9967d3019484

⚠ This migration contains destructive operations that may cause data loss.
```

Each `├─` line under `App space` is an operation, one step of an app migration. A data transform changes existing rows, here filling in `displayName`, and you write its queries in `migration.ts`, as [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) shows. A `⚠` marks a [destructive](https://www.prisma.io/docs/orm/migrations/how-migrations-work#every-operation-checks-itself) operation, one that removes or changes something that already exists, such as setting `NOT NULL`, which deletes no rows but still counts. `db migrate` applies destructive operations without stopping to ask you, so the time to catch one is while you are reviewing the migration: run `npx prisma migration show <dir>` with the migration's directory name in `migrations/app/`.

## Check before, preview, then apply [#check-before-preview-then-apply]

Before you apply migrations to staging or production, run the following commands in order, so that you check the migration files, then see what would run, and only then run it:

  

#### bun

```bash
# 1. Were any migration files edited by hand or deleted? Needs no database.
bunx prisma migration check

# 2. Which migrations would run?
bunx prisma db migrate --show --db "$PRODUCTION_DATABASE_URL"

# 3. Run them.
bunx prisma db migrate --db "$PRODUCTION_DATABASE_URL"
```

#### pnpm

```bash
# 1. Were any migration files edited by hand or deleted? Needs no database.
pnpm prisma migration check

# 2. Which migrations would run?
pnpm prisma db migrate --show --db "$PRODUCTION_DATABASE_URL"

# 3. Run them.
pnpm prisma db migrate --db "$PRODUCTION_DATABASE_URL"
```

#### yarn

```bash
# 1. Were any migration files edited by hand or deleted? Needs no database.
yarn prisma migration check

# 2. Which migrations would run?
yarn prisma db migrate --show --db "$PRODUCTION_DATABASE_URL"

# 3. Run them.
yarn prisma db migrate --db "$PRODUCTION_DATABASE_URL"
```

#### npm

```bash
# 1. Were any migration files edited by hand or deleted? Needs no database.
npx prisma migration check

# 2. Which migrations would run?
npx prisma db migrate --show --db "$PRODUCTION_DATABASE_URL"

# 3. Run them.
npx prisma db migrate --db "$PRODUCTION_DATABASE_URL"
```

The examples in the rest of this section use a project with two migrations, `init` and `add_user_phone`, where the production database has applied only `init`.

`npx prisma migration status --db "$PRODUCTION_DATABASE_URL"` never changes the database, so you can run it against production whenever you want to know which contract state that database matches. It draws your migration history, marks each migration as applied or pending, and shows which contract state the database matches:

```text
○   967cb9f  @contract
│↑  20260707T1006_add_user_phone  2d2cec8 → 967cb9f  1 ops  ⧗ pending
○   2d2cec8  @db (db)
│↑  20260707T1005_init                  ∅ → 2d2cec8  2 ops  ✓ applied
○   ∅
```

Read the diagram from the bottom up, because it starts with an empty database and ends with the contract you last emitted: `∅` is an empty database, each `○` line is a contract state shown by the first 7 characters of its hash, and each `│↑` line is a migration from the state below it to the one above. You never have to type a whole hash when you name one of these states, because commands accept any prefix of 6 or more characters that matches one hash. The labels on the right say what points at each state:

* `@contract` is the contract you last emitted.
* `@db` is the contract state the database's marker records.
* `(db)` is the `db` [ref](https://www.prisma.io/docs/orm/migrations/the-migration-graph#name-important-states-with-refs), a file in `migrations/app/refs/` that names the contract state you last applied in development.

When migrations are pending, `migration status` also prints a `db migrate --to <hash>` command that you can copy, and if that hash is your `@contract` state you can leave `--to` off, because that is the state `db migrate` runs to anyway.

`db migrate --show` is the preview, and it changes nothing: it draws the same history, marks each migration it would apply with `will run`, and lists them in the order they would run:

```text
○   967cb9f  @contract
│↑  20260707T1006_add_user_phone  2d2cec8 → 967cb9f  ↑ will run
○   2d2cec8  @db (db)
│↑  20260707T1005_init                  ∅ → 2d2cec8
○   ∅

ℹ The following 1 migration will run:

  20260707T1006_add_user_phone  2d2cec8 → 967cb9f
```

`--show` tells you which migrations will run, but not what is inside them, so when you want one migration's operations and its SQL, run `npx prisma migration show 20260707T1006_add_user_phone` instead, as [Reviewing what you planned](https://www.prisma.io/docs/orm/migrations/generating-a-migration#reviewing-what-you-planned) shows.

After applying, `npx prisma migration log --db "$PRODUCTION_DATABASE_URL"` shows you what that database has actually had applied to it, rather than what your local files say: it prints the **ledger**, the database's own list of every migration applied to it. Like `--show`, it changes nothing:

```text
Applied at                  Migration                     Change             Ops
2026-07-07 10:05:32 +00:00  20260707T1005_init            ∅ → 2d2cec8        2 ops
2026-07-07 10:09:55 +00:00  20260707T1006_add_user_phone  2d2cec8 → 967cb9f  1 ops
```

In a pipeline, nobody reads the preview, so the job is step 3 alone, with `--to <ref>` so it applies only the migrations someone has pointed the ref at; [Choosing a target](#choosing-a-target) explains refs. `db migrate` checks the marker before it runs anything and fails with `MIGRATION.MARKER_MISMATCH` when the marker names a state outside your history, and [Drift](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery#drift-when-the-database-isnt-where-migrations-left-it) says what to do then. [Migrate a shared database from a workflow](https://www.prisma.io/docs/guides/integrations/github-actions#migrate-a-shared-database) shows the job.

## Choosing a target [#choosing-a-target]

By default `db migrate` runs everything that is pending, so when you want to stop part way, name the contract state you want to stop at with `--to`. The example below uses `prod`, a [ref](https://www.prisma.io/docs/orm/migrations/the-migration-graph#name-important-states-with-refs) created with `npx prisma migration ref set prod <dir>`, which points `prod` at the state after that migration:

  

#### bun

```bash
bunx prisma db migrate --to prod --db "$PRODUCTION_DATABASE_URL"
```

#### pnpm

```bash
pnpm prisma db migrate --to prod --db "$PRODUCTION_DATABASE_URL"
```

#### yarn

```bash
yarn prisma db migrate --to prod --db "$PRODUCTION_DATABASE_URL"
```

#### npm

```bash
npx prisma db migrate --to prod --db "$PRODUCTION_DATABASE_URL"
```

When the state you want is an earlier one than the database already matches, plan a rollback migration first, as [Rollbacks and recovery](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery) shows, because `db migrate` only ever runs migrations you already have. That is also why, if no migrations lead from the state the database matches to the one you name, the run fails with an error whose `code` is `MIGRATION.PATH_UNREACHABLE`. The [`db migrate` reference](https://www.prisma.io/docs/cli/db-migrate#options) lists every form of `--to` and the other options.

## When something goes wrong [#when-something-goes-wrong]

When an operation fails, `db migrate` stops and prints what failed and why:

```text
✘ [MIGRATION.RUNNER_FAILED] Operation pgvector.install-vector-extension failed during execution: create extension "vector"
  why: extension "vector" is not available
  docs: https://docs.prisma.io/docs/orm/v8/reference/error-reference/MIGRATION.RUNNER_FAILED
```

Here, an operation from the pgvector [extension package](#extension-spaces) failed because the `vector` PostgreSQL extension is not available on the database server. Install it there, or enable it in your database host's settings, and then run `db migrate` again.

On PostgreSQL you can do that without any tidying up first, because a failed run leaves no changes in the database at all. The whole run is one transaction, so everything the failed run did is rolled back, while migrations applied in *earlier* runs stay applied. The error itself tells you where it stopped, because it names the operation and the failing step, which is either the SQL statement or a [check before or after it](https://www.prisma.io/docs/orm/migrations/how-migrations-work#every-operation-checks-itself), such as the check that no row still holds `NULL` before a column becomes `NOT NULL`. And when you fix the problem and run the command again, it does not repeat work that is already done, because `db migrate` skips each operation whose change is already in the database, unless the operation has no postcheck.

MongoDB does not give you that clean slate, because a run there is not one transaction. Operations that finished before the failure stay in the database, and a re-run stops at the precheck of any collection the failed run already created.

`db migrate` also refuses to start when the marker records a contract state that none of your migrations starts or ends at, because it cannot then work out which migrations to run. It fails with an error whose `code` is `MIGRATION.MARKER_MISMATCH`, and no operation runs. You see this when the database's contract state was set by something other than the migrations you have on disk, which happens in the following situations:

* **`npx prisma db update`**, which replaces `prisma db push` for local development and preview environments. Plan your next migration with `--from` so that it starts at the migration you last applied, as [Drift](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery#drift-when-the-database-isnt-where-migrations-left-it) shows.
* **A migration from a Git branch you have not merged**, which a shared database such as staging already applied. Merge that branch so that you have the migration too, and if your branch also added migrations, plan one migration from the state that database matches, as [A worked example](https://www.prisma.io/docs/orm/migrations/the-migration-graph#a-worked-example) shows.

A database that already had tables gets its marker from `npx prisma db sign`, so `db migrate` refuses to run against it until a migration in your history ends at the signed state, as [The automatic baseline](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-automatic-baseline) shows. For a database Prisma ORM 7 migrated, follow [Transfer migration ownership](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#4-transfer-migration-ownership) in the upgrade guide.

## Development vs. production [#development-vs-production]

The command is the same everywhere, and what changes is the work you do around it.

**In development**, you emit the contract, plan a migration, review it, and then apply it:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name my_change
# Review the new migration directory before you apply it.
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name my_change
# Review the new migration directory before you apply it.
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name my_change
# Review the new migration directory before you apply it.
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name my_change
# Review the new migration directory before you apply it.
npx prisma db migrate --advance-ref db
```

In development, add `--advance-ref db` so the next `migration plan` starts from what you just applied, and leave the flag off in CI and production, where you never plan a migration anyway. [The db ref](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-db-ref-skipping---from) covers what happens without it and how to fix a missed flag. If you edit `migration.ts` while reviewing the migration, recompile it with `node migrations/app/<dir>/migration.ts` before you apply, as [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) explains.

**In CI and production**, you never plan a migration, because migrations arrive through your repository, already reviewed and merged. For that to work, commit the whole `migrations/` directory and your contract files, which means:

* each migration's directory under `migrations/app/`
* the refs in `migrations/app/refs/`, such as `prod.json`, which `db migrate --to prod` reads
* the copies of your contract that `migration plan` saved under `migrations/snapshots/`, one directory per contract state
* one directory per [extension package](#extension-spaces) that ships migrations, such as `migrations/pgvector/`
* `contract.prisma`, `contract.json`, and `contract.d.ts`

When you deploy by hand, run the three commands in [Check before, preview, then apply](#check-before-preview-then-apply). The point of the `migration check` step is to tell you that what you are about to apply is still what was reviewed. In a pipeline, the deploy job runs only the last of them, `db migrate` with `--to <ref>`, which that section explains. That one command is all the pipeline needs, because `db migrate` refuses to run when a migration's `ops.json` or `migration.json` no longer matches the hash recorded for it.

Each migration's `migration.json` records a hash, `migrationHash`, computed from the rest of `migration.json` and from `ops.json`. If either file changes after the hash was recorded, for example because you edited it by hand, `migration check` fails with an error whose `code` is `MIGRATION.CHECK_HASH_MISMATCH`, as [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) explains. To fix it, either restore the migration's files from Git, or move the hand edit into `migration.ts` and recompile with `node migrations/app/<dir>/migration.ts`.

One case needs a different fix. If the error comes back right after you recompile, and the migration's backfill updates a model with a `temporal.updatedAtString()` column, recompiling cannot fix it. [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration#worked-example-making-a-column-required) shows how to write that backfill instead.

When a contract snapshot under `migrations/snapshots/` no longer matches the hash in its directory name, `migration check` fails with an error whose `code` is `MIGRATION.CHECK_SNAPSHOT_CONTENT_MISMATCH`. Other commands that read that snapshot, such as `migration plan --from <that state>` or `migration ref set prod <that state>`, fail with a different code, `MIGRATION.CONTRACT_SNAPSHOT_CONTENT_MISMATCH`. Recompiling `migration.ts` fixes neither error, so restore the edited snapshot from Git. MongoDB snapshots are not checked yet.

If two deployments can run at once, what happens next depends on your database. On PostgreSQL, when two `db migrate` runs start against the same database, one of them waits for the other. On MongoDB, if another run updates the marker while yours is running, yours fails with `Marker was modified by another process during migration execution.` When that happens, run `npx prisma migration status` to see which contract state the database matches, and then run `db migrate` again.

## Extension spaces [#extension-spaces]

If your project uses a [Prisma ORM extension package](https://www.prisma.io/docs/orm/extensions/using-extensions), such as pgvector support, the output shows more than one **contract space**, which is a separate migration history: your app has one, and so does each extension package that ships migrations. `migration plan` writes an extension's migrations to `migrations/<space>/`, such as `migrations/pgvector/`, and you have to commit that directory, because `db migrate` fails without it. A single run applies every space and reports each one separately, while `--to` applies only to your app. What an extension space ends up matching is decided by what you committed rather than by what is in `node_modules`, because `db migrate` applies the migrations in that committed directory until the database matches the newest state there, not the package version you have installed:

```text
✔ Applied 2 migration(s) (20 operation(s)) across 2 contract space(s)

Extension space: pgvector
├─ Enable extension "vector"
└─ marker 3d2c56a2944685bd21b05bc8a8d73164397df51c014201902932fbe7e80ff1b8
App space
├─ Create table "user"
└─ ...
```

> [!NOTE]
> What's early
> 
> Applying, targeting, previewing, refs, the ledger, and applying several contract spaces in one run all work today. Not built yet: a rehearsal that applies migrations to a throwaway copy of the database first, and a check at apply time that `ops.json` still matches `migration.ts`. Until then, preview with `--show` and rehearse on a staging database.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. In an existing project, run `npx prisma skills sync`. Ask your agent to:

* "Check migration status against staging and apply whatever is pending."
* "List what `db migrate --to prod` would run, then run `migration show` on each migration and summarize the destructive operations."
* "Apply the pending migrations and advance the `db` ref."

## See also [#see-also]

* [Rollbacks and recovery](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery): when the database needs an earlier contract state
* [The migration graph](https://www.prisma.io/docs/orm/migrations/the-migration-graph): markers, refs, and how migrations connect
* [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration): producing what `db migrate` runs
* [Studio with Prisma ORM](https://www.prisma.io/docs/studio/prisma-next): read the ledger as a visual timeline, with the executed SQL and a schema diff per migration

## Related pages

- [`Editing a migration`](https://www.prisma.io/docs/orm/migrations/editing-a-migration): A migration is TypeScript you own. Fill in backfills, reorder steps, or write raw SQL, then recompile it with one command.
- [`Generating a migration`](https://www.prisma.io/docs/orm/migrations/generating-a-migration): Turn a change to your contract into a migration you can review, with the migration plan command.
- [`How migrations work`](https://www.prisma.io/docs/orm/migrations/how-migrations-work): Change your contract, plan a migration, review it, apply it. Operations can check the database before and after they run.
- [`Rollbacks and recovery`](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery): Rolling back is one more migration that makes the database match an earlier contract state. Recovery is fixing a failed migration and running it again.
- [`The migration graph`](https://www.prisma.io/docs/orm/migrations/the-migration-graph): You and a teammate each changed your Prisma contract on separate branches. The migration graph is how Prisma ORM applies both changes to every database after the branches merge.

# Editing a migration (/docs/orm/migrations/editing-a-migration)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A migration is TypeScript you own. Fill in backfills, reorder steps, or write raw SQL, then recompile it with one command.

Location: ORM > Migrations > Editing a migration

Each of your app's migrations is a directory in `migrations/app/`, and the file you edit inside it is `migration.ts`, a TypeScript file that describes the change as a list of calls such as `this.addColumn(...)`. `npx prisma migration plan` writes the first draft of that file for you, but it can only work out the parts that follow from your contract. The decisions that depend on your data are left to you: what value existing rows should get, which order the steps should run in, and how to write a statement that has no method of its own.

The file that actually runs against your database is not the one you edit. `npx prisma db migrate`, which replaces [`prisma migrate deploy`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7), runs the SQL in each migration's `ops.json`, and fixing that SQL by hand does not work, because Prisma ORM notices: `npx prisma migration check` fails and `npx prisma db migrate` refuses to run. Edit `migration.ts` instead and then recompile it, which means running the file itself with Node.js from your project root. Recompiling rewrites both `ops.json` and `migration.json` for you, and never connects to a database:

```bash
node migrations/app/20260707T1008_add_display_name/migration.ts
```

```text
Wrote ops.json + migration.json to /path/to/my-app/migrations/app/20260707T1008_add_display_name
```

You can run the file like this because the Prisma ORM CLI already needs Node.js 22.18 or later, and those versions run `migration.ts` directly, with no build step. Run it from your project root: if you change into the migration directory first and run it from there, the command fails with an error whose `code` is `CONFIG.FILE_NOT_FOUND`.

The other file recompiling rewrites, `migration.json`, is what makes a hand-edit detectable. It records the contract state the migration starts `from`, the state it ends at, `to`, and a hash of the migration. `npx prisma migration check` recomputes that hash from `ops.json` and `migration.json` and compares it with the stored one, so any change to either file that did not come from a recompile no longer matches. The check never reads `migration.ts`, which is why an edit you make there counts for nothing until you recompile.

Editing a migration only changes what happens on databases that have not applied it yet, because a database that already applied it will not apply it again. When you need to change a database that has already applied the migration, plan a new migration for the change instead. When you only want to try your edit against a development database that already applied it, drop and recreate that database with your own tools, because Prisma ORM 8 has no replacement for `prisma migrate reset`. Then run `npx prisma db migrate --advance-ref db`, which points the [`db` ref](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-db-ref-skipping---from), a name for a contract state stored as a file in `migrations/app/refs/`, at what you just applied, so the next `migration plan` starts from there.

## Worked example: making a column required [#worked-example-making-a-column-required]

Say you add a required `displayName` field to `User` in your contract, the `contract.prisma` file that replaced `schema.prisma`. The rows already in your `user` table have no `displayName`, so you have to decide what those rows get. Start by running `npx prisma contract emit`, which replaces `prisma generate` and writes `contract.json` and `contract.d.ts`, and then plan the migration as [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-second-migration-planning-a-delta) describes:

  

#### bun

```bash
bunx prisma migration plan --name add_display_name
```

#### pnpm

```bash
pnpm prisma migration plan --name add_display_name
```

#### yarn

```bash
yarn prisma migration plan --name add_display_name
```

#### npm

```bash
npx prisma migration plan --name add_display_name
```

```text
⚠ Planned migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit

from:       967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4
to:         866ab885a8a4bd8d9f5adc47784c068be7895a7182c55cc29f9f9967d3019484
app space:  migrations/app/20260707T1008_add_display_name
```

In that output, `self-emit` is what the CLI calls recompiling, and `app space` is the directory the new migration was written to. The output says `node migration.ts`, but run the file from your project root, as `node migrations/app/<dir>/migration.ts`, for the reason given above. `migration plan` writes the change as three steps rather than one, because rows that already exist need a value for the new required column: `addColumn` adds the column as nullable, `dataTransform` holds the backfill you write, and `setNotNull` makes the column required:

```ts title="migration.ts (as planned)"
override get operations() {
  return [
    this.addColumn({
      schema: 'public',
      table: 'user',
      column: col('displayName', 'text', { codecRef: { codecId: 'pg/text@1' } }),
    }),
    this.dataTransform(endContract, 'backfill-user-displayName', {
      check: () => placeholder('backfill-user-displayName:check'),
      run: () => placeholder('backfill-user-displayName:run'),
    }),
    this.setNotNull({ schema: 'public', table: 'user', column: 'displayName' }),
  ];
}
```

The table is called `user` because the contract from [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration#your-first-migration) maps `User` to it with `@@map("user")`. Without `@@map`, the table name is the model name exactly as written, so it would be `User`.

A `dataTransform` is where you say what should happen to the rows already in the table, and it takes two callbacks. Each one returns a query built with the [`sql` query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder), not a SQL string. `check` returns the rows that still need the backfill, which is how Prisma ORM tells whether there is any work left to do, and `run` is the query that changes them. Inside each `where`, `f` holds the table's columns and `fns` holds [functions](https://www.prisma.io/docs/orm/reference/sql-query-builder#expressions-and-functions) such as `eq`, which is why `fns.eq(f.displayName, null)` becomes `IS NULL`. When you want to set a column from another column, pass [`update()`](https://www.prisma.io/docs/orm/reference/sql-query-builder#update) a callback instead of a plain object: `update((f) => ({ displayName: f.email }))`. The imports at the top of the file below come from snapshots, which are copies of your contract that `migration plan` saves in `migrations/snapshots/<hash>/`, and this migration imports the snapshot from before it and the one from after it, so the queries you write are typed against the contract you mean.

```ts title="migration.ts (filled in)"
#!/usr/bin/env -S node
import type { Contract as End } from '../../snapshots/866ab885a8a4bd8d9f5adc47784c068be7895a7182c55cc29f9f9967d3019484/contract';
import endContractJson from '../../snapshots/866ab885a8a4bd8d9f5adc47784c068be7895a7182c55cc29f9f9967d3019484/contract.json' with { type: 'json' };
import type { Contract as Start } from '../../snapshots/967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4/contract';
import startContractJson from '../../snapshots/967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4/contract.json' with { type: 'json' };
import { Migration, MigrationCLI, col } from '@prisma/orm-postgres/migration';
import postgresAdapter from '@prisma/orm-postgres/adapter/runtime';
import { sql } from '@prisma/orm-postgres/builder/runtime';
import { createExecutionContext, createSqlExecutionStack } from '@prisma/orm-postgres/family-runtime';
import postgresTarget, { PostgresContractSerializer } from '@prisma/orm-postgres/target/runtime';

const endContract = new PostgresContractSerializer().deserializeContract<End>(endContractJson);
const stack = createSqlExecutionStack({ target: postgresTarget, adapter: postgresAdapter });

const db = sql<End>({
  context: createExecutionContext({ contract: endContract, stack }),
  rawCodecInferer: stack.adapter.rawCodecInferer,
});

export default class M extends Migration<Start, End> {
  override readonly endContractJson = endContractJson;
  override readonly startContractJson = startContractJson;

  override get operations() {
    return [
      this.addColumn({
        schema: 'public',
        table: 'user',
        column: col('displayName', 'text', { codecRef: { codecId: 'pg/text@1' } }),
      }),
      this.dataTransform(endContract, 'backfill-user-displayName', {
        check: () =>
          db.public.user
            .select('id')
            .where((f, fns) => fns.eq(f.displayName, null))
            .limit(1),
        run: () =>
          db.public.user
            .update({ displayName: 'Anonymous' })
            .where((f, fns) => fns.eq(f.displayName, null)),
      }),
      this.setNotNull({ schema: 'public', table: 'user', column: 'displayName' }),
    ];
  }
}

MigrationCLI.run(import.meta.url, M);
```

If you compare that with the file `migration plan` wrote, the differences are all things you add or rename. The planned file's migration import also brings in `placeholder`, and it does not have the four other `@prisma/orm-postgres` imports or the `endContract`, `stack`, and `db` statements, which only build queries and never connect to a database, so you write those in yourself. The planned file also names its snapshot `contract.json` imports `endContract` and `startContract`, renamed here to `endContractJson` and `startContractJson` so that the name `endContract` is free for the deserialized contract. The only other thing you touch is the `placeholder(...)` calls, which become your `check` and `run` queries. The rest of each operation, such as `codecRef`, stays exactly as `migration plan` wrote it.

Now recompile the file with `node migrations/app/20260707T1008_add_display_name/migration.ts`. If you left a `placeholder(...)` call in it, recompiling fails with an error whose `code` is `MIGRATION.UNFILLED_PLACEHOLDER`, and `npx prisma db migrate` fails as well, because `ops.json` is still empty. Once it recompiles, read the `UPDATE` it produced in `ops.json` and check that it sets the value you meant on the rows you meant:

```json title="ops.json (the compiled dataTransform)"
{
  "id": "data_migration.backfill-user-displayName",
  "label": "Data transform: backfill-user-displayName",
  "operationClass": "data",
  "target": { "id": "postgres" },
  "precheck": [
    {
      "description": "Check backfill-user-displayName has work to do",
      "sql": "SELECT EXISTS (SELECT \"id\" AS \"id\" FROM \"public\".\"user\" WHERE \"displayName\" IS NULL LIMIT 1) AS ok",
      "params": []
    }
  ],
  "execute": [
    {
      "description": "Run backfill-user-displayName",
      "sql": "UPDATE \"public\".\"user\" SET \"displayName\" = $1 WHERE \"displayName\" IS NULL",
      "params": ["Anonymous"]
    }
  ],
  "postcheck": [
    {
      "description": "Verify backfill-user-displayName resolved all violations",
      "sql": "SELECT NOT EXISTS (SELECT \"id\" AS \"id\" FROM \"public\".\"user\" WHERE \"displayName\" IS NULL LIMIT 1) AS ok",
      "params": []
    }
  ]
}
```

There is one case where a correct-looking backfill still leaves you stuck, and it involves timestamps that Prisma ORM fills in for you. A column declared as `temporal.updatedAtString()` gets the current time whenever a row is created or updated, the way `@updatedAt` did in Prisma ORM 7. The `User` in this example has no such column, but the starter contract from `npx prisma orm init` does have one, called `updatedAt`. On a model like that, your backfill's `update` also sets `updatedAt`, and that is enough to make `npx prisma migration check` fail right after every recompile with an error whose `code` is `MIGRATION.CHECK_HASH_MISMATCH`, so `npx prisma db migrate` refuses to run.

The way out is to write the backfill against a contract of your own rather than the real one. Build `db` from an intermediate contract and pass that same contract to `dataTransform`, which the next section works through in full. In that contract, make `displayName` optional and declare `updatedAt` as `TimestamptzString`, a type Prisma ORM does not set for you, so the backfill leaves that column alone.

## When a backfill reads a column the migration removes [#when-a-backfill-reads-a-column-the-migration-removes]

Sooner or later a backfill has to read a column that the same migration takes away. Suppose the next migration replaces the boolean `isAdmin` on `User` with a required text column, `role`. Change your contract, run `npx prisma contract emit`, and plan the migration with `npx prisma migration plan --name replace_is_admin`. The examples below use the directory that command printed, `migrations/app/20260708T0900_replace_is_admin`, and yours has a different timestamp. The backfill reads `isAdmin` to decide each row's `role`, and that is where the trouble starts, because the end contract has no `isAdmin` and the start contract has no `role`. If you build `db` from the end contract, TypeScript rejects `f.isAdmin`, and recompiling fails with an error that does not name the column, so the cause is hard to spot.

What you need instead is a contract that describes the database as it is while the backfill runs, and you write that one yourself. Copy your whole contract into the migration directory as `intermediate.prisma`, then in its `User` model add `isAdmin` back and make `role` optional, because at that point no row has a `role` yet.

```prisma title="intermediate.prisma (User, other fields left out)"
// use prisma-8

model User {
  id          Int     @id
  displayName String
  isAdmin     Boolean
  role        String?

  @@map("user")
}
```

Keep `// use prisma-8` as the first line of the copy. `contract emit` skips any `.prisma` file that does not start with it, and because `intermediate.prisma` is the only file in the intermediate contract, emitting it without that line fails with an error whose `code` is `CONTRACT.SOURCE_LOAD_FAILED`.

In the same migration directory, add `intermediate.config.ts`, a second config file whose `contract` is `intermediate.prisma`. It needs no `db.connection`, because emitting a contract never connects to a database. If your contract uses an extension package, such as pgvector, add the same `extensions` array here as in your project's `prisma.config.ts`, such as `extensions: [pgvector]` inside `ormConfig({ ... })`, because this file does not take it from there:

```ts title="intermediate.config.ts"
import { definePrismaConfig } from 'prisma/config';
import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';
export default definePrismaConfig({ orm: ormConfig({ contract: './intermediate.prisma' }) });
```

Emit the intermediate contract with `--config` pointing at that file. Run this from your project root, because the `--config` path starts there. The `./intermediate.prisma` path inside the config resolves from the directory the config file is in, so it names the copy in the migration directory:

```bash
npx prisma contract emit --config migrations/app/20260708T0900_replace_is_admin/intermediate.config.ts
```

The command writes `intermediate.json` and `intermediate.d.ts` next to `intermediate.prisma`, so the migration directory now holds four `intermediate.*` files. Commit all four along with the migration, because the migration no longer recompiles without them:

```text title="migrations/app/20260708T0900_replace_is_admin/"
├── intermediate.config.ts
├── intermediate.d.ts
├── intermediate.json
├── intermediate.prisma
├── migration.json
├── migration.ts
└── ops.json
```

Now fill in this migration's own planned `migration.ts`, rather than copying the `displayName` file, whose snapshot imports point at other contracts. In the listing, `<start hash>` and `<end hash>` stand for the hashes your planned file already imports, so keep those imports as they are.

The listing builds `db` from the intermediate contract and passes that same contract to `dataTransform`. Those two have to be the same contract: if you pass a different one, `node migration.ts` fails with an error whose `code` is `MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH`.

The listing also moves the planned `dropColumn` for `isAdmin` to after the backfill, so `isAdmin` is still there when the backfill reads it. The backfill's `dataTransform` has two `run` callbacks, which run in the order you list them, so the second one sets `member` only on the rows the first one left empty.

```ts title="migration.ts (filled in)"
#!/usr/bin/env -S node
import type { Contract as End } from '../../snapshots/<end hash>/contract';
import endContractJson from '../../snapshots/<end hash>/contract.json' with { type: 'json' };
import type { Contract as Start } from '../../snapshots/<start hash>/contract';
import startContractJson from '../../snapshots/<start hash>/contract.json' with { type: 'json' };
import type { Contract as Mid } from './intermediate';
import midContractJson from './intermediate.json' with { type: 'json' };
import { Migration, MigrationCLI, col } from '@prisma/orm-postgres/migration';
import postgresAdapter from '@prisma/orm-postgres/adapter/runtime';
import { sql } from '@prisma/orm-postgres/builder/runtime';
import { createExecutionContext, createSqlExecutionStack } from '@prisma/orm-postgres/family-runtime';
import postgresTarget, { PostgresContractSerializer } from '@prisma/orm-postgres/target/runtime';

const stack = createSqlExecutionStack({ target: postgresTarget, adapter: postgresAdapter });
const midContract = new PostgresContractSerializer().deserializeContract<Mid>(midContractJson);

const db = sql<Mid>({
  context: createExecutionContext({ contract: midContract, stack }),
  rawCodecInferer: stack.adapter.rawCodecInferer,
});

export default class M extends Migration<Start, End> {
  override readonly endContractJson = endContractJson;
  override readonly startContractJson = startContractJson;

  override get operations() {
    return [
      this.addColumn({ schema: 'public', table: 'user', column: col('role', 'text', { codecRef: { codecId: 'pg/text@1' } }) }),
      this.dataTransform(midContract, 'backfill-user-role', {
        check: () => db.public.user.select('id').where((f, fns) => fns.eq(f.role, null)).limit(1),
        run: [
          () => db.public.user.update({ role: 'admin' }).where((f, fns) => fns.eq(f.isAdmin, true)),
          () => db.public.user.update({ role: 'member' }).where((f, fns) => fns.eq(f.role, null)),
        ],
      }),
      this.setNotNull({ schema: 'public', table: 'user', column: 'role' }),
      this.dropColumn({ schema: 'public', table: 'user', column: 'isAdmin' }),
    ];
  }
}

MigrationCLI.run(import.meta.url, M);
```

If you would rather not keep an intermediate contract around, you can reach the same result by splitting the change into two migrations. First add `role` to your contract as optional and plan, and in that migration add a `dataTransform` that sets `role` from `isAdmin`, with `db` built from its end contract, which still describes both columns. Then remove `isAdmin`, make `role` required, and plan again. That second plan writes a `handle-nulls-user-role` placeholder, which you fill in with what should happen to rows where `role` is still empty. Splitting the change needs no `intermediate.*` files at all, unless `User` has a `temporal.updatedAtString()` column.

## Raw SQL [#escape-hatch-raw-sql]

When the statement you need has no method of its own, such as `COMMENT ON`, you write the SQL yourself. The [Migration API reference](https://www.prisma.io/docs/orm/reference/migration-api) lists every method that does exist, so check it first. Import `rawSql` from `@prisma/orm-postgres/migration` and add the call to the `operations` array alongside the other operations. You also say what kind of change the statement is, by setting `operationClass` to one of the [four classes](https://www.prisma.io/docs/orm/migrations/how-migrations-work#every-operation-checks-itself): `additive`, `widening`, `destructive`, or `data`. `npx prisma db migrate` runs all four of them, and adds a data-loss warning for `destructive`. Give each operation its own `id`, because error messages name it and Prisma ORM does not check that it is unique, so two operations sharing an `id` leave you unable to tell which one an error is about. The `label` is the text the CLI prints. One limit matters before you write any SQL: one `npx prisma db migrate` run on PostgreSQL is [one transaction](https://www.prisma.io/docs/orm/migrations/applying-a-migration#when-something-goes-wrong), so `rawSql` cannot run `CREATE INDEX CONCURRENTLY`, or anything else that has to run outside a transaction. For an index, use `this.createIndex`, which is a plain `CREATE INDEX` and blocks writes while it builds. The example below is only an illustration, because it enables the `pgcrypto` PostgreSQL extension, which you would really do with `createExtension('pgcrypto')` from the same module:

```ts
rawSql({
  id: 'extension.pgcrypto',
  label: 'Enable extension "pgcrypto"',
  operationClass: 'additive',
  target: { id: 'postgres' },
  precheck: [
    { description: 'not yet enabled', sql: "SELECT NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pgcrypto')" },
  ],
  execute: [{ description: 'enable it', sql: 'CREATE EXTENSION IF NOT EXISTS pgcrypto' }],
  postcheck: [
    { description: 'now enabled', sql: "SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pgcrypto')" },
  ],
}),
```

Give each operation a precheck and a postcheck if you can, because they are what lets Prisma ORM decide whether your SQL needs to run at all and whether it did what you meant, in the order that [Every operation checks itself](https://www.prisma.io/docs/orm/migrations/how-migrations-work#every-operation-checks-itself) describes. Each check is a query whose first row must have `true` in its first column. Leaving either one out has a consequence worth knowing about before you do it, because an empty `precheck` lets the operation run, and an empty `postcheck` never passes before the operation, which means that operation runs on every `npx prisma db migrate` that applies its migration.

## The same pattern on MongoDB [#the-same-pattern-on-mongodb]

The same backfill pattern works on MongoDB, with different imports and a differently shaped `check`. Import `dataTransform` from `@prisma/orm-mongo/target/migration`, and write its `check` as an object whose `source` is a callback that returns the query. The example below needs no `db` statements, because it builds its queries directly: `AggregateCommand` for the `check` query and `RawUpdateManyCommand` for the `run` update, both from `@prisma/orm-mongo/query-ast/execution`. A call such as `new RawUpdateManyCommand('products', { status: { $exists: false } }, { $set: { status: 'active' } })` takes the collection name, a filter, and an update. Here those two queries come back from the helpers `existingProductsWithoutStatus` and `backfillRun`, and each of them takes the end contract's `storageHash`, because every MongoDB query records the hash of the contract it was built for. The `setValidation` step is in the listing only because this migration also adds fields to `products`, and the collection's validator has to include them. Both helpers are in the full [retail-store example](https://github.com/prisma/orm/blob/main/examples/retail-store/migrations/app/20260513T0508_backfill_product_status/migration.ts):

```ts title="migration.ts (MongoDB, excerpt)"
import { dataTransform, setValidation } from '@prisma/orm-mongo/target/migration';

override get operations() {
  const storageHash = this.endContract.storage.storageHash;
  const productsValidator = this.endContract.collection.products.validator;
  return [
    setValidation('products', productsValidator.jsonSchema, {
      validationLevel: productsValidator.validationLevel,
      validationAction: productsValidator.validationAction,
    }),
    dataTransform('backfill-product-status', {
      check: { source: () => existingProductsWithoutStatus(storageHash) },
      run: () => backfillRun(storageHash),
    }),
  ];
}
```

## Starting from a blank migration [#starting-from-a-blank-migration]

Not every migration comes from a contract change. When you want a data-only migration, which changes rows and leaves your contract state as it is, or a migration you intend to write entirely by hand, run `npx prisma migration new`. It writes an empty `ops.json`, a `migration.json`, and a `migration.ts` that already has the snapshot imports, the class, and an empty `operations` array. Nothing was planned for you, so there is no `placeholder` import to remove, but you do have to add the `@prisma/orm-postgres` imports and the `endContract`, `stack`, and `db` statements from the filled-in `displayName` listing.

`migration new` always ends at the contract state in your `contract.json`, and a data-only migration starts there too, so you pass that state's hash with `--from`. `--from` takes the contract hash in the `to` field of an existing migration's `migration.json`, or any start of that hash that matches only one migration's `to` hash.

To find your current contract's hash, run `npx prisma migration graph` and look for the row labelled `@contract`. It shows the first 7 characters of the hash, and you can pass those 7 characters to `--from`. The [`migration new` reference](https://www.prisma.io/docs/cli/migration-new) lists the rest of the options:

  

#### bun

```bash
bunx prisma migration new --name backfill_scores --from <hash>
```

#### pnpm

```bash
pnpm prisma migration new --name backfill_scores --from <hash>
```

#### yarn

```bash
yarn prisma migration new --name backfill_scores --from <hash>
```

#### npm

```bash
npx prisma migration new --name backfill_scores --from <hash>
```

For a data-only migration, always pass `--from`. Without it, `migration new` starts from the `db` ref, which names your current contract after `db migrate --advance-ref db`, so the migration would start and end at the same state. Without `--from`, `migration new` takes that as a mistake and stops with an error whose `code` is `MIGRATION.NO_CHANGES`, which tells you to change your contract first, or to pass `--from` if you want a data-only migration.

Write your operations in the new `migration.ts` and recompile it. Until you do, the migration is still the empty one the command wrote, so `npx prisma migration check` and `npx prisma migration plan` both fail.

## Editing checklist [#editing-checklist]

1. Edit `migration.ts`, never `ops.json`, then recompile it.
2. Review the diff of `ops.json`, the file that runs.
3. Run `npx prisma migration check`, which prints `✔ All checks passed` when nothing is wrong.
4. Commit `migration.ts`, `ops.json`, `migration.json`, the `migrations/snapshots/<hash>/` directories that `migration.ts` imports, and your `contract.json` and `contract.d.ts`. If the migration has `intermediate.*` files, commit those too.

> [!NOTE]
> What's early
> 
> Hand-written MongoDB data transforms cannot use the query builder for updates. No command notices a `migration.ts` edit that you did not recompile, so recompile after every edit.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8), instruction files for your coding agent. In an existing project, run `npx prisma skills sync`. Ask your agent to:

* "Fill in the placeholder in the latest migration: backfill `displayName` with the user's email prefix."
* "Add a data transform to this migration that normalizes existing `phone` values before the unique constraint."
* "Recompile the migration I just edited and show me the ops.json diff."

## See also [#see-also]

* [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration): where the first draft of `migration.ts` comes from
* [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration): run the edited migration
* [Migration API](https://www.prisma.io/docs/orm/reference/migration-api): every method and helper `migration.ts` can call
* [Data Migrations in Prisma 8](https://www.prisma.io/blog/data-migrations-in-prisma-next): how `dataTransform` was designed

## Related pages

- [`Applying a migration`](https://www.prisma.io/docs/orm/migrations/applying-a-migration): The db migrate command applies the migrations you planned, until your database matches your contract, with a preview, checks on every operation, and safe re-runs.
- [`Generating a migration`](https://www.prisma.io/docs/orm/migrations/generating-a-migration): Turn a change to your contract into a migration you can review, with the migration plan command.
- [`How migrations work`](https://www.prisma.io/docs/orm/migrations/how-migrations-work): Change your contract, plan a migration, review it, apply it. Operations can check the database before and after they run.
- [`Rollbacks and recovery`](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery): Rolling back is one more migration that makes the database match an earlier contract state. Recovery is fixing a failed migration and running it again.
- [`The migration graph`](https://www.prisma.io/docs/orm/migrations/the-migration-graph): You and a teammate each changed your Prisma contract on separate branches. The migration graph is how Prisma ORM applies both changes to every database after the branches merge.

# Generating a migration (/docs/orm/migrations/generating-a-migration)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Turn a change to your contract into a migration you can review, with the migration plan command.

Location: ORM > Migrations > Generating a migration

This tutorial takes a change you have made to your contract, the `contract.prisma` file that replaced `schema.prisma`, and turns it into a migration that you read and approve before it runs against a database. To create a project first, see the [quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql).

Two commands do the work, and you run them in this order every time you change your contract. `npx prisma contract emit` replaces `prisma generate`: it reads `contract.prisma` and writes `contract.json` and `contract.d.ts` next to it, so that everything downstream reads your latest edit and not the version before it. `npx prisma migration plan` then reads `contract.json` and writes a new migration for the change, without applying it. Planning never connects to a database, which means you can run it in CI or in a sandbox with no database credentials. To work out what your change is a change from, `migration plan` looks by default at the `db` [ref](https://www.prisma.io/docs/orm/migrations/the-migration-graph#terms-used-on-this-page), a file in `migrations/app/refs/` that records the contract version you last applied in development.

## Your first migration [#your-first-migration]

Say your contract has a single model:

```prisma title="contract.prisma"
// use prisma-8

model User {
  id    Int     @id
  email String
  name  String?

  @@map("user")
}
```

Keep `// use prisma-8` as the first line of `contract.prisma`. If you [split your contract across several files](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#split-the-contract-across-several-files), every one of them needs that line too. `contract emit` and the Prisma editor extension read only the `.prisma` files that start with it, and skip the others without a warning. If no file starts with it, `contract emit` fails with an error whose `code` is `CONTRACT.SOURCE_LOAD_FAILED`.

Run both commands, passing `--name init` so that the new migration directory is named `<timestamp>_init`:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name init
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name init
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name init
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name init
```

```text
│  contract:    src/prisma/contract.json
│  migrations:  migrations/app
│  name:        init

✔ Planned 2 operation(s)
ℹ No db ref set — planning from an empty database. Run db init, db update, or db sign if a database already exists.

migrations/app/20260707T1005_init
├─ Create schema "public"
└─ Create table "user"

from:       (baseline)
to:         2d2cec8641643159cfc94e499e5eacbd75218e0389d938139b278f68618d6b13
app space:  migrations/app/20260707T1005_init

ℹ DDL preview

CREATE SCHEMA IF NOT EXISTS "public";
CREATE TABLE "public"."user" (
  "email" text NOT NULL,
  "id" int4 NOT NULL,
  "name" text,
  PRIMARY KEY ("id")
);
```

Read the rest of that output closely, because it tells you what was planned and where it was written:

* **`Planned 2 operation(s)`** counts the steps in the migration, which are listed underneath the directory name, and the DDL preview below them is the SQL those steps run.
* **`to:`** is the hash of your contract. Each version of your contract is a contract state, and Prisma ORM identifies a state by that hash rather than by a version number.
* **`from: (baseline)`** tells you this is a baseline migration, meaning a first migration that goes from an empty database to a contract state. The word means other things elsewhere, which [Baselines](https://www.prisma.io/docs/orm/migrations/the-migration-graph#baselines) sorts out.
* **`app space:`** is the directory the new migration was written to. Your app's migrations are in `migrations/app/`, and each [Prisma ORM extension package](https://www.prisma.io/docs/orm/extensions/using-extensions) that ships migrations gets a directory of its own beside it. Prisma ORM looks for `migrations/` in the directory you run commands from, which is normally the project root.

The `No db ref set` line is telling you that nothing in this project records which contract state your database matches, so `migration plan` assumed an empty database and planned from there. That assumption is right for a new project. If you already have a database, tell Prisma ORM what is in it before you plan anything, and which command does that depends on what the database holds:

* If Prisma ORM 7 migrated the database, follow the steps in the [upgrade guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#4-transfer-migration-ownership) first.
* If the database is empty, you need nothing: `npx prisma db migrate` creates the tables for you, though it does not create the database itself.
* If every table in the database already matches your contract, run [`npx prisma db sign`](https://www.prisma.io/docs/cli/db-sign) and then read [The automatic baseline](#the-automatic-baseline) below. `db sign` checks the tables against your contract and then writes the [marker](https://www.prisma.io/docs/orm/migrations/the-migration-graph#terms-used-on-this-page), which is the record in the database of which contract state it matches.
* If the database has only some of your tables, run [`npx prisma db init`](https://www.prisma.io/docs/cli/db-init). It adds what is missing and nothing else, and it stops if matching your contract would need a change that could lose data, such as dropping a column.
* If this is a development or preview database that you want to match your contract without keeping migration files for it, run [`npx prisma db update`](https://www.prisma.io/docs/cli/db-update). Unlike `db init`, it will make changes that could lose data, so it asks you to type the database name first.

A migration is a directory, and there is no SQL file in it. `migration.ts` is the one you read and sometimes edit, and the `ops.json` and `migration.json` beside it are what `db migrate` reads, as [What a migration contains](https://www.prisma.io/docs/orm/migrations/how-migrations-work#what-a-migration-contains) describes. Commit all three, along with `contract.prisma`, `contract.json`, `contract.d.ts`, and any new directories under `migrations/snapshots/`, which are saved copies of your contract. The change itself is in `migration.ts`, written as a list of method calls:

```ts title="migrations/app/20260707T1005_init/migration.ts"
#!/usr/bin/env -S node
import type { Contract as End } from '../../snapshots/2d2cec8641643159cfc94e499e5eacbd75218e0389d938139b278f68618d6b13/contract';
import endContract from '../../snapshots/2d2cec8641643159cfc94e499e5eacbd75218e0389d938139b278f68618d6b13/contract.json' with { type: 'json' };
import { Migration, MigrationCLI, col, primaryKey } from '@prisma/orm-postgres/migration';

export default class M extends Migration<never, End> {
  override readonly endContractJson = endContract;

  override get operations() {
    return [
      this.createSchema({ schema: 'public' }),
      this.createTable({
        schema: 'public',
        table: 'user',
        columns: [
          col('email', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
          col('id', 'int4', { notNull: true, codecRef: { codecId: 'pg/int4@1' } }),
          col('name', 'text', { codecRef: { codecId: 'pg/text@1' } }),
        ],
        constraints: [primaryKey(['id'])],
      }),
    ];
  }
}

MigrationCLI.run(import.meta.url, M);
```

Everything the migration will do is in that `operations` list, so reading it tells you exactly what will happen, and editing it is how you change what happens. A change as simple as this one needs no edit. [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) covers the cases where you do edit the file, such as adding a data backfill, reordering operations, or running raw SQL, and the recompile step that makes your edit count.

## The second migration: planning a delta [#the-second-migration-planning-a-delta]

Apply that first migration to your development database by running `npx prisma db migrate --advance-ref db`. This is the first command here that connects to a database, and it uses [`db.connection`](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) in `prisma.config.ts` unless you pass a connection string with `--db`. The `--advance-ref db` part is what records the result: it points the `db` ref at the contract state you just applied, so the next time you run `migration plan` it starts from there and plans only what has changed since.

Now add an optional `phone String?` field to `User`, and run both commands again:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_user_phone
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_user_phone
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_user_phone
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_user_phone
```

```text
│  contract:    src/prisma/contract.json
│  migrations:  migrations/app
│  name:        add_user_phone

✔ Planned 1 operation(s)

migrations/app/20260707T1006_add_user_phone
└─ Add column "phone" to "user"

from:       2d2cec8641643159cfc94e499e5eacbd75218e0389d938139b278f68618d6b13
to:         967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4
app space:  migrations/app/20260707T1006_add_user_phone

ℹ DDL preview

ALTER TABLE "public"."user" ADD COLUMN "phone" text;
```

To plan from a contract state other than the one the `db` ref names, say which one with `--from`, as in `--from 20260707T1005_init`. When you give `--from` a migration directory name, you are naming the contract state that exists once that migration has run. The [`migration plan` reference](https://www.prisma.io/docs/cli/migration-plan#options) lists every form the flag accepts.

### The db ref: skipping --from [#the-db-ref-skipping---from]

Once your first migration is applied, every change you make after that follows the same routine, which does the job `migrate dev` did in Prisma ORM 7 whenever you wanted migration files out of it, as the [command table](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#commands) shows:

1. Edit your contract.
2. Run `npx prisma contract emit`. If you skip this, `migration plan` reads the `contract.json` from before your edit, so it either prints `No changes detected` or plans a migration that is missing your latest change.
3. Run `npx prisma migration plan --name <name>`.
4. Review what it planned with `npx prisma migration show <dir>`, where `<dir>` is the new migration's directory name. If you edit `migration.ts`, [recompile it](https://www.prisma.io/docs/orm/migrations/editing-a-migration) before you go any further, because until you do, your edit is not part of what will run.
5. Apply it. In development that is `npx prisma db migrate --advance-ref db`. In CI and production it is `npx prisma db migrate --to <ref>`, without `--advance-ref`, where the ref names the state that environment should reach.

The step that is easy to get out of order is the last one, and the symptom is a migration that repeats work you already planned. If you plan a second migration before you have applied the first one with `--advance-ref db`, the `db` ref still names the older contract state, so Prisma ORM plans the first migration's changes a second time, and warns that planning from that state forks the migration graph. To fix that, delete the directory of the repeated migration, run `npx prisma db migrate --to <dir> --advance-ref db` with the name of the directory whose changes it repeated, and plan again. The `--to` is needed because your contract already holds the newer change, which has no migration yet. That command applies the first migration if your database does not have it, and points the `db` ref at it either way. To plan the second migration without applying the first, pass `--from <dir>` to `migration plan` instead, which leaves the `db` ref alone. Deleting the directory is how you discard any migration that has not run on a database, and the matching directory under `migrations/snapshots/` can stay.

Commit `migrations/app/refs/db.json` with the migration files. On a fresh clone it then points at the contract state the team's development databases are at, so the first `migration plan` chains from there. Without it, a clone that has migrations but no `db` ref is the last row of the table below, and `migration plan` stops with an error. When a merge conflicts on that file, take the hash your own database is at, which `npx prisma migration status` prints next to its `@db` label, or set the ref afterwards with `npx prisma migration ref set db <dir>`.

`db migrate --advance-ref db` is not the only command that updates the `db` ref. When `npx prisma db sign`, `db init`, and `db update` change the database configured in `prisma.config.ts`, they point the `db` ref at the new state as well. `db sign` is the one to watch, because it updates the ref even when you pass `--db` to sign a different database, so add `--no-advance-ref` when you do.

When you leave `--from` off, what `migration plan` does depends on whether `migrations/app/` already has migrations in it and whether the `db` ref exists. The combinations are:

| Migrations in `migrations/app/` | `db` ref | What `migration plan` does                    |
| ------------------------------- | -------- | --------------------------------------------- |
| None                            | None     | Plans from an empty database                  |
| None                            | Exists   | Writes a baseline migration, then your change |
| Some                            | Exists   | Plans from the state the `db` ref points at   |
| Some                            | None     | Stops with an error                           |

That last row is an error because Prisma ORM has migrations but nothing recording which contract state your database matches, and it will not guess. The error prints the commands that resolve it: one sets the `db` ref, one plans with `--from`, and one plans with `--from @empty`.

### The automatic baseline [#the-automatic-baseline]

If you started from an existing database, `db sign` and `db update` leave you in the second row of that table: you have no migration files yet, but the `db` ref names a contract state. What that means in practice is that you should run `migration plan` before you ever run `db migrate`. Planning writes a baseline migration ending at the state your database already matches, plus a second migration for your own change if `contract.json` has changed since. You need that baseline because `db migrate` fails against the database until one migration's `to:` hash matches the marker, and it never runs the baseline there, since the marker already records that the database matches that state. [Baselines](https://www.prisma.io/docs/orm/migrations/the-migration-graph#baselines) has the full rule.

There is one situation where that automatic baseline is not the one you want. If a deployed database, such as production, matches an older version of your contract than your development database does, a baseline planned the usual way would end at your development database's contract state, which is not the state production matches. Plan the baseline from the older version instead:

1. Change your contract back to the deployed version, for example with `git show <commit>:<contract path> > <contract path>`.
2. Run `npx prisma contract emit`.
3. Run `npx prisma migration plan --name baseline --from @empty`.
4. Run `npx prisma db sign --db "$PRODUCTION_DATABASE_URL" --no-advance-ref` against the deployed database. It writes the marker there, and `--no-advance-ref` leaves your `db` ref alone.
5. Restore your current contract and run `npx prisma contract emit` again.
6. Plan the change with `npx prisma migration plan --name <name> --from <baseline dir>`, the baseline's directory name.

None of these steps changes your `db` ref.

## When the planner needs your input [#when-the-planner-needs-your-input]

Some changes cannot be planned in full, because the answer depends on your data rather than on your contract. Adding a **required** field with no default to a table that already has rows is the common one: `migration plan` writes the `ADD COLUMN` and the `SET NOT NULL`, but only you know what the rows that already exist should contain, so it leaves that part for you to fill in as a **placeholder**. To see one, apply `add_user_phone`, then add a required `displayName String` field to `User` and run both commands again:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_display_name
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_display_name
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_display_name
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_display_name
```

```text
│  contract:    src/prisma/contract.json
│  migrations:  migrations/app
│  name:        add_display_name

⚠ Planned migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit

from:       967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4
to:         866ab885a8a4bd8d9f5adc47784c068be7895a7182c55cc29f9f9967d3019484
app space:  migrations/app/20260707T1008_add_display_name
```

Open the new `migration.ts` and you will find a `dataTransform` step between the `ADD COLUMN` and the `SET NOT NULL`, which is the step that updates the rows already in the table. The two `placeholder(...)` calls inside it mark where your queries go: the first finds the rows that still need a `displayName`, and the second fills the value in. Write both with the [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder), then recompile the file, which is the step the output above calls self-emit. Until you fill the placeholders in and recompile, this migration cannot run at all, so a forgotten placeholder costs you a failed deploy rather than a wrong database. [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) walks through writing both queries and recompiling.

## Reviewing what you planned [#reviewing-what-you-planned]

You can inspect a planned migration before anything runs, with these commands, none of which connects to a database:

  

#### bun

```bash
# One migration in detail: operations, metadata, DDL preview
bunx prisma migration show 20260707T1006_add_user_phone
# The whole migration history, with your new migration in place
bunx prisma migration graph
# Integrity check: hashes match, no files missing, every migration starts from empty or where another ends, refs point at known states
bunx prisma migration check
```

#### pnpm

```bash
# One migration in detail: operations, metadata, DDL preview
pnpm prisma migration show 20260707T1006_add_user_phone
# The whole migration history, with your new migration in place
pnpm prisma migration graph
# Integrity check: hashes match, no files missing, every migration starts from empty or where another ends, refs point at known states
pnpm prisma migration check
```

#### yarn

```bash
# One migration in detail: operations, metadata, DDL preview
yarn prisma migration show 20260707T1006_add_user_phone
# The whole migration history, with your new migration in place
yarn prisma migration graph
# Integrity check: hashes match, no files missing, every migration starts from empty or where another ends, refs point at known states
yarn prisma migration check
```

#### npm

```bash
# One migration in detail: operations, metadata, DDL preview
npx prisma migration show 20260707T1006_add_user_phone
# The whole migration history, with your new migration in place
npx prisma migration graph
# Integrity check: hashes match, no files missing, every migration starts from empty or where another ends, refs point at known states
npx prisma migration check
```

`migration check` also tells you the result in its exit code, if you run it from a script. `0` means every check passed, `4` means an integrity failure such as a missing file or an `ops.json` that someone edited by hand, and `2` means it could not find a migration you named. The one thing it cannot tell you is whether you remembered to [recompile](https://www.prisma.io/docs/orm/migrations/editing-a-migration) after your last edit. To check that yourself, stage the migration with `git add`, then recompile it. If `git status` then shows no unstaged change to `ops.json` or `migration.json`, they were already up to date. This does not work for a backfill on a model with an `updatedAt` column. [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration#worked-example-making-a-column-required) explains why, and how to write that backfill.

> [!NOTE]
> What's early
> 
> Planning covers tables, columns, indexes, constraints, and the backfill placeholder shown above. What it cannot do yet is notice that you renamed something: if you rename an optional field, it plans the change as **drop column + add column**, and `migration plan` prints a warning that the change can lose data. Take that warning seriously, because `db migrate` runs destructive operations without asking, so read `migration show <dir>` before you apply anything. To rename a column and keep the data in it, edit `migration.ts`, replace that pair of operations with a [`rawSql` operation](https://www.prisma.io/docs/orm/migrations/editing-a-migration#escape-hatch-raw-sql) that runs `ALTER TABLE ... RENAME COLUMN`, and recompile. One more difference from Prisma ORM 7: `migration plan` never asks you questions the way `migrate dev` did.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. In an existing project, run `npx prisma skills sync`. The skills are instruction files your agent reads, so you can ask it to:

* "Add a required `displayName` field to User, emit the contract, and plan the migration."
* "Plan a migration named `add-orders-table` and show me its DDL preview before I commit it."
* "Run `migration check` and explain any integrity failures."

## See also [#see-also]

* [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration): fill placeholders, add data steps, write raw SQL
* [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration): run what you planned
* [Studio with Prisma ORM](https://www.prisma.io/docs/studio/prisma-next): once applied, see the same operations as a visual diff in Prisma Studio
* [TypeScript Migrations in Prisma 8](https://www.prisma.io/blog/typescript-migrations-in-prisma-next): a blog post on the design of `migration.ts`

## Related pages

- [`Applying a migration`](https://www.prisma.io/docs/orm/migrations/applying-a-migration): The db migrate command applies the migrations you planned, until your database matches your contract, with a preview, checks on every operation, and safe re-runs.
- [`Editing a migration`](https://www.prisma.io/docs/orm/migrations/editing-a-migration): A migration is TypeScript you own. Fill in backfills, reorder steps, or write raw SQL, then recompile it with one command.
- [`How migrations work`](https://www.prisma.io/docs/orm/migrations/how-migrations-work): Change your contract, plan a migration, review it, apply it. Operations can check the database before and after they run.
- [`Rollbacks and recovery`](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery): Rolling back is one more migration that makes the database match an earlier contract state. Recovery is fixing a failed migration and running it again.
- [`The migration graph`](https://www.prisma.io/docs/orm/migrations/the-migration-graph): You and a teammate each changed your Prisma contract on separate branches. The migration graph is how Prisma ORM applies both changes to every database after the branches merge.

# How migrations work (/docs/orm/migrations/how-migrations-work)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Change your contract, plan a migration, review it, apply it. Operations can check the database before and after they run.

Location: ORM > Migrations > How migrations work

A migration is how Prisma ORM changes your database when your contract changes. Your contract is the `contract.prisma` file that replaced `schema.prisma`, and `npx prisma orm init` puts it in `src/prisma/`. After you edit it, run `npx prisma contract emit`, which replaces `prisma generate`. Next to `contract.prisma` it writes the files the rest of Prisma ORM reads: `contract.json`, which the migration commands read, and `contract.d.ts`, which your client's types come from.

Prisma ORM 8 supports PostgreSQL and MongoDB. SQLite is experimental, and MySQL is not supported, as [Supported databases](https://www.prisma.io/docs/orm/supported-databases) lists.

You run this loop many times a day:

<ConceptAnimation name="migration-loop" />

1. **Change your contract**: edit `contract.prisma`, then run `npx prisma contract emit`.
2. **Plan a migration**: `migration plan` works out what has to change in the database by comparing your new contract with an earlier contract state, and writes what it finds as a migration directory under `migrations/app/`. A contract state is one version of your contract, named by its hash, so it is how Prisma ORM refers to your contract as it stood at a particular moment. Unless you tell it otherwise, the earlier state it compares against is the `db` ref, the file `migrations/app/refs/db.json` naming the contract state you last applied in development.
3. **Review it**: before anything touches the database, run `npx prisma migration show <dir>` to see the operations and SQL that `db migrate` will run. If you want the migration to change rows as well, [edit `migration.ts` and recompile it](https://www.prisma.io/docs/orm/migrations/editing-a-migration) by running `node migrations/app/<dir>/migration.ts` from your project root, which rewrites `ops.json`. Nothing extra is needed to run that file, because the Prisma ORM CLI already requires Node.js 22.18 or later, which runs `migration.ts` directly.
4. **Apply it**: `db migrate` starts by reading the database's marker, the record in the database of which contract state it matches, so it knows how much of your history the database has already seen, and then runs the migrations from that state to your current contract. In development, add [`--advance-ref db`](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-db-ref-skipping---from) so the next `migration plan` starts from what you just applied.

This example uses the contract from [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration#your-first-migration), whose `User` model is stored in the table `user` because it sets `@@map("user")`. Its first migration is already applied, with `npx prisma db migrate --advance-ref db`, and a database connection is set up as in the [quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql). Add an optional `phone String?` field to `User`, then run:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_user_phone
bunx prisma migration show 20260707T1006_add_user_phone
bunx prisma db migrate --advance-ref db
```

#### pnpm

```bash
pnpm prisma contract emit
pnpm prisma migration plan --name add_user_phone
pnpm prisma migration show 20260707T1006_add_user_phone
pnpm prisma db migrate --advance-ref db
```

#### yarn

```bash
yarn prisma contract emit
yarn prisma migration plan --name add_user_phone
yarn prisma migration show 20260707T1006_add_user_phone
yarn prisma db migrate --advance-ref db
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_user_phone
npx prisma migration show 20260707T1006_add_user_phone
npx prisma db migrate --advance-ref db
```

`migration plan` prepares the SQL but doesn't run it:

```text
✔ Planned 1 operation(s)

migrations/app/20260707T1006_add_user_phone
└─ Add column "phone" to "user"

from:       2d2cec8641643159cfc94e499e5eacbd75218e0389d938139b278f68618d6b13
to:         967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4
app space:  migrations/app/20260707T1006_add_user_phone

ℹ DDL preview

ALTER TABLE "public"."user" ADD COLUMN "phone" text;
```

A table name is the model name exactly as written unless the model sets `@@map`, so without `@@map("user")` this `User` model would be the table `"User"`, and a `UserProfile` model is the table `"UserProfile"`. These are the same names Prisma ORM 7 used.

The `app space:` line tells you which migration history the new directory was written into. A contract space is a separate migration history, so your own migrations stay in `migrations/app/` while each [Prisma ORM extension package](https://www.prisma.io/docs/orm/migrations/applying-a-migration#extension-spaces) that ships migrations, such as pgvector, keeps its migrations in its own directory under `migrations/`.

`db migrate` applies the migration and confirms what it applied:

```text
✔ Applied 1 migration(s) (1 operation(s)) across 1 contract space(s)
```

The first time you run `migration plan`, there are no migrations and no `db` ref on disk yet, so there is no earlier state to compare against and Prisma ORM plans as if the database were empty. If you want it to start somewhere else, pass `--from`, such as `--from 20260707T1006_add_user_phone` for the state after that migration. The [`migration plan` reference](https://www.prisma.io/docs/cli/migration-plan#options) lists the other forms `--from` accepts, and [The db ref](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-db-ref-skipping---from) covers what `migration plan` starts from when you leave `--from` off.

`db migrate` needs a database to talk to, and it takes that from `db.connection` in [`prisma.config.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract), such as `db: { connection: process.env["DATABASE_URL"]! }`, unless you pass a URL with the `--db` flag. In CI and production, run `npx prisma db migrate --to <ref>`, where the ref names the state that environment should reach, as [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration) explains.

> [!NOTE]
> If you used Prisma ORM 8 before 8.0.0-rc.12
> 
> In Prisma ORM 8 releases before 8.0.0-rc.12, a model without `@@map` named its table with a lowercase first letter, such as `"userProfile"` for a `UserProfile` model. If your tables were created with those names, download the [`add-model-map` script](https://github.com/prisma/orm/blob/v8.0.0-rc.12/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.11-to-8.0.0-rc.12/scripts/psl-verbatim-table-names/add-model-map.mjs) into your project root and run it there before you plan your next migration:
> 
> ```bash title="Terminal"
> curl -O https://raw.githubusercontent.com/prisma/orm/v8.0.0-rc.12/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.11-to-8.0.0-rc.12/scripts/psl-verbatim-table-names/add-model-map.mjs
> node add-model-map.mjs '**/*.prisma'
> ```
>
> The script adds `@@map` with the name the table has now, such as `@@map("userProfile")`, to each model that has no `@@map`, in every `.prisma` file in your project, including any you keep in a migration directory. If you plan without running it, `migration plan` stops with [`MIGRATION.TABLE_NAME_CASE_CHANGED`](https://www.prisma.io/docs/orm/reference/error-reference#MIGRATION.TABLE_NAME_CASE_CHANGED) instead of dropping the table and creating an empty one.

## What a migration contains [#what-a-migration-contains]

A migration directory is named with a timestamp and the `--name` you passed. `migrations/` is in the directory you run commands from, normally your project root:

```text
migrations/
├── app/
│   └── 20260707T1006_add_user_phone/
│       ├── migration.ts     # the change, as TypeScript
│       ├── ops.json         # the operations, as JSON
│       └── migration.json   # where this migration fits in history
└── snapshots/
    └── <contract hash>/
        ├── contract.json    # snapshot of one contract state
        └── contract.d.ts    # types for that snapshot; they type-check migration.ts
```

After `migration plan`, commit the new migration directory, any new directories under `migrations/snapshots/`, `contract.prisma`, `contract.json`, and `contract.d.ts`.

### migration.ts: the file you edit [#migrationts-the-file-you-edit]

`migration plan` writes the change as `migration.ts`, a TypeScript class with one call per step, such as `this.addColumn(...)` for a new column, so you can read and change it like any other TypeScript file. [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) explains how to change it.

### ops.json: the file Prisma runs [#opsjson-the-file-prisma-runs]

`migration plan` also writes the same operations as JSON in `ops.json`, and `ops.json` is what `db migrate` actually runs, never `migration.ts`, so an edit to `migration.ts` changes nothing until you [recompile it](https://www.prisma.io/docs/orm/migrations/editing-a-migration).

### migration.json: its place in history [#migrationjson-the-history-marker]

`migration.json` records where this migration fits in your migration history:

* the contract hash it starts `from`
* the contract hash it ends at, `to`
* when it was created
* its own hash, `migrationHash`, which `npx prisma migration check` reads

Do not edit `migration.json` or `ops.json` by hand, because both are written for you from `migration.ts`. Edit `migration.ts` and recompile instead.

Because that `from` hash is what ties one migration to another, your [migration history](https://www.prisma.io/docs/orm/migrations/the-migration-graph) branches when two people plan migrations from the same contract state on separate branches, and [a worked example](https://www.prisma.io/docs/orm/migrations/the-migration-graph#a-worked-example) shows the one migration to plan after the merge.

## Every operation checks itself [#every-operation-checks-itself]

Inside `ops.json`, an operation is not only the change itself: it also carries the checks that decide whether the change needs to run and whether it worked. Here are the parts of the operation that adds the `phone` column:

* **Precheck**: confirms the database is in the state the change expects, here that `"user"` has no `phone` column.
* **Execute**: the statements that make the change, here `ALTER TABLE "public"."user" ADD COLUMN "phone" text`.
* **Postcheck**: confirms the change is in the database, here that the `phone` column exists. Some operations have no postcheck. `db migrate` skips an operation only when its postcheck already passes, so an operation with no postcheck always runs.

When `db migrate` reaches an operation, it runs the postcheck first. If the postcheck passes, the change is already in the database, so `db migrate` skips the operation. If it does not pass, `db migrate` runs the precheck, then the statements, then the postcheck again, and it stops the run if either check fails. Once the operations are done, it checks the database against the contract before it updates the marker, which catches a database that satisfied every individual operation but still doesn't match what you declared.

Say `"user"` already has a `phone` column of another type. The postcheck only asks whether a `phone` column exists, so it passes and the operation is skipped. The check against the contract then finds the wrong type, and the run fails with an error whose `code` is `MIGRATION.RUNNER_FAILED` and whose `why:` line reads `The resulting database schema does not satisfy the destination contract.` To see which columns differ, run `npx prisma db verify --schema-only`. Then change the column by hand to the type your contract declares, here `text`, with `ALTER TABLE "public"."user" ALTER COLUMN "phone" TYPE text;`, and run `db migrate` again. [Drift](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery#drift-when-the-database-isnt-where-migrations-left-it) covers other changes made outside a migration.

Each operation also has an `operationClass`, which says what kind of change the operation makes to the database and which you choose yourself when you write a raw SQL operation:

* **Additive**: adds something new, like a column.
* **Widening**: loosens a constraint or lets a type accept more values, like dropping `NOT NULL` from a column.
* **Destructive**: removes or changes something that exists, like dropping a column, and can lose data.
* **Data**: changes rows, not structure.

Destructive operations are the only class that gets a warning, and it is only a warning: nothing stops and waits for your answer. `migration plan` prints `This migration contains destructive operations that may cause data loss.` when it writes the migration, and `npx prisma migration show <dir>` prints it for any migration on disk, so you see it while reviewing. `db migrate` runs those operations without asking and prints the warning again afterwards.

Those checks are also what ends a run early when the database isn't in the state your migration assumed, because a precheck stops the run before the change is made, for example when a migration sets `NOT NULL` on a column that still holds `NULL`. The error names the operation and the check that failed, so you know exactly which assumption was wrong. [When something goes wrong](https://www.prisma.io/docs/orm/migrations/applying-a-migration#when-something-goes-wrong) covers what a stopped run leaves behind on each database and how to pick up from it.

## The commands [#the-commands]

The migration commands are part of the [Prisma ORM CLI](https://www.prisma.io/docs/cli) and run as `npx prisma <command>`. The commands in this table read only files, so they need no database connection:

| Command                                          | What it does                                                                                                                           |
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| [`migration plan`](https://www.prisma.io/docs/cli/migration-plan)          | [Generate a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration) from your contract changes                                              |
| [`migration new`](https://www.prisma.io/docs/cli/migration-new)            | Write an empty migration for a [data-only or hand-written change](https://www.prisma.io/docs/orm/migrations/editing-a-migration#starting-from-a-blank-migration) |
| [`migration show <target>`](https://www.prisma.io/docs/cli/migration-show) | Print one migration's operations, DDL preview, and metadata                                                                            |
| `migration list`                                 | List every on-disk migration                                                                                                           |
| `migration graph`                                | Draw your [migration history](https://www.prisma.io/docs/orm/migrations/the-migration-graph) as a graph                                                          |
| `migration check`                                | Check that each migration's `migrationHash` still matches its files and no files are missing, before you commit a hand edit            |

`<target>` is a migration's directory name, its path under `migrations/app/`, or the first 6 or more characters of its `migrationHash`.

The commands in this table connect to a database:

| Command                                     | What it does                                                                    |
| ------------------------------------------- | ------------------------------------------------------------------------------- |
| [`db migrate`](https://www.prisma.io/docs/cli/db-migrate)             | [Apply pending migrations](https://www.prisma.io/docs/orm/migrations/applying-a-migration)                |
| [`migration status`](https://www.prisma.io/docs/cli/migration-status) | Show which contract state the database matches and which migrations are pending |
| `migration log`                             | Show the history of migrations the database has actually applied                |

If you used Prisma ORM 7, these commands replace its migrate commands:

* `migrate dev` becomes `migration plan`, then `db migrate --advance-ref db`. `migrate dev` also had a second job, making a development database match the contract without writing migration files, and that job is now `db update`, which changes the database directly. [The db ref](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-db-ref-skipping---from) lists what each of these does to the ref.
* `migrate deploy` becomes `db migrate`.
* `migrate reset` has no equivalent. Drop and recreate the database with your own tools, then run `npx prisma db migrate --advance-ref db` to run your migrations again, or `npx prisma db init` to create what your contract declares without running them.
* `migrate diff` becomes `migration show <dir>`, which prints one migration, or `db update --dry-run`, which shows the operations that would make a database match the contract.
* Baselining, marking an existing database as already migrated, is now [`npx prisma db sign`](https://www.prisma.io/docs/cli/db-sign), which checks that the tables match your contract before it writes the marker. For a database Prisma ORM 7 migrated, follow [Prisma ORM 7 to 8 (PostgreSQL)](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#4-transfer-migration-ownership).

[Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#commands) has the full table, including `migrate resolve`.

Here is the whole loop, from idea to typed code:

<video preload="metadata" src="/docs/img/orm/next/migrations/migration-loop.mp4" aria-label="A 30-second walkthrough: a feature idea becomes a contract change, the migration is planned, reviewed, and applied, and the new column appears in Prisma Studio and in autocompleted application code." style="{ width: &#x22;100%&#x22;, borderRadius: &#x22;0.75rem&#x22;, border: &#x22;1px solid var(--color-fd-border)&#x22; }" />

## The same model for SQL and MongoDB [#the-same-model-for-sql-and-mongodb]

The commands, the file layout, the migration history, and the checks work the same way on PostgreSQL and MongoDB. On PostgreSQL, operations run SQL statements such as `ALTER TABLE`. On MongoDB, they create collections, indexes, and JSON Schema validators.

Each database keeps its own [marker and ledger](https://www.prisma.io/docs/orm/migrations/the-migration-graph#terms-used-on-this-page), where the ledger is that database's list of every migration applied to it, and `migration log` is the command that reads it.

> [!NOTE]
> Migrations are early
> 
> Planning, editing, applying, and [rolling back](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery) work today, but there is no squash command and no shadow-database dry run yet.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8), instruction files for your coding agent. In an existing project, run `npx prisma skills sync`. Ask your agent to:

* "Add a `phone` field to the User model and plan a migration for it."
* "Show me the pending migrations and what SQL they will run."
* "Explain what the ops.json in the latest migration does."

## See also [#see-also]

* [Studio with Prisma ORM](https://www.prisma.io/docs/studio/prisma-next): read your applied migration history: a visual diff, the executed SQL, and a schema diff per migration
* [The migration graph](https://www.prisma.io/docs/orm/migrations/the-migration-graph): why migrations form a graph
* [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration) and [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration): the hands-on loop
* [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration): backfills, raw SQL, and the recompile step
* [Rethinking Database Migrations](https://www.prisma.io/blog/rethinking-database-migrations): why this design exists

## Related pages

- [`Applying a migration`](https://www.prisma.io/docs/orm/migrations/applying-a-migration): The db migrate command applies the migrations you planned, until your database matches your contract, with a preview, checks on every operation, and safe re-runs.
- [`Editing a migration`](https://www.prisma.io/docs/orm/migrations/editing-a-migration): A migration is TypeScript you own. Fill in backfills, reorder steps, or write raw SQL, then recompile it with one command.
- [`Generating a migration`](https://www.prisma.io/docs/orm/migrations/generating-a-migration): Turn a change to your contract into a migration you can review, with the migration plan command.
- [`Rollbacks and recovery`](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery): Rolling back is one more migration that makes the database match an earlier contract state. Recovery is fixing a failed migration and running it again.
- [`The migration graph`](https://www.prisma.io/docs/orm/migrations/the-migration-graph): You and a teammate each changed your Prisma contract on separate branches. The migration graph is how Prisma ORM applies both changes to every database after the branches merge.

# Rollbacks and recovery (/docs/orm/migrations/rollbacks-and-recovery)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Rolling back is one more migration that makes the database match an earlier contract state. Recovery is fixing a failed migration and running it again.

Location: ORM > Migrations > Rollbacks and recovery

People use "rollback" for two different problems, and Prisma ORM deals with them differently, so work out which one you have. If the migration applied but the change it made was wrong, you want a rollback, which in Prisma ORM is one more migration. If the migration failed partway, you want recovery instead: find the cause, fix it, and run the migration again, which is safe to do.

## Rollback: a migration like any other [#rollback-a-migration-like-any-other]

Prisma ORM has no `migrate down` command and no "down migration" files, because undoing a change is not a special kind of operation here. To undo a change you add a new migration to your [migration history](https://www.prisma.io/docs/orm/migrations/the-migration-graph) that changes the database back to an earlier state, and it is planned and applied like every other migration. If you know git, this is `git revert` rather than `git reset`: you add something that undoes the change instead of deleting it from history.

<ConceptAnimation name="migration-rollback" />

Suppose you applied `20260707T1008_add_display_name` in production and now need to undo it. Undoing it means planning a migration with [`npx prisma migration plan`](https://www.prisma.io/docs/orm/migrations/generating-a-migration), which writes the difference between the two contract states you name. A contract state is one version of your contract, the `contract.prisma` file that replaced `schema.prisma`, named by its hash. You name a state with the migration directories you already have: a directory name means the state after that migration, and `^` after the name means the state before it. To undo `add_display_name`, then, you plan from its own state back to the state before it:

  

#### bun

```bash
bunx prisma migration plan \
  --from 20260707T1008_add_display_name \
  --to "20260707T1008_add_display_name^" \
  --name rollback_display_name
```

#### pnpm

```bash
pnpm prisma migration plan \
  --from 20260707T1008_add_display_name \
  --to "20260707T1008_add_display_name^" \
  --name rollback_display_name
```

#### yarn

```bash
yarn prisma migration plan \
  --from 20260707T1008_add_display_name \
  --to "20260707T1008_add_display_name^" \
  --name rollback_display_name
```

#### npm

```bash
npx prisma migration plan \
  --from 20260707T1008_add_display_name \
  --to "20260707T1008_add_display_name^" \
  --name rollback_display_name
```

```text
✔ Planned 1 operation(s)

migrations/app/20260707T1010_rollback_display_name
└─ ⚠ Drop column "displayName" from "user"

⚠ This migration contains destructive operations that may cause data loss.

from:       866ab885a8a4bd8d9f5adc47784c068be7895a7182c55cc29f9f9967d3019484
to:         967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4
app space:  migrations/app/20260707T1010_rollback_display_name

ℹ DDL preview

ALTER TABLE "public"."user" DROP COLUMN "displayName";
```

Read the migration before you apply it, because `db migrate` runs destructive operations without asking you to confirm, and this one drops a column. Open its `migration.ts`, and run `npx prisma migration show 20260707T1010_rollback_display_name` to see its SQL. When you are happy with it, complete the rollback in this order:

1. **Save the data, if you need it.** Dropping the column deletes what was stored in it for good, so if you still need that data, copy it somewhere first. To copy it into a table that already exists, add a [`rawSql` operation](https://www.prisma.io/docs/orm/migrations/editing-a-migration#escape-hatch-raw-sql) running an `INSERT ... SELECT` before the `dropColumn` call in `migration.ts`. Then [recompile the migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) by running `node migrations/app/20260707T1010_rollback_display_name/migration.ts` from your project root, so that your edit reaches the file `db migrate` actually runs.
2. **Revert the change in your contract.** Your contract describes the database you want, so undoing the change in the database means undoing it in the contract too: remove `displayName` from your contract file, then run `npx prisma contract emit`, the command that replaces `prisma generate` and rewrites `contract.json`. Step 4 depends on this, because `db migrate` applies migrations until the database matches the state recorded in `contract.json`.
3. **Commit the migration and the contract together.** The two only make sense as a pair, so put them in one commit: the new migration's directory, your contract file, `contract.json`, and `contract.d.ts`. No new directory appears under `migrations/snapshots/`, which is expected, because a rollback ends at a contract state that already has one.
4. **Apply the rollback.** In CI and production, run `npx prisma db migrate`, the command that replaces [`migrate deploy`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7). In development, add [`--advance-ref db`](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-db-ref-skipping---from) so that the next `migration plan` starts from what you just applied.

Once you have applied the rollback, `npx prisma db verify` passes, which confirms the database matches your reverted contract. A database that never had `add_display_name` applied needs neither that migration nor its rollback, and it runs neither, because `db migrate` runs the fewest migrations that end at the contract state you asked for.

Undoing several migrations at once works the same way. Plan one migration with `npx prisma migration plan --from <newest-migration-dir> --to "<oldest-migration-to-undo>^" --name rollback_changes`, then follow the same steps. The difference is step 2, where instead of deleting a single field you restore your whole contract file from a commit made before the oldest migration you are undoing, for example with `git checkout <commit> -- src/prisma/contract.prisma`.

### One planning caveat after a rollback [#one-planning-caveat-after-a-rollback]

The first migration you plan after a rollback prints a warning when you do not pass `--from`, even if you applied the rollback with `--advance-ref db`:

```text
⚠ The default origin ref 'db' points at 967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4, which already has a migration leading to 866ab885a8a4bd8d9f5adc47784c068be7895a7182c55cc29f9f9967d3019484. Planning from it forks the migration graph; pass --from to choose the origin explicitly.
```

Without `--from`, `migration plan` starts from the `db` ref, the file in `migrations/app/refs/` naming the contract state you last applied in development. After a rollback that state already has a migration starting from it, because the rollback ends at exactly the state `add_display_name` starts from. The migration is planned anyway, and it starts from the state the rollback ended at, so you can keep it. To plan without the warning, pass `--from` with the rollback's directory name:

  

#### bun

```bash
bunx prisma migration plan --from 20260707T1010_rollback_display_name --name add_nickname
```

#### pnpm

```bash
pnpm prisma migration plan --from 20260707T1010_rollback_display_name --name add_nickname
```

#### yarn

```bash
yarn prisma migration plan --from 20260707T1010_rollback_display_name --name add_nickname
```

#### npm

```bash
npx prisma migration plan --from 20260707T1010_rollback_display_name --name add_nickname
```

Once you apply this migration with `--advance-ref db`, the `db` ref names a state that no migration starts from, and `migration plan` no longer prints the warning.

## Recovery: when a migration fails partway [#recovery-when-a-migration-fails-partway]

When a migration fails, `db migrate` stops at the operation that failed rather than carrying on, and it tells you which operation it was and why:

```text
✘ [MIGRATION.RUNNER_FAILED] Operation alterNullability.setNotNull.user.nickname failed during precheck: ensure no NULL values in "nickname"
  why: Migration runner failed
  docs: https://docs.prisma.io/docs/orm/v8/reference/error-reference/MIGRATION.RUNNER_FAILED
```

How much a failed run leaves behind depends on your database, and [when something goes wrong](https://www.prisma.io/docs/orm/migrations/applying-a-migration#when-something-goes-wrong) explains what you are left to clean up on PostgreSQL and on MongoDB before you try again.

1. **Read which check failed.** The error tells you where the run stopped, because it names the operation and the [check](https://www.prisma.io/docs/orm/migrations/how-migrations-work#every-operation-checks-itself) that failed, and a precheck is a check that runs before its operation rather than after. In the example above, the precheck found rows with `NULL` in `nickname`, so the run stopped before setting the column to `NOT NULL`.
2. **Fix the cause, then run `npx prisma db migrate` again.** Re-running the same command is the whole of recovery, because there is no `migrate resolve` step first, and in development you add `--advance-ref db` as usual. Sometimes the cause is the environment, such as a PostgreSQL extension the server lacks or permissions it is missing. Sometimes it is the migration itself, which is why a migration can pass in development and fail in production, where the data is different. In the example above the data is what stopped the run, so you would edit the migration to [fill in `nickname` for existing rows](https://www.prisma.io/docs/orm/migrations/editing-a-migration#worked-example-making-a-column-required) before the `setNotNull`, recompile as in the rollback's step 1, and apply again.

### Drift: when the database changed without a migration [#drift-when-the-database-isnt-where-migrations-left-it]

Drift is what you have when your database no longer matches what your migrations say it should. The [marker](https://www.prisma.io/docs/orm/migrations/the-migration-graph#terms-used-on-this-page) is the record in the database of which contract state that database matches, and which kind of drift you have depends on whether the marker is part of the problem.

In the first kind, the marker records a contract state that no migration ends at. You usually get there through [`npx prisma db update`](https://www.prisma.io/docs/cli/db-update), which makes a database match your contract without a migration. The next `db migrate` fails with an error whose `code` is `MIGRATION.MARKER_MISMATCH` before it runs any operation. To fix it, write the migration your history is missing before you change the contract again: run `npx prisma migration plan --from <newest-migration-dir> --name <name>`. That migration ends at the state `db update` applied, so the next `db migrate` there has nothing to run.

In the second kind, only tables or columns changed, for example with a hand-run `ALTER`. The marker still records the last contract state applied, so `db migrate` still runs. It skips an operation whose change is already in the database, and it fails if an operation's check fails, or if your contract describes something missing or different once the operations have run.

Before you decide what to do about drift, find out which contract state the database matches. These commands only read, and both connect to `db.connection` in `prisma.config.ts`, or to the URL you pass with `--db`:

* **[`npx prisma migration status`](https://www.prisma.io/docs/cli/migration-status)** shows you the contract state the marker records, labeled `@db`, which despite the name is not the `db` ref.
* **[`npx prisma db verify`](https://www.prisma.io/docs/cli/db-verify)** checks both the marker and the tables against your contract, and lists each difference under `Schema issues`. Pass `--schema-only` when you want it to check the tables alone.

When a change was made by hand, you have to decide whether you want to keep it, and either answer gives you a way out:

* **Undo it.** Change the tables back by hand until `npx prisma db verify --schema-only --strict` passes. The marker never changed, so there is nothing else you need to put right.
* **Keep it.** Add the change to your contract, run `npx prisma contract emit`, then plan and apply a migration as usual. `db migrate` skips the change you already made there.

[`npx prisma db sign`](https://www.prisma.io/docs/cli/db-sign) fixes neither kind of drift, because it is for [baselining](https://www.prisma.io/docs/orm/migrations/the-migration-graph#baselines) a database that has no marker at all but whose tables already match your contract. For a database that Prisma ORM 7 migrated, follow [step 4 of the upgrade guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#4-transfer-migration-ownership) instead.

> [!NOTE]
> What's early
> 
> Rolling back, the warnings about destructive operations, and re-running a failed migration all work today. What does not exist yet is a way to try a migration on a temporary copy of the database first. For anything unusual, ask on [Discord](https://pris.ly/discord).

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8), instruction files for your coding agent. In an existing project, run `npx prisma skills sync`. Ask your agent to:

* "Plan a rollback for the last migration and show me its destructive operations."
* "This db migrate run failed. Read the error, fix the migration, and re-run it."
* "Check whether staging has drifted from the contract and explain the differences."

## See also [#see-also]

* [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration): what happens when a run fails
* [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration): fixing a migration that failed on data
* [The migration graph](https://www.prisma.io/docs/orm/migrations/the-migration-graph): why a rollback is one more migration

## Related pages

- [`Applying a migration`](https://www.prisma.io/docs/orm/migrations/applying-a-migration): The db migrate command applies the migrations you planned, until your database matches your contract, with a preview, checks on every operation, and safe re-runs.
- [`Editing a migration`](https://www.prisma.io/docs/orm/migrations/editing-a-migration): A migration is TypeScript you own. Fill in backfills, reorder steps, or write raw SQL, then recompile it with one command.
- [`Generating a migration`](https://www.prisma.io/docs/orm/migrations/generating-a-migration): Turn a change to your contract into a migration you can review, with the migration plan command.
- [`How migrations work`](https://www.prisma.io/docs/orm/migrations/how-migrations-work): Change your contract, plan a migration, review it, apply it. Operations can check the database before and after they run.
- [`The migration graph`](https://www.prisma.io/docs/orm/migrations/the-migration-graph): You and a teammate each changed your Prisma contract on separate branches. The migration graph is how Prisma ORM applies both changes to every database after the branches merge.

# The migration graph (/docs/orm/migrations/the-migration-graph)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

You and a teammate each changed your Prisma contract on separate branches. The migration graph is how Prisma ORM applies both changes to every database after the branches merge.

Location: ORM > Migrations > The migration graph

Say you are Alice, and on your branch you add a `phone` field to your contract, the `contract.prisma` file that replaced `schema.prisma`. Bob adds an `avatar` field on his branch, and both branches merge the same afternoon. Your laptop, Bob's laptop, staging, and production each hold a different version of the database, and each one needs the merged version without losing work or repeating a change.

Prisma ORM 7 keeps migrations as timestamped SQL directories and applies them in name order, so where a migration sits in the history is decided by its name. In Prisma ORM 8, each migration records the contract versions it starts and ends at instead, so migrations are linked to each other rather than ordered by time, and those links are the migration graph.

## When this matters [#when-this-matters]

Most of the time you can build a whole app without thinking about the graph at all, because a single line of migrations needs no explaining. It is worth understanding when you are in one of these situations:

* Two people, or two AI agents, change the contract on separate branches and merge.
* You roll a database back to an earlier version of your contract and then forward again.
* A database is several contract states out of date, after a fresh clone or on a long-lived staging database.

## The short version [#the-short-version]

Each migration records the contract state it starts from and the state it ends at, so a migration is a link between two named versions of your contract rather than a step in a numbered queue. That is why branching, merging, and rolling back are all the same act: you plan one more migration with `npx prisma migration plan` and tell it which state to start from.

> [!NOTE]
> You probably need only these five commands
> 
> Every time you change the contract, run `npx prisma contract emit`, which replaces `prisma generate`. Then plan a migration with `npx prisma migration plan --name <name>`, and in development apply it with `npx prisma db migrate --advance-ref db`. `npx prisma migration graph` draws the whole history, and `npx prisma migration status` tells you which contract state a database matches and what `db migrate` would run next.
> 
> Keep `--advance-ref db` on that command in development, so that your next `migration plan` starts from what you just applied instead of planning it again, as [The db ref](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-db-ref-skipping---from) explains.

## Terms [#terms-used-on-this-page]

| Term               | Meaning                                                                                                                                                                                                                                                                                                                                                                      |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Contract**       | Your `contract.prisma` file, compiled to `contract.json`.                                                                                                                                                                                                                                                                                                                    |
| **Contract state** | One version of your contract, named by its hash.                                                                                                                                                                                                                                                                                                                             |
| **Hash**           | An identifier computed from the database layout your contract describes, not from the text of `contract.prisma`. The graph shows its first seven characters, like `4437973`.                                                                                                                                                                                                 |
| **Node**           | A contract state, drawn as a `○` row in `migration graph` output.                                                                                                                                                                                                                                                                                                            |
| **Edge**           | A migration, drawn as a `↑`, `↓`, or `⟲` row. Applying it changes the database from one node's state to the other's.                                                                                                                                                                                                                                                         |
| **Marker**         | The record in the database of which contract state it matches. Reading it does not check the tables.                                                                                                                                                                                                                                                                         |
| **Ledger**         | The database's own list of every migration applied to it, and when each ran.                                                                                                                                                                                                                                                                                                 |
| **Ref**            | A name for a contract state, like `prod`, stored as a file in `migrations/app/refs/`.                                                                                                                                                                                                                                                                                        |
| **Contract space** | A separate migration history with its own directory in `migrations/`. Your app's is `migrations/app/`. Each [Prisma ORM extension package](https://www.prisma.io/docs/orm/extensions/using-extensions) that ships migrations, such as pgvector support, has its own, and one `db migrate` run applies all of them, as [Extension spaces](https://www.prisma.io/docs/orm/migrations/applying-a-migration#extension-spaces) shows. |

## How it works [#how-it-works]

A migration on disk is a directory in `migrations/app/`, and what makes it part of a graph rather than an item in a list is that it names both ends of its own change. Its `ops.json` lists the operations, the steps it runs, such as adding a column, and [What a migration contains](https://www.prisma.io/docs/orm/migrations/how-migrations-work#what-a-migration-contains) lists the rest of its files. Its `migration.json` records the hash it starts `from` and the hash it ends at, `to`, so a migration that ends where another one starts is joined to it. To change what a migration does, edit its `migration.ts` and recompile with `node migrations/app/<dir>/migration.ts`, as [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) shows.

<ConceptAnimation name="migration-graph" />

A database with no **marker** counts as empty, so `db migrate` starts it from the first migration. If the database already has tables but no marker, Prisma ORM still counts it as empty, which is not what you want, so read [Baselines](#baselines) before you run anything against it.

## A worked example [#a-worked-example]

Here is the situation from the top of the page, after Bob's branch merged first. [Name important states with refs](#name-important-states-with-refs) explains `@contract` and `(prod)`:

  

#### bun

```bash
bunx prisma migration graph
```

#### pnpm

```bash
pnpm prisma migration graph
```

#### yarn

```bash
yarn prisma migration graph
```

#### npm

```bash
npx prisma migration graph
```

```text
│  migrations:  migrations

  ○   e377d00  @contract
  │↑  20260922T0627_alice_merge      1a76a3c → e377d00  1 ops
○ │   5e1f082
│↑│   20260922T0627_alice_add_phone  4437973 → 5e1f082  1 ops
│ ○   1a76a3c  (prod)
│ │↑  20260922T0627_bob_add_avatar   4437973 → 1a76a3c  1 ops
│─╯
○     4437973
│↑    20260922T0626_init                   ∅ → 4437973  3 ops
○     ∅

1 space(s), 5 contract(s), 4 migration(s)
```

Read it from the bottom up, because the earliest state is the bottom row and every row above it is a later one. Each `↑` row shows a migration's directory name, its start and end hashes, and its operation count, and `--legend` prints a key to the other symbols.

From an empty database (`∅`), `init` produces contract state `4437973`. Alice's migration starts there and produces `5e1f082`, and Bob's starts from the same state and produces `1a76a3c`, which is why the drawing splits in two. Bob merged first, so `main` now points the `prod` ref at `1a76a3c`, and production will be migrated there. Alice's branch still holds a migration that starts from `4437973`, which is no longer the head.

After Alice rebases onto `main`, her `contract.prisma` holds both fields, `phone` and `avatar`, and production is at `1a76a3c`, where `prod` points. So the migration production needs is one from `prod` to that merged contract. If git reports a conflict in `contract.prisma`, `contract.json`, or `contract.d.ts`, she resolves it in `contract.prisma` and runs `npx prisma contract emit`, which rewrites the other two. She accepts `main`'s `refs/prod.json` as it is, and if `refs/db.json` conflicts too, she can take either side, because the `db update` in the last step below points it at the merged state. Then she plans one migration from `prod`:

  

#### bun

```bash
bunx prisma migration plan --name alice_merge --from prod
```

#### pnpm

```bash
pnpm prisma migration plan --name alice_merge --from prod
```

#### yarn

```bash
yarn prisma migration plan --name alice_merge --from prod
```

#### npm

```bash
npx prisma migration plan --name alice_merge --from prod
```

That is `alice_merge` in the drawing, from `1a76a3c` to the merged contract `e377d00`, and it adds `phone` to a database that already has `avatar`. `migration plan` always ends at whatever is in `contract.json`, which now holds the merged contract. If her old `migration.ts` had operations she wrote by hand, such as a `dataTransform`, she copies them into the new file and recompiles it, because the planner derives the schema changes from the contract but cannot carry over what she wrote.

Her old migration, `alice_add_phone`, can stay on disk or be deleted. Either way it never runs, because `db migrate` follows the path from the database's marker to its target, and `5e1f082` is not on the path from `prod` to `@contract`, so it cannot run out of order. Her own development database is the one database that is at `5e1f082`, and the quickest way to bring it to the merged contract is `npx prisma db update`, which changes a development database directly and points the `db` ref at the new state, so her next plan starts from the right place.

## What happens when you run db migrate [#what-happens-when-you-run-db-migrate]

`npx prisma db migrate` works out for itself which migrations your database still needs. It starts from the state in the marker and runs the migrations on the path to its target, which is `contract.json` unless `--to` names a contract state instead. If an operation fails, the run stops there, and [When something goes wrong](https://www.prisma.io/docs/orm/migrations/applying-a-migration#when-something-goes-wrong) explains how to re-run while [Recovery](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery#recovery-when-a-migration-fails-partway) explains what to do next.

Once your history has branches, more than one path can lead to the target, so `db migrate` has to pick one. It takes the path with the fewest migrations, and on a tie the migration with the earlier `createdAt` in its `migration.json`. That is also why a migration whose end state leads nowhere is never run: a database at `4437973` runs `bob_add_avatar` and then `alice_merge`, and never `alice_add_phone`, because no path through it reaches the target. The choice does not change where you end up, because both paths end at the same contract state, and `db migrate` checks the tables against that state before it updates the marker. To see the path it picked before anything runs, use `npx prisma db migrate --show`.

When no chain of migrations leads from the marker to the target, the run fails with an error whose `code` is `MIGRATION.PATH_UNREACHABLE`, and that usually means one of two things. Either `--to` names a state you did not intend, which is worth checking first, or the migration you need has not been planned yet. In the second case, plan it from the hash the marker holds with `npx prisma migration plan --from <hash> --name <name>`, and to find that hash run `npx prisma migration status`, which prints it next to its `@db` label.

## Inspecting the graph [#inspecting-the-graph]

| Question you have                                                                         | Command                       | Needs a database? |
| ----------------------------------------------------------------------------------------- | ----------------------------- | ----------------- |
| What does the whole graph look like?                                                      | `npx prisma migration graph`  | No                |
| Which migration directories exist on disk?                                                | `npx prisma migration list`   | No                |
| Was an `ops.json` or `migration.json` edited by hand, or does a ref name a missing state? | `npx prisma migration check`  | No                |
| Which contract state does my database match, and what would `db migrate` run next?        | `npx prisma migration status` | Yes               |
| What has actually been applied, and when?                                                 | `npx prisma migration log`    | Yes               |

`migration log` reads the **ledger**, so it tells you what actually ran rather than what should have run, and a rollback appears there as one more applied migration instead of erasing anything. Run `migration check` before you commit a migration you edited, and after you move a ref. It catches an `ops.json` or `migration.json` that was changed by hand, and a ref naming a state that does not exist, and it needs no database connection. A deploy pipeline does not need it: `db migrate --to <ref>` refuses a hand-edited migration file on its own. See [Reviewing what you planned](https://www.prisma.io/docs/orm/migrations/generating-a-migration#reviewing-what-you-planned) for its exit codes.

### Try it on real fixtures [#try-it-on-real-fixtures]

The [Prisma ORM repository](https://github.com/prisma/orm) has branched histories, including a `diamond` fixture with the same `init`, `alice_add_phone`, and `bob_add_avatar` migrations, in `examples/prisma-8-demo/fixtures/`. To draw one, build the repository and pass the example's `prisma.config.ts` to `migration graph` with `--config`.

## Name important states with refs [#name-important-states-with-refs]

Hashes are hard to remember and hard to talk about, so Prisma ORM lets you give the states that matter a name of your own. A **ref** is that name: you create one and point it at a state with `npx prisma migration ref set`, and then you pass the name instead of a hash, for example to `db migrate --to`. The name `prod` below is only an example:

  

#### bun

```bash
bunx prisma migration ref set prod 1a76a3c
bunx prisma migration ref list
bunx prisma db migrate --to prod
```

#### pnpm

```bash
pnpm prisma migration ref set prod 1a76a3c
pnpm prisma migration ref list
pnpm prisma db migrate --to prod
```

#### yarn

```bash
yarn prisma migration ref set prod 1a76a3c
yarn prisma migration ref list
yarn prisma db migrate --to prod
```

#### npm

```bash
npx prisma migration ref set prod 1a76a3c
npx prisma migration ref list
npx prisma db migrate --to prod
```

A ref named for an environment, such as `prod` or `staging`, names the contract state your deploy pipeline will migrate that environment to. It is a promise the repository makes, not a record of what is deployed; the marker in the database records that. Point it at the new state when a change merges to `main`, and have the pipeline run `db migrate --to prod` so it never applies more than the repository has promised.

To say which state a ref should point at, `ref set` takes a hash or a prefix of one, a ref name, a migration directory name, or `<dir>^`, but none of the `@` tokens below. Once the ref exists, `db migrate --to prod` applies migrations until the database matches the state `prod` names, and the database it changes is the one `prisma.config.ts` connects to, unless you pass a connection string with `--db`.

Some states you only need to refer to once, so Prisma ORM reserves a few tokens that start with `@`. Each names a contract state without creating a ref:

* `@contract`: the contract in `contract.json`.
* `@db`: the contract state in the marker of the database you are connected to. The `db` ref is a file, so it can name a different state.
* `@empty`: the empty database, before any migration.

Not every command takes every token. `migration plan` is offline and cannot read a database, so of the three its `--from` takes only `@empty`; each command's reference lists what it accepts, such as [`db migrate --show`](https://www.prisma.io/docs/cli/db-migrate#options). So if you want to see the path from the contract you have now to the state `prod` names, without changing anything, run `npx prisma db migrate --show --from @contract --to prod`.

## What the graph gives you [#what-the-graph-gives-you]

### Parallel work without ordering conflicts [#parallel-work-without-ordering-conflicts]

Two branches can plan migrations at the same time without either one knowing about the other, because nothing about a migration depends on when it was planned. Cleaning up afterwards is one `migration plan --from prod`, as [A worked example](#a-worked-example) shows.

### History you can trust [#history-you-can-trust]

A migration only ever runs against a database that matches the state it starts `from`. Before any operation runs, `db migrate` checks that the marker is a state in your migration history and stops if it is not. That check reads only the marker, not the tables. `db migrate` checks the tables only after it has run operations, and never when it has nothing to run, so to compare the tables against your contract directly, run `npx prisma db verify --schema-only`.

That marker check is also what you run into after using `npx prisma db update`, which, like Prisma ORM 7's `db push`, changes a database to match the contract without writing a migration. Because the contract it applied is one that no migration ends at, your next `db migrate` run stops at the check. [Drift](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery#drift-when-the-database-isnt-where-migrations-left-it) explains what to do next.

### Rollback as one more migration [#rollback-as-a-normal-move]

Undoing a change is not a special mode you switch into, because a migration can go backwards, from a later contract state to an earlier one, and you plan and apply it like any other migration. [Rollbacks and recovery](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery) shows the commands, including reverting your contract before you apply the rollback.

### More than one shape of history [#more-than-one-shape-of-history]

Straight lines, branches, and branches that join again all use the same commands, so there is nothing new to learn the first time your history stops being a straight line.

## Baselines [#baselines]

The word "baseline" turns up in several different places, and which one you are looking at depends on where you saw it:

* **A kind of migration.** A first migration from an empty database to a contract state, such as `init` above.
* **A label in command output.** `(baseline)` in `migration plan` output means the migration starts from an empty database.
* **A Prisma ORM 7 task.** What Prisma ORM 7 called baselining, marking an existing database as already migrated, is `npx prisma db sign` in Prisma ORM 8.

Reach for [`npx prisma db sign`](https://www.prisma.io/docs/cli/db-sign) when a database has no marker and its tables already match your contract. It checks the tables, writes the marker, and points the `db` ref at the signed contract. Signing alone is not enough to start migrating, though, because `db migrate` refuses a signed database until a migration in your history ends at the signed state. Your next `migration plan` writes that one for you, because the `db` ref now names the signed state; [The automatic baseline](https://www.prisma.io/docs/orm/migrations/generating-a-migration#the-automatic-baseline) explains what it writes. For a database Prisma ORM 7 migrated, follow [Transfer migration ownership](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#4-transfer-migration-ownership) instead.

## Database-specific details [#database-specific-details]

Nothing above changes with your database, because the graph and the commands are the same on every database that [Prisma ORM 8 supports](https://www.prisma.io/docs/orm/supported-databases). What does differ is where the marker and ledger are stored, and how much of a failed `db migrate` run is left behind, which [When something goes wrong](https://www.prisma.io/docs/orm/migrations/applying-a-migration#when-something-goes-wrong) covers.

* **PostgreSQL**: the marker is the `prisma_contract.marker` table and the ledger is the `prisma_contract.ledger` table.
* **MongoDB**: the marker and ledger are documents in a `_prisma_migrations` collection, which is new in Prisma ORM 8 because Prisma ORM 7 had no migrations on MongoDB.

## Adding a migration you write yourself [#adding-a-migration-you-write-yourself]

`npx prisma migration new` writes an empty migration for a change you write yourself, such as a data update. The migration always ends at the contract state in your current `contract.json`. Without `--from`, it starts where `migration plan` would: at the `db` ref, or at an empty database when there are no migrations and no `db` ref yet. When there are migrations but no `db` ref, it stops and asks for `--from`. [`migration new`](https://www.prisma.io/docs/cli/migration-new) lists every case.

Unlike the `--from` of `migration plan`, the `--from` of `migration new` takes only a contract hash that an existing migration ends at, which is the `to` hash in that migration's `migration.json`. You can shorten the hash to its first characters, such as the 7 that `migration graph` shows, as long as they match only one migration's `to` hash. It does not take a ref name, a migration directory name, or an `@` name such as `@db`. So to start from `e377d00` in the drawing above, run `npx prisma migration new --name backfill --from e377d00`. Because `e377d00` is also the `@contract` state, that migration starts and ends at the same state, which is what a data-only migration does.

## Release-candidate limitations [#release-candidate-limitations]

The graph itself, the way `db migrate` chooses which migrations to run, refs, the marker, and the ledger all work today. These are not built yet:

* **No squash.** You cannot yet collapse a long chain of migrations into one.
* **No split.** You cannot yet break one large migration into smaller ones after the fact.

## Common tasks [#common-tasks]

| Task                                                    | Command                                                            |
| ------------------------------------------------------- | ------------------------------------------------------------------ |
| Create a migration after you change the contract        | `npx prisma migration plan --name <name>`                          |
| Plan the migration production needs after a merge       | `npx prisma migration plan --name <name> --from prod`              |
| Apply migrations to your development database           | `npx prisma db migrate --advance-ref db`                           |
| See the whole graph                                     | `npx prisma migration graph`                                       |
| See which contract state a database matches             | `npx prisma migration status`                                      |
| Apply migrations until a database matches a named state | `npx prisma db migrate --to prod`                                  |
| Name a contract state `prod`                            | `npx prisma migration ref set prod <hash>`                         |
| List the refs you have named                            | `npx prisma migration ref list`                                    |
| Plan a rollback of the migration in `<dir>`             | `npx prisma migration plan --from <dir> --to <dir>^ --name <name>` |
| Apply a rollback migration you planned                  | `npx prisma db migrate --to <earlier-ref-or-hash>`                 |
| Check migration files and refs offline                  | `npx prisma migration check`                                       |

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. In an existing project, run `npx prisma skills sync`. Ask your agent to:

* "Draw the migration graph for this project and explain the branches."
* "Which contract state is the `prod` ref pointing at, and does the database match it?"
* "Two feature branches both added migrations. Draw the graph and plan the one migration production needs from the `prod` ref."

## See also [#see-also]

* [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work): what a migration contains, and how you plan, review, and apply one
* [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration): running `db migrate` in development and production
* [Studio with Prisma ORM](https://www.prisma.io/docs/studio/prisma-next): browse the same ledger visually in Prisma Studio, one entry per migration
* [Rollbacks and recovery](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery): planning and applying a migration back to an earlier state

## Related pages

- [`Applying a migration`](https://www.prisma.io/docs/orm/migrations/applying-a-migration): The db migrate command applies the migrations you planned, until your database matches your contract, with a preview, checks on every operation, and safe re-runs.
- [`Editing a migration`](https://www.prisma.io/docs/orm/migrations/editing-a-migration): A migration is TypeScript you own. Fill in backfills, reorder steps, or write raw SQL, then recompile it with one command.
- [`Generating a migration`](https://www.prisma.io/docs/orm/migrations/generating-a-migration): Turn a change to your contract into a migration you can review, with the migration plan command.
- [`How migrations work`](https://www.prisma.io/docs/orm/migrations/how-migrations-work): Change your contract, plan a migration, review it, apply it. Operations can check the database before and after they run.
- [`Rollbacks and recovery`](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery): Rolling back is one more migration that makes the database match an earlier contract state. Recovery is fixing a failed migration and running it again.

# Error reference (/docs/orm/reference/error-reference)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Every structured error code Prisma ORM can emit, by namespace, with the condition that raises it.

Location: ORM > Reference > Error reference

Every user-facing Prisma ORM error is a structured envelope identified by a dotted `NAMESPACE.SUBCODE` code (see [ADR 239](https://github.com/prisma/prisma/blob/main/docs/architecture%20docs/adrs/ADR%20239%20-%20Errors%20are%20structural%20envelopes%20with%20dotted%20namespace%20codes.md) and [Error Handling](https://github.com/prisma/prisma/blob/main/docs/Error%20Handling.md)). This page lists every published code. Each code anchors as `#<CODE>` — the exact fragment every emitted error carries in its `docsUrl`. This page is generated from the canonical reference in the `prisma/prisma` repository, whose CI requires every code in production source to be documented before it ships.

Recognize an error programmatically with `isStructuredError` from your facade package's `utils/structured-error` subpath (for example `@prisma/orm-postgres/utils/structured-error`) and match on `error.code`, never `instanceof`. Envelopes carry `message`, and optionally `why`, `fix`, `where`, `cause`, `docsUrl`, and the structured context each entry below lists as its **Payload**. The payload arrives on `error.meta` when the envelope was built by `structuredError` and on `error.details` when it was built by `runtimeError`; a few codes are raised both ways, so read whichever property the envelope carries.

Exit codes (CLI): an expected structured failure exits `2`, a user abort exits `3`, and `1` is reserved for internal errors (bugs). Codes on this page exit `2` unless the entry says otherwise.

Some codes are not failures to run at all. `db verify`, `db sign` and `migration check` answer a question about the project, and a bad answer is still an answer: they finish, report their findings as diagnostics on a successful envelope, and exit `4`. Exit `2` is reserved for the cases where those commands could not do the job: an unknown `--space`, a migration reference that resolves to nothing, an unreachable database, a contract that has not been emitted. Every entry whose code can arrive on one of those runs says so and names the command. Each of those commands declares the numbers it can exit with, and its `--help` text spells out what each one means.

A command may also **complete with findings**: it ran to its end and has a result to report, and the problems it found ride that result as diagnostics carrying the codes on this page. Those runs exit with a documented per-command code in the `4`–`99` band rather than `2`, and the entry below says so. `prisma orm init` is the case today: its scaffold is on disk whatever happens next, so a failed dependency install or contract emit is a finding on a completed run at exit `4` or `5`.

Codes that predate the dotted scheme were renamed at 0.16; the full old→new crosswalk (`PN-DOMAIN-NNNN` → `NAMESPACE.SUBCODE`) is in [ADR 239](https://github.com/prisma/prisma/blob/main/docs/architecture%20docs/adrs/ADR%20239%20-%20Errors%20are%20structural%20envelopes%20with%20dotted%20namespace%20codes.md).

Namespaces:

| Namespace   | Covers                                                                                                             |
| ----------- | ------------------------------------------------------------------------------------------------------------------ |
| `CONFIG`    | Loading and validating `prisma.config.ts`                                                                          |
| `CLI`       | Command-line argument and invocation errors                                                                        |
| `CONTRACT`  | Contract authoring, emission, validation, and the contract↔database relationship (markers, schema verification)    |
| `PSL`       | The PSL source text itself (parse, format, interpret), including a Prisma ORM 7 schema read as the contract source |
| `ORM`       | ORM client and query-builder DSL API misuse                                                                        |
| `RUNTIME`   | Query execution and runtime wiring                                                                                 |
| `DRIVER`    | Database driver connection and protocol failures                                                                   |
| `MIGRATION` | Migration authoring, planning, checking, and execution                                                             |
| `PLAN`      | Query plan constraints                                                                                             |
| `BUDGET`    | Query budget violations                                                                                            |
| `LINT`      | Query lint findings                                                                                                |
| `PARADEDB`  | ParadeDB extension: search-function arguments                                                                      |
| `POSTGIS`   | PostGIS extension: geometry construction and validation                                                            |
| `SUPABASE`  | Supabase extension: config wiring and JWT handling                                                                 |

## CONFIG [#config]

### CONFIG.CONTRACT_MISSING [#CONFIG.CONTRACT_MISSING]

The `contract` section is missing (or incomplete) in `prisma.config.ts` when a command needs it, raised by `prisma contract emit` when the config has no contract configuration, no schema path, or the referenced authoring entrypoint cannot be resolved. Payload: none.

### CONFIG.DB_CONNECTION_REQUIRED [#CONFIG.DB_CONNECTION_REQUIRED]

A DB-connected command (`migrate`, `db init`, `db sign`, `db verify`, `db update`, `inspect-live-schema`, and the migration scaffold commands) was run with no database connection available: no `--db <url>` flag and no `db.connection` in `prisma.config.ts`. The fix text names the exact retry command when known. Payload: `missingFlags` (optional).

### CONFIG.DRIVER_REQUIRED [#CONFIG.DRIVER_REQUIRED]

A DB-connected command was run but `prisma.config.ts` has no control-plane `driver` entry (e.g. `driver: postgresDriver`). Raised by the migration command scaffold, `migrate`, `db sign`, `db verify`, and `inspect-live-schema`. Payload: none.

### CONFIG.EVALUATION_FAILED [#CONFIG.EVALUATION_FAILED]

The config module could not be evaluated at all: a syntax error in `prisma.config.ts`, or the module threw during import. Raised by the config loader for any command that needs config; loading fails outright (no per-section diagnostics are possible for a module that does not evaluate) and every command exits `2` with this error. The underlying evaluation error's message is carried in `why` and the original error in `cause` (in-process only). The path, when known, is carried in `where.path`. Payload: none.

### CONFIG.FAMILY_READ_MARKER_REQUIRED [#CONFIG.FAMILY_READ_MARKER_REQUIRED]

Reserved: `db verify` needs the family package to export `verify.readMarker()` and it is absent. Declared in the shared error factories but not raised by any command today.

### CONFIG.FILE_NOT_FOUND [#CONFIG.FILE_NOT_FOUND]

No `prisma.config.ts` (or the explicitly passed config path) could be found when loading configuration, raised by the config loader for any command that needs config. The fix is to run `prisma orm init` to create one. The path, when known, is carried in `where.path`. Payload: none.

### CONFIG.MISSING_EXTENSION_PACKS [#CONFIG.MISSING_EXTENSION_PACKS]

The contract declares extension packs that the CLI config does not provide matching descriptors for; raised when resolving framework components for any command that loads the contract. The fix is to add the missing extension descriptors to `extensions` in `prisma.config.ts`. Payload: `missingExtensionPacks`, `providedComponentIds`.

### CONFIG.QUERY_RUNNER_FACTORY_REQUIRED [#CONFIG.QUERY_RUNNER_FACTORY_REQUIRED]

Reserved: `db verify` needs `db.queryRunnerFactory` in `prisma.config.ts` and it is absent. Declared in the shared error factories but not raised by any command today.

### CONFIG.VALIDATION_FAILED [#CONFIG.VALIDATION_FAILED]

`prisma.config.ts` loaded but a config section is missing or malformed, as seen by the ORM's own config loader (the language server, the vite plugin, and any tool that calls `loadConfig` outside a command run). The loader validates the `orm` section against its schema and returns one diagnostic per problem, each tagged with the top-level subsection it concerns (`meta.section`: `family`, `target`, `adapter`, `driver`, `extensions`, `db`, `contract`, `migrations`, or `formatter`); a command fails with the diagnostic (exit `2`) only when it reads that section. Under the `prisma` CLI the same problems are reported by the engine instead, as `CLI.CONFIG_FIELD_INVALID` diagnostics (one per field, `meta.section: 'orm'`, `meta.field` the dotted path, `where.path` the config file that declared the field) accompanying `CLI.CONFIG_SECTION_INVALID`. Also raised by framework-component resolution for fields like `frameworkComponents[]`, `frameworkComponents[].kind`/`familyId`/`targetId`, `contract.targetFamily`, and `contract.target`, and by contract-path resolution when `config.contract.output` is absent (those sites carry no `section`). Payload: `field` (loader diagnostics), `section` (loader diagnostics; optional elsewhere).

### CONFIG.VERSION_MARKER_MISSING [#CONFIG.VERSION_MARKER_MISSING]

The config module evaluated, but its default export was not created by the current `defineConfig`: a plain object export, a spread copy of a `defineConfig` result, or a config produced by a different `defineConfig` (for example a classic Prisma ORM 7 config file). Raised by the config loader before validation; loading fails outright and every command exits `2` with this error. The fix is to create the config with `defineConfig` (imported from your target package's `/config` entrypoint, for example `@prisma/orm-postgres/config`) and export its return value directly. The path, when known, is carried in `where.path`. Payload: none.

## CLI [#cli]

### CLI.CONFIG_ARG_MISSING_PATH [#CLI.CONFIG_ARG_MISSING_PATH]

The migration-file CLI (`prisma migration`) received `--config` without a path argument, either a bare trailing `--config`, or `--config` immediately followed by another flag (e.g. `--config --dry-run`). The CLI fails fast instead of consuming the next flag as the config path or silently falling back to default config discovery. Payload: `nextToken` (present only when another flag followed `--config`).

### CLI.CONSENT_OPERATIONS_MISSING [#CLI.CONSENT_OPERATIONS_MISSING]

`db update` was told the plan is destructive but was given no operations to name, so the consent prompt would have asked you to authorise a list of nothing. The command refuses instead of prompting. This is an inconsistency between the CLI and the control API rather than something your project can be wrong about; run `prisma db update --dry-run` to see the plan, and report the run. Payload: none.

### CLI.CONSENT_TOKEN_UNRESOLVED [#CLI.CONSENT_TOKEN_UNRESOLVED]

`db update` could not derive a name for the database it is about to change, so there is nothing for the consent prompt to ask you to type, and an empty token would let a bare Enter (or `--confirm ""`) authorise data loss. The name comes from the `database` a driver connection object carries, or from the connection URL (its first path segment, else its host), falling back to the target id. Name the database in `db.connection` or pass `--db <url>`. Payload: none.

### CLI.CONTRACT_ARG_CONFLICT [#CLI.CONTRACT_ARG_CONFLICT]

`prisma db sign` was given a contract reference twice, once as the positional argument and once as `--contract`, and there is no rule for which one wins. Pass it once. Payload: `positional`, `flag`.

### CLI.ADVANCE_REF_ARG_CONFLICT [#CLI.ADVANCE_REF_ARG_CONFLICT]

`prisma db sign` was told both which ref to advance (`--advance-ref <name>`) and not to advance any ref (`--no-advance-ref`), and there is no rule for which one wins. Pass one of them. Payload: `advanceRef`.

### CLI.FILE_NOT_FOUND [#CLI.FILE_NOT_FOUND]

A file the command needs does not exist at the given path. Produced by several commands: the migration command scaffold, `migrate`, `migration plan`, `migration show`, `db sign`, `db update`, `db verify`, and `ref` all raise it when the emitted `contract.json` (or another required file) is missing from the expected location. Most sites carry the path in `where.path`; the `migration new` contract-file site carries it in the summary text only. Payload: none.

### CLI.FILE_WRITE_FAILED [#CLI.FILE_WRITE_FAILED]

Writing a file failed: currently raised when `format` cannot write the formatted PSL source back to disk (e.g. the file is not writable). The underlying failure is attached as `cause`. Payload: none.

### CLI.INIT_AUTHORING_SCHEMA_PATH_MISMATCH [#CLI.INIT_AUTHORING_SCHEMA_PATH_MISMATCH]

During `prisma orm init`, `--authoring` and `--schema-path` disagree on file extension, for example `--authoring psl` with a schema path ending in `.ts`. Raised before any scaffold files are written, so the project tree stays untouched. Payload: `authoring`, `schemaPath`, `actualExtension`, `expectedExtension`.

### CLI.INIT_EMIT_FAILED [#CLI.INIT_EMIT_FAILED]

During `prisma orm init`, the `prisma contract emit` step failed after a successful dependency install. Scaffolded files and installed dependencies remain on disk; the user fixes the contract file and re-runs the emit command. `init` completes with this as a finding and exits 5. Payload: `filesWritten`, `cause`.

### CLI.INIT_FLAG_CONFLICT [#CLI.INIT_FLAG_CONFLICT]

`prisma orm init --from-prisma7-schema <path>` was combined with `--schema-path` or `--authoring`. The first names an existing Prisma ORM 7 schema as the contract source; the other two describe a starter schema to write, so the pair contradicts itself. Raised before anything is read or written. Maps to init exit code 2 (PRECONDITION). Payload: `flags` (the two kebab-case flag names).

### CLI.INIT_INSTALL_FAILED [#CLI.INIT_INSTALL_FAILED]

During `prisma orm init`, dependency installation failed and the pnpm-to-npm fallback either did not apply or also failed. On a normal run the scaffold is already on disk, and the next actions carry the install command that was attempted and the emit that was waiting on it. On the Prisma ORM 7 path the first install runs before anything is written, to check that the target package can read the schema; when that install fails, `filesWritten` is empty and the next action is to run `init` again once the dependencies install. `init` completes with this as a finding and exits 4. Payload: `filesWritten`, plus `install` (the attempted command, the manager, its exit code and the tail of its stderr).

### CLI.INIT_INVALID_FLAG_VALUE [#CLI.INIT_INVALID_FLAG_VALUE]

A flag passed to `prisma orm init` has a value outside its allowed set (for example `--target` with something other than `postgres` or `mongodb`). Maps to init exit code 2 (PRECONDITION). Payload: `flag`, `value`, `allowed`.

### CLI.INIT_INVALID_MANIFEST [#CLI.INIT_INVALID_MANIFEST]

`prisma orm init` could not parse the project's `package.json` as JSON. Init reads the manifest to merge scripts and to skip `@types/node` when already declared, so a malformed file is a hard precondition failure the user can fix and re-run. Maps to init exit code 2 (PRECONDITION). Payload: `path`, `cause`.

### CLI.INIT_INVALID_OUTPUT_DOCUMENT [#CLI.INIT_INVALID_OUTPUT_DOCUMENT]

`prisma orm init` completed but its own success output document failed schema validation. This indicates a bug in Prisma ORM itself, not user error. The engine-hosted `init` settles it as an errored envelope at exit 2 (the commander `init`, deleted in the S5 cutover, mapped it to exit 1), because the ORM's error boundary converts every failure into a structured settlement and the engine reserves exit 1 for a throw that reaches it uncaught. Payload: none.

### CLI.INIT_INVALID_TSCONFIG [#CLI.INIT_INVALID_TSCONFIG]

`prisma orm init` could not parse the project's existing `tsconfig.json`, even with JSONC tolerance (comments and trailing commas). Init merges required compiler options into it, so an unreadable file blocks the run; raised before any scaffold file is written. Maps to init exit code 2 (PRECONDITION). Payload: `path`, `cause`.

### CLI.INIT_MISSING_FLAGS [#CLI.INIT_MISSING_FLAGS]

`prisma orm init` ran non-interactively (e.g. `--yes`, or stdin is not a TTY) but one or more required inputs (`--target`, `--authoring`, `--schema-path`) were not supplied as flags. Every missing flag is listed so scripts and agents can react without parsing English. When detection found a Prisma ORM 7 project, the message also names `--from-prisma7-schema <path>` as the alternative. Maps to init exit code 2 (PRECONDITION). Payload: `missingFlags`, `prisma7SchemaPath` (`null` when nothing Prisma ORM 7 was found).

### CLI.INIT_PRISMA7_CONFIG_COLLISION [#CLI.INIT_PRISMA7_CONFIG_COLLISION]

On the Prisma ORM 7 path of `prisma orm init`, `prisma.config.*` evaluated as a Prisma ORM 7 config (no `$prismaConfig` marker) while a `prisma7.config.*` also exists. Init renames the Prisma ORM 7 config to `prisma7.config.*` so Prisma ORM can write its own, and cannot rename onto an existing file. Nothing is written. Maps to init exit code 2 (PRECONDITION). Payload: `prismaConfigPath`, `prisma7ConfigPath`.

### CLI.INIT_PRISMA7_CONFIG_UNREADABLE [#CLI.INIT_PRISMA7_CONFIG_UNREADABLE]

On the Prisma ORM 7 path of `prisma orm init`, `prisma.config.*` exists but failed to evaluate (typically a Prisma ORM 7 config importing `prisma/config` in a checkout whose dependencies are not installed). Init cannot tell whether the file is Prisma ORM 7's, to rename, or its own, to replace, so it refuses rather than overwrite it. The fix is to install the project's dependencies so the config evaluates, or rename it to `prisma7.config.<ext>` by hand; when a `prisma7.config.*` already exists, init leaves `prisma.config.*` alone and the fix is to install the dependencies and fix the error in it instead. The normal path is unaffected: without the flag or a yes to the Prisma ORM 7 question, the file is treated as it is today. Nothing is written. Maps to init exit code 2 (PRECONDITION). Payload: `path`, `why`, `prisma7ConfigPath` (`null` when none exists).

### CLI.INIT_PRISMA7_PROVIDER_UNSUPPORTED [#CLI.INIT_PRISMA7_PROVIDER_UNSUPPORTED]

On the Prisma ORM 7 path of `prisma orm init`, the schema's `datasource` block declares a provider Prisma ORM has no target for, or no string provider at all. The supported list is in the payload. When the provider is not a string literal, passing `--target` names the database instead; a string provider with no target is refused whatever `--target` says. Nothing is written or installed. Maps to init exit code 2 (PRECONDITION). Payload: `schemaPath`, `provider` (`null` when not a string literal), `supported`.

### CLI.INIT_PRISMA7_SCHEMA_INVALID [#CLI.INIT_PRISMA7_SCHEMA_INVALID]

The path `prisma orm init` was asked to use as a Prisma ORM 7 schema (`--from-prisma7-schema`, or the path the interactive question named) does not exist, or neither it nor any `.prisma` file under it has a `datasource` block. Nothing is written. Maps to init exit code 2 (PRECONDITION). Payload: `schemaPath`, `reason` (`absent` or `no-datasource`).

### CLI.INIT_PRISMA7_SCHEMA_REFUSED [#CLI.INIT_PRISMA7_SCHEMA_REFUSED]

On the Prisma ORM 7 path of `prisma orm init`, the target package's Prisma ORM 7 contract source refused the schema, for example because it contains a `view` block or an `Unsupported(...)` field. Init runs the source after installing the target package and `dotenv` and before any consent question or file change, so the project is unchanged apart from those two packages. The `why` lists each diagnostic as `<sourceId>:<line>:<column> <code> <message>`. The next actions say to edit the schema as each finding says (the target package's README lists every refusal and its fix) or to run init without `--from-prisma7-schema`, and give the command that removes the two packages. Maps to init exit code 2 (PRECONDITION). Payload: `schemaPath`, `summary`, `diagnostics`, `packagesAdded` (the packages the project did not declare before the check; the remove command names only these).

### CLI.INIT_PRISMA7_SOURCE_UNAVAILABLE [#CLI.INIT_PRISMA7_SOURCE_UNAVAILABLE]

On the Prisma ORM 7 path of `prisma orm init`, the target package cannot read the Prisma ORM 7 schema. Either it has no `prisma7Schema` export while `--from-prisma7-schema` asked for one (`reason: no-prisma7-source`), or it could not be loaded from the project after init installed it (`reason: not-resolvable`). When the user entered the Prisma ORM 7 path by answering yes to init's question instead of passing the flag, a package without `prisma7Schema` is not an error: init warns and runs as a fresh init. Nothing is written apart from the target package and `dotenv` the check installed, and the next actions give the command that removes them. Maps to init exit code 2 (PRECONDITION). Payload: `schemaPath`, `packageName`, `reason`, `packagesAdded` (the packages the project did not declare before the check).

### CLI.INIT_PRISMA7_TARGET_MISMATCH [#CLI.INIT_PRISMA7_TARGET_MISMATCH]

On the Prisma ORM 7 path of `prisma orm init`, `--target` names a different database than the schema's `datasource` provider, for example `--target mongodb` for a schema that declares `provider = "postgresql"`. With `--from-prisma7-schema` it is refused before anything is asked, installed, or written. Without the flag init does not ask its Prisma ORM 7 question and runs as a fresh init, so this code is not raised. Maps to init exit code 2 (PRECONDITION). Payload: `schemaPath`, `provider`, `target` (as passed).

### CLI.INIT_PROBE_FAILED [#CLI.INIT_PROBE_FAILED]

`prisma orm init --probe-db --strict-probe` was run and the database probe could not complete (no `DATABASE_URL`, network or auth error, driver not installed). Without `--strict-probe` these surface as warnings; strict mode escalates them to fatal. Scaffolded files are already on disk when this fires. Maps to init exit code 2 (PRECONDITION). Payload: `filesWritten`, `cause`.

### CLI.INIT_REINIT_NEEDS_FORCE [#CLI.INIT_REINIT_NEEDS_FORCE]

`prisma orm init` ran non-interactively in a directory that already has a `prisma.config.ts`, and consent to overwrite the existing scaffold was not given. Re-scaffolding is destructive, so it needs explicit consent: interactively, `init` asks the user to type the working directory's name back; non-interactively, the same consent is granted by `--confirm <directory name>`. Neither `--yes` nor any flag skips it. Maps to init exit code 2 (PRECONDITION). Payload: none.

The code was raised by the commander `init` (deleted in the S5 cutover), whose consent flag was `--force`. The engine-hosted `init` reaches the same outcome through the engine's own `CLI.CONSENT_REQUIRED`, which names the exact `--confirm` value to pass.

### CLI.INIT_SKILL_INSTALL_FAILED [#CLI.INIT_SKILL_INSTALL_FAILED]

Retired. `prisma orm init` used to fetch the agent skills from GitHub with `skills add`, and raised this at exit `6` when that fetch failed. The skills now ship inside the `@prisma/orm-*` packages a project installs, and `orm init` no longer touches them at all: skills setup belongs to the family-level `prisma init` command, and `prisma skills sync` copies the skills out of the installed packages whenever it runs. Init's remaining failure exits are `4` (dependency install failed) and `5` (contract emission failed); there is no exit `6`, and nothing raises this code.

### CLI.INIT_STRICT_PROBE_WITHOUT_PROBE [#CLI.INIT_STRICT_PROBE_WITHOUT_PROBE]

`prisma orm init --strict-probe` was supplied without `--probe-db`. Init is offline-by-default, so no probe runs without `--probe-db`; rather than silently ignoring the strict flag, init errors and tells the user to add `--probe-db` or drop `--strict-probe`. Maps to init exit code 2 (PRECONDITION). Payload: none.

### CLI.INIT_USER_ABORTED [#CLI.INIT_USER_ABORTED]

The user cancelled an interactive `prisma orm init` prompt (Ctrl-C, escape, or declining a selection) before all required inputs were supplied. No files were modified. Severity is `info`, not `error`; maps to init exit code 3 (USER_ABORTED). Payload: none.

Raised by the commander `init` (deleted in the S5 cutover). On the engine-hosted `init` a cancelled prompt is the engine's own `CLI.PROMPT_CANCELLED`, which exits 3 for every command rather than only this one; the engine-hosted `init` keeps this code for a consent the user declines, which settles as an errored envelope at exit 2 like every other structured failure there. Because that command's consent declares a token, the engine answers a wrong or absent answer with `CLI.PROMPT_INVALID` or `CLI.CONSENT_REQUIRED` before a decline can be expressed, so the code is the refusal that runs if a future consent drops its token.

### CLI.INIT_WRITE_FAILED [#CLI.INIT_WRITE_FAILED]

`prisma orm init` could not write one of the files it scaffolds: a directory sitting where the file goes, permissions, a full disk. Everything that can be read and parsed is checked before the first write, so this is the failure that survives that check; the files written before it are already on disk and are listed so a follow-up run or agent knows the state it is resuming from. On the Prisma ORM 7 path the config rename happens before the first write, so a completed rename is listed too (`filesRenamed`, `from` and `to`); it stays in place and a re-run writes the missing files beside it. Maps to init exit code 2 (PRECONDITION). Payload: `path`, `cause`, `filesWritten`, `filesRenamed`.

### CLI.INVALID_OUTPUT_FORMAT [#CLI.INVALID_OUTPUT_FORMAT]

The main CLI received a `--format` value other than `pretty` or `json`. Raised during global-flag resolution, before any command logic runs. Payload: `value`, `allowed`.

### CLI.INVALID_VERIFY_MODE [#CLI.INVALID_VERIFY_MODE]

`prisma db verify` was given a contradictory mode combination: `--marker-only` together with `--schema-only`, or `--strict` together with `--marker-only` (strict requires schema verification, which marker-only skips). Payload: none.

### CLI.JSON_FORMAT_UNSUPPORTED [#CLI.JSON_FORMAT_UNSUPPORTED]

Reserved: a command was asked for a `--json` sub-format it does not support; the error lists the formats the command does accept. Declared in the shared error factories but not raised by any command today. Payload: `command`, `format`, `supportedFormats`.

### CLI.OUTPUT_FORMAT_CONFLICT [#CLI.OUTPUT_FORMAT_CONFLICT]

The main CLI received mutually exclusive output flags: `--format pretty` together with `--json`. Use `--format json` or `--json` alone for JSON output. Payload: none.

### CLI.PROJECT_MANIFEST_INVALID [#CLI.PROJECT_MANIFEST_INVALID]

A `package.json` found while resolving the project import root is not valid JSON, or parses to something other than a JSON object. Emission reads the nearest manifest to decide which package names generated files should import; fix the manifest's JSON and re-run. The parse failure (when there is one) is attached as `cause`. Payload: `path`.

### CLI.PROJECT_MANIFEST_UNREADABLE [#CLI.PROJECT_MANIFEST_UNREADABLE]

A `package.json` found while resolving the project import root exists but could not be read (e.g. a permissions failure). Absent manifests continue the walk up; a read failure stops it, because silently skipping would emit against the wrong project's dependencies. The read failure is attached as `cause`. Payload: `path`.

### CLI.PROMPT_REQUIRED [#CLI.PROMPT_REQUIRED]

Raised by `@prisma/cli-engine`, not by this repository: a command asked a question that has no default, and the session could not show it: stdin is not a terminal, `--no-interactive` was passed, or `--yes` was asked to answer a prompt that declares no default. The `CLI` namespace is shared with the engine (see [ADR 239](https://github.com/prisma/prisma/blob/main/docs/architecture%20docs/adrs/ADR%20239%20-%20Errors%20are%20structural%20envelopes%20with%20dotted%20namespace%20codes.md)); it is listed here because it settles runs of the ORM's commands. `prisma orm init` translates it for the two prompts that stand in for a required flag, so a missing `--target` or `--authoring` still reports `CLI.INIT_MISSING_FLAGS` with the full missing list. Payload: none.

### CLI.UNEXPECTED [#CLI.UNEXPECTED]

Catch-all for an unanticipated failure inside a CLI command: an unclassified exception is wrapped in this envelope with the original message as the `why`. Thrown across nearly every command (migrate, db init/sign/update/verify, migration plan/new/show/status/log, contract emit, ref, inspect-live-schema, config loading). Payload: none.

### CLI.UNKNOWN_FLAG [#CLI.UNKNOWN_FLAG]

The migration-file CLI (`prisma migration`) received a flag it does not recognise; wraps clipanion's unknown-syntax error at the parser boundary so consumers can build "did you mean" suggestions from meta instead of parsing the message. Payload: `flag`, `knownFlags`.

## CONTRACT [#contract]

### CONTRACT.ARGUMENT_INVALID [#CONTRACT.ARGUMENT_INVALID]

A builder or helper on the contract-authoring surface is called with a bad argument: a composed authoring helper receives too many arguments or a malformed trailing options object, `field.sql({ id })` / `field.sql({ unique })` is used without a matching inline `.id(...)` / `.unique(...)` declaration, `model("Name", ...)` is called without a model definition, a nanoid ID generator is given a size outside 2–255, or an authored index combines its cross-field parameters invalidly (fields and an expression together or neither, an expression without `name:`/`map:`, or `map:` combined with `name:`). Also raised when a contract targets SQLite and declares an expression or partial index: SQLite's namespace construction rejects `expression:`/`where:` because the target does not support them. Also raised when a column with a literal default has type parameters that its codec does not accept (meta: `modelName`, `fieldName`, `codecId`, `reason: 'type-params-invalid'`; the codec's error is the `cause`). Raised while authoring/building the contract, before emit. Payload: varies per site.

### CONTRACT.AGGREGATE_DESCRIPTOR_AMBIGUOUS [#CONTRACT.AGGREGATE_DESCRIPTOR_AMBIGUOUS]

The SQL emitter cannot name one result type for an aggregate: two trait-matching aggregate descriptors both claim a contributed codec, or a descriptor whose result reuses its input's codec also answers calls that carry no input. Raised while generating `contract.d.ts`, so the emitted types can never disagree with what the runtime registry resolves. Payload: `operation`; plus `codecId` and `traits` when two traits claim one codec, the contested codec being nameable only in that case.

### CONTRACT.AGGREGATE_DESCRIPTOR_DUPLICATE [#CONTRACT.AGGREGATE_DESCRIPTOR_DUPLICATE]

Two composed components contribute an aggregate descriptor for the same `(operation, input)` overload, keyed as `sum:trait:numeric`, `sum:codec:pg/int8@1`, or `count:none`. Each overload resolves to exactly one result codec, so exactly one target, adapter, or extension may claim it. Raised while the control stack collects contributions (e.g. during `contract emit`); the runtime plane enforces the same rule as `RUNTIME.DUPLICATE_AGGREGATE_DESCRIPTOR`. Payload: `key`, `contributedBy`, `owner`.

### CONTRACT.AGGREGATE_DESCRIPTOR_INVALID [#CONTRACT.AGGREGATE_DESCRIPTOR_INVALID]

A composed component contributes an aggregate descriptor whose shape the framework cannot read: a missing or empty `operation`, an `input` match that is not `none` / `any` / `codec` / `trait`, an `output` that is not `self` / `codec`, a non-boolean `nullable`, a `nullable: false` descriptor with no `emptyResultJson` (a non-nullable result must declare the value it answers with over no result row), or a `self` output on a match that may carry no input to reuse. Raised while the control stack collects contributions (e.g. during `contract emit`); the runtime plane enforces the same rule as `RUNTIME.AGGREGATE_DESCRIPTOR_INVALID`. Payload: `contributedBy`, `descriptor`.

### CONTRACT.AGGREGATE_OUTPUT_CODEC_MISSING [#CONTRACT.AGGREGATE_OUTPUT_CODEC_MISSING]

The SQL emitter is asked to emit an aggregate result row whose declared result codec the composed stack does not contribute: the emitted type would name a codec absent from the contract's codec map, and every consumer reading it would resolve `never`. Contribute the codec, or declare a result codec the stack contributes. Raised while generating `contract.d.ts`. Payload: `operation`, `outputCodecId`.

### CONTRACT.CODEC_DESCRIPTOR_MISSING [#CONTRACT.CODEC_DESCRIPTOR_MISSING]

The control plane resolves a codec referenced by the contract (a `CodecRef.codecId`) against the contract's pack stack and finds no registered codec descriptor for that id. Hit during control-plane operations (emit, migration tooling) when a contract references a codec no composed pack provides. Payload: `codecId`.

### CONTRACT.CAST_REFUSED [#CONTRACT.CAST_REFUSED]

A value handed to a data type's cast, or to an authoring entry that reads written text, is not one that type takes: it is not in the shape the source type stores, its magnitude is outside the range the receiving type holds, or the text is not a boolean. Raised by a target's or extension's casts and authoring entries. A contract source reading a column default reports it to the author as the PSL diagnostic `PSL_INVALID_DEFAULT_LITERAL`. Payload: `why`, `fix`.

### CONTRACT.CHECK_NAME_RESERVED [#CONTRACT.CHECK_NAME_RESERVED]

An authored `@@check` / `check()`'s `name:` prefix matches the shape a derived enforcement check would use for a column of the same table (`<table>_<column>_check` or `<table>_<column>_elem_not_null`), so it cannot be told apart from a derived check once a non-`managed` table strips those. The message and `collidingColumns` meta name the column(s) whose derived-check shape the prefix matches. Raised while building a SQL contract, once the table's real columns are in hand. The fix is to choose a different `name:`. Payload: `tableName`, `prefix`, `collidingColumns`.

### CONTRACT.CHECK_ON_STI_VARIANT [#CONTRACT.CHECK_ON_STI_VARIANT]

A model declares `@@check` / `check()` but is a single-table-inheritance variant (`@@base` with no own `@@map`), so it shares its base model's storage table and has no table of its own to declare the check on. Raised while building a SQL contract, as a backstop for the TS authoring path; the PSL surface refuses this earlier, at interpretation, with a span-anchored `PSL_CHECK_ON_STI_VARIANT` diagnostic naming the base model. The fix is to declare the check on the base model instead. Payload: `tableName`, `modelName`.

### CONTRACT.CHECK_OPTOUT_INVALID [#CONTRACT.CHECK_OPTOUT_INVALID]

A `@noCheck` / `.noCheck(...)` declaration is invalid. Either it does not apply to the column: the named kind is not derivable for the column's shape (`membership` on a column with no domain-enum value set, `elementNotNull` on a column that is not a list of scalars), or the bare form waives nothing because the column derives no generated checks, or the declaration is malformed: a kind is named twice, or `noCheck()` is called more than once on one field builder. Raised by both authoring paths (TS `defineContract` and PSL interpretation) on `managed` tables. Payload: `modelName`, `fieldName`, `reason`, and `kind` for per-kind failures.

### CONTRACT.COLLECTION_INVALID [#CONTRACT.COLLECTION_INVALID]

A Mongo model's collection attachment is wrong: the model declares `indexes`, `collectionOptions`, or `controlPolicy` but has no collection, or a single collection has `collectionOptions` / `controlPolicy` declared by more than one model. Raised by the Mongo `defineContract` builder. Payload: `modelName`, `collection`, `reason`.

### CONTRACT.CONSTRAINT_INVALID [#CONTRACT.CONSTRAINT_INVALID]

A model declares an empty unique constraint (a unique with no fields), raised during SQL contract lowering (meta: `modelName`). Also raised when a CHECK constraint reaches SQLite migration DDL rendering: the SQLite target does not support CHECK constraints, and `sql.checkConstraint` is a Postgres-only capability. A `@@check` is refused earlier, by the PSL capability gate; a `check()` declared through the TypeScript builder is not, because capabilities reach the contract only after it is built, so this is where a SQLite `check()` is refused (meta: `constraintName`, and `tableName` where available).

### CONTRACT.PRINT_OUTPUT_IS_PROJECT_FILE [#CONTRACT.PRINT_OUTPUT_IS_PROJECT_FILE]

`prisma contract print --output` was asked to write over a file the project needs: the `prisma.config.ts` in the directory of the config that defines the `orm` section, or one of the files `contract emit` writes (the JSON `contract.output` names, and the `.d.ts` beside it). Writing there would put PSL where the CLI reads its config when `--config` names no other file, or the next `contract emit` would write over the printed PSL. The check compares the files the paths name: a path through a symbolic link, or one that differs only in case on a volume that ignores case, counts as the same file. Raised before the source is read, so nothing is written. Pick another `--output` path. Payload: `output` and `file`, both relative to the invocation directory.

### CONTRACT.PRINT_OUTPUT_IS_SOURCE [#CONTRACT.PRINT_OUTPUT_IS_SOURCE]

`prisma contract print --output` was asked to write over a file it reads: the resolved `--output` path is one of the contract source's inputs, or sits inside a directory of source files. Writing there would destroy the source the printed contract is made from. The same code is raised when the path names a new file that a glob input of the source would match once written, because the next `contract emit` would read the printed file together with the source files; `source` is then the glob. Pick another `--output` path, outside the files the config names. Raised before the source is read, so nothing is written and the source file is untouched. Payload: `output` and `source`, both relative to the invocation directory.

### CONTRACT.PRINT_UNSUPPORTED [#CONTRACT.PRINT_UNSUPPORTED]

`contract print` cannot write the loaded contract as Prisma ORM PSL that reads back as the same contract, so it writes nothing. The message names what it stopped on. Raised when the configured family cannot print a contract (no meta), or when the target's descriptor has no `buildPslContract` hook (meta: `targetId`). The Postgres printer raises it in each case below; each case is one function in its `psl-print/refusals.ts`, in this order. Every case is a contract that passes validation. The printer takes a validated contract and does not check its structure again.

* Column types and defaults:
  * no PSL type in the configured stack produces a column's codec, native type and type parameters, including a column that has no value for an argument its type constructor requires. Add the extension that contributes the type to the config (meta: `coordinate`, `nativeType`, `codecId`);
  * a string type argument holds a quote, backslash or line break, which the PSL source reads back differently (meta: `coordinate`, `argument`);
  * a domain enum column defaults to a value that is not a member of the enum (meta: `coordinate`, `pslTypeName`);
  * a column's literal default has no PSL literal that reads back as the stored value, including when the column's codec has no data type in the stack (meta: `coordinate`, `pslTypeName`).
* Generated values:
  * a column pairs the wall-clock-now generator with a different generator (meta: `coordinate`, `onCreate`, `onUpdate`);
  * a column generates a value on update other than through a temporal preset (meta: `coordinate`, `onCreate`, `onUpdate`);
  * a column is generated by a generator no PSL default function of the Postgres adapter produces (meta: `coordinate`, `onCreate`, `onUpdate`);
  * a column has both an id generator and a database default (meta: `coordinate`, `onCreate`);
  * a generated value names a column no field is stored in (meta: `coordinate`).
* Fields and columns:
  * a field and its column disagree where PSL writes them once: the field is optional and the column is not nullable or the reverse, a column of a single-table variant is not nullable, one of them is a list and the other is not, a scalar field's codec or type parameters differ from its column's, or they do not name the enum and value set the PSL source derives for a field typed by an enum (meta: `coordinate`);
  * a model or value-object field's type is a union of types (meta: `coordinate`, `kind`), or a field is a dictionary (meta: `coordinate`);
  * a value-object field carries type parameters or a value set, which the PSL source does not keep on a value-object field (meta: `coordinate`);
  * a value-object field uses a codec that no Postgres codec in the configured stack names a native type for (meta: `coordinate`, `codecId`);
  * a value-object field uses a codec that names a native type only from type parameters (meta: `coordinate`, `codecId`);
  * a field is stored in no column (meta: `namespaceId`, `modelName`, `field`);
  * a model stores a column under a field name the model does not declare (meta: `namespaceId`, `modelName`, `field`);
  * a column is typed by a named type the contract does not declare, or its native type or codec is not the named type's (meta: `coordinate`, `typeRef`);
  * a column has its own control policy (meta: `coordinate`, `control`);
  * a table has no model stored in it (meta: `namespaceId`, `table`), or a column is stored by no field, other than the primary key columns that link a multi-table variant to its base (meta: `namespaceId`, `table`, `column`).
* Models:
  * a model has an owner (meta: `namespaceId`, `modelName`, `owner`);
  * a multi-table variant is linked to its base other than through the base's primary key columns as its unnamed primary key and an unnamed foreign key that cascades on delete (meta: `namespaceId`, `modelName`);
  * one model name is declared in more than one namespace (meta: `modelName`, `namespaces`);
  * a domain enum is declared outside the default namespace (meta: `namespaceId`, `names`);
  * a value object is declared outside the default namespace (meta: `namespaceId`, `names`).
* Keys, checks and indexes:
  * a check or index has a prefix, but its name is not that prefix followed by the hash of its content (meta: `namespaceId`, `table`, `name`, `prefix`);
  * a managed table lacks a check the PSL source derives for an enum or list column, or has a check with that check's name but not its prefix and expression (meta: `namespaceId`, `table`, `name`);
  * an index has options but no type (meta: `namespaceId`, `table`, `index`), or an option whose value is not a string (meta: `namespaceId`, `table`, `index`, `key`).
* Relations:
  * a to-one relation has no foreign key behind it (meta: `model`, `field`);
  * a foreign key has no relation that travels it (meta: `namespaceId`, `table`, `columns`);
  * a relation targets a model in another contract space, which the printer does not write yet (meta: `model`, `field`, `space`);
  * a many-to-many relation goes through a table whose model has no relation back to the relation's model (meta: `model`, `field`);
  * a one-to-many or one-to-one relation has no foreign key of its own, and the model it targets has no relation back that holds the foreign key (meta: `model`, `field`);
  * a relation names no fields to join on (meta: `model`, `field`).
* Enums and value sets:
  * a value set is not the value set of an enum or native enum of that name holding exactly its values, or an enum has no value set holding its members (meta: `namespaceId`, `name`);
  * an enum and a native enum would derive the same value set (meta: `namespaceId`, `name`);
  * a native enum has no value set holding its members (meta: `namespaceId`, `typeName`);
  * a native enum has its own control policy (meta: `namespaceId`, `typeName`, `control`).
* Namespaces, meta and roots:
  * a storage or domain namespace holds nothing PSL writes, or the contract lacks a namespace the PSL source would create, such as the default namespace (meta: `plane`, `namespaceId`);
  * a namespace is named `unbound` and is not the late-binding namespace, which PSL writes as `namespace unbound` (meta: `namespaceId`);
  * the contract has top-level `meta` entries (meta: `keys`);
  * the contract has roots other than one per model that is not a variant, keyed by its table name (meta: `root`).
* Row-level security:
  * a table has row-level security enabled but no model (meta: `namespaceId`, `table`);
  * a policy is on a table with no model (meta: `namespaceId`, `table`, `name`);
  * a policy is on a table without row-level security (meta: `namespaceId`, `table`, `name`);
  * a wire-named policy's name is not its block name followed by the hash of its content (meta: `namespaceId`, `table`, `name`);
  * a role is declared outside the unbound namespace (meta: `namespaceId`, `name`);
  * a row-level security setting or role is filed under a key the PSL source would not file it under (meta: `namespaceId`, `kind`, `name`);
  * a row-level security setting, role or policy records a namespace other than the one it is stored in (meta: `namespaceId`, `kind`, `name`).
* Names and storage entries:
  * a table or column is named `__proto__`, which the PSL source loses when it reads the name from `@@map` or `@map` (meta: `kind`, `name`);
  * a name PSL writes as an identifier is not one, or is `__proto__`: a namespace, model, field, value object, enum, enum member, native enum, named type, policy, role or index option key. `NaN` and `Infinity` are number words, not identifiers (meta: `kind`, `name`);
  * a namespace holds a storage entity kind other than tables, value sets, native enums, row-level security settings, policies and roles (meta: `namespaceId`, `kind`, `names`).

### CONTRACT.DATA_TYPE_DUPLICATE [#CONTRACT.DATA_TYPE_DUPLICATE]

Two components in the composed stack register the same data type id, which has exactly one owner. Raised while assembling the stack's data types. Payload: `dataType`, `contributedBy`, `owner`.

### CONTRACT.DATA_TYPE_ENTRY_DUPLICATE [#CONTRACT.DATA_TYPE_ENTRY_DUPLICATE]

Two components contribute an authoring entry under the same key, so the stack cannot tell which one reads that data type's written form. Raised while merging authoring contributions. Payload: `key`, `contributedBy`, `owner`.

### CONTRACT.DATA_TYPE_ID_INVALID [#CONTRACT.DATA_TYPE_ID_INVALID]

A string given where a data type id belongs is not `owner/name` in lower case, or carries a version (a versioned id names a codec, not a data type). Raised by `dataTypeId()` while declaring a data type or a cast. Payload: `id`.

### CONTRACT.DATA_TYPE_NOT_WRITABLE [#CONTRACT.DATA_TYPE_NOT_WRITABLE]

A data type declares a cast from a type no contract source can write, so the cast could never be exercised. Raised while checking the assembled data types. Payload: `dataType`, `source`, `contributedBy`.

### CONTRACT.DATA_TYPE_UNREGISTERED [#CONTRACT.DATA_TYPE_UNREGISTERED]

Something names a data type that no component in the stack registers: a codec's `dataType`, an authoring entry's key, a type its number classifier returns, or a type a cast takes values of. Raised while checking the assembled data types. Payload: `dataType`, `contributedBy`.

### CONTRACT.DATA_TYPE_WRITTEN_FORM_DUPLICATE [#CONTRACT.DATA_TYPE_WRITTEN_FORM_DUPLICATE]

Two authoring entries claim the same written form — the same literal tag, or the same plain string, boolean, or number syntax — so a written default would have two readers. Raised while checking the assembled data types. Payload: `claim`, `key`, `contributedBy`, `owner`, `ownerContributedBy`.

### CONTRACT.DEFAULT_INVALID [#CONTRACT.DEFAULT_INVALID]

A field's default declaration is invalid: `defaultSql` is used on an enum field, a field declares both `default` and `executionDefaults`, or a field is nullable while carrying `executionDefaults`. Raised while authoring/building a SQL contract. Payload: `modelName`, `fieldName`, `reason`. The SQL TypeScript builder also raises it when the column's codec refuses the value passed to `.default(value)`, because the value is not the codec's input type (for example a string on `field.dateTime()`, whose codec takes a `Temporal.Instant`); TypeScript reports the same mistake as a type error when the field comes from the `defineContract` factory; the message carries the codec's own message, the original error is the `cause`, and the meta is `modelName`, `fieldName`, `codecId`, `reason: 'codec-refused-default'` and, for a list column, the 1-based `elementPosition`. It raises it too when the build has a codec lookup and no pack in the contract declares the column's codec, so the default cannot be checked (`reason: 'codec-not-found'`; list the pack that owns the codec in `extensions`), and when a list field has a default that is not an array (`reason: 'list-default-not-array'`). The Mongo TypeScript builder raises it for execution defaults it cannot key to one collection field: on a variant model's field (`reason: 'executionDefaults-on-variant'`; declare the field on the base model, whose defaults apply to every variant), or with different phases on two models stored in the same collection (`reason: 'executionDefaults-conflict'`; identical ones are merged). The PSL interpreter reports the same cases as `PSL_PRESET_ON_VARIANT_FIELD` and `PSL_PRESET_CONFLICT`. Also raised by the Postgres adapter's DDL renderer when a hand-authored `col(...)` pairs an `autoincrement()` default with a type that isn't `SERIAL`/`BIGSERIAL`/`SMALLSERIAL` (or their `SERIAL4`/`SERIAL8`/`SERIAL2` aliases). Meta in that case: `nativeType`. Also raised by the TypeScript `sql` template tag when the body cannot be canonicalized, with the same message as the PSL diagnostics `PSL_TAGGED_LITERAL_NUL` and `PSL_TAGGED_LITERAL_TOO_LARGE` (meta: `reason`, `offset`) or is exactly `now()` or `autoincrement()` (``Write .default(now()) instead of sql`now()`; now() is a Prisma default function, not raw SQL.``; meta: `reason: 'reserved-function'`, `expression`), or fails the SQL body check (`Default SQL must not contain semicolons, SQL comment tokens, dollar-quoting, or subqueries.`; meta: `reason: 'unsafe-sql'`, `expression`), and by both the Postgres and SQLite migration planners when a function default in the contract fails that same check at DDL time (meta: `expression`).

### CONTRACT.DEFAULT_SQL_INTERPOLATION [#CONTRACT.DEFAULT_SQL_INTERPOLATION]

The TypeScript `sql` template tag was called with interpolated values: ``sql`...` does not support interpolation; write the SQL as one literal.`` Interpolation is already a type error (`...values: readonly never[]`); this is the runtime backstop. Meta: `interpolations` (how many values were passed).

### CONTRACT.ENTITY_KIND_INVALID [#CONTRACT.ENTITY_KIND_INVALID]

An entity attached to the contract declares a framework-wire namespace entry kind (`table` or `valueSet`), which only the framework itself may mint. Raised while building a SQL contract with pack-contributed entities. Payload: `entityKind`, `namespaceId`.

### CONTRACT.ENTITY_KIND_UNKNOWN [#CONTRACT.ENTITY_KIND_UNKNOWN]

An entity handle passed to the contract has an `entityKind` that no composed pack registers, so the builder cannot lower it, or contract entries carry a kind no composed pack recognizes when the framework hydrates entities from an emitted contract. Raised during SQL contract lowering and entity hydration. Payload: `entityKind`.

### CONTRACT.ENUM_CODEC_NOT_IN_PACK_STACK [#CONTRACT.ENUM_CODEC_NOT_IN_PACK_STACK]

An enum declares a `codecId` that no family, target, or extension pack in the contract provides, so its member values cannot be encoded. Raised by both authoring paths (TS `defineContract` and PSL interpretation) when the codec lookup built from the contract's packs has no descriptor for the id. Payload: `codecId`.

### CONTRACT.ENUM_INVALID [#CONTRACT.ENUM_INVALID]

An enum declaration is malformed: it has no members, a duplicate member name or value, or the declaration key in `defineContract({ enums })` does not match the `enumType` name. Raised while authoring a contract (framework `enumType`, SQL and Mongo builders). Payload: `enumName`, `member`, `reason`.

### CONTRACT.ENUM_UNKNOWN [#CONTRACT.ENUM_UNKNOWN]

A Mongo field references an enum that is not declared in `defineContract({ enums })`. Raised by the Mongo contract builder. Payload: `modelName`, `fieldName`, `enumName`.

### CONTRACT.EXPORT_INVALID [#CONTRACT.EXPORT_INVALID]

The TS contract module's export is not a plain JSON-serializable contract object: a non-object export, circular references, getters, or function-valued properties. Raised by the CLI while loading a TypeScript contract source. Payload: `path`, `reason`, `key`.

### CONTRACT.FIELD_UNKNOWN [#CONTRACT.FIELD_UNKNOWN]

An index or column mapping references a field the model does not declare (unknown field in the contract definition, or a Mongo model index over an undeclared field). Raised while lowering/building the contract. Payload: `modelName`, `fieldName`, `indexSignature`.

### CONTRACT.FOREIGN_KEY_INVALID [#CONTRACT.FOREIGN_KEY_INVALID]

A foreign key's target refs are empty or inconsistent: no target ref given, refs point at different models, or compound refs disagree on `spaceId`, `namespaceId`, or `tableName`. Raised by the SQL contract DSL while declaring the FK. Payload: `mismatch`, `first`, `second`.

### CONTRACT.IDENTITY_INVALID [#CONTRACT.IDENTITY_INVALID]

A model's identity is wrong: multiple fields marked `.id()`, identity declared both inline and in `.attributes(...)`, an empty identity, a model with non-owning relations but no id to anchor them, or an M:N target with no primary/unique key to derive junction columns from. Raised while lowering/building a SQL contract. Payload: `modelName`, `reason`.

### CONTRACT.IDENTIFIER_INVALID [#CONTRACT.IDENTIFIER_INVALID]

A SQL identifier or literal fails escaping-safety checks while rendering DDL/SQL: an empty identifier, a null byte in an identifier or string literal, or a native enum label exceeding PostgreSQL's 63-byte limit. Raised by the Postgres and SQLite SQL utilities (formerly the `SqlEscapeError` class, removed at 0.17). Payload: `value`, `context`.

### CONTRACT.INDEX_INVALID [#CONTRACT.INDEX_INVALID]

A Mongo variant model declares an index that conflicts with the discriminator scope of its variant, or a SQL index option value is not a string, finite number, or boolean. Raised by the Mongo contract builder and the Postgres index DDL renderer. Payload: `variantName`, `indexLabel`, `reason`, `key`.

### CONTRACT.INFER_UNSUPPORTED [#CONTRACT.INFER_UNSUPPORTED]

`contract infer` is not available: either the configured family does not implement the `PslContractInferCapable` capability (no meta at that site), or the family supports inference but the database shape cannot be expressed yet: duplicate table names across schemas, a column typed by a native enum that an extension pack space already describes in another schema, or native enum adoption with content spanning multiple schemas. Meta at the shape sites: `tableName`, `columnName`, `schemas`.

### CONTRACT.INTROSPECTION_UNSUPPORTED [#CONTRACT.INTROSPECTION_UNSUPPORTED]

Introspection read an unrecognized or malformed database shape: an unknown referential action rule, or a malformed index reloption entry. Raised by the Postgres and SQLite control adapters. Payload: `rule`, `entry`, `indexName`.

### CONTRACT.INVALID_JSON_LITERAL [#CONTRACT.INVALID_JSON_LITERAL]

The body of a JSON default is not a JSON document, or holds a number outside the range a JSON number holds (`JSON.parse` reads such a numeral as `Infinity`, which `JSON.stringify` writes back as `null`). Raised while canonicalizing a JSON default body. Contract sources report it to the author as the PSL diagnostic `PSL_INVALID_JSON_LITERAL`. Payload: `why`, `fix`.

### CONTRACT.MARKER_MISMATCH [#CONTRACT.MARKER_MISMATCH]

The contract hash does not match the marker (signature) stored in the database. `db verify` reports it as an `error` diagnostic on a completed run that exits `4`; the SQL runtime reports it as a warning during startup marker verification. Fix path: migrate the database or re-sign if the divergence is intentional. Payload: `expected`, `actual`.

### CONTRACT.MARKER_MISSING [#CONTRACT.MARKER_MISSING]

No contract marker (database signature) is found in the database at all. `db verify` reports it as an `error` diagnostic on a completed run that exits `4`; the runtime reports it as a warning during startup marker verification. Fix path: `prisma db sign`. Payload: none notable.

### CONTRACT.MARKER_READ_FAILED [#CONTRACT.MARKER_READ_FAILED]

A driver-level failure occurred while reading the contract marker table: connectivity, permissions, or locking problems rather than bad marker content. Raised whenever a CLI/control operation reads the marker. Payload: `space`.

### CONTRACT.MARKER_REQUIRED [#CONTRACT.MARKER_REQUIRED]

A command that requires a pre-signed database (marker present) as a precondition found none; also the default failure code stamped onto a non-ok verify result when no more specific code applies, which is how `db verify --strict` reports a database holding elements no contract declares. On `db verify` it is an `error` diagnostic on a completed run that exits `4`; everywhere else it is a precondition failure at exit `2`. Those are two unrelated jobs for one code: "sign the database first" and "strict mode found elements no contract declares", and splitting them would let the exit code follow from the code alone. Fix path: run `prisma db init` first, or declare the extra elements in a contract. Payload: none notable.

### CONTRACT.MARKER_ROW_CORRUPT [#CONTRACT.MARKER_ROW_CORRUPT]

The marker row exists but its column values fail schema validation: the row is corrupt or written by an incompatible version. Fix path: delete the row and re-sign with `prisma db sign`. Payload: `space`.

### CONTRACT.MODEL_BASE_MISSING [#CONTRACT.MODEL_BASE_MISSING]

A variant model names a `base` that is not a model in the contract, so its type in `contract.d.ts` cannot include the base's fields. Raised while emitting `contract.d.ts`. Payload: `variant`, `base`.

### CONTRACT.MODEL_RELATION_TARGET_MISSING [#CONTRACT.MODEL_RELATION_TARGET_MISSING]

A same-space relation points at a model the contract does not declare. Raised while emitting the `Models` namespace in `contract.d.ts`; only cross-space relations may reference models outside the contract. Payload: `owner`, `relationName`, `target` (`namespaceId`, `modelName`).

### CONTRACT.MODEL_TOKEN_INVALID [#CONTRACT.MODEL_TOKEN_INVALID]

A model token is misused in the TS authoring DSL: an unnamed token is used in `.ref(...)` or as a relation target (tokens need `model("Name", ...)`), or a token is assigned under a `models` key that does not match its name. Payload: `tokenModelName`, `assignedKey`.

### CONTRACT.MODEL_TYPE_NAME_COLLISION [#CONTRACT.MODEL_TYPE_NAME_COLLISION]

Two models produce the same emitted type name in the `Models` namespace of `contract.d.ts`, formed as `<namespace>_<Model>`, for example a `public_User` model beside a `public` namespace holding `User`, or a model named `AnyTask` beside a polymorphic base `Task`. Raised while emitting `contract.d.ts`. Payload: `memberName`, `sources`.

### CONTRACT.MODEL_TYPE_NAME_INVALID [#CONTRACT.MODEL_TYPE_NAME_INVALID]

An emitted model type name, formed as `<namespace>_<Model>`, is not a TypeScript identifier, for example because the namespace contains a hyphen. Raised while emitting `contract.d.ts`. Payload: `memberName`, `source`.

### CONTRACT.MODEL_UNKNOWN [#CONTRACT.MODEL_UNKNOWN]

A relation, foreign key, junction (`through`) reference, or context declaration names a model that is not declared in the contract. Raised while lowering/building a SQL contract. Payload: `sourceModel`, `relationName`, `targetModel`.

### CONTRACT.MODEL_VARIANT_MISSING [#CONTRACT.MODEL_VARIANT_MISSING]

A polymorphic base names a variant that is not a model in the same namespace, so the `Any<Base>` union in `contract.d.ts` cannot be formed. Raised while emitting `contract.d.ts`. Payload: `base`, `variantName`.

### CONTRACT.MODULE_EXPORT_MISSING [#CONTRACT.MODULE_EXPORT_MISSING]

The contract module at the configured path loads but exposes neither a `default` nor a `contract` export, so the CLI cannot obtain the contract from it. Raised when resolving a TS contract from config (SQL and Mongo). Payload: `path`.

### CONTRACT.NAME_DUPLICATE [#CONTRACT.NAME_DUPLICATE]

Two declarations claim the same name: duplicate namespace entries, model names, value objects, relations, tables (two models mapping to one table, or duplicate table in a namespace), column mappings (two fields to one column), indexes, value-sets (enum and pack entity minting the same value-set), or pack entities of the same kind and name in one namespace. Raised while authoring/building a contract. Payload: `kind`, `name`, `namespaceId`, `first`, `second`.

### CONTRACT.NAMESPACE_INVALID [#CONTRACT.NAMESPACE_INVALID]

A namespace name is empty, whitespace-only, or a reserved sentinel (`__unbound__`, `__unspecified__`, or Postgres's reserved `unbound`), either in the declared `namespaces` list or on a model. Raised by the SQL contract builder. Payload: `namespace`, `reason`, `modelKey`.

### CONTRACT.NAMESPACE_UNKNOWN [#CONTRACT.NAMESPACE_UNKNOWN]

A model references a namespace that is not in the contract's declared `namespaces` list. Raised by the SQL contract builder. Payload: `modelKey`, `namespace`, `declared`.

### CONTRACT.NAMESPACE_UNSUPPORTED [#CONTRACT.NAMESPACE_UNSUPPORTED]

Namespaces are declared (contract-level list or a model-level `namespace`) on a target that has no schema/namespace concept, i.e. SQLite. Raised by the SQL contract builder. Payload: `namespaces`, `modelKey`, `targetId`.

### CONTRACT.NATIVE_TYPE_INVALID [#CONTRACT.NATIVE_TYPE_INVALID]

A native type name in the contract fails the identifier-safety pattern required to render it into DDL. Raised by the Postgres and SQLite migration planners while building column DDL. Payload: `nativeType`.

### CONTRACT.PACK_CONTRIBUTION_INVALID [#CONTRACT.PACK_CONTRIBUTION_INVALID]

A composed pack's contribution is malformed or collides with another contribution; this is the extension-author-facing bucket. Covers: entity types colliding with reserved helper keys, duplicate entity kinds or index-type registrations, a registered entity kind with no `lowerEntityHandles` lowering, an invalid `indexTypes` shape, entries-slot collisions between a model attribute and a block entry kind, a model attribute that lowers to a malformed index, bad authoring-helper paths, a codec registered with an entity-ref arg but no `columnFromEntity` hook, and print-time contribution mismatches (a block keyword with no PSL block descriptor, or a descriptor whose discriminator disagrees with the block's kind). Raised during contract authoring/lowering and PSL printing. Payload: `packId`, `contribution`, `reason`, `keyword`, `paramName`, `codecId`.

### CONTRACT.PACK_FAMILY_MISMATCH [#CONTRACT.PACK_FAMILY_MISMATCH]

A pack passed to `defineContract` belongs to the wrong family: a non-SQL pack in a SQL contract (or non-Mongo in a Mongo contract), a target pack whose family disagrees with the contract's, or an extension pack from another family. Payload: `packId`, `packFamilyId`, `contractFamilyId`.

### CONTRACT.PACK_MISSING [#CONTRACT.PACK_MISSING]

A cross-space reference names a contract space that is not declared in the contract's `extensions`, so the space cannot be resolved. Raised during SQL contract lowering. Payload: `spaceId`, `context`.

### CONTRACT.PACK_REF_INVALID [#CONTRACT.PACK_REF_INVALID]

Something other than an extension pack reference was passed in `defineContract`'s `extensions` list (e.g. a family or target pack). Payload: `packId`, `kind`.

### CONTRACT.PACK_TARGET_MISMATCH [#CONTRACT.PACK_TARGET_MISMATCH]

An extension pack targets a different database target than the contract does (e.g. a Postgres-only extension pack in a SQLite contract). Raised by the SQL and Mongo contract builders. Payload: `packId`, `packTargetId`, `contractTargetId`.

### CONTRACT.POLICY_INVALID [#CONTRACT.POLICY_INVALID]

An RLS policy declaration is invalid: it targets a model in another contract space, its prefix exceeds the length limit or is declared twice in one namespace, or it targets a table that is not RLS-enabled or not present in the namespace. Raised by the Postgres `defineContract` builder and while deriving the Postgres schema tree from the contract. Payload: `prefix`/`policyName`, `tableName`, `namespaceId`, `reason`.

### CONTRACT.RELATION_INVALID [#CONTRACT.RELATION_INVALID]

A relation's shape is wrong: `.sql(...)` on a non-belongsTo relation, mismatched field counts between the two sides, an N:M relation without `through` metadata, or a relation target referencing a field of another model. Raised while authoring/building a contract (SQL and Mongo). Payload: `modelName`, `relationName`, `reason`.

### CONTRACT.ROLE_INVALID [#CONTRACT.ROLE_INVALID]

A role entity is declared more than once in the entities list, or a role name is not a plain SQL identifier. Raised by the Postgres contract builder and RLS DDL rendering. Payload: `role`, `reason`.

### CONTRACT.SCHEMA_VERIFICATION_FAILED [#CONTRACT.SCHEMA_VERIFICATION_FAILED]

Schema verification found that the live database schema does not satisfy the contract: missing/extra/mismatched tables, columns, or other elements. `db verify` and `db sign` both report it as an `error` diagnostic on a completed run that exits `4`: for `db verify` that is the drift verdict, and for `db sign` it is the reason no signature was written. `db verify` raises one such diagnostic per contract space whose schema failed. Fix path: `prisma db update` or adjust the contract. Payload: `space` (the contract space, on `db verify`), `issues` (the drifted element paths); the underlying operation result also carries `verificationResult`.

### CONTRACT.SOURCE_IMPORT_DISALLOWED [#CONTRACT.SOURCE_IMPORT_DISALLOWED]

The TypeScript contract module imports something outside the contract-source import allowlist; contract sources must stay pure so they can be bundled and evaluated deterministically. Raised by the CLI while loading a TS contract source. Payload: `allowlist`, `disallowed`.

### CONTRACT.SOURCE_DIAGNOSTIC [#CONTRACT.SOURCE_DIAGNOSTIC]

One finding a contract source reported with a code that is not yet dotted, such as the Prisma ORM PSL interpreter's `PSL_UNSUPPORTED_FIELD_TYPE` or a parser's `PSL_PARSE_ERROR`. This is its only producer case: it exists until those codes convert to dotted ones, and a source code that is already dotted, such as `PSL.PRISMA7_VIEW_UNSUPPORTED`, is reported under its own code instead. Never raised on its own; carried, one per such source diagnostic, in the `diagnostics` list of a `CONTRACT.SOURCE_LOAD_FAILED` error during `contract emit` or `contract print`, printed under it in the terminal and serialized as the envelope's `diagnostics` in JSON. `summary` is `<file>:<line>:<column> <source code>: <message>` (the location is omitted when the source gave none). `where` carries `path` and `line`. Payload: `code` (the source's own diagnostic code). Fix: edit the schema at each location the findings name, then run the command again. One such source code is `PSL_UNKNOWN_DEFAULT_FUNCTION`, reported by the Prisma ORM PSL interpreter for a `@default` function the composed stack does not register; its message lists the supported functions, and for the removed `dbgenerated(...)` it is ``Default function "dbgenerated" was removed. Write the SQL as a tagged literal: @default(sql`<expression>`). Supported functions: <list>.``

### CONTRACT.SOURCE_LOAD_FAILED [#CONTRACT.SOURCE_LOAD_FAILED]

Loading the contract source failed: bundling or evaluating the TypeScript contract module (esbuild bundle error, or the module threw on import), the contract source provider returning a failure or a malformed result during `contract emit` or `contract print`, or `format` failing to read the PSL source file. The underlying failure is attached as `cause` where one exists. Payload: `path`, `stage` (`bundle` or `import`) at the TS-loader site; `diagnostics`, `issues`, `providerMeta` at the emit provider site; none at the format read site. At the emit provider site the error also carries a `diagnostics` list with one finding per source diagnostic: under the source's own code when it is dotted (for example `PSL.PRISMA7_VIEW_UNSUPPORTED`), otherwise as `CONTRACT.SOURCE_DIAGNOSTIC`.

### CONTRACT.TABLE_AMBIGUOUS [#CONTRACT.TABLE_AMBIGUOUS]

A storage table name resolves in more than one namespace of the contract and needs namespace qualification to disambiguate. Raised whenever a bare table name is resolved against contract storage (authoring and runtime paths). Payload: `tableName`, `candidates`.

### CONTRACT.TABLE_MISMATCH [#CONTRACT.TABLE_MISMATCH]

A foreign key or index references a table name that disagrees with the table the target model is actually mapped to. Raised while building a SQL contract. Payload: `sourceModel`, `referencedTable`, `mappedTable`.

### CONTRACT.TARGET_MISMATCH [#CONTRACT.TARGET_MISMATCH]

The contract's target does not match the target configured in `prisma.config.ts` (e.g. a Postgres contract with a SQLite config). `db verify` reports it as an `error` diagnostic on a completed run that exits `4`. Payload: `expected`, `actual`.

### CONTRACT.TYPE_UNKNOWN [#CONTRACT.TYPE_UNKNOWN]

A field references a storage type that cannot be resolved: a storage type instance not in `definition.types`, an unknown storage type name, or a field that never resolves to a storage descriptor. Raised during SQL contract lowering. Payload: `modelName`, `fieldName`, `typeRef`.

### CONTRACT.UNREADABLE [#CONTRACT.UNREADABLE]

The emitted contract file could not be read or parsed while computing `migration status`; reported as a warn-severity diagnostic on the status result rather than a thrown error, with the hint to re-run `prisma contract emit`. Payload: none (diagnostic carries `message` and `hints`).

### CONTRACT.TYPES_RENDER_FAILED [#CONTRACT.TYPES_RENDER_FAILED]

A command advancing a ref (`db sign`, `db init`, `db update`, `migrate --advance-ref`) could not render the `contract.d.ts` of the contract it is about to snapshot: the family accepted the JSON but the emitter refused it (for example a to-one relation with no declared nullability). Raised before the command touches the database, so nothing is migrated and no ref or snapshot is written; run `prisma contract emit` to see the emitter's own diagnosis. The emitter's error is attached as `cause`. Payload: none (`where.path` names the contract JSON).

### CONTRACT.VALIDATION_FAILED [#CONTRACT.VALIDATION_FAILED]

Aggregate contract validation failed: structural validation of the contract JSON (`ContractValidationError` with a `phase` of structural/domain/storage), semantic validation during `buildContract`, or storage/model validators rejecting the built contract. Raised at emit/authoring time and whenever a contract is loaded and validated. Also raised by `migration new` when the emitted contract has no `storageHash`; that site has no meta. Payload: `errors` (aggregate site); the error class also carries `phase`.

### CONTRACT.VERIFY_FAILED [#CONTRACT.VERIFY_FAILED]

`db verify` failed for a reason the verify result did not classify under a more specific code (marker, target, or schema-verification codes). Reported as an `error` diagnostic on a completed run that exits `4`, with the verify result's own text as the summary. Payload: none.

### CONTRACT.WIRE_NAME_PREFIX_TOO_LONG [#CONTRACT.WIRE_NAME_PREFIX_TOO_LONG]

An authored wire-name prefix (an index name, an RLS policy prefix, or a check's `name:` prefix) exceeds the 54-byte maximum: Postgres identifiers cap at 63 bytes and the wire name appends a 9-byte `_<8hex>` content-hash suffix. Raised at contract lowering. Payload: `prefix`, `maxBytes`.

## PSL [#psl]

### PSL.FORMAT_OPTION_INVALID [#PSL.FORMAT_OPTION_INVALID]

`resolveFormatOptions` was given an invalid formatting option: a non-positive/non-integer `indent` or an unrecognized `newline` value. Raised before any PSL source is read. Payload: `option`, `received`.

### PSL.PARSE_FAILED [#PSL.PARSE_FAILED]

`format()` was asked to format PSL source that has parse errors; formatting refuses to run on an unparseable document. The message carries the first diagnostic and a count of the rest; the CLI `format` command wraps this into a structured failure telling the user to fix the parse errors, attaching the parser error as `cause`. Payload: `diagnostics`.

### PSL.PRISMA6_MONGO_COMPOSITE_ID_UNSUPPORTED [#PSL.PRISMA6_MONGO_COMPOSITE_ID_UNSUPPORTED]

`@@id` on a model; a MongoDB document is identified by its `_id` field alone. Declare the id as `id String @id @default(auto()) @map("_id") @db.ObjectId`. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_COMPOSITE_INDEX_PATH_UNSUPPORTED [#PSL.PRISMA6_MONGO_COMPOSITE_INDEX_PATH_UNSUPPORTED]

An `@@index`, `@@unique`, or `@@fulltext` path that reaches into a composite type, such as `address.city(sort: Asc)`, which the Mongo contract cannot express yet. Index a top-level field or remove the index. A dotted path without a call, such as `address.city`, fails at parse time instead. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_COMPOSITE_MAP_UNSUPPORTED [#PSL.PRISMA6_MONGO_COMPOSITE_MAP_UNSUPPORTED]

`@map` on a field of a composite `type`, which the Mongo contract cannot express yet. Removing `@map` renames the stored field, so keep the schema until Prisma ORM supports it. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_CONTRACT_INVALID [#PSL.PRISMA6_MONGO_CONTRACT_INVALID]

The Prisma 6 MongoDB schema gives a contract that Prisma ORM rejects, for a cause the source has no specific diagnostic for: a structured error was thrown while the contract was built, or the contract failed the domain or storage check. This is a bug in Prisma ORM; the message names the cause, and the user should report it with the schema. Reported at the schema path by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file> <message>` (the terminal prints the code before it), and `where` carries `path`. Payload: none; the error's `providerMeta` carries `schemaPath` and the thrown error's `code`.

### PSL.PRISMA6_MONGO_DEFAULT_UNSUPPORTED [#PSL.PRISMA6_MONGO_DEFAULT_UNSUPPORTED]

A `@default` other than `now()` on a `DateTime` field and `auto()` on the id: a literal, `uuid()`, `cuid()`, `dbgenerated(...)`, `now()` on another type, or `auto()` on another field. MongoDB has no stored defaults, and Prisma ORM fills only `now()`. Remove the default and set the value when documents are created. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_ID_NOT_OBJECTID [#PSL.PRISMA6_MONGO_ID_NOT_OBJECTID]

The model's `@id` is not a required `String @db.ObjectId` stored as `_id`. Declare it as `id String @id @default(auto()) @map("_id") @db.ObjectId`. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_IGNORED_FIELD_REFERENCED [#PSL.PRISMA6_MONGO_IGNORED_FIELD_REFERENCED]

An `@ignore`d field is used by `@unique`, `@@unique`, `@@index`, `@@fulltext`, or a relation's `fields:` or `references:`, and Prisma 6 still creates that index or reads that key. Remove `@ignore` from the field, or remove what uses it. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_INDEX_ARGUMENT_UNSUPPORTED [#PSL.PRISMA6_MONGO_INDEX_ARGUMENT_UNSUPPORTED]

An index argument a Mongo contract index cannot carry, such as `length`, or an unknown argument. `sort` is read, and `map` and `name` are accepted and dropped, since Mongo verify matches indexes by keys and options. Remove the argument. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_LIST_RELATION_UNSUPPORTED [#PSL.PRISMA6_MONGO_LIST_RELATION_UNSUPPORTED]

A list relation whose keys live in a list field (a many-to-many relation on MongoDB), which Prisma ORM does not support yet. Remove the relation fields and keep the key list as a plain field. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_NATIVE_TYPE_UNSUPPORTED [#PSL.PRISMA6_MONGO_NATIVE_TYPE_UNSUPPORTED]

A `@db.*` attribute other than `@db.ObjectId`, or `@db.ObjectId` on a field that is not a `String`. Remove it; the stored BSON type then follows the field type. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_OPTIONAL_GENERATED_FIELD_UNSUPPORTED [#PSL.PRISMA6_MONGO_OPTIONAL_GENERATED_FIELD_UNSUPPORTED]

`@default(now())` or `@updatedAt` on an optional field. Make the field required, or remove the attribute and set the value when documents are written. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_PROVIDER_MISMATCH [#PSL.PRISMA6_MONGO_PROVIDER_MISMATCH]

The Prisma 6 schema has no `datasource` block, or its `provider` is not `mongodb`. Use the source only with a MongoDB schema. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_REFERENTIAL_ACTION_UNSUPPORTED [#PSL.PRISMA6_MONGO_REFERENTIAL_ACTION_UNSUPPORTED]

`onDelete`, `onUpdate`, or `map` on `@relation`. Prisma ORM enforces no referential actions on MongoDB, and MongoDB has no foreign key constraint for `map` to name. Remove the argument and handle related documents in application code. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_SCHEMA_READ_FAILED [#PSL.PRISMA6_MONGO_SCHEMA_READ_FAILED]

The schema path could not be read, or the schema directory holds no `.prisma` file. Fix the path. Reported at the schema path by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file> <message>` (the terminal prints the code before it), and `where` carries `path`. Payload: none; the error's `providerMeta` carries the schema path.

### PSL.PRISMA6_MONGO_SCHEMA_UNSUPPORTED [#PSL.PRISMA6_MONGO_SCHEMA_UNSUPPORTED]

`@@schema` on a model or enum; a MongoDB contract has one database, bound by the connection string. Remove `@@schema`. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_TEXT_INDEX_LIMIT [#PSL.PRISMA6_MONGO_TEXT_INDEX_LIMIT]

A model with more than one `@@fulltext`; MongoDB allows one text index per collection. Merge the fields into one `@@fulltext`. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_UNKNOWN_ATTRIBUTE [#PSL.PRISMA6_MONGO_UNKNOWN_ATTRIBUTE]

An attribute the source does not read. Remove it. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_UNSUPPORTED_TYPE [#PSL.PRISMA6_MONGO_UNSUPPORTED_TYPE]

A field of type `Unsupported("...")`, which has no Prisma ORM codec, or of a type name that is not a scalar type, enum, composite type, or model. For `Unsupported`, Prisma 6 rejects `@ignore` on the field; remove the field, or add `@@ignore` to the model, which also needs `@ignore` on every relation field that points to it. For an unknown name, correct the type name. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_UPDATED_AT_TYPE_UNSUPPORTED [#PSL.PRISMA6_MONGO_UPDATED_AT_TYPE_UNSUPPORTED]

`@updatedAt` on a field that is not a `DateTime`. Remove `@updatedAt` and set the value when documents are written. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA6_MONGO_VIEW_UNSUPPORTED [#PSL.PRISMA6_MONGO_VIEW_UNSUPPORTED]

A `view` block; Prisma ORM has no views on MongoDB. Remove the view from the schema the source reads. Reported by the Prisma 6 MongoDB contract source (`prisma6Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_CONTRACT_INVALID [#PSL.PRISMA7_CONTRACT_INVALID]

The Prisma ORM 7 schema gives a contract that Prisma ORM rejects, for a cause the source has no specific diagnostic for: a structured error was thrown while the contract was built, or the contract failed the domain, storage consistency, or model storage reference check. This is a bug in Prisma ORM; the message names the cause, and the user should report it with the schema. Reported at the schema path by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none; the error's `providerMeta` carries `schemaPath` and the thrown error's `code`.

### PSL.PRISMA7_ENUM_NAMESPACE_MISMATCH [#PSL.PRISMA7_ENUM_NAMESPACE_MISMATCH]

A field uses an enum declared under a different `@@schema`; a Postgres enum lives in one schema and a Prisma ORM column references the enum of its own namespace. Declare the enum in the model's schema, or move the model. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_IGNORED_FIELD_REFERENCED [#PSL.PRISMA7_IGNORED_FIELD_REFERENCED]

An `@ignore`d field is used by `@id`, `@unique`, `@@id`, `@@unique`, `@@index`, or a relation's `fields:`, and Prisma ORM 7 still creates that key, index, or foreign key over its column. Remove `@ignore` from the field. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_INDEX_ARGUMENT_UNSUPPORTED [#PSL.PRISMA7_INDEX_ARGUMENT_UNSUPPORTED]

An index argument Prisma ORM indexes cannot carry (`sort`, `length`, `ops`, an unknown index type), or an indexed field that is not a column. Remove the argument. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_JSON_NULL_DEFAULT_UNSUPPORTED [#PSL.PRISMA7_JSON_NULL_DEFAULT_UNSUPPORTED]

A `Json` default of `"null"`, or a `Json[]` default holding it: the contract cannot tell the JSON value null apart from SQL `NULL`. Remove the `@default` or give it another JSON value. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_JUNCTION_ID_UNSUPPORTED [#PSL.PRISMA7_JUNCTION_ID_UNSUPPORTED]

An implicit many-to-many relation on a model without a single-field `@id`. Give the model a single-field `@id`, or write the junction model out. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_JUNCTION_NAME_COLLISION [#PSL.PRISMA7_JUNCTION_NAME_COLLISION]

A model in the same schema as an implicit many-to-many junction has the junction model's name (`PostToTag`, or the relation name). Rename the model and keep its table with `@@map`. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_NATIVE_TYPE_UNSUPPORTED [#PSL.PRISMA7_NATIVE_TYPE_UNSUPPORTED]

A `@db.*` type with no Prisma ORM codec (`Citext`, `Bit`, `VarBit`, `Xml`, `Oid`, `Money`, or an unknown spelling). Add `@ignore` to the field when no key, index, or relation uses it, or `@@ignore` to the model. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_OPTIONAL_GENERATED_FIELD_UNSUPPORTED [#PSL.PRISMA7_OPTIONAL_GENERATED_FIELD_UNSUPPORTED]

An ORM-side generator such as `@default(uuid())`, or `@updatedAt`, on an optional field. Remove the generator or `@updatedAt` and keep the `?`. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_PROVIDER_MISMATCH [#PSL.PRISMA7_PROVIDER_MISMATCH]

The Prisma ORM 7 schema has no `datasource` block, or its `provider` is not one the target accepts (`postgresql` or `postgres` for Postgres). Use the source only with a schema for the configured target. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_REFERENTIAL_ACTION_UNSUPPORTED [#PSL.PRISMA7_REFERENTIAL_ACTION_UNSUPPORTED]

`SetNull` on a relation over a required foreign key field, or `SetDefault` over a required field with no column default. Make the fields optional, give them a column default, or choose another action. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_RELATION_MODE_UNSUPPORTED [#PSL.PRISMA7_RELATION_MODE_UNSUPPORTED]

`relationMode = "prisma"`, or the older `referentialIntegrity = "prisma"`. Remove it or set `relationMode = "foreignKeys"`. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_RELATION_NAME_SHARED [#PSL.PRISMA7_RELATION_NAME_SHARED]

Two or more implicit many-to-many relations in the same schema use the same relation name; Prisma ORM 7 creates one table for all of them, wired to only one. Give each relation its own name. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_RELATION_UNRESOLVED [#PSL.PRISMA7_RELATION_UNRESOLVED]

A relation field that cannot be paired: no matching side, an ambiguous unnamed pair, a singular back-relation over a non-unique foreign key, a `fields`/`references` mismatch, or a required relation field over an optional foreign key field. Name both sides with `@relation("name")`, add the missing `fields`/`references`, or make the relation field optional. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_SCHEMA_READ_FAILED [#PSL.PRISMA7_SCHEMA_READ_FAILED]

The schema path could not be read, or the schema directory holds no `.prisma` file. Fix the path. Reported at the schema path by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none; the error's `providerMeta` carries the schema path.

### PSL.PRISMA7_TABLE_COLLISION [#PSL.PRISMA7_TABLE_COLLISION]

Two models map to the same table in one schema, or a model maps to the table of an implicit many-to-many relation. Give each model its own table with `@@map`. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_UNKNOWN_ATTRIBUTE [#PSL.PRISMA7_UNKNOWN_ATTRIBUTE]

An attribute Prisma ORM 7 for the target does not have, or one the source does not read (`@@fulltext`, `@shardKey`). Remove it. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_UNKNOWN_DEFAULT [#PSL.PRISMA7_UNKNOWN_DEFAULT]

A `@default` value the source cannot read, or one the column's data type or codec refuses. The message is `Field "<Model>.<field>": @default <reason>`. Every reason below carries ` at element <n>` after the value it is about when that value is one element of a list. The reasons that come from reading the value are: `holds text that this contract source does not read: <the reading entry's message>`; `holds a <tag> literal, which this stack does not register.`; `holds a <string|boolean|number> value, which this target has no data type for.`; `holds a <value type> value, which <column type> has no cast from; it casts from <types>.` (or `it casts from nothing`); and `holds a value that <codecId> does not read: <the codec's message>`. The rest do not involve the value's type — an unknown function, an enum member on a non-enum field or a non-member, and a `dbgenerated(...)` argument list that is not a single positional string with text in it. Write a value of a type the column's type is or casts from, an enum member, or a supported function. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_UNSUPPORTED_TYPE [#PSL.PRISMA7_UNSUPPORTED_TYPE]

`Unsupported("...")` or an unknown field type. Add `@@ignore` to the model, or correct the type name. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_UPDATED_AT_TYPE_UNSUPPORTED [#PSL.PRISMA7_UPDATED_AT_TYPE_UNSUPPORTED]

`@updatedAt` on a column whose codec has no "now" generator in the target, such as `@db.Date`. Remove `@updatedAt`. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_UPDATED_AT_WITH_DEFAULT_UNSUPPORTED [#PSL.PRISMA7_UPDATED_AT_WITH_DEFAULT_UNSUPPORTED]

`@updatedAt` combined with `@default`. Remove the `@default`; `@updatedAt` still sets the value on create and update. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL.PRISMA7_VIEW_UNSUPPORTED [#PSL.PRISMA7_VIEW_UNSUPPORTED]

A `view` block; Prisma ORM has no views. Remove the view, or replace it with a model over the underlying table. Reported by the Prisma ORM 7 contract source (`prisma7Schema`) during `contract emit` or `contract print`, as a finding in the `diagnostics` list of `CONTRACT.SOURCE_LOAD_FAILED`, never on its own. `summary` is `<file>:<line>:<column> <message>`, with only the file when there is no position (the terminal prints the code before it), and `where` carries `path` and, when known, `line`. Payload: none.

### PSL_BACKTICK_STRING_REQUIRES_TAG [#PSL_BACKTICK_STRING_REQUIRES_TAG]

A backtick string appears somewhere other than after a tag, for example ``@map(`x`)`` or `` provider = `x` ``: ``A backtick string must follow a tag, as in tag`...`.`` Reported at the string. Write a `"` or `'` string there, or put the tag in front of it, as in ``@default(sql`...`)``.

### PSL_UNKNOWN_DEFAULT_LITERAL_TAG [#PSL_UNKNOWN_DEFAULT_LITERAL_TAG]

A `@default` tagged literal uses a tag no pack in the stack registered: `Unknown literal tag "<tag>". Known tags: <tags in registration order>.` Every SQL target registers `sql`; Postgres also registers `pg.sql` and SQLite `sqlite.sql`. Reported at the literal when the default is lowered.

### PSL_DEPRECATED_SCALAR_NAME [#PSL_DEPRECATED_SCALAR_NAME]

A warning, not an error: a Mongo schema types a field with a deprecated scalar name, `Int`, `Float`, `Boolean` or `DateTime`: `Scalar type "<old>" is deprecated and will be removed; use "<new>" (stored as BSON <bsonType>).` Reported at the type through the contract source's `reportWarning`; `prisma contract emit` prints it and still writes the contract, which is the same as the new name gives, and the language server shows it with warning severity. Rename the type to `Int32`, `Double`, `Bool` or `Date`.

### PSL_DEFAULT_TYPE_INCOMPATIBLE [#PSL_DEFAULT_TYPE_INCOMPATIBLE]

A written `@default` value has a data type the column's type neither is nor casts from: `Field "<Model>.<field>": <column type> has no cast from <value type>; it casts from <types>`, or `; it casts from nothing` when the column's type declares no cast at all. A written value has a data type of its own — a number's comes from its own size and precision, so on Postgres `42` is `pg/int2` and `100000000000000099` is `pg/int8` — and a data type declares which other types' values it takes. Inside a written list the message names the element: `Field "<Model>.<field>" at element 2: ...`.

The same code reports a written form this target has no data type for at all: `Field "<Model>.<field>"[ at element <n>]: this target has no data type for a <string|boolean|number> value` — `true` on SQLite, for instance, which registers no boolean entry.

Reported at the `@default` attribute. See [ADR 254](https://github.com/prisma/prisma/blob/main/docs/architecture%20docs/adrs/ADR%20254%20-%20Data%20types%20and%20casts.md).

### PSL_INVALID_DEFAULT_LITERAL [#PSL_INVALID_DEFAULT_LITERAL]

A written `@default` value that whatever read it refused: the authoring entry's parse, a cast, or the column's codec. A `pgvector.Vector(3)` column given two elements, a magnitude no double holds written on a `Float` column, a body a tag's parse cannot read, or a number no data type of the target holds — `no data type of this target holds the number <text>`, which is how SQLite refuses a whole number past 64 bits. The message is `Field "<Model>.<field>": <the message of whatever refused it>`, with ` at element <n>` after the field path when it is one element of a written list. Reported at the `@default` attribute. See [ADR 254](https://github.com/prisma/prisma/blob/main/docs/architecture%20docs/adrs/ADR%20254%20-%20Data%20types%20and%20casts.md).

### PSL_INVALID_JSON_LITERAL [#PSL_INVALID_JSON_LITERAL]

A ``@default(json`...`)`` body is not a JSON document: `Field "<Model>.<field>": <the JSON parser's message>`, with ` at element <n>` after the field path when it is one element of a written list. It is `PSL_INVALID_DEFAULT_LITERAL` narrowed to the one case of a `json` body, so that a malformed document is distinguishable from a value a cast or a codec refused. Reported at the `@default` attribute.

### PSL_TAGGED_LITERAL_NUL [#PSL_TAGGED_LITERAL_NUL]

A tagged literal's body contains a NUL character: `Tagged literals must not contain NUL characters.` Reported at the literal when the default is lowered.

### PSL_TAGGED_LITERAL_TOO_LARGE [#PSL_TAGGED_LITERAL_TOO_LARGE]

A tagged literal's canonical body is larger than 65536 UTF-8 bytes: `Tagged literal exceeds 65536 bytes.` Reported at the literal when the default is lowered.

### PSL_LIST_AUTOINCREMENT_UNSUPPORTED [#PSL_LIST_AUTOINCREMENT_UNSUPPORTED]

A list column declares `@default(autoincrement())`: `Field "<Model>.<field>" is a list and cannot use autoincrement(); it is a Prisma marker for a sequence-backed scalar column, not SQL.` Every other storage default lowers on a list column. Reported at the attribute.

### PSL_INVALID_DEFAULT_SQL [#PSL_INVALID_DEFAULT_SQL]

A ``@default(sql`...`)`` body fails the SQL family's body check: `Default SQL must not contain semicolons, SQL comment tokens, dollar-quoting, or subqueries.` (the rule the migration planners apply at DDL time, run at authoring time so it has a source span), or is exactly `now()` or `autoincrement()`: ``Write @default(now()) instead of sql`now()`; now() is a Prisma default function, not raw SQL.`` The message names the tag as written (`sql`, `pg.sql` or `sqlite.sql`). Reported at the literal.

### PSL_UNSUPPORTED_ENUM_MEMBER_ATTRIBUTE [#PSL_UNSUPPORTED_ENUM_MEMBER_ATTRIBUTE]

An enum member carries an attribute, as in `USER @map("user")`: `enum "<Enum>": member "<member>" carries @<attribute>, but an enum member takes no attributes`. Reported by the SQL and Mongo PSL readers, once per attribute, at the attribute. Remove the attribute. To store a value other than the member's name, write it as the member's value, as in `USER = "user"`.

### PSL_PRESET_ON_VARIANT_FIELD [#PSL_PRESET_ON_VARIANT_FIELD]

A Mongo field preset that sets execution defaults, such as `temporal.createdAt()`, is declared on a field of a polymorphic variant model (one with `@@base`): `Preset "<preset>" on variant "<Model>" field "<field>": execution defaults apply to every document in collection "<collection>", so declare them on the base model.` Execution defaults are keyed by collection and field, so a default on one variant would also fill that field on the base model and every sibling variant. Declare the field on the base model; variants inherit it. Reported at the preset.

### PSL_PRESET_CONFLICT [#PSL_PRESET_CONFLICT]

Two Mongo models stored in the same collection declare field presets with different execution defaults for the same stored field, for example `temporal.createdAt()` on one and `temporal.updatedAt()` on the other. Execution defaults are keyed by collection and field, so the collection can have only one. Identical presets are merged. Use the same preset on both models. Reported at the second preset.

## ORM [#orm]

### ORM.AGGREGATE_OPERATION_RESERVED [#ORM.AGGREGATE_OPERATION_RESERVED]

A contributed aggregate operation carries a name a collection builder member already owns (`select`, `include`, `where`, `combine`, `aggregate`, …, or a collection instance field). Aggregate operations surface as reducer methods on the ORM collection, in one flat namespace with the query-builder members, so a same-named operation would shadow the member it collides with. Raised at ORM composition (`orm(...)`), where the collection surface is assembled. Rename the contributed operation. Payload: `operation`.

### ORM.AGGREGATE_PROJECTION_ONLY [#ORM.AGGREGATE_PROJECTION_ONLY]

An aggregate operation contributed from outside the closed SQL aggregate alphabet (`count`, `sum`, `avg`, `min`, `max`) was used in HAVING, ORDER BY, or another comparison position. Such an operation reaches SQL only through its descriptor's lowering hook, a rendering meant for the SELECT projection, where the value crosses the driver boundary. HAVING and ORDER BY compare the value inside the database, where that rendering would change SQL semantics (a textual rendering compares and sorts lexicographically), so the query builder refuses at authoring time. Project the aggregate in a select and filter or order on the projected value, or use an operation from the alphabet. Payload: `operation`.

### ORM.AGGREGATE_SELECTOR_INVALID [#ORM.AGGREGATE_SELECTOR_INVALID]

An `aggregate()` or `groupBy().aggregate()` selector is not a valid aggregation descriptor, or an aggregate function that requires a column/field (e.g. sum, avg) was given none. Thrown when the ORM client builds the aggregate query plan. Payload: `method`, `model`, `alias`, `fn`.

### ORM.AGGREGATE_SELECTOR_MISSING [#ORM.AGGREGATE_SELECTOR_MISSING]

`aggregate()` or `groupBy().aggregate()` was called with zero aggregation selectors; at least one is required. Payload: `method`, `model` (or `namespaceId`, `tableName`).

### ORM.AGGREGATE_UNSUPPORTED [#ORM.AGGREGATE_UNSUPPORTED]

An aggregate was invoked for an operation/input pair the composed target declares no descriptor for: an undeclared pair has no result identity to type or decode, so it is rejected before any SQL is built rather than executed into a driver-native value. Raised by ORM aggregate planning and decoding, and by the SQL-builder lane's aggregate functions; the typed surfaces already make such a call a type error, so reaching this at runtime means a dynamic or cast invocation. Payload: `operation`, plus `table`/`column`/`inputCodecId` where an input is involved. Contribute an aggregate descriptor for the pair, or aggregate an input the target declares.

### ORM.ARGUMENT_INVALID [#ORM.ARGUMENT_INVALID]

A method argument on the ORM client, or on the `sql()` / Mongo query-builder DSLs, is malformed or missing a required part: a `null` where-arg, `upsert()` without conflict columns or without a create value for a conflict column, a custom collection registered as an instance / against a nonexistent model in `orm({ collections })`, invalid builder argument shapes, `$and`/`$or` with no expressions, a limit, offset or skip that is negative or not an integer, or malformed lookup/group/update specs. For SQL, the limit/offset check runs in relational-core when the `SelectAst` is constructed, so every SQL lane and target raises it before any SQL is rendered. That check also refuses integers above `Number.MAX_SAFE_INTEGER`, and does not check a limit or offset bound as a parameter. Payload: `method`, `argument` (`limit` or `offset` for the SQL limit/offset check), `model`, `column`, `key`.

### ORM.CAPABILITY_MISSING [#ORM.CAPABILITY_MISSING]

The requested operation requires a contract capability the contract does not declare, currently the `returning` capability needed for mutations that read back the affected row. Raised by the ORM client and the `sql()` builder. Payload: `capability`, `action`.

### ORM.COLUMN_UNKNOWN [#ORM.COLUMN_UNKNOWN]

A mutation payload or where-expression references a column that does not exist on the resolved table. Thrown while compiling the query plan or binding the where clause, by the ORM client and by the `sql()` builder DSL. Payload: `namespaceId`, `tableName`, `column`.

### ORM.CURSOR_VALUE_MISSING [#ORM.CURSOR_VALUE_MISSING]

Cursor pagination was requested but the cursor object lacks a value for one of the `orderBy` columns, so the position cannot be anchored. Payload: `column`.

### ORM.FIELD_IMMUTABLE [#ORM.FIELD_IMMUTABLE]

A Mongo mutation payload attempts to write `_id`, which is immutable. Thrown by the Mongo ORM client for create/update/upsert payloads. Payload: `field`.

### ORM.FIELD_UNKNOWN [#ORM.FIELD_UNKNOWN]

A shorthand relation filter references a field that is not defined on the related model. Thrown by the SQL ORM client while resolving the filter. Payload: `model`, `field`.

### ORM.FILTER_UNSUPPORTED [#ORM.FILTER_UNSUPPORTED]

A shorthand equality filter targets a field whose codec does not support equality comparisons (lacks the equality trait). Payload: `model`, `field`, `trait`.

### ORM.GROUP_BY_FIELD_MISSING [#ORM.GROUP_BY_FIELD_MISSING]

`groupBy()` was called with zero fields; at least one grouping field is required. Payload: `namespaceId`, `tableName`.

### ORM.HAVING_EXPRESSION_UNSUPPORTED [#ORM.HAVING_EXPRESSION_UNSUPPORTED]

A `groupBy().having()` expression uses a kind the grouped-having compiler does not allow: `ParamRef`/`PreparedParamRef`, list values, non-aggregate expressions, or another unsupported comparable kind. Only aggregate metric expressions are supported. Payload: `kind`.

### ORM.INCLUDE_INVALID [#ORM.INCLUDE_INVALID]

An `include()` usage is structurally invalid: the refinement callback returned something that is not a collection, include-scalar selector, or `combine()` descriptor; a `combine()` branch is invalid or empty; or an include-only action was called outside an `include()` refinement callback. Payload: `relation`, `branch`, `action`.

### ORM.INCLUDE_UNSUPPORTED [#ORM.INCLUDE_UNSUPPORTED]

The include is well-formed but not supported in this position: scalar aggregations or `combine()` on a to-one relation (SQL), or including an embed relation / compound reference (Mongo; only reference relations can be included). Payload: `relation`, `kind`, `model`.

### ORM.MODEL_UNKNOWN [#ORM.MODEL_UNKNOWN]

The Mongo ORM client was asked to operate on a model name that is not in the contract (collection compile, or a raw-pipeline root bound to an unknown model). Payload: `model`, `root`.

### ORM.MUTATION_DATA_MISSING [#ORM.MUTATION_DATA_MISSING]

`create()` or `createAndCount()` was called with zero rows; at least one row of data is required. Payload: `method`, `namespaceId`, `tableName`.

### ORM.MUTATION_DEFAULTS_MISSING [#ORM.MUTATION_DEFAULTS_MISSING]

`mongoOrm()` was built over a contract with execution defaults (fields such as `temporal.createdAt()` that the ORM fills on write) without `mutationDefaults`, so those fields would never be written. Pass the execution context, `mongoOrm({ contract, executor, mutationDefaults: context })`, or create the client with `mongo()`. Payload: `fields` (`<collection>.<field>` for each default).

### ORM.MUTATION_ROW_MISSING [#ORM.MUTATION_ROW_MISSING]

A mutation that expected the database to return a row got none: `create()`/`upsert()` read-back, MTI base or variant INSERT, or a nested create. The Prisma-classic analogue of P2025. Payload: `operation`, `model`, `tableName`, `phase`.

### ORM.OPERATION_UNSUPPORTED [#ORM.OPERATION_UNSUPPORTED]

A valid ORM method was called in a configuration that does not support it: mutating an MTI variant collection with a method that requires `createAll()`, passing `onConflict: 'skip'` to `createAll()` on an MTI variant collection, Mongo `upsert()` with dot-path field operations, or a Mongo mutation carrying windowing (`orderBy`/`offset`/`limit`) or includes. Payload: `method`, `model`, `reason`, `field`.

### ORM.RELATION_LINK_DUPLICATE [#ORM.RELATION_LINK_DUPLICATE]

A `connect()` nested mutation violated a unique constraint on the junction table: the junction link is likely already present. The original driver error is preserved as `cause`. Payload: `relation`, `junction`.

### ORM.RELATION_MUTATION_INVALID [#ORM.RELATION_MUTATION_INVALID]

A nested relation mutation's input is malformed: a relation field without a mutator callback or returning an invalid descriptor, `create` without data, `connect`/`disconnect` with a missing or empty criterion, duplicate connect criteria resolving to the same junction link, or conflicting values for a junction column. Payload: `kind`, `relation`, `model`, `problem`, `junction`, `column`.

### ORM.RELATION_MUTATION_UNSUPPORTED [#ORM.RELATION_MUTATION_UNSUPPORTED]

A nested relation mutation kind is not supported in this position: `disconnect()` outside `update()` nested mutations, or `create()`/`connect()` through a junction table with required columns the relation API cannot populate (`disconnect()` stays available). Payload: `kind`, `relation`.

### ORM.RELATION_ROW_MISSING [#ORM.RELATION_ROW_MISSING]

A `connect()`/`disconnect()` nested mutation's criterion matched no row on the related model. Payload: `kind`, `relation`.

### ORM.RELATION_UNKNOWN [#ORM.RELATION_UNKNOWN]

A referenced relation name does not exist on the model, in `include()` (SQL and Mongo) or when resolving relation metadata from the contract. Payload: `model`, `relation`.

### ORM.ROW_IDENTITY_MISSING [#ORM.ROW_IDENTITY_MISSING]

The operation needs a primary key or unique constraint the table does not have: `update()`/`delete()` targeting a single row, a `create()` or `update()` with nested relation mutations (which updates and reloads the row by that key), or keying the include read-back after a mutation. Payload: `model`, `table`.

### ORM.TABLE_UNKNOWN [#ORM.TABLE_UNKNOWN]

The table a collection resolves to does not exist in the contract's storage for the namespace. Thrown during storage resolution or query planning. Payload: `namespaceId`, `tableName`.

### ORM.WHERE_MISSING [#ORM.WHERE_MISSING]

A Mongo mutation method (e.g. update/delete variants) requires a prior `.where()` filter and none was set. Payload: `method`.

## RUNTIME [#runtime]

### RUNTIME.ABORTED [#RUNTIME.ABORTED]

An in-flight `query()` or `execute()` operation was cancelled via the per-operation `AbortSignal` passed as the call's `{ signal }` option. `details.phase` says where the abort was observed: `encode`, `decode`, `stream`, or the middleware phases `beforeQuery` / `beforeExecute` / `afterQuery` / `afterExecute` / `onRow`; the envelope's `cause` carries `signal.reason` verbatim. Payload: `phase`.

### RUNTIME.AGGREGATE_DESCRIPTOR_INVALID [#RUNTIME.AGGREGATE_DESCRIPTOR_INVALID]

A component contributed an aggregate descriptor whose shape the SQL aggregate registry cannot read: a missing or empty `operation`, an `input` that is not `none` / `any` / `codec` / `trait` (including an unknown trait name), an `output` that is not `self` / `codec`, a non-boolean `nullable`, a `nullable: false` descriptor with no `emptyResultJson`, a `self` output on an operation that consumes no input, or a non-callable `lower`. `emptyResultJson` is the value a non-nullable operation answers with when no result row reaches the caller, stated in the result codec's canonical JSON: `0` under `pg/int8number@1`, `'0'` under `pg/int8@1`. Raised while the execution context assembles the registry. Payload: `descriptor`.

### RUNTIME.AGGREGATE_LOWERING_MISSING [#RUNTIME.AGGREGATE_LOWERING_MISSING]

An aggregate descriptor declares an operation outside the closed SQL aggregate alphabet (`count`, `sum`, `avg`, `min`, `max`) and carries no `lower` hook. An alphabet operation lowers to a plain aggregate call by default; renderers know no other operation, so any other name must build its expression through a lowering hook from existing AST nodes. Raised while the execution context assembles the aggregate registry. Payload: `operation`, `key`.

### RUNTIME.AGGREGATE_OUTPUT_CODEC_MISSING [#RUNTIME.AGGREGATE_OUTPUT_CODEC_MISSING]

An aggregate descriptor names a result codec the composed stack does not register, either its `output` names the codec outright, or a `self` output over an exact input match reuses an input codec the stack never composes. A resolved aggregate decodes its result through the declared codec, so an unregistered one could never decode anything. Raised while the execution context assembles the aggregate registry. Payload: `operation`, `key`, `outputCodecId`.

### RUNTIME.AMBIGUOUS_AGGREGATE_DESCRIPTOR [#RUNTIME.AMBIGUOUS_AGGREGATE_DESCRIPTOR]

Two trait-matching aggregate descriptors for one operation both claim a registered codec: the codec advertises both traits, so the result codec is undetermined. Contribute an exact codec descriptor for that operation, or narrow the overlapping trait contributions. Raised while the execution context assembles the aggregate registry, so it never surfaces mid-query. Payload: `operation`, `codecId`, `traits`.

### RUNTIME.ANNOTATION_INAPPLICABLE [#RUNTIME.ANNOTATION_INAPPLICABLE]

A lane terminal (SQL DSL `.build()`, ORM collection terminal) received an annotation whose declared `applicableTo` set does not include the operation kind being built: the runtime check that backs up the type-level annotation validation when it is bypassed via casts or dynamic invocation. Payload: `namespace`, `terminalName`, `kind`, `applicableTo`.

### RUNTIME.ARGUMENT_INVALID [#RUNTIME.ARGUMENT_INVALID]

A built-in Postgres query operation or full-text helper received an argument it cannot use. One case is the `language` of `fullTextMatches`, `fullTextRank` and `fullTextHeadline`, of the `tsquery` parsers (`websearchToTsquery`, `toTsquery`, `plaintoTsquery`, `phrasetoTsquery`) and of the `tsquery` template tag: the language is written into the SQL as an inline literal rather than a bound parameter, so it is checked against the text-search configurations a stock PostgreSQL server ships with and anything else is refused. The other case is a literal part of a `tsquery` template with an invalid JavaScript escape, such as `\u`: JavaScript gives the tag no text for that part, so the tag refuses it rather than drop it. Raised while the query is being built, before any SQL reaches the database. Payload: `helper`, `argument`, `received`.

### RUNTIME.AST_INVALID [#RUNTIME.AST_INVALID]

A lowered SQL AST is structurally invalid: a subquery projecting other than one column, an INSERT with zero rows, a missing column value, an empty onConflict column list or do-update-set, an UPDATE with no SET assignments, an INSERT target table absent from contract storage, or an AST node constructed with invalid arguments (empty FunctionSource column aliases, a CaseExpr with no branches, a raw query declaring a `__proto__` result column, a name that cannot survive as a column, so alias it in SQL and declare the alias). Raised by the Postgres and SQLite SQL renderers and by AST node construction in relational-core. Payload: `node`, `table`, `column`; construction sites carry node-specific fields.

### RUNTIME.AST_UNSUPPORTED [#RUNTIME.AST_UNSUPPORTED]

The authored SQL AST uses a feature this target cannot render, e.g. DEFAULT as a value in INSERT … VALUES, WITH ORDINALITY on function sources, or returned-column aliases on function sources, all on SQLite. Raised by the target adapters' renderers. Payload: `node` (INSERT DEFAULT site); `target`, `feature` (function-source sites).

### RUNTIME.BINDING_INVALID [#RUNTIME.BINDING_INVALID]

A target facade client (`@prisma/orm-postgres`, `@prisma/orm-sqlite`, `@prisma/orm-mongo`) received a connection binding whose shape is wrong for the target: malformed connection string, unsupported binding kind, or missing required fields. Raised at `connect(...)` / client construction. Payload: `received`, `reason`.

### RUNTIME.BINDING_MISSING [#RUNTIME.BINDING_MISSING]

A target facade client was asked to connect with no binding at all (no connection string, no environment fallback). Payload: `expected`.

### RUNTIME.CODEC_DESCRIPTOR_ARRAY_UNSUPPORTED [#RUNTIME.CODEC_DESCRIPTOR_ARRAY_UNSUPPORTED]

A codec projection used `CodecRef.many` against a SQLite codec descriptor: SQLite has no stored scalar-array codec protocol, so projecting the whole stored array would be ambiguous. Use a scalar CodecRef or an explicit target representation. Payload: `codecId`.

### RUNTIME.CODEC_DESCRIPTOR_INVALID [#RUNTIME.CODEC_DESCRIPTOR_INVALID]

A codec descriptor handed to a target codec-descriptor registry (Postgres, SQLite) is not a valid descriptor for that target: wrong discriminant, missing target descriptor methods, or a malformed params schema. Extend the target's descriptor class or adapt a generic descriptor with the target's wrapper (`postgresCodec()` / `sqliteCodec()`). Payload: `codecId`.

### RUNTIME.CODEC_DESCRIPTOR_MISSING [#RUNTIME.CODEC_DESCRIPTOR_MISSING]

A column (or AST-carried CodecRef) references a `codecId` for which no runtime component registered a codec descriptor: usually the extension pack that owns the codec is missing from the runtime stack. Surfaces at SQL context construction during the contract codec walk, or lazily when the AST codec resolver materializes a codec at query time. Payload: `codecId`; on the column path also `table`, `column`.

### RUNTIME.CODEC_MISSING [#RUNTIME.CODEC_MISSING]

Runtime validation of the contract found columns whose `codecId` has no implementation in the codec registry; the error lists every affected column. Surfaces when the codec registry's completeness is validated at context/runtime setup. Payload: `contractTarget`, `invalidCodecs` (list of `{ namespaceId, table, column, codecId }`).

### RUNTIME.CODEC_PARAMETERIZATION_MISMATCH [#RUNTIME.CODEC_PARAMETERIZATION_MISMATCH]

A column's codec reference disagrees with the codec's parameterization: a parameterized codec is used with no `typeParams` (and its schema requires some), or `typeParams` are supplied to a non-parameterized codec. Surfaces during the SQL context's contract codec walk. Payload: `table`, `column`, `codecId`, `expected`, `actual`.

### RUNTIME.CONTENT_HASH_REQUIRES_RESOLVED_COMMAND [#RUNTIME.CONTENT_HASH_REQUIRES_RESOLVED_COMMAND]

Mongo middleware called `ctx.contentHash(plan)` (or `computeMongoContentHash`) during `beforeExecute`, when `plan.command` is still an unresolved lowered draft rather than a resolved wire command. Compute the hash from `afterExecute`, or use the param mutator instead of reading `plan.command` structurally. Payload: `phase`.

### RUNTIME.CONTRACT_FAMILY_MISMATCH [#RUNTIME.CONTRACT_FAMILY_MISMATCH]

At SQL context construction, the contract's target family (e.g. `mongo`) does not match the runtime stack's family (`sql`): the contract was emitted for a different database family than the stack being assembled. Payload: `actual`, `expected`.

### RUNTIME.CONTRACT_TARGET_MISMATCH [#RUNTIME.CONTRACT_TARGET_MISMATCH]

At SQL context construction, the contract's target (e.g. `sqlite`) does not match the runtime stack's target descriptor (e.g. `postgres`): the contract and the adapter/driver stack disagree about the database target. Payload: `actual`, `expected`.

### RUNTIME.DDL_UNSUPPORTED [#RUNTIME.DDL_UNSUPPORTED]

`lower()` was asked to lower DDL on a surface that cannot do it: the runtime adapter (DDL lowering is a control-plane concern), or the synchronous control lowering path (DDL default literals require async codec encoding; use `lowerToExecuteRequest()`). Raised by the Postgres and SQLite adapters. Payload: `surface`.

### RUNTIME.DECODE_FAILED [#RUNTIME.DECODE_FAILED]

A codec's `decode` threw while converting a wire value into its output type during result decoding, surfaces per column (SQL), per document field (Mongo), or per included-relation column (ORM client), with the original error attached as `cause`. Also thrown when a returned row is missing an expected projection alias, or when the JSON array for an include alias fails to parse. Payload: `table`, `column` (or `alias` / `collection` + `path`), `codec`, `wirePreview`. When a Mongo codec raised the code itself, its own details (for the target's codecs, `codecId` and `received`) are kept alongside.

Codecs also raise this code directly, as a structured envelope with `meta.codecId` and `meta.received`. The integer guards: `pg/int8number@1` and `sqlite/bigintnumber@1` (the `BigIntNumber` type) refuse a stored value outside the safe integer range ±(2^53 − 1) and any non-integral value rather than rounding it; `pg/int8@1`, `pg/unboundedint@1`, and `sqlite/bigint@1` refuse a wire or JSON value that is not a decimal integer. On a flat read the codec's envelope surfaces unchanged; on an `.include()` read the ORM client wraps it in a fresh `RUNTIME.DECODE_FAILED` carrying `table`, `column`, and `codec`, with the codec's envelope on `cause`. One SQLite caveat: on a flat read, `node:sqlite` itself refuses an INTEGER outside the safe range before any codec runs, so for an out-of-band stored value the structured envelope is guaranteed on the include/JSON path, not the flat path.

On Mongo, `mongo/json@1` (a `Json` field) raises this code when the stored value is not JSON at some depth: `mongo/json@1 wire value contains a non-JSON BSON <type> at <path>`, where `<type>` is the BSON `$type` alias (`date`, `objectId`, `decimal`, `binData`, `regex`, `timestamp`, `long` for one outside the safe-integer range, `double` for `NaN` or `±Infinity`, `undefined`, `symbol`, `javascript`, `minKey`, `maxKey`, or the constructor name of an object the driver does not produce) and `<path>` is the dot-notation path inside the field, with array indices as segments, or `the root`. A subdocument with `$ref` and `$id`, which the driver reads as a `DBRef`, decodes back to the document it was stored as, each member checked at its own path (`link.$id`). A stored subdocument that merely has a `_bsontype` key is read as that document, not as the type it names. The codec's envelope carries `meta.codecId`, `meta.received` (the BSON type) and `meta.valuePath` (the path inside the field); the runtime's wrapper copies them into its `details` beside `collection` and `path`, the field's own path in the document. A `long` in the safe-integer range and the driver's `Int32` and `Double` wrappers decode as numbers. Such a field should be `Bson`, which admits any BSON value.

**Aggregates reach the same guards.** `count()` and `sum()` over integers declare a number-flavoured result codec, so a tally or total past ±(2^53 − 1) raises this code: `pg/int8number@1 value must be an integer within the safe integer range, got 9007199254740992`, instead of returning a rounded value. It fires on the wire path and on the `.include()` path alike: the include projection is a JSON number, but the guard runs after `JSON.parse`, and rounding is monotone, so a value that was outside the range is still outside it. Where the magnitude is real rather than a bug, switch that call to the lossless variant beside it: `countBigInt()`, `sumBigInt()`, or `avgDecimal()`.

### RUNTIME.DUPLICATE_AGGREGATE_DESCRIPTOR [#RUNTIME.DUPLICATE_AGGREGATE_DESCRIPTOR]

Two components claim the same aggregate overload: the same `(operation, input)` pair, keyed as `sum:trait:numeric`, `sum:codec:pg/int8@1`, or `count:none`. Each overload resolves to exactly one result codec, so exactly one target, adapter, or extension may contribute it. Payload: `key`.

### RUNTIME.DUPLICATE_AUTHORING_DISCRIMINATOR [#RUNTIME.DUPLICATE_AUTHORING_DISCRIMINATOR]

Two authoring contributions register the same discriminator key, the same `entityType` key or the same `pslBlock` parser keyword, when the framework authoring surface assembles its descriptor registry. Each contribution must use a unique key. Payload: `label`, `key`, `existingPath`, `path`.

### RUNTIME.DUPLICATE_CODEC [#RUNTIME.DUPLICATE_CODEC]

Two runtime stack contributors (target pack, extension packs) register a codec with the same id, while the SQL context or Mongo execution stack collects codecs, or while a target codec-descriptor registry (Postgres, SQLite) is composed. Remove the duplicate contribution. Payload: `codecId`; on the Mongo path also `existingOwner`, `incomingOwner`; on the target registry path also `target`.

### RUNTIME.DUPLICATE_MUTATION_DEFAULT_GENERATOR [#RUNTIME.DUPLICATE_MUTATION_DEFAULT_GENERATOR]

Two runtime stack contributors register a mutation default generator with the same id while the SQL context or the Mongo execution context collects them. Payload: `id`, `existingOwner`, `incomingOwner`.

### RUNTIME.ENCODE_FAILED [#RUNTIME.ENCODE_FAILED]

A codec's `encode` threw while converting a user-supplied parameter value to driver wire format during query execution (SQL param encoding, or Mongo param-ref resolution), with the original error attached as `cause`. Payload: `label`, `codec`; SQL path also `paramIndex`. On Mongo, a value written through the ORM is labelled with its field path, the payload adds `collection`, and the message reads `Failed to encode field <path> in collection '<collection>' with codec '<id>': …`. When a Mongo codec raised the code itself, its own details (for the target's codecs, `codecId` and `received`) are kept alongside.

Codecs also raise this code directly, as a structured envelope with `meta.codecId` and `meta.received`, which surfaces unchanged: writing a value outside ±(2^53 − 1), or a non-integral number, through `pg/int8number@1` or `sqlite/bigintnumber@1` (the `BigIntNumber` type) raises it before any SQL executes.

On Mongo, `mongo/json@1` (a `Json` field) raises this code for any value that is not a plain JSON value at some depth: `mongo/json@1 value must be a JSON value; received <kind> at <path>`. `<kind>` is the `_bsontype` tag of a BSON value (`ObjectId`, `Long`, `Decimal128`, `Binary`, …), `Date`, `bigint`, `symbol`, `function`, `undefined`, `NaN`, `Infinity`, `-Infinity`, `sparse array hole`, `circular reference`, or the constructor name of any other non-plain object (`Map`, `Uint8Array`, a class name); `<path>` is the dot-notation path inside the value, or `the root`. The codec's envelope carries `meta.codecId`, `meta.received` (the kind) and `meta.valuePath` (the path inside the value); the runtime's wrapper copies them into its `details` beside `label`, `collection` and `codec`. `mongo/bson@1` (a `Bson` field) raises the same shape, `mongo/bson@1 value must be a BSON value; received <kind> at <path>`, for `undefined`, `bigint`, `symbol`, a function, a `DBRef` instance (write the `{ $ref, $id }` document instead), a sparse-array hole, a circular reference, an object carrying a `_bsontype` the driver's `bson` did not create (`<tag> not created by bson 7`: a literal look-alike such as `{ _bsontype: 'MinKey' }`, or a value from another major version of `bson`), or a non-plain object other than a `Date`, native `RegExp` or `Uint8Array` (`Map`, `Set`, a class instance, another typed array).

The integer codecs also check the JS type of the value they are given, and report that separately from the range: `pg/int8number@1` and `sqlite/bigintnumber@1` read a `number`, while `pg/int8@1`, `pg/unboundedint@1`, and `sqlite/bigint@1` read a `bigint`. A value of the other type raises `<codec> value must be a <number|bigint>, got <type> <value>` with `meta.received` naming the type that arrived: the message you get from passing `9n` where a `number` is read, rather than a range complaint about a value plainly inside the range.

The exact integer codecs make one exception, and only on the JSON side. `encodeJson` on `pg/int8@1`, `pg/unboundedint@1`, and `sqlite/bigint@1` also accepts a `number`, because a schema language writes no `bigint` literal. The number must be an integer within the safe range, and a value that is not raises `<codec> number literal must be an integer within the safe integer range, got <value>`: a `number` past that range was already rounded before the codec saw it, so its digits no longer name the value that was written. The PSL interpreter therefore does not hand these codecs a rounded number: it reads a number `@default` from its source text, gives the codec the plain number when that decodes, and the decimal text of the literal when it does not, so `BigInt @default(0)` still arrives as the JSON number `0` while `BigInt @default(9007199254739999999)` arrives as its digits. `encode`, the wire path a query parameter travels, takes no such number; it requires the `bigint`.

### RUNTIME.EXECUTION_RESULT_MISSING [#RUNTIME.EXECUTION_RESULT_MISSING]

A statistics execution completed without returning statement statistics. This indicates a runtime or middleware implementation violated the execution contract instead of returning `{ affectedRows }`. Payload: none.

### RUNTIME.ITERATOR_CONSUMED [#RUNTIME.ITERATOR_CONSUMED]

An `AsyncIterableResult` (the return value of `query()`) was iterated a second time: each result can be consumed only once, whether via a `for await` loop or via `toArray()`/`await`. Store the array from `toArray()` if you need to reuse the rows. Payload: `consumedBy`, `suggestion`.

### RUNTIME.JSON_SCHEMA_VALIDATION_FAILED [#RUNTIME.JSON_SCHEMA_VALIDATION_FAILED]

The `arktype-json` codec rejected a JSON value that does not satisfy the column's arktype schema, on encode (writing) or decode (reading). Also thrown when the schema itself cannot be rehydrated from the contract's stored JSON IR. Payload: `codecId`, `issues` (validation) or `jsonIr` (rehydration).

### RUNTIME.MIDDLEWARE_FAMILY_MISMATCH [#RUNTIME.MIDDLEWARE_FAMILY_MISMATCH]

A middleware registered on the runtime declares a `familyId` (e.g. `sql`) that differs from the runtime's family, e.g. a SQL-only middleware added to a Mongo runtime. Checked when the runtime validates its middleware list. Payload: `middleware`, `middlewareFamilyId`, `runtimeFamilyId`.

### RUNTIME.MIDDLEWARE_INCOMPATIBLE [#RUNTIME.MIDDLEWARE_INCOMPATIBLE]

A middleware declares a `targetId` without also declaring a `familyId`, an invalid combination, since target scoping only makes sense within a family. Checked when the runtime validates its middleware list. Payload: `middleware`, `targetId`.

### RUNTIME.MIDDLEWARE_RESULT_MISMATCH [#RUNTIME.MIDDLEWARE_RESULT_MISMATCH]

Middleware returned a query result for a statistics operation, or statistics for a row query. Middleware interception results must carry the same `operation` discriminant as the operation they intercept. Payload: `expected`, `received`.

### RUNTIME.MIDDLEWARE_TARGET_MISMATCH [#RUNTIME.MIDDLEWARE_TARGET_MISMATCH]

A middleware declares a `targetId` (e.g. `postgres`) that differs from the runtime's configured target. Checked when the runtime validates its middleware list. Payload: `middleware`, `middlewareTargetId`, `runtimeTargetId`.

### RUNTIME.MISSING_EXTENSION_PACK [#RUNTIME.MISSING_EXTENSION_PACK]

At SQL context construction, the contract requires one or more extension packs that no component in the runtime stack provides. Add the missing pack(s) to the stack. Payload: `packIds`.

### RUNTIME.MONGO_STATISTICS_RESULT_INVALID [#RUNTIME.MONGO_STATISTICS_RESULT_INVALID]

A Mongo update or delete command did not return exactly one result object with the required numeric native count field. Updates require `modifiedCount`; deletes require `deletedCount`. Payload: `commandKind`, `countField`.

### RUNTIME.MONGO_STATISTICS_UNSUPPORTED [#RUNTIME.MONGO_STATISTICS_UNSUPPORTED]

Statistics execution was requested for a Mongo command that does not expose affected-row statistics. Only update and delete command kinds provide the native counts used by this operation. Payload: `commandKind`.

### RUNTIME.MUTATION_DEFAULT_GENERATOR_MISSING [#RUNTIME.MUTATION_DEFAULT_GENERATOR_MISSING]

The contract declares column or field defaults produced by a mutation default generator (e.g. a nanoid/uuid generator, or `timestampNow` behind `temporal.createdAt()`) that no runtime component provides, detected up front when the SQL context or the Mongo execution context validates generator coverage, or at mutation time when a generator-kind default spec is resolved. Payload: `ids` (validation pass) or `id` (resolution).

### RUNTIME.NAMESPACE_UNKNOWN [#RUNTIME.NAMESPACE_UNKNOWN]

At query-render time a table references a namespace that is not present, or not materialised as a database schema, on the contract. Raised by the Postgres and SQLite SQL renderers. Payload: `table`, `namespaceId`, `reason`.

### RUNTIME.NO_ROWS [#RUNTIME.NO_ROWS]

`firstOrThrow()` was called on a query result that returned no rows. Use `first()` if an empty result is acceptable.

### RUNTIME.PARAM_REF_CODEC_REQUIRED [#RUNTIME.PARAM_REF_CODEC_REQUIRED]

While building a query expression, a plain JS value was passed where no codec could be derived: `toExpr` cannot construct a ParamRef for a bare value without an explicit `CodecRef`. Provide a codec at the call site or use a column-bound builder path.

### RUNTIME.PARAM_REF_MISSING_CODEC [#RUNTIME.PARAM_REF_MISSING_CODEC]

The Postgres SQL renderer reached lowering with a ParamRef that carries no bound `CodecRef`, an internal invariant of the AST-bound codec contract, usually indicating a builder path that constructed a ParamRef without threading the column codec. Payload: `paramIndex`, `name`.

### RUNTIME.PREPARE_BIND_ON_ADHOC [#RUNTIME.PREPARE_BIND_ON_ADHOC]

An AST containing a prepared-statement bind-site reference (`PreparedParamRef`) was submitted to the ad-hoc `execute()` path. Bind-site references are only valid inside `runtime.prepare(...)`. Payload: `name`.

### RUNTIME.PREPARE_MISSING_PARAM [#RUNTIME.PREPARE_MISSING_PARAM]

Executing a prepared statement without supplying a value for one of its declared parameters: the lookup fails rather than silently binding `undefined`. Payload: `name`.

### RUNTIME.PREPARE_UNUSED_PARAM [#RUNTIME.PREPARE_UNUSED_PARAM]

`runtime.prepare(declaration, callback)` found declared parameter names that the callback's plan never references. Remove the unused declarations or reference them in the plan. Payload: `unused`.

### RUNTIME.RAW_ROW_COLUMN_MISSING [#RUNTIME.RAW_ROW_COLUMN_MISSING]

A whole-query raw statement returned a result that omits a column its row spec declares. The runtime never parses the SQL, so the spec is its only description of the result: a column the spec names and the statement does not return is a mismatch the caller has to resolve, by correcting the spec or the statement. Distinct from `RUNTIME.DECODE_FAILED`, which means a codec rejected a value the runtime did expect. Surplus result columns the spec does not declare are dropped silently and never raise this. See [ADR 247](https://github.com/prisma/prisma/blob/main/docs/architecture%20docs/adrs/ADR%20247%20-%20Whole-query%20raw%20SQL%20is%20the%20fragment%20mechanism%20at%20statement%20position.md). Payload: `column`, `declaredColumns`, `resultColumns`.

### RUNTIME.RAW_SQL_UNSUPPORTED_INTERPOLATION [#RUNTIME.RAW_SQL_UNSUPPORTED_INTERPOLATION]

A raw-SQL tagged template interpolated a JS value whose type cannot be auto-inferred to a codec (anything other than number, bigint, string, boolean, or Uint8Array). Wrap the value in `param(...)` with an explicit codec.

### RUNTIME.TEMPORAL_UNAVAILABLE [#RUNTIME.TEMPORAL_UNAVAILABLE]

A value that only a global `Temporal` implementation can produce or read was needed in a runtime that has none. Two paths raise it, and they carry different metadata:

* A Temporal-backed codec (`pg/date-temporal@1`, `pg/timestamp-temporal@1`, `pg/timestamptz-temporal@1`, `pg/time-temporal@1`) encoding or decoding a value. Payload: `codecId`, `operation` (`'encode'` or `'decode'`).
* The `instantNow` mutation-default generator producing a value, for `temporal.createdAt()`, `temporal.updatedAt()`, or for a `temporal.timestamptz(…)` / `timestamp(…)` preset given an `onCreate`/`onUpdate` of `'now'`. No codec is involved. Payload: `generatorId`.

The check is lazy: registering the target, validating a contract, building a runtime, resolving a descriptor and constructing a codec instance all succeed without `Temporal`. Only producing or interpreting a value fails.

That covers more than an explicit write. It is raised on **reads**, because the check is the first thing a Temporal codec does on decode: selecting the column is enough. And it is raised on an &#x2A;*insert into a table carrying `temporal.updatedAt()`**, because that column's clock produces a `Temporal.Instant` even when your code never mentions a temporal value; that path reports `generatorId` rather than `codecId`, since no codec has been reached yet.

Install a global implementation before any query runs (`import 'temporal-polyfill/full/global'`), or author the column with its `*String` type (`DateString`, `TimestampString(p)`, `TimestamptzString(p)`, `TimeString(p)`) to read and write PostgreSQL's own text, which needs no Temporal at all.

### RUNTIME.TRANSACTION_CLOSED [#RUNTIME.TRANSACTION_CLOSED]

A query result created inside a transaction was read after the transaction ended. Await the result or call `.toArray()` inside the transaction callback.

### RUNTIME.TRANSACTION_COMMIT_FAILED [#RUNTIME.TRANSACTION_COMMIT_FAILED]

Committing a transaction failed; the runtime attempts a cleanup rollback and destroys the connection if that also fails. The driver's commit error is attached as `cause`. Payload: `commitError`.

### RUNTIME.TRANSACTION_ROLLBACK_FAILED [#RUNTIME.TRANSACTION_ROLLBACK_FAILED]

Rolling back a transaction after the callback threw itself failed; the connection is destroyed rather than returned to the pool. The original callback error is attached as `cause`. Payload: `rollbackError`.

### RUNTIME.TYPE_PARAMS_INVALID [#RUNTIME.TYPE_PARAMS_INVALID]

A parameterized codec's `paramsSchema` rejected the `typeParams` carried by a codec reference (or the schema returned a Promise; runtime validation requires a synchronous Standard Schema validator). The `arktype-json` codec also throws it when the contract's serialized schema expression does not match the rehydrated schema, indicating a stale or hand-edited contract. Payload: `codecId`, `typeParams` (plus `table`/`column` or `typeName` on the contract-walk path).

## DRIVER [#driver]

### DRIVER.ALREADY_CONNECTED [#DRIVER.ALREADY_CONNECTED]

Calling `connect(binding)` on a driver, or `connect()` on a target facade client (Postgres, SQLite, Mongo) or the CLI control client, when it is already connected. Close with `close()` before reconnecting with a new binding. Payload: `bindingKind`.

### DRIVER.CONNECTION_FAILED [#DRIVER.CONNECTION_FAILED]

A control-plane driver could not establish a database connection (`driver.create(url)` in the SQLite, Postgres, and Mongo control drivers). The `why` carries the underlying driver message and the original error is attached as `cause`; connection URLs in meta are redacted. Payload: `path` (SQLite); `sqlState` plus redacted URL fields (Postgres); redacted URL fields (Mongo).

### DRIVER.NOT_CONNECTED [#DRIVER.NOT_CONNECTED]

Using a driver, a target facade client, or the CLI control client before `connect(...)` has been called (or after it was closed), surfaces from runtime `query` / `execute`, a prepared statement's `query(target, params, options?)`, `acquireConnection`, or `explain`, including lazily when iterating a query result.

### DRIVER.PREPARE_FAILED [#DRIVER.PREPARE_FAILED]

A prepared statement failed again after the PostgreSQL driver discarded a stale handle and retried with a fresh handle. The normalized PostgreSQL error is attached as `cause`. Payload: `handle`.

## MIGRATION [#migration]

### MIGRATION.AMBIGUOUS_MIGRATION_REF [#MIGRATION.AMBIGUOUS_MIGRATION_REF]

A migration reference (directory name or hash prefix) passed to a CLI command matches migrations in more than one contract space, so the command cannot tell which one you mean. Re-run with `--space <id>` to pick a space. Payload: `ref`, `spaceIds`.

### MIGRATION.BUNDLE_NOT_FOUND_FOR_GRAPH_NODE [#MIGRATION.BUNDLE_NOT_FOUND_FOR_GRAPH_NODE]

A hash resolves to a node in the migration graph, but no on-disk migration package has that hash as its destination (`to`), so there is no bundle to read for it. Hit when resolving a ref or hash to a migration bundle (e.g. `migration show`, contract-at resolution). Payload: `hash`, `explicitLabel` (when the user supplied a named reference).

### MIGRATION.CHECK_CONTRACT_UNREADABLE [#MIGRATION.CHECK_CONTRACT_UNREADABLE]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: the `contract.json` for a contract space cannot be read or validated. Re-emit the extension contract artifacts or fix the descriptor producing the invalid contract.

### MIGRATION.CHECK_DANGLING_REF [#MIGRATION.CHECK_DANGLING_REF]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a ref file points at a contract hash that does not exist in the space's migration graph. Update the ref with `prisma ref set <name> <valid-hash>` or delete it.

### MIGRATION.CHECK_DECLARED_BUT_UNMIGRATED [#MIGRATION.CHECK_DECLARED_BUT_UNMIGRATED]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: an extension is declared in `extensions` but has no on-disk migrations directory under `migrations/`. Re-emit the extension's contract-space artifacts, or remove the extension from `extensions`.

### MIGRATION.CHECK_DUPLICATE_MIGRATION_HASH [#MIGRATION.CHECK_DUPLICATE_MIGRATION_HASH]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: multiple migration packages in the same contract space share the same `migrationHash`, so the packages are not uniquely content-addressed. Re-emit one of the conflicting packages.

### MIGRATION.CHECK_FILE_MISSING [#MIGRATION.CHECK_FILE_MISSING]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a required file (`migration.json` or `ops.json`) is missing from a migration package directory. Re-emit the package or restore it from version control.

### MIGRATION.CHECK_HASH_MISMATCH [#MIGRATION.CHECK_HASH_MISMATCH]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: the `migrationHash` stored in `migration.json` does not match the hash recomputed from the package contents: the package was edited or partially written since emit. Re-emit the package or restore it from version control.

### MIGRATION.CHECK_HEAD_REF_MISSING [#MIGRATION.CHECK_HEAD_REF_MISSING]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a contract space has no `refs/head.json`. Re-emit the contract-space migrations and head-ref artifacts, or restore the file from version control.

### MIGRATION.CHECK_HEAD_REF_NOT_IN_GRAPH [#MIGRATION.CHECK_HEAD_REF_NOT_IN_GRAPH]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: the hash in a space's `refs/head.json` is not a node in that space's migration graph. Re-emit the space's migrations or restore the missing migration package.

### MIGRATION.CHECK_NOOP_SELF_EDGE [#MIGRATION.CHECK_NOOP_SELF_EDGE]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a migration has identical source and target hashes and declares no data invariant, a true no-op self-edge. Add a data operation if it was meant to carry one, or delete the migration.

### MIGRATION.CHECK_ORPHAN_SPACE_DIR [#MIGRATION.CHECK_ORPHAN_SPACE_DIR]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a contract-space directory exists under `migrations/` but no declared extension claims it. Remove the directory or declare the extension in `extensions`.

### MIGRATION.CHECK_PACKAGE_UNLOADABLE [#MIGRATION.CHECK_PACKAGE_UNLOADABLE]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a migration package directory exists but could not be loaded (parse or validation failure); the row's detail names the underlying cause. Re-emit the package or restore it from version control.

### MIGRATION.CHECK_PROVIDED_INVARIANTS_MISMATCH [#MIGRATION.CHECK_PROVIDED_INVARIANTS_MISMATCH]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: the `providedInvariants` list stored in `migration.json` disagrees with the one derived from `ops.json`. Re-emit the package so the two files agree.

### MIGRATION.CHECK_REF_UNREADABLE [#MIGRATION.CHECK_REF_UNREADABLE]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a ref file in a space's `refs/` directory cannot be read or parsed. Repair or remove the corrupt ref file.

### MIGRATION.CHECK_SNAPSHOT_CONTENT_MISMATCH [#MIGRATION.CHECK_SNAPSHOT_CONTENT_MISMATCH]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a contract snapshot's declared `storage.storageHash` agrees with the migration's `to` hash, but the snapshot's content recomputes to a different storage hash — the file under `migrations/snapshots/<hash>/` has been edited (or corrupted) since it was written. Restore `migrations/snapshots/` from version control, or re-run the command that produced the migration to regenerate its snapshot.

### MIGRATION.CHECK_SNAPSHOT_HASH_MISMATCH [#MIGRATION.CHECK_SNAPSHOT_HASH_MISMATCH]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a migration declares a destination hash `to` but the contract snapshot stored for that hash has a different inner `storage.storageHash`. Re-emit the package so `migration.json` and its snapshot agree.

### MIGRATION.CHECK_SNAPSHOT_UNPARSEABLE [#MIGRATION.CHECK_SNAPSHOT_UNPARSEABLE]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: either the migration's `to` value is not a well-formed 64-hex hash, or the contract snapshot stored for it exists but cannot be parsed. Re-emit the package, or restore `migrations/snapshots/` from version control.

### MIGRATION.CHECK_SPACE_DISJOINTNESS_VIOLATION [#MIGRATION.CHECK_SPACE_DISJOINTNESS_VIOLATION]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a storage element (table/collection) is claimed by more than one contract space. Update the contracts so each storage element is owned by exactly one space.

### MIGRATION.CHECK_TARGET_MISMATCH [#MIGRATION.CHECK_TARGET_MISMATCH]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a contract space's declared database target differs from the project's configured target. Update the extension to target the configured database, or change the project target.

### MIGRATION.CHECK_UNREACHABLE_MIGRATION [#MIGRATION.CHECK_UNREACHABLE_MIGRATION]

A `migration check` finding, carried as an `error` diagnostic on a completed run that exits `4`: a migration's `from` hash is not produced by any other migration (and is not the empty state), so the migration is unreachable in the graph. Delete it or re-emit a connecting migration.

### MIGRATION.CONSENT_PLAN_MISMATCH [#MIGRATION.CONSENT_PLAN_MISMATCH]

An apply carrying consent was refused because the plan recomputed for it is not the plan that was consented to. `db update` recomputes the plan at apply time and compares its hash against the one the consent was given for; a mismatch means the schema, the contract, or the database moved in between, so applying would carry out operations nobody agreed to. Re-run the command and review the freshly planned operations before consenting again. Payload: `consentedPlanHash`, `planHash`.

### MIGRATION.CONTRACT_DESERIALIZATION_FAILED [#MIGRATION.CONTRACT_DESERIALIZATION_FAILED]

A contract JSON on disk failed to deserialize into a valid contract: either a snapshot-store entry read while migration tooling resolved a contract at a ref or hash, or the emitted `contract.json` read as the fallback source by `db sign` / `db update --to` (invalid JSON, or a value that is not a JSON object). Re-emit the owning migration package (or re-run `prisma contract emit` for the emitted contract), or restore the file from version control. Payload: `filePath`, `message`. Also raised by `migration new` when the emitted `contract.json` fails to deserialize; that site has no meta and attaches the deserialization failure as `cause`.

### MIGRATION.CONTRACT_SNAPSHOT_CONTENT_MISMATCH [#MIGRATION.CONTRACT_SNAPSHOT_CONTENT_MISMATCH]

A contract snapshot loaded from `migrations/snapshots/<hash>/contract.json` does not reproduce the storage hash it is addressed by: the store is content-addressed, and the file has been edited (or corrupted) since it was written. Raised at the snapshot-store load seam, so every command that resolves a contract from the store (`migration plan`, `ref set`, `db sign` / `db update --to`, aggregate contract resolution) refuses instead of treating the edited content as the recorded contract. The envelope names the file and both hashes (meta: `storageHash`, `computedHash`, `jsonPath`). Restore `migrations/snapshots/` from version control, or re-run the command that authored the referencing migration to regenerate the snapshot.

### MIGRATION.CONTRACT_SNAPSHOT_HASH_MISMATCH [#MIGRATION.CONTRACT_SNAPSHOT_HASH_MISMATCH]

While writing a contract snapshot, the contract JSON's inner `storage.storageHash` does not equal the storage hash the snapshot is being filed under: the two must agree by construction. Primarily an authoring/tooling invariant rather than something a user causes directly. Payload: `storageHash`, `actualHash`, `dir`.

### MIGRATION.CONTRACT_SNAPSHOT_MISSING [#MIGRATION.CONTRACT_SNAPSHOT_MISSING]

A contract snapshot expected under `migrations/snapshots/` for a given storage hash does not exist on disk, so commands that need the contract at that hash (`migration plan`, `ref`-based resolution, `migration check`) cannot proceed. Re-run the command that authored the referencing migration to regenerate the snapshot, or restore `migrations/snapshots/` from version control. Payload: `storageHash`, `expectedPath`.

### MIGRATION.CONTRACT_SPACE_LAYOUT_VIOLATION [#MIGRATION.CONTRACT_SPACE_LAYOUT_VIOLATION]

The on-disk `migrations/` directory and the `extensions` declaration in config disagree: an orphan space directory exists with no declaring extension, or a declared extension has no migrations directory. All layout offences are bundled into one envelope. Raised when db commands load the contract-space aggregate. Payload: `violations` (list of `{kind, spaceId}`).

### MIGRATION.CONTRACT_SPACE_VIOLATION [#MIGRATION.CONTRACT_SPACE_VIOLATION]

A contract-space check raised under one code, in two lanes with different exits. As an error at exit `2` when the check could not run: a space's target mismatches the project target, two spaces claim the same storage element, a space contract is unreadable, or aggregate introspection failed (`db verify`, `db run`). As an `error`-severity diagnostic on a completed `db verify` run that exits `4`, including under `--marker-only`, when the check ran and found per-space marker drift: a marker hash mismatch, missing invariants, or an orphan marker row, reported next to the single-contract marker findings that already settle there. The envelope's `why` lists the specific violations. Payload: `violations`.

### MIGRATION.CONTRACT_VIEW_MISSING [#MIGRATION.CONTRACT_VIEW_MISSING]

A migration object's `endContract`/`startContract` accessor was read, but the instance carries no `endContractJson`/`startContractJson` to build the contract view from, typically a migration that overrides `describe()` and carries no contract. Payload: `className`, `accessor`, `jsonField`.

### MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH [#MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH]

At migration authoring/emit time, a `dataTransform(endContract, …)` produced a query plan whose storage hash does not match the contract passed to `dataTransform`: the query builder was configured with a different contract reference than the migration itself. Make both use the same imported `endContract`. Payload: `dataTransformName`, `expected`, `actual`.

### MIGRATION.DESCRIBE_INVALID [#MIGRATION.DESCRIBE_INVALID]

A migration author class's `describe()` result is unusable: it carries neither an `endContractJson` nor an override, or the returned metadata fails validation. Raised while loading/describing an authored migration. Payload: `reason`.

### MIGRATION.DESCRIPTOR_HEAD_HASH_MISMATCH [#MIGRATION.DESCRIPTOR_HEAD_HASH_MISMATCH]

An extension descriptor publishes a `contractSpace` whose `headRef.hash` does not match the hash recomputed from its `contractJson`: the descriptor was published with a stale head hash, typically because the contract was bumped without rerunning the extension's emit pipeline. Payload: `extensionId`, `recomputedHash`, `headRefHash`.

### MIGRATION.DESTINATION_CONTRACT_MISMATCH [#MIGRATION.DESTINATION_CONTRACT_MISMATCH]

Runner-level failure during apply (`db init`, `db update`, `migrate`): the plan's destination storage hash (or profile hash) does not match the destination contract handed to the runner alongside it. Indicates the plan and contract came from different emits. Payload: `planStorageHash`/`contractStorageHash` (or `planProfileHash`/`contractProfileHash`).

### MIGRATION.DESTRUCTIVE_CHANGES [#MIGRATION.DESTRUCTIVE_CHANGES]

The planned operations include destructive changes (e.g. DROP) and the command was run without explicit consent. `db update` asks for that consent instead of failing: interactively it asks you to type the name of the database it is about to change, and outside an interactive terminal it is granted by `--confirm <database>` (`--yes` accepts declared prompt defaults and never grants consent; `--confirm` is read only when the run is non-interactive or `--yes` is set, so a script run from a terminal needs `--no-interactive --confirm <database>`). The name is the `database` a driver connection object carries, or the connection URL's first path segment, else its host, falling back to the target id. A run with nobody to ask and no `--confirm` settles as `CLI.CONSENT_REQUIRED` at exit 2; a run whose prompt is cancelled settles as `CLI.PROMPT_CANCELLED` at exit 3. `--dry-run` never asks; it settles as this error instead. Use it to preview the operations first. `migration plan` raises the same refusal before writing an auto-baseline package (planned on an empty migrations directory from the `db` ref) whose operations would remove data when applied; there the consent token is the project directory name, so a non-interactive run passes `--no-interactive --confirm <directory>`, and a consented re-run that no longer plans the consented baseline settles as `MIGRATION.CONSENT_PLAN_MISMATCH`. Payload at the `migration plan` site: `destructiveOperations`, `planHash`.

### MIGRATION.DIR_EXISTS [#MIGRATION.DIR_EXISTS]

`migration new`/`migration plan` refused to scaffold because the target migration directory already exists: each migration needs a unique directory. Pick a different `--name` or delete the existing directory. Payload: `dir`.

### MIGRATION.DUPLICATE_INVARIANT_IN_EDGE [#MIGRATION.DUPLICATE_INVARIANT_IN_EDGE]

Two `dataTransform` operations on the same migration declare the same `invariantId`. Invariants are stored per-migration as a set, so two operations cannot share a routing identity; rename one, or drop the `invariantId` on the operation that need not be routing-visible. Payload: `invariantId`.

### MIGRATION.DUPLICATE_MIGRATION_HASH [#MIGRATION.DUPLICATE_MIGRATION_HASH]

While reconstructing the migration graph, two migrations were found sharing the same `migrationHash`; each migration must have a unique content-addressed identity. Regenerate one of the conflicting migrations. Payload: `migrationHash`.

### MIGRATION.DUPLICATE_SPACE_ID [#MIGRATION.DUPLICATE_SPACE_ID]

The per-space migration planner received the same contract-space id more than once, usually a repeated entry in `extensions`. Deduplicate the inputs. Payload: `spaceId`.

### MIGRATION.EXECUTION_FAILED [#MIGRATION.EXECUTION_FAILED]

A migration operation's SQL step failed while being executed against the database during apply (`db init`, `db update`, `migrate`). The envelope carries the database error detail so you can see which statement failed and why. Payload: `operationId`, `stepDescription`, `sql`, `sqlState`, `constraint`, `table`, `column`, `detail`.

### MIGRATION.FILE_MISSING [#MIGRATION.FILE_MISSING]

A required migration file is absent: either an on-disk package is missing `migration.json`/`ops.json` (migration-tools loader; re-emit via the package's `migration.ts`), or a `migration.ts` source file was expected at a package directory and not found (scaffold one with `migration new` or `migration plan`). Payload: `file`, `dir` (loader variant) or `dir` (source-file variant).

### MIGRATION.FOREIGN_KEY_VIOLATION [#MIGRATION.FOREIGN_KEY_VIOLATION]

SQLite only: after applying migration plans with `PRAGMA foreign_keys` temporarily off (needed for recreate-table operations), the post-apply `PRAGMA foreign_key_check` reported broken references, and the whole transaction is rolled back. Payload: `violations` (rows from the pragma).

### MIGRATION.HASH_MISMATCH [#MIGRATION.HASH_MISMATCH]

A migration package on disk is corrupt: the `migrationHash` stored in `migration.json` does not match the hash recomputed from the package contents. Raised whenever migration tooling loads packages (plan, list, apply). Re-emit the package via its `migration.ts` or restore from version control. Payload: `dir`, `storedHash`, `computedHash`.

### MIGRATION.HASH_NOT_IN_GRAPH [#MIGRATION.HASH_NOT_IN_GRAPH]

A contract hash the user supplied (or that a ref resolved to) is not a node in the on-disk migration graph, raised during plan resolution (`migration plan --from`), `ref set`, and `migration new --from` (including `--from` on an empty migrations directory, where there is no migration target it could name). The envelope lists the reachable hashes and suggests a valid one or running `migration plan` to introduce it. Payload: `hash`/`resolvedHash`, `reachableHashes` or `reachableRefs`; none at the `migration new` sites.

### MIGRATION.INVALID_DEFAULT_EXPORT [#MIGRATION.INVALID_DEFAULT_EXPORT]

The `migration.ts` in a package directory does not default-export a valid migration: it must export a `Migration` subclass or a factory function returning a plan-shaped object (`operations` array plus `targetId` and `destination`). Payload: `dir`, `actualExport` (when known).

### MIGRATION.INVALID_DEST_NAME [#MIGRATION.INVALID_DEST_NAME]

A copy-destination name in a migration package's copy list is not a single path segment (contains `..` or directory separators). Use a simple file name such as `contract.json`. Payload: `destName`.

### MIGRATION.INVALID_INVARIANT_ID [#MIGRATION.INVALID_INVARIANT_ID]

An `invariantId` on a `dataTransform` is empty or contains whitespace/control characters. Pick an id without spaces, tabs, newlines, or control characters. Payload: `invariantId`.

### MIGRATION.INVALID_JSON [#MIGRATION.INVALID_JSON]

A migration file (`migration.json` or `ops.json`) exists but is not parseable JSON. Re-emit the package via its `migration.ts` or restore from version control. Payload: `filePath`, `parseError`.

### MIGRATION.INVALID_MANIFEST [#MIGRATION.INVALID_MANIFEST]

A `migration.json` manifest parsed as JSON but failed schema validation. Re-emit the package or restore from version control. Payload: `filePath`, `reason`.

### MIGRATION.INVALID_NAME [#MIGRATION.INVALID_NAME]

The migration name given to `migration new`/`migration plan --name` contains no valid characters after sanitization (only a-z and 0-9 are kept). Provide a name with at least one alphanumeric character. Payload: `slug`.

### MIGRATION.INVALID_OPERATION_ENTRY [#MIGRATION.INVALID_OPERATION_ENTRY]

An operation returned by an authored migration class failed schema validation during emit: each entry of `operations` must carry `id`, `label`, and an `operationClass` of `additive`, `widening`, `destructive`, or `data`. Also raised when deserializing a persisted Mongo migration plan hits a malformed or unknown entry (filter, pipeline stage, DML/DDL/inspection command). Payload: `index`, `reason` (emit validation) or `context`, `kind` (plan deserialization).

### MIGRATION.INVALID_REF_FILE [#MIGRATION.INVALID_REF_FILE]

A ref file under `migrations/<space>/refs/` is not valid JSON or does not match the expected `{ "hash": "<64 hex>", "invariants": [...] }` shape. Payload: `path`, `reason`.

### MIGRATION.INVALID_REF_NAME [#MIGRATION.INVALID_REF_NAME]

A ref name is syntactically invalid: names must be lowercase alphanumeric with hyphens or forward slashes, with no `.` or `..` segments. Raised by `ref` commands and any ref-consuming tooling. Payload: `refName`.

### MIGRATION.INVALID_REF_VALUE [#MIGRATION.INVALID_REF_VALUE]

The value given for a ref (e.g. to `ref set`) is not a valid contract hash: it must be 64 lowercase hex chars or `empty`. Payload: `value`.

### MIGRATION.INVALID_REFS [#MIGRATION.INVALID_REFS]

A legacy `refs.json` file is invalid: it must be a flat object mapping valid ref names to contract hash strings. Payload: `path`, `reason`.

### MIGRATION.INVALID_SPACE_ID [#MIGRATION.INVALID_SPACE_ID]

A contract-space id (e.g. via `--space` or in planner input) does not match the required pattern `[a-z][a-z0-9_-]{0,63}`: space ids double as directory names under `migrations/`, so the rule is conservative. Payload: `spaceId`.

### MIGRATION.LEGACY_MARKER_SHAPE [#MIGRATION.LEGACY_MARKER_SHAPE]

The database's marker table (`prisma_contract.marker` on Postgres, `_prisma_marker` on SQLite) has the pre-per-space shape (no `space` column). The transitional auto-migration has been removed; drop the marker table and re-run `prisma db init` to reinitialise from a clean baseline. Detected during `db init`/`db update`/apply. Payload: `table`, `columns` (runner variant) or `runnerErrorCode` (marker-read variant).

### MIGRATION.LEGEND_HUMAN_ONLY [#MIGRATION.LEGEND_HUMAN_ONLY]

`migration list --legend` was combined with a machine-readable or silent output flag (`--json`, `--dot`, or `--quiet`); the legend is human-only decoration on stderr. Drop one of the flags. Payload: `conflictingFlag`.

### MIGRATION.MARKER_CAS_FAILURE [#MIGRATION.MARKER_CAS_FAILURE]

While finalizing an apply, the compare-and-swap update of the database's contract marker found the marker had been modified by another process mid-migration: a concurrent migration raced this one. Payload: `space`, `expectedStorageHash`, `destinationStorageHash`.

### MIGRATION.MARKER_MISMATCH [#MIGRATION.MARKER_MISMATCH]

The live database marker's contract hash is not reachable anywhere in the on-disk migration graph: the database and the local migration history have diverged. The fix depends on which side is canonical: `migration plan` (catch the graph up), `ref set db <markerHash>` (fix a drifted local ref), or investigate out-of-band migration. Payload: `markerHash`, `reachableHashes`.

### MIGRATION.MARKER_NOT_IN_HISTORY [#MIGRATION.MARKER_NOT_IN_HISTORY]

A warning diagnostic (not a hard failure) in `migration status`: the database's marker hash does not match any migration in the history, meaning the database was updated outside the migration system. Hints suggest `db sign` (overwrite marker) or `db update` (push the contract).

### MIGRATION.MARKER_ORIGIN_MISMATCH [#MIGRATION.MARKER_ORIGIN_MISMATCH]

Runner-level failure during apply: the plan asserts an origin contract, but the database marker is missing, or its storage hash (or profile hash) differs from the plan's origin: the database is not at the state the plan was computed from. Re-plan from the database's actual state; `db init` intercepts this code to render an init-specific "already initialised at a different contract" message. Payload: `expectedOriginStorageHash` plus `markerStorageHash`/`markerProfileHash` depending on the branch.

### MIGRATION.MISSING_INVARIANTS [#MIGRATION.MISSING_INVARIANTS]

A diagnostic in `migration status`: the active ref requires data invariants that the database marker does not record as provided. If no path through the graph can supply them, status escalates to `MIGRATION.NO_INVARIANT_PATH`. Payload: `ref` (when a ref is active), `invariants` (the missing ids).

### MIGRATION.NO_CHANGES [#MIGRATION.NO_CHANGES]

`migration new` found the from and to contract hashes identical: there is nothing to migrate. Change the contract and re-run `prisma contract emit` first, or pass `--from <hash>` explicitly to author a data-only migration on the current contract hash. Payload: none.

### MIGRATION.NO_INVARIANT_PATH [#MIGRATION.NO_INVARIANT_PATH]

The target (or named ref) requires data invariants, and no path through the migration graph from the current state covers all of them. Add a migration on the path that runs a `dataTransform` with each missing `invariantId`, or retarget the ref. Payload: `required`, `missing`, `structuralPath` (edges: `dirName`, `migrationHash`, `from`, `to`, `invariants`), `refName` (when applicable). Also raised per space by `migrate` in show/plan mode when a space's path requires invariants not available on disk; that site's meta is `spaceId`, `missing`.

### MIGRATION.NO_MIGRATIONS [#MIGRATION.NO_MIGRATIONS]

`migration show` was given a non-path reference but the app space has no migration packages at all, so there is nothing to resolve against. Create a migration with `prisma migration plan` first. Payload: none.

### MIGRATION.OPERATION_UNSUPPORTED [#MIGRATION.OPERATION_UNSUPPORTED]

A Mongo migration check uses a filter feature the check evaluator does not support: an unsupported filter operator, or an aggregation-expression filter. Payload: `operator`.

### MIGRATION.PACKAGE_NOT_FOUND [#MIGRATION.PACKAGE_NOT_FOUND]

`migration show` or `migration check` resolved its target (a directory path, or a migration reference) but no loaded on-disk migration package matches it, either no package lives at the given path, or the resolved migration's package failed to load. `migration check` raises it at exit `2`: it could not run the check at all, which is different from running it and finding something. Pass a directory name, hash prefix, or path to an on-disk migration package, or inspect the migrations directory for corruption. Payload: none.

### MIGRATION.PATH_UNREACHABLE [#MIGRATION.PATH_UNREACHABLE]

An apply command (`migrate`/`db update`) cannot find a path through the on-disk migration graph from the database's current marker to the requested target: the connecting edge was never planned. The fix walks you through `migration plan` (with the right `--from`/`--to`) then `migrate`. Payload: carries the underlying failure's meta (`fromHash`, `targetHash`, `deadEnds`, `kind`).

### MIGRATION.PLANNING_FAILED [#MIGRATION.PLANNING_FAILED]

Migration planning (typically during `db init`/`db update`) failed because of conflicts, e.g. the live database already contains objects that clash with the plan. The envelope aggregates each conflict's summary and suggested fix. Payload: `conflicts`.

### MIGRATION.PLAN_NOT_ARRAY [#MIGRATION.PLAN_NOT_ARRAY]

An authored migration's `operations` getter returned something other than an array. Fix the migration class so `operations` returns an array of operations. Payload: `dir`, `actualValue` (when known).

### MIGRATION.PLAN_ORIGIN_UNKNOWN [#MIGRATION.PLAN_ORIGIN_UNKNOWN]

`migration plan` or `migration new` was run without `--from` and without a `db` ref while migrations already exist on disk. Planning would silently fall back to an empty-database origin and produce a migration that recreates everything the existing history already creates, so the command refuses. Set the `db` ref (`migration ref set db <contract>` or `db update`), pass `--from <contract>`, or (for `migration plan`) pass `--from @empty` to deliberately plan from an empty database. Payload: `reachableRefs`.

### MIGRATION.POLICY_VIOLATION [#MIGRATION.POLICY_VIOLATION]

A planned operation's class (e.g. `destructive`) is not allowed by the execution-time operation policy in force for the command. Runner-level failure during apply. Payload: `operationId`, `operationClass`, `allowedClasses`.

### MIGRATION.POSTCHECK_FAILED [#MIGRATION.POSTCHECK_FAILED]

After executing a migration operation, one of its postcheck steps (a query expected to return true) did not hold, so the apply is rolled back. Payload: `operationId`, `phase`, `stepDescription`.

### MIGRATION.POSTGRES_CONTROL_STACK_MISSING [#MIGRATION.POSTGRES_CONTROL_STACK_MISSING]

A `PostgresMigration` operation (e.g. `createTable`, `dataTransform`) was invoked on an instance constructed without a control stack: normal CLI-driven runs always assemble one from `prisma.config.ts`, so this indicates a test fixture or ad-hoc consumer used the no-arg constructor (valid only for introspection). Payload: `operation`.

### MIGRATION.PRECHECK_FAILED [#MIGRATION.PRECHECK_FAILED]

Before executing a migration operation, one of its precheck steps (a query expected to return true) did not hold: the database is not in the state the operation requires, so the apply stops and rolls back. Payload: `operationId`, `phase`, `stepDescription`.

### MIGRATION.PROVIDED_INVARIANTS_MISMATCH [#MIGRATION.PROVIDED_INVARIANTS_MISMATCH]

The `providedInvariants` stored in `migration.json` disagrees with the canonical value derived from `ops.json`: the manifest was likely hand-edited without re-emitting (a same-ids-different-order case is called out explicitly). Re-emit the package. Payload: `filePath`, `stored`, `derived`, `difference` (`{missing, extra}`).

### MIGRATION.REF_AMBIGUOUS [#MIGRATION.REF_AMBIGUOUS]

A contract or migration reference prefix matches more than one candidate (raised by the shared ref-resolution mapper used across CLI commands, and by `migration new --from` when the prefix matches several migration target hashes). Provide a longer prefix or the full hash. Payload: `input`, `candidates`, and at the shared-mapper site `grammar`.

### MIGRATION.REF_INVALID_FORMAT [#MIGRATION.REF_INVALID_FORMAT]

A contract or migration reference is syntactically invalid: it is not a hash, ref name, or migration directory name in any accepted form (raised by the shared ref-resolution mapper). Payload: `input`.

### MIGRATION.REF_NOT_FOUND [#MIGRATION.REF_NOT_FOUND]

A contract or migration reference does not resolve: no matching hash, ref name, or migration directory name exists in the migration graph or refs index (raised by the shared ref-resolution mapper used across CLI commands). Payload: `input`, `grammar`.

### MIGRATION.REF_NOT_RESOLVABLE [#MIGRATION.REF_NOT_RESOLVABLE]

A ref name resolves to nothing: no pointer file with that name exists, and the fallback hash is not a node in the migration graph either, so there is no contract to materialize. Create the ref with `ref set`, advance it via `db update --advance-ref`, or pass a graph-node hash. Payload: `refName`, `identifier`.

### MIGRATION.REF_SET_BUNDLE_NOT_FOUND [#MIGRATION.REF_SET_BUNDLE_NOT_FOUND]

`ref set` resolved the given hash to a graph node, but no on-disk migration bundle has that hash as its destination, so the ref would point at a node with no backing package. Re-emit the migration that produces this hash. Payload: `hash`.

### MIGRATION.REF_SET_EMPTY_SENTINEL [#MIGRATION.REF_SET_EMPTY_SENTINEL]

`ref set` was asked to point a ref at the empty-database sentinel hash, which is a planner internal and not a valid ref target. Use a real contract hash from the migration graph. Payload: `hash`.

### MIGRATION.REF_WRONG_GRAMMAR [#MIGRATION.REF_WRONG_GRAMMAR]

A reference parsed, but as the wrong kind for the argument position, e.g. a migration-only reference where a contract reference is required (raised by the shared ref-resolution mapper). The message and fix come from the resolver's own diagnosis. Payload: `input`, `expectedGrammar`.

### MIGRATION.RUNNER_FAILED [#MIGRATION.RUNNER_FAILED]

Generic wrapper for a migration runner failure during execution that has no more specific code; the summary/why carry the underlying detail (also used to surface the legacy-marker-shape condition from marker reads, with `meta.runnerErrorCode`). `migrate` and `db init` map unrecognized apply failures through it, passing the failure's own meta through unchanged. Inspect the reported summary/why detail and address the underlying failure before re-running the command. Payload: the wrapped failure's meta, when it has any; `runnerErrorCode` at the legacy-marker-shape site.

### MIGRATION.SAME_SOURCE_AND_TARGET [#MIGRATION.SAME_SOURCE_AND_TARGET]

A migration's `from` and `to` hashes are identical and it declares no data-transform operations, a pure no-op self-edge, which is only allowed when the migration runs at least one `dataTransform`. Change the contract, add a dataTransform, or delete the migration. Payload: `dirName`, `hash`.

### MIGRATION.SCHEMA_VERIFY_FAILED [#MIGRATION.SCHEMA_VERIFY_FAILED]

After applying migrations, the runner introspected the database and the resulting schema does not satisfy the destination contract; the apply is rolled back. Runner-level failure during `db init`/`db update`/`migrate`. Payload: `issues` (schema diff issues).

### MIGRATION.SNAPSHOT_MISSING [#MIGRATION.SNAPSHOT_MISSING]

A `--from` reference cannot produce a contract: either a ref name has no pointer file and the fallback hash is not a graph node (`viaRef: true`), or an explicit `--from <hash>` was given on an empty migration graph and names no ref (`viaRef: false`). Payload: `identifier`, `viaRef`. Also raised by `db sign` when a contract reference resolves to a hash but no migration produces that hash and the emitted contract does not match; that site has no meta.

### MIGRATION.SPACE_NOT_FOUND [#MIGRATION.SPACE_NOT_FOUND]

`migration list --space <id>` (and similar space-scoped commands) named a contract space with no directory under `migrations/`. Distinct from an existing-but-empty space, which renders an empty state and exits 0. The envelope lists the space directories that do exist. Payload: `spaceId`, `availableSpaces`.

### MIGRATION.SQLITE_CONTROL_STACK_MISSING [#MIGRATION.SQLITE_CONTROL_STACK_MISSING]

SQLite twin of `MIGRATION.POSTGRES_CONTROL_STACK_MISSING`: a `SqliteMigration` operation needing the control adapter was invoked on an instance constructed without a control stack (only introspection is valid in that form). Payload: `operation`.

### MIGRATION.TABLE_NAME_CASE_CHANGED [#MIGRATION.TABLE_NAME_CASE_CHANGED]

The planner would drop table `X` and create table `Y` in the same namespace, where `X` is `Y` with its first letter lowered; the columns are not compared. That is the shape of a schema upgraded across the release in which a model with no `@@map` stopped lowering the first letter of its table name (`model UserProfile` now names `"UserProfile"`, previously `"userProfile"`); planning it would recreate the table empty. Reported as a conflict inside `MIGRATION.PLANNING_FAILED`. Add `@@map("X")` to the model (or run the `add-model-map` codemod) to keep the existing table, or rename it by hand with `ALTER TABLE "X" RENAME TO "Y"`, after which the plan is empty. Payload: `droppedTable`, `createdTable`.

### MIGRATION.TARGET_MISMATCH [#MIGRATION.TARGET_MISMATCH]

A migration script declares one `targetId` but the loaded `prisma.config.ts` declares another; the script can only run against a config targeting the same database. Switch configs or pass `--config <path>`. Payload: `migrationTargetId`, `configTargetId`.

### MIGRATION.TARGET_NOT_APP_SPACE [#MIGRATION.TARGET_NOT_APP_SPACE]

A filesystem-path target given to a migration command does not resolve to an app-space migration directory: it points outside the app space's migrations directory, or at that directory's root itself. Pass an app-space migration directory or use a hash prefix. Payload: none.

### MIGRATION.TARGET_UNSUPPORTED [#MIGRATION.TARGET_UNSUPPORTED]

The configured target does not provide migration support (no planner/runner via `target.migrations`), so migration commands like `db init` cannot run against it. Select a target that provides migrations.

### MIGRATION.UNFILLED_PLACEHOLDER [#MIGRATION.UNFILLED_PLACEHOLDER]

A scaffolded migration still contains a `placeholder(...)` call that the author never replaced with a real query; it throws when the migration is emitted or run. The `slot` names the exact location to edit (e.g. `"backfill-product-status:check.source"`). Payload: `slot`.

### MIGRATION.UNKNOWN_INVARIANT [#MIGRATION.UNKNOWN_INVARIANT]

A ref declares required invariants that no migration anywhere in the graph provides, either the ref has a typo or the providing migration has not been authored yet. Payload: `unknown`, `declared`, `refName` (when applicable).

### MIGRATION.UNKNOWN_REF [#MIGRATION.UNKNOWN_REF]

A ref name was used (read, resolved, or deleted via `ref` commands) but no ref file with that name exists. Create it with `prisma ref set <name> <hash>`, or run `ref list` to see what exists. Payload: `refName`, `filePath` or `availableRefs` depending on the site.

## PLAN [#plan]

### PLAN.HASH_MISMATCH [#PLAN.HASH_MISMATCH]

At execute time, the plan's `meta.storageHash` does not match the runtime contract's storage hash: the plan was built against a different version of the contract than the one the runtime holds. Rebuild the plan against the current contract. Payload: `planStorageHash`, `runtimeStorageHash`.

### PLAN.TARGET_MISMATCH [#PLAN.TARGET_MISMATCH]

At execute time, the plan's `meta.target` does not match the runtime contract's target, e.g. a plan built for postgres submitted to a sqlite runtime. Payload: `planTarget`, `runtimeTarget`.

## BUDGET [#budget]

### BUDGET.ROWS_EXCEEDED [#BUDGET.ROWS_EXCEEDED]

The `budgets` middleware blocks (or warns about) a query expected or observed to return more rows than the configured `maxRows` budget. Thrown before execution for an unbounded SELECT (no LIMIT, no aggregate-without-GROUP-BY) or when the AST-based row estimate exceeds the budget, and during row streaming when the observed row count crosses `maxRows`; raw-SQL guardrails also emit it for raw SELECT text without a LIMIT clause. Payload: `source` (`'ast'` or `'observed'`), `estimatedRows`, `observedRows`, `maxRows`.

### BUDGET.TIME_EXCEEDED [#BUDGET.TIME_EXCEEDED]

The `budgets` middleware reports after execution that a query's latency exceeded the configured `maxLatencyMs` budget. Default severity is warn (logged); it throws when the latency severity is configured as `error` or the runtime runs in strict mode. Payload: `latencyMs`, `maxLatencyMs`.

## LINT [#lint]

### LINT.DELETE_WITHOUT_WHERE [#LINT.DELETE_WITHOUT_WHERE]

The `lints` middleware found a DELETE plan with no WHERE clause and blocks execution to prevent an accidental full-table deletion. Default severity is error (throws); configurable to warn. Payload: `table`.

### LINT.NO_LIMIT [#LINT.NO_LIMIT]

The `lints` middleware (or raw-SQL guardrails) found a SELECT with no LIMIT, which may return an unboundedly large result set. Default severity is warn (logged, execution proceeds); raw-SQL plans are checked heuristically against the SQL text. Payload: `table` (AST path) or `sql` snippet (raw path).

### LINT.READ_ONLY_MUTATION [#LINT.READ_ONLY_MUTATION]

Raw-SQL guardrails found a mutating statement (INSERT/UPDATE/DELETE/DDL) in a plan whose meta annotations declare a read-only intent (`read`, `report`, or `readonly`). Default severity is error (throws). Payload: `sql`, `intent`.

### LINT.SELECT_STAR [#LINT.SELECT_STAR]

The `lints` middleware found a query that selects all columns, via the builder's selectAll intent on AST plans, or a literal `SELECT *` in raw SQL. Default severity is warn on the AST path, error on the raw path. Payload: `table` (AST path) or `sql` snippet (raw path).

### LINT.UPDATE_WITHOUT_WHERE [#LINT.UPDATE_WITHOUT_WHERE]

The `lints` middleware found an UPDATE plan with no WHERE clause and blocks execution to prevent an accidental full-table update. Default severity is error (throws); configurable to warn. Payload: `table`.

## PARADEDB [#paradedb]

### PARADEDB.ARGUMENT_INVALID [#PARADEDB.ARGUMENT_INVALID]

A ParadeDB search-function helper received an invalid argument: a malformed query object, an out-of-range numeric option, or an option combination the function does not accept. Raised while authoring/lowering the search expression. Payload: `helper`, `argument`, `received`.

## POSTGIS [#postgis]

### POSTGIS.GEOMETRY_INVALID [#POSTGIS.GEOMETRY_INVALID]

A PostGIS geometry constructor (`point`, `polygon`, `bboxPolygon`, …) received invalid input: non-finite coordinates, a ring that is not closed, too few points, or a malformed bounding box. Raised at construction time, before the value reaches the database. Payload: `constructor`, `received`, `reason`.

## SUPABASE [#supabase]

### SUPABASE.CONFIG_INVALID [#SUPABASE.CONFIG_INVALID]

The Supabase extension's runtime configuration is invalid: missing or contradictory connection/auth settings (formerly the `SupabaseConfigError` class, removed at 0.17). Payload: `reason`.

### SUPABASE.JWT_INVALID [#SUPABASE.JWT_INVALID]

A JWT handed to the Supabase runtime failed validation: malformed token, missing claims, or signature/JWKS mismatch (formerly the `InvalidJwtError` class, removed at 0.17). Payload: `reason`.

## TESTKIT [#testkit]

Raised by the codec conformance testkits (`@internal/postgres-codec-testkit`, `@internal/sqlite-codec-testkit`) while running an extension author's conformance cases against a live database.

### TESTKIT.CODEC_DESCRIPTOR_MISSING [#TESTKIT.CODEC_DESCRIPTOR_MISSING]

A conformance case names a codec id the target's built-in descriptor registry does not know, and the case supplies no descriptor of its own. The harness projects and decodes through the codec descriptor under test, so an extension codec must be supplied on the case. Payload: `codecId`.

### TESTKIT.CONFORMANCE_CASE_INVALID [#TESTKIT.CONFORMANCE_CASE_INVALID]

A `many` conformance case carries a value that is neither an array nor null: the harness maps element-wise over array cases and has nothing to map over. Give the case an array of element values, or null.

### TESTKIT.PROJECTION_MALFORMED [#TESTKIT.PROJECTION_MALFORMED]

The executed JSON projection came back in a shape the codec descriptor does not declare: the projected document is missing its value key, or an array projection produced something other than a JSON array or null. This points at the projection SQL the descriptor under test renders. Payload: `codecId` (when the case is known).

## Related pages

- [`Migration API`](https://www.prisma.io/docs/orm/reference/migration-api): Every method and helper a migration.ts can use: the Migration class, the PostgreSQL operations, the column and constraint helpers, rawSql, and the MongoDB operations.
- [`ORM client reference`](https://www.prisma.io/docs/orm/reference/orm-client): Reference for the Prisma ORM client's query, mutation, filter, and aggregate methods.
- [`Pipeline builder reference`](https://www.prisma.io/docs/orm/reference/pipeline-builder): Reference for the Prisma ORM MongoDB pipeline builder's stages, accumulators, expression helpers, and write methods.
- [`Raw queries reference`](https://www.prisma.io/docs/orm/reference/raw-queries): Reference for Prisma ORM raw queries: PostgreSQL raw SQL and MongoDB raw commands.
- [`SQL query builder reference`](https://www.prisma.io/docs/orm/reference/sql-query-builder): Reference for the Prisma ORM SQL query builder's select, mutation, and grouped query methods.

# Prisma ORM API reference (/docs/orm/reference)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Reference index for the Prisma ORM client, SQL query builder, pipeline builder, raw queries, and runtime APIs.

Location: ORM > Prisma ORM API reference

Prisma ORM gives you three typed ways to write a query. In Prisma ORM 7 you wrote `findMany({ where, include })`, but now each of those arguments is a method you chain: `.where(...).include(...)`. See [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7), which maps each argument to its method.

* The **ORM client** is at `db.orm`. It has model methods such as `where()`, `create()`, and `include()`, it works on both PostgreSQL and MongoDB, and it covers everyday reads and writes across your models.
* The **SQL query builder** is at `db.sql`. It has table methods that match SQL, such as `select()`, `innerJoin()`, and `groupBy()`, it is PostgreSQL only, and it returns whatever shape your `select()` asks for, not objects shaped like your models.
* The **pipeline builder** is at `db.query`. It builds MongoDB aggregation pipelines, and it is MongoDB only.

When none of the three can express the query you need, write raw SQL on PostgreSQL or a raw command on MongoDB. See [Raw queries](https://www.prisma.io/docs/orm/reference/raw-queries). For connecting and disconnecting the client, transactions, and prepared statements, see [Transactions and runtime](https://www.prisma.io/docs/orm/reference/transactions-and-runtime).

## Running a query [#running-a-query]

The ORM client sends its own queries: `first()`, `create()`, `update()`, `upsert()`, `delete()`, and `aggregate()` send the query the moment you call them. `all()`, `createAll()`, `updateAll()`, and `deleteAll()` return a result object and send the query when you `await` that object or loop over it with `for await`. `all()` is what replaced `findMany`.

The SQL query builder and the pipeline builder send nothing on their own: `.build()` gives you a built query. Pass it to `runtime.query(...)` for rows, or to `runtime.execute(...)` for a write that returns no rows. Get `runtime` from `db.runtime()` once and reuse it.

### PostgreSQL [#postgresql]

```ts
const runtime = db.runtime();
const admins = await db.orm.public.User.where((u) => u.kind.eq('admin')).all();
const plan = db.sql.public.user.select('id', 'email').where((f, fns) => fns.eq(f.kind, 'admin')).build();
const rows = await runtime.query(plan);
```

`User` is the model name and `user` is the table name, which the [example schema](https://www.prisma.io/docs/orm/reference/orm-client#example-schema) sets with `@@map("user")`. Without `@@map`, the two names are the same. The ORM client compares on the column, `u.kind.eq(...)`, while the SQL query builder compares through `fns`, `fns.eq(f.kind, ...)`.

### MongoDB [#mongodb]

```ts
const runtime = await db.runtime();
const admins = await db.orm.users.where({ role: 'admin' }).all();
const plan = db.query.from('users').match((f) => f.role.eq('admin')).build();
const docs = await runtime.query(plan);
```

`db.runtime()` returns a promise on MongoDB, so `await` it. `users` is the collection name, and both `db.orm` and `db.query.from()` are keyed by it. The ORM client's `where()` takes an object of field values, while the pipeline builder's `match()` takes a callback that compares on the field, `f.role.eq(...)`. Two different things are named `query`: `db.query` builds a pipeline, and `runtime.query(...)` runs a query that has already been built.

- [ORM client reference](https://www.prisma.io/docs/orm/reference/orm-client): Every ORM client method, with PostgreSQL and MongoDB behavior documented side by side.

- [SQL query builder reference](https://www.prisma.io/docs/orm/reference/sql-query-builder): Every SQL query builder method for building typed, table-level queries against PostgreSQL.

- [Pipeline builder reference](https://www.prisma.io/docs/orm/reference/pipeline-builder): Every MongoDB pipeline-builder stage, accumulator, expression helper, and write method.

- [Raw queries reference](https://www.prisma.io/docs/orm/reference/raw-queries): Raw SQL on PostgreSQL and raw commands on MongoDB, for queries the typed APIs cannot express.

- [Transactions and runtime reference](https://www.prisma.io/docs/orm/reference/transactions-and-runtime): Connecting and disconnecting the client, transactions, prepared statements, and execution options.

- [Migration API reference](https://www.prisma.io/docs/orm/reference/migration-api): Every method and helper a migration.ts can call, with the SQL each PostgreSQL operation runs, and the MongoDB operations.

## Related pages

- [`Coming from Prisma ORM 7`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7): What each Prisma ORM 7 schema attribute, command, and query is called in Prisma ORM 8, and what is not available.
- [`Core concepts`](https://www.prisma.io/docs/orm/core-concepts): The ideas every Prisma ORM command and API builds on: contracts, emitting, plans, the database signature, codecs, and the migration graph.
- [`Extensions`](https://www.prisma.io/docs/orm/extensions): Every package that plugs into Prisma ORM: database packages, column types, indexes, query operations, and middleware, by Prisma and the community.
- [`Overview`](https://www.prisma.io/docs/orm/data-modeling): Describe the data your application needs with models, primary keys, scalar fields, and relations.
- [`Prisma 7`](https://www.prisma.io/docs/orm/v7): Prisma ORM is a next-generation Node.js and TypeScript ORM that provides type-safe database access, migrations, and a visual data editor.

# Migration API (/docs/orm/reference/migration-api)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Every method and helper a migration.ts can use: the Migration class, the PostgreSQL operations, the column and constraint helpers, rawSql, and the MongoDB operations.

Location: ORM > Reference > Migration API

Each migration is its own folder inside `migrations/app/`, and the file you edit in it is `migration.ts`. `app` is the fixed name of the folder that holds your project's migrations; extension packages that ship their own migrations get folders of their own next to it.

In Prisma ORM 8, `schema.prisma` is now `contract.prisma`, your contract: the same language and the same models. `npx prisma migration plan` writes `migration.ts` from a change to the contract, and saves a frozen copy of the contract for the migration to point at; when this page says a migration's start or end contract, it means one of those copies. You edit `migration.ts`, then run it with Node.js, and it writes `ops.json`, the SQL that will run, next to itself. [`npx prisma db migrate`](https://www.prisma.io/docs/cli/db-migrate) applies `ops.json` to the database.

This page lists everything `migration.ts` can call. For the editing workflow, with a worked backfill, read [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration).

On PostgreSQL, everything comes from one module:

```ts
import { Migration, MigrationCLI, col, primaryKey, unique, foreignKey, checkExpression, lit, fn, rawSql, createExtension, placeholder } from '@prisma/orm-postgres/migration';
```

`migration plan` writes the import line with only the names the migration needs. When you add a call by hand, add its name to the import line. On MongoDB the module is `@prisma/orm-mongo/target/migration`; the path really does contain `target`, and it is not a placeholder. See [MongoDB operations](#mongodb-operations).

## The migration file [#the-migration-file]

`migration.ts` exports one class that extends `Migration`. This is what `migration plan` writes for a migration that adds one column:

```ts title="migrations/app/20260921T1408_add_user_bio/migration.ts"
#!/usr/bin/env -S node
import type { Contract as End } from '../../snapshots/155ebf55586e71f917e8b534544f97d97523544e862ae74b8e70d2af933df807/contract';
import endContract from '../../snapshots/155ebf55586e71f917e8b534544f97d97523544e862ae74b8e70d2af933df807/contract.json' with { type: 'json' };
import type { Contract as Start } from '../../snapshots/1e8412e162dbbe69f4bb3bf8d07f0280ae67eaab15c34dcf201e67468315428d/contract';
import startContract from '../../snapshots/1e8412e162dbbe69f4bb3bf8d07f0280ae67eaab15c34dcf201e67468315428d/contract.json' with { type: 'json' };
import { Migration, MigrationCLI, col } from '@prisma/orm-postgres/migration';

export default class M extends Migration<Start, End> {
  override readonly startContractJson = startContract;
  override readonly endContractJson = endContract;

  override get operations() {
    return [
      this.addColumn({
        schema: 'public',
        table: 'user',
        column: col('bio', 'text', { codecRef: { codecId: 'pg/text@1' } }),
      }),
    ];
  }
}

MigrationCLI.run(import.meta.url, M);
```

The four imports at the top point at snapshots, which are copies of your contract that `migration plan` saves under `migrations/snapshots/<hash>/`: one for the contract the migration starts from and one for the contract it ends at. You never type those paths; `migration plan` writes them. `codecRef` on the column names how its values are read and written; leave it as `migration plan` wrote it. The last line is what makes the file runnable with Node.js; keep it as written.

| Member                  | What it is                                                                                                                                                                                                                                                                        |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Migration<Start, End>` | The base class. `Start` and `End` are the two snapshots' types.                                                                                                                                                                                                                   |
| `startContractJson`     | The start snapshot's `contract.json`.                                                                                                                                                                                                                                             |
| `endContractJson`       | The end snapshot's `contract.json`.                                                                                                                                                                                                                                               |
| `operations`            | The list of changes. They run in the order you list them, table changes and data changes alike, so a `dataTransform` between two column changes runs between them. Each entry is one call to a method or helper on this page. Return the list as it is; do not `await` the calls. |
| `this.endContract`      | A read-only view of the end contract, for looking up names and settings in your own code. `this.endContract.namespace.public.table.user` is the `user` table in the `public` schema (`namespace` in that path means the PostgreSQL schema).                                       |
| `this.startContract`    | The same for the start contract, or `null` on a first migration.                                                                                                                                                                                                                  |

A first migration starts from an empty database, so it has no start snapshot. `migration plan` writes it as `extends Migration<never, End>`, without the two `Start` imports and without `startContractJson`.

Running the file turns `operations` into `ops.json`, and also writes `migration.json`, which records the start and end contracts. Node.js 22.18 or later runs the `.ts` file directly, with no build step. Run it from your project root: it reads `prisma.config.ts` from the directory you run it in, to learn which database and extensions the project uses, and it never connects to a database.

```bash
node migrations/app/20260921T1408_add_user_bio/migration.ts
```

```text
Wrote ops.json + migration.json to /path/to/my-app/migrations/app/20260921T1408_add_user_bio
```

| Flag              | What it does                                                                    |
| ----------------- | ------------------------------------------------------------------------------- |
| `--dry-run`       | Prints `migration.json` and `ops.json` to the terminal instead of writing them. |
| `--config <path>` | Reads that config file instead of `./prisma.config.ts`.                         |
| `--help`          | Prints the flags.                                                               |

Any other flag fails with an error whose `code` is `CLI.UNKNOWN_FLAG`.

## Operation classes and checks [#operation-classes-and-checks]

Every operation carries an `operationClass`, which says what kind of change it makes. The methods below set it for you, and `rawSql` asks you for it. The class changes nothing about what runs: `npx prisma db migrate` applies every class, and marks each destructive operation with `⚠` and a data-loss warning.

| Class         | Meaning                                                      | Example                               |
| ------------- | ------------------------------------------------------------ | ------------------------------------- |
| `additive`    | Adds something new                                           | Add a column, create an index         |
| `widening`    | Loosens a rule, or renames something without losing anything | Drop `NOT NULL`, rename an index      |
| `destructive` | Removes or changes something that exists, and can lose data  | Drop a column, change a column's type |
| `data`        | Changes rows, not tables                                     | A `dataTransform`                     |

Most operations also carry two check queries, a precheck and a postcheck, and `db migrate` runs them in this order:

1. The postcheck, which asks "is the change already there?". If it passes, the operation is skipped. This is what lets you run `db migrate` again after a run stopped partway: what already landed is skipped.
2. The precheck, which asks "is the database in the state this change expects?". If it fails, the run stops.
3. The statements.
4. The postcheck again. If it fails now, the run stops.

The methods below write both checks for you; you write them yourself only in `rawSql`. [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work#every-operation-checks-itself) has the full rule.

## PostgreSQL operations [#postgresql-operations]

Each operation is a method you call on the migration, `this.<name>({ ... })`, with one options object. Every method takes `schema`. For `createSchema` it is the schema to create. For every other method it is the PostgreSQL schema the table is in, which is `public` unless your contract sets another. Names are quoted for you: pass `user`, not `"user"`. Pass the table name, which is the model name exactly as written, such as `User`, unless the model sets `@@map`: a model with `@@map("user")` has the table `user`. Runs is the SQL for this page's example names.

### Schemas and tables [#schemas-and-tables]

| Method         | Options                                      | Runs                                 | Class       |
| -------------- | -------------------------------------------- | ------------------------------------ | ----------- |
| `createSchema` | `schema`                                     | `CREATE SCHEMA IF NOT EXISTS "app"`  | additive    |
| `createTable`  | `schema`, `table`, `columns`, `constraints?` | `CREATE TABLE "public"."post" (...)` | additive    |
| `dropTable`    | `schema`, `table`                            | `DROP TABLE "public"."post"`         | destructive |

`columns` is a list of [`col(...)`](#column-and-constraint-helpers) calls and `constraints` a list of `primaryKey(...)`, `unique(...)`, `foreignKey(...)`, and `checkExpression(...)` calls, all rendered inside the `CREATE TABLE` statement. That section shows a full `createTable` call and the SQL it produces.

### Columns [#columns]

| Method            | Options                                                      | Runs                                                                                 | Class       |
| ----------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ----------- |
| `addColumn`       | `schema`, `table`, `column`                                  | `ALTER TABLE "public"."user" ADD COLUMN "bio" text`                                  | additive    |
| `dropColumn`      | `schema`, `table`, `column`                                  | `ALTER TABLE "public"."user" DROP COLUMN "bio"`                                      | destructive |
| `alterColumnType` | `schema`, `table`, `column`, `options`                       | `ALTER TABLE "public"."post" ALTER COLUMN "views" TYPE bigint USING "views"::bigint` | destructive |
| `setNotNull`      | `schema`, `table`, `column`                                  | `ALTER TABLE "public"."post" ALTER COLUMN "views" SET NOT NULL`                      | destructive |
| `dropNotNull`     | `schema`, `table`, `column`                                  | `ALTER TABLE "public"."post" ALTER COLUMN "views" DROP NOT NULL`                     | widening    |
| `setDefault`      | `schema`, `table`, `column`, `defaultSql`, `operationClass?` | `ALTER TABLE "public"."user" ALTER COLUMN "name" SET DEFAULT 'anonymous'`            | additive    |
| `dropDefault`     | `schema`, `table`, `column`                                  | `ALTER TABLE "public"."user" ALTER COLUMN "name" DROP DEFAULT`                       | destructive |

`addColumn` takes a `col(...)` call as `column`. The other methods take the column's name as a string.

`alterColumnType` takes the new type in `options`, which has four fields:

| Field                   | What to put in it                                                                                                                                                                             |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qualifiedTargetType`   | The new type, as it appears in the `ALTER COLUMN ... TYPE` statement: `'bigint'`, `'varchar(255)'`.                                                                                           |
| `formatTypeExpected`    | The same type, spelled the way PostgreSQL itself names it. The postcheck compares the column's type after the change with this string, and the run stops if they differ. See the table below. |
| `rawTargetTypeForLabel` | The type as the CLI prints it in the operation's label. It affects nothing else, so use the same value as `qualifiedTargetType`.                                                              |
| `using`                 | Optional. The expression in the `USING` clause, for a conversion PostgreSQL cannot do on its own. Without it, the column is cast to the new type with `::`.                                   |

```ts
this.alterColumnType({
  schema: 'public',
  table: 'post',
  column: 'views',
  options: { qualifiedTargetType: 'bigint', formatTypeExpected: 'bigint', rawTargetTypeForLabel: 'bigint' },
}),
```

PostgreSQL spells most types the way you wrote them. These are the common ones it spells differently, as `\d post` in psql prints them:

| You write                  | `formatTypeExpected`                                      |
| -------------------------- | --------------------------------------------------------- |
| `varchar(255)`, `varchar`  | `character varying(255)`, `character varying`             |
| `char(3)`                  | `character(3)`                                            |
| `int4`, `int8`, `int2`     | `integer`, `bigint`, `smallint`                           |
| `float8`, `float4`         | `double precision`, `real`                                |
| `bool`                     | `boolean`                                                 |
| `timestamptz`, `timestamp` | `timestamp with time zone`, `timestamp without time zone` |
| `int[]`                    | `integer[]`                                               |

`text`, `integer`, `bigint`, `numeric(10,2)`, `jsonb`, `uuid`, `date`, `bytea`, and `citext` are spelled the same in both places.

`setDefault` runs `SET` followed by whatever you pass as `defaultSql`, so include the keyword: `defaultSql: "DEFAULT 'anonymous'"`, or `defaultSql: 'DEFAULT now()'`. When the column already has a default and you are replacing it, set `operationClass: 'widening'`, which only changes how the CLI reports the operation.

`setNotNull` has an extra precheck that fails while the column still holds a `NULL`, so backfill the column with a `dataTransform` first. [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration#worked-example-making-a-column-required) shows the three steps.

### Constraints [#constraints]

| Method                  | Options                                       | Runs                                                                                                                                           | Class       |
| ----------------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `addPrimaryKey`         | `schema`, `table`, `constraint`, `columns`    | `ALTER TABLE "public"."tag" ADD CONSTRAINT "tag_pkey" PRIMARY KEY ("id")`                                                                      | additive    |
| `addUnique`             | `schema`, `table`, `constraint`, `columns`    | `ALTER TABLE "public"."user" ADD CONSTRAINT "user_name_key" UNIQUE ("name")`                                                                   | additive    |
| `addForeignKey`         | `schema`, `table`, `foreignKey`               | `ALTER TABLE "public"."comment" ADD CONSTRAINT "comment_post_fkey" FOREIGN KEY ("postId") REFERENCES "public"."post" ("id") ON DELETE CASCADE` | additive    |
| `dropConstraint`        | `schema`, `table`, `constraint`, `kind?`      | `ALTER TABLE "public"."user" DROP CONSTRAINT "user_name_key"`                                                                                  | destructive |
| `addCheckConstraint`    | `schema`, `table`, `constraint`, `expression` | `ALTER TABLE "public"."post" ADD CONSTRAINT "post_title_len" CHECK (length("title") > 0)`                                                      | additive    |
| `renameCheckConstraint` | `schema`, `table`, `from`, `to`               | `ALTER TABLE "public"."post" RENAME CONSTRAINT "post_title_len" TO "post_title_nonempty"`                                                      | widening    |
| `dropCheckConstraint`   | `schema`, `table`, `constraint`               | `ALTER TABLE "public"."post" DROP CONSTRAINT "post_title_nonempty"`                                                                            | destructive |

In these calls, `constraint` is the name to give the constraint, or the name of the one to drop, and `columns` is the list of column names it covers:

```ts
this.addUnique({ schema: 'public', table: 'user', constraint: 'user_name_key', columns: ['name'] }),
```

`foreignKey` is an object: `name`, `columns` (on this table), `references` with its own `schema`, `table`, and `columns`, and optional `onDelete` and `onUpdate`, each one of `'noAction'`, `'restrict'`, `'cascade'`, `'setNull'`, or `'setDefault'`:

```ts
this.addForeignKey({
  schema: 'public',
  table: 'comment',
  foreignKey: {
    name: 'comment_post_fkey',
    columns: ['postId'],
    references: { schema: 'public', table: 'post', columns: ['id'] },
    onDelete: 'cascade',
  },
}),
```

`dropConstraint` removes a primary key, unique, or foreign key constraint by name. Pass its kind as `kind`, one of `'primaryKey'`, `'unique'`, or `'foreignKey'`. `kind` is recorded in `ops.json` for reporting only and does not change the SQL; it defaults to `'unique'`. A check constraint has its own `dropCheckConstraint`.

`addCheckConstraint` adds a check to a table that already exists; `checkExpression(...)`, listed under [helpers](#column-and-constraint-helpers), is the same thing inside a `createTable`. In both, `expression` is SQL and goes into the statement as you wrote it, so quote column names yourself: `'length("title") > 0'`.

There is no method that renames a table or a column. [Raw SQL](#raw-sql) shows a column rename; a table rename is the same shape around `ALTER TABLE ... RENAME TO`.

### Indexes [#indexes]

| Method        | Options                                                          | Runs                                                                    | Class       |
| ------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------- | ----------- |
| `createIndex` | `schema`, `table`, `index`, `columns` or `expression`, `extras?` | `CREATE INDEX "post_author_idx" ON "public"."post" ("authorId")`        | additive    |
| `renameIndex` | `schema`, `table`, `from`, `to`                                  | `ALTER INDEX "public"."post_author_idx" RENAME TO "post_author_id_idx"` | widening    |
| `dropIndex`   | `schema`, `table`, `index`                                       | `DROP INDEX "public"."post_author_id_idx"`                              | destructive |

`createIndex` takes either `columns`, a list of column names, or `expression`, one SQL string that becomes everything between the parentheses, such as `'lower("title")'`. Everything else goes in `extras`:

| Field     | What it is                                                                                          |
| --------- | --------------------------------------------------------------------------------------------------- |
| `unique`  | `true` for `CREATE UNIQUE INDEX`.                                                                   |
| `where`   | The partial-index condition, as SQL, without the `WHERE` keyword.                                   |
| `type`    | The index method: `'gin'` renders `USING "gin"`.                                                    |
| `options` | Index storage parameters as an object: `{ fastupdate: false }` renders `WITH ("fastupdate" = off)`. |

The call below runs `CREATE UNIQUE INDEX "post_title_lower_idx" ON "public"."post" (lower("title")) WHERE ("views" > 0)`:

```ts
this.createIndex({
  schema: 'public',
  table: 'post',
  index: 'post_title_lower_idx',
  expression: 'lower("title")',
  extras: { unique: true, where: '"views" > 0' },
}),
```

There is no `CONCURRENTLY` option, because one `npx prisma db migrate` run is [one transaction](https://www.prisma.io/docs/orm/migrations/applying-a-migration#when-something-goes-wrong), so the index is built inside it and blocks writes to the table until it is done.

### Native enum types [#native-enum-types]

| Method                 | Options                         | Runs                                                      | Class       |
| ---------------------- | ------------------------------- | --------------------------------------------------------- | ----------- |
| `createNativeEnumType` | `schema`, `typeName`, `members` | `CREATE TYPE "public"."role" AS ENUM ('admin', 'member')` | additive    |
| `addNativeEnumValue`   | `schema`, `typeName`, `value`   | `ALTER TYPE "public"."role" ADD VALUE 'guest'`            | additive    |
| `dropNativeEnumType`   | `schema`, `typeName`            | `DROP TYPE "public"."role"`                               | destructive |

`members` and `value` are the enum's values as strings, and `addNativeEnumValue` adds one value per call, so call it once for each value you add:

```ts
this.createNativeEnumType({ schema: 'public', typeName: 'role', members: ['admin', 'member'] }),
this.addNativeEnumValue({ schema: 'public', typeName: 'role', value: 'guest' }),
```

### Row-level security [#row-level-security]

| Method                    | Options                         | Runs                                                                                               | Class       |
| ------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------- | ----------- |
| `enableRowLevelSecurity`  | `schema`, `table`               | `ALTER TABLE "public"."post" ENABLE ROW LEVEL SECURITY`                                            | additive    |
| `disableRowLevelSecurity` | `schema`, `table`               | `ALTER TABLE "public"."post" DISABLE ROW LEVEL SECURITY`                                           | destructive |
| `createRlsPolicy`         | `schema`, `table`, `policy`     | `CREATE POLICY "post_read_all" ON "public"."post" AS PERMISSIVE FOR SELECT TO public USING (true)` | additive    |
| `renameRlsPolicy`         | `schema`, `table`, `from`, `to` | `ALTER POLICY "post_read_all" ON "public"."post" RENAME TO "post_read_any"`                        | widening    |
| `dropRlsPolicy`           | `schema`, `table`, `policy`     | `DROP POLICY "post_read_any" ON "public"."post"`                                                   | destructive |

`policy` describes the policy in full:

```ts
this.createRlsPolicy({
  schema: 'public',
  table: 'post',
  policy: {
    naming: { kind: 'exact', name: 'post_read_all' },
    tableName: 'post',
    namespaceId: 'public',
    operation: 'select',
    roles: ['public'],
    using: 'true',
    permissive: true,
  },
}),
```

`naming.name` is the policy's name, and `kind` is always `'exact'`. `tableName` and `namespaceId` take the same values as `table` and `schema`. `operation` is one of `'select'`, `'insert'`, `'update'`, `'delete'`, or `'all'`. `roles` becomes the `TO` clause. `using` and `withCheck` are SQL conditions and go in as written; `SELECT` and `DELETE` policies take only `using`, `INSERT` policies only `withCheck`. `permissive: false` makes the policy `AS RESTRICTIVE`. `dropRlsPolicy` takes the policy's name as `policy`.

### Extensions [#extensions]

| Call                    | Options                                        | Runs                                        | Class    |
| ----------------------- | ---------------------------------------------- | ------------------------------------------- | -------- |
| `createExtension(name)` | the extension's name                           | `CREATE EXTENSION IF NOT EXISTS "pgcrypto"` | additive |
| `this.installExtension` | `extensionName`, `invariantId`, `id`, `label?` | `CREATE EXTENSION IF NOT EXISTS citext`     | additive |

`createExtension` is a plain function, not a method, and is the one to use for an extension your migration needs, such as `pgcrypto` or `citext`. It goes in the `operations` list like any other call:

```ts
override get operations() {
  return [
    createExtension('pgcrypto'),
    this.addColumn({ schema: 'public', table: 'user', column: col('token', 'text') }),
  ];
}
```

It has no precheck or postcheck, so if a `db migrate` run stops partway and you run it again, this operation runs again, which is harmless because of `IF NOT EXISTS`.

`installExtension` is only for the first migration of an [extension package](https://www.prisma.io/docs/orm/extensions) that ships its own migrations, and there `extensionName`, `invariantId`, and `id` are all required. `id` names the operation in error messages, `label` is the text the CLI prints, and `invariantId` is a name other migrations in that package can refer to the install by. Only extension packages use `invariantId`; the optional `invariantId` on `dataTransform` and `rawSql` is for them too, so leave it out.

### Data [#data]

| Call                                          | Arguments                                                                                                                        | Class |
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----- |
| `this.dataTransform(contract, name, options)` | `endContract`, the contract object built below; a name for the operation; and `options` with `run`, `check?`, and `invariantId?` | data  |

`run` is a callback that returns an update built with the [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder), or a list of such callbacks that run in order. `check` is a callback that returns a query for the rows still needing the change. You write that one query; the precheck passes while it finds rows, and the postcheck passes once it finds none.

Both callbacks build their queries with `db`, a query builder, and `db` needs a contract object built from the end snapshot's JSON. `migration plan` does not write those lines; you add them whenever a migration has a `dataTransform`. Pass the same contract object as the `contract` argument (not `this.endContract`, which is only a view for looking names up). The planned file already uses the name `endContract` for the JSON import, so first rename the import to free the name:

```ts
import endContract from '../../snapshots/<end hash>/contract.json' with { type: 'json' }; // [!code --]
import endContractJson from '../../snapshots/<end hash>/contract.json' with { type: 'json' }; // [!code ++]
```

```ts
  override readonly endContractJson = endContract; // [!code --]
  override readonly endContractJson = endContractJson; // [!code ++]
```

Then add these lines above the class, copied as they are; they build `db` and never connect to a database:

```ts
import postgresAdapter from '@prisma/orm-postgres/adapter/runtime';
import { sql } from '@prisma/orm-postgres/builder/runtime';
import { createExecutionContext, createSqlExecutionStack } from '@prisma/orm-postgres/family-runtime';
import postgresTarget, { PostgresContractSerializer } from '@prisma/orm-postgres/target/runtime';

const endContract = new PostgresContractSerializer().deserializeContract<End>(endContractJson);
const stack = createSqlExecutionStack({ target: postgresTarget, adapter: postgresAdapter });

const db = sql<End>({
  context: createExecutionContext({ contract: endContract, stack }),
  rawCodecInferer: stack.adapter.rawCodecInferer,
});
```

Then the operation itself, from the worked example on Editing a migration. Inside each `where`, `f` holds the table's columns and `fns` the comparison functions:

```ts
this.dataTransform(endContract, 'backfill-user-displayName', {
  check: () =>
    db.public.user
      .select('id')
      .where((f, fns) => fns.eq(f.displayName, null))
      .limit(1),
  run: () =>
    db.public.user
      .update({ displayName: 'Anonymous' })
      .where((f, fns) => fns.eq(f.displayName, null)),
}),
```

`migration plan` writes a `dataTransform` with `placeholder('<name>:check')` and `placeholder('<name>:run')` in the two positions wherever a change needs your decision about existing rows; you replace each `placeholder(...)` call with a query. [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) shows the whole file, and what to do when the backfill reads a column the migration removes.

### Raw SQL [#raw-sql]

| Call                | Argument                              | Class                        |
| ------------------- | ------------------------------------- | ---------------------------- |
| `rawSql(operation)` | an operation object you write in full | the `operationClass` you set |

Use `rawSql` for a statement that has no method on this page, such as a rename or `COMMENT ON`. `db migrate` checks the database against the end contract after applying a migration, so a raw change has to match a change in your contract: to rename a column, rename the field in `contract.prisma`, run `migration plan`, and replace the `dropColumn` and `addColumn` it writes with one `rawSql`. Pass it an object with these fields:

| Field                              | What it is                                                                                                                                                   |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                               | A name for the operation, used in error messages. Any string; keep it unique within the migration. The planner's own look like `index.post.post_author_idx`. |
| `label`                            | The text the CLI prints while applying it.                                                                                                                   |
| `operationClass`                   | One of the [four classes](#operation-classes-and-checks).                                                                                                    |
| `target`                           | Always `{ id: 'postgres' }`.                                                                                                                                 |
| `precheck`, `execute`, `postcheck` | Lists of steps, each `{ description, sql, params? }`. `execute` holds the statements; the other two hold the checks, described below.                        |
| `summary?`                         | A longer description, optional.                                                                                                                              |
| `invariantId?`                     | Optional; leave it out.                                                                                                                                      |

```ts
rawSql({
  id: 'rename.user.bio',
  label: 'Rename column "bio" to "biography" on "user"',
  operationClass: 'widening',
  target: { id: 'postgres' },
  precheck: [
    {
      description: 'column "bio" exists',
      sql: `SELECT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'user' AND column_name = 'bio')`,
    },
  ],
  execute: [{ description: 'rename', sql: `ALTER TABLE "public"."user" RENAME COLUMN "bio" TO "biography"` }],
  postcheck: [
    {
      description: 'column "biography" exists',
      sql: `SELECT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'user' AND column_name = 'biography')`,
    },
  ],
}),
```

#### Writing the checks [#writing-the-checks]

A step's `sql` can use `$1`, `$2`, and so on, with the values in `params`. A check passes when its query returns `true` in the first column of its first row. It fails when the query returns `false` or no rows.

Write the precheck so that `true` means "go ahead", as in "column `bio` exists" above. Write the postcheck so that `true` means "the change is there", as in "column `biography` exists". Remember the [order](#operation-classes-and-checks): the postcheck runs first, and if it already passes the operation is skipped. An empty `precheck` always lets the statements run. An empty `postcheck` never passes beforehand, so the operation runs on every `db migrate` that reaches it, including a second run after a failure.

## Column and constraint helpers [#column-and-constraint-helpers]

These are plain functions from the same module. `createTable` and `addColumn` take what they return.

| Helper                                                                       | Returns                                                                                                                                                                                                                                                                                                                                             |
| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `col(name, type, options?)`                                                  | A column. `type` is the PostgreSQL type as SQL, such as `'text'`, `'integer'`, `'timestamptz'`, or `'varchar(255)'`. `options` holds `notNull`, `primaryKey` (renders `PRIMARY KEY` on the column; for a single-column key it does the same as the `primaryKey(...)` constraint, which is what `migration plan` writes), `default`, and `codecRef`. |
| `lit(value)`                                                                 | A literal default for `col`: `default: lit(0)` renders `DEFAULT 0`.                                                                                                                                                                                                                                                                                 |
| `fn(expression)`                                                             | A function default for `col`: `default: fn('now()')` renders `DEFAULT (now())`.                                                                                                                                                                                                                                                                     |
| `primaryKey(columns, { name? })`                                             | A `PRIMARY KEY` table constraint.                                                                                                                                                                                                                                                                                                                   |
| `unique(columns, { name? })`                                                 | A `UNIQUE` table constraint.                                                                                                                                                                                                                                                                                                                        |
| `foreignKey(columns, refTable, refColumns, { name?, onDelete?, onUpdate? })` | A `FOREIGN KEY` table constraint, with positional arguments; the `foreignKey` option of `this.addForeignKey` is a different shape, an object. `refTable` is a table in the same schema. To reference a table in another schema, use `this.addForeignKey` after the table exists.                                                                    |
| `checkExpression(name, expression)`                                          | A `CHECK` table constraint. `expression` is SQL, written as it should appear.                                                                                                                                                                                                                                                                       |
| `placeholder(name)`                                                          | What `migration plan` leaves where you have to write a query. Running a migration that still contains one fails with an error whose `code` is `MIGRATION.UNFILLED_PLACEHOLDER`.                                                                                                                                                                     |

`migration plan` writes `codecRef` on every column it plans, such as `{ codecId: 'pg/text@1' }`, which names how the column's values are read and written. Leave it as written. There is no published list of these ids, so leave `codecRef` out of a column you write by hand: the column is created the same way, and both `npx prisma migration check`, which verifies the migration files, and `db migrate` accept it.

```ts
this.createTable({
  schema: 'public',
  table: 'post',
  columns: [
    col('id', 'integer', { notNull: true }),
    col('title', 'text', { notNull: true }),
    col('authorId', 'integer', { notNull: true }),
    col('views', 'integer', { notNull: true, default: lit(0) }),
    col('createdAt', 'timestamptz', { notNull: true, default: fn('now()') }),
    col('meta', 'jsonb'),
  ],
  constraints: [
    primaryKey(['id']),
    unique(['title'], { name: 'post_title_key' }),
    foreignKey(['authorId'], 'user', ['id'], { name: 'post_author_fkey', onDelete: 'cascade' }),
    checkExpression('post_views_min', '"views" >= 0'),
  ],
}),
```

```sql
CREATE TABLE "public"."post" (
  "id" integer NOT NULL,
  "title" text NOT NULL,
  "authorId" integer NOT NULL,
  "views" integer DEFAULT 0 NOT NULL,
  "createdAt" timestamptz DEFAULT (now()) NOT NULL,
  "meta" jsonb,
  PRIMARY KEY ("id"),
  CONSTRAINT "post_title_key" UNIQUE ("title"),
  CONSTRAINT "post_author_fkey" FOREIGN KEY ("authorId") REFERENCES "user" ("id") ON DELETE CASCADE,
  CONSTRAINT "post_views_min" CHECK ("views" >= 0)
)
```

## MongoDB operations [#mongodb-operations]

A MongoDB `migration.ts` has the same shape, and everything comes from one module:

```ts
import { Migration, MigrationCLI, placeholder, createCollection, dropCollection, createIndex, dropIndex, setValidation, collMod, validatedCollection, dataTransform } from '@prisma/orm-mongo/target/migration';
```

The operations are plain functions rather than methods, so `operations` returns calls such as `createCollection('products')`, not `this.createCollection(...)`. `this.endContract.collection.products` is the `products` collection in the end contract, with its `validator`.

A data transform's `run` callback returns a query object with three fields: the `collection`, a `command` such as `RawUpdateManyCommand`, and `meta`, which carries `storageHash`, the hash of the end contract. The check's `source` returns the same kind of object with an `AggregateCommand`. These two helpers are from the [retail-store example](https://github.com/prisma/orm/blob/main/examples/retail-store/migrations/app/20260513T0508_backfill_product_status/migration.ts); the first finds documents with no `status` and limits to one, and the second sets it, where `RawUpdateManyCommand` takes the collection name, a filter, and an update:

```ts
import {
  AggregateCommand,
  MongoExistsExpr,
  MongoLimitStage,
  MongoMatchStage,
  type MongoQueryPlan,
  RawUpdateManyCommand,
} from '@prisma/orm-mongo/query-ast/execution';

function existingProductsWithoutStatus(storageHash: string): MongoQueryPlan {
  return {
    collection: 'products',
    command: new AggregateCommand('products', [
      new MongoMatchStage(new MongoExistsExpr('status', false)),
      new MongoLimitStage(1),
    ]),
    meta: { target: 'mongo', storageHash, lane: 'mongo-pipeline' },
  };
}

function backfillRun(storageHash: string): MongoQueryPlan {
  return {
    collection: 'products',
    command: new RawUpdateManyCommand(
      'products',
      { status: { $exists: false } },
      { $set: { status: 'active' } },
    ),
    meta: { target: 'mongo', storageHash, lane: 'mongo-raw' },
  };
}
```

The migration's `operations` then uses both, alongside `setValidation` from `@prisma/orm-mongo/target/migration`:

```ts
override get operations() {
  const storageHash = this.endContract.storage.storageHash;
  const productsValidator = this.endContract.collection.products.validator;
  return [
    setValidation('products', productsValidator.jsonSchema, {
      validationLevel: productsValidator.validationLevel,
      validationAction: productsValidator.validationAction,
    }),
    dataTransform('backfill-product-status', {
      check: { source: () => existingProductsWithoutStatus(storageHash) },
      run: () => backfillRun(storageHash),
    }),
  ];
}
```

| Function                                      | Arguments                                                                                                                                                                                                               | Class                                                               |
| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `createCollection(name, options?)`            | `options`: `validator`, `validationLevel`, `validationAction`, `capped`, `size`, `max`, `timeseries`, `collation`, `changeStreamPreAndPostImages`, `clusteredIndex`                                                     | additive                                                            |
| `dropCollection(name)`                        |                                                                                                                                                                                                                         | destructive                                                         |
| `createIndex(collection, keys, options?)`     | `keys`: a list of `{ field, direction }`; `options`: `unique`, `sparse`, `name`, `expireAfterSeconds`, `partialFilterExpression`, `collation`, `weights`, `default_language`, `language_override`, `wildcardProjection` | additive                                                            |
| `dropIndex(collection, keys)`                 | the same `keys` the index was created with                                                                                                                                                                              | destructive                                                         |
| `setValidation(collection, schema, options?)` | `schema`: a JSON Schema object; `options`: `validationLevel` (`'strict'` or `'moderate'`) and `validationAction` (`'error'` or `'warn'`)                                                                                | destructive                                                         |
| `collMod(collection, options, meta?)`         | `options`: `validator`, `validationLevel`, `validationAction`, `changeStreamPreAndPostImages: { enabled }`; `meta`: `id`, `label`, `operationClass`                                                                     | destructive, unless you pass `meta: { operationClass: 'additive' }` |
| `validatedCollection(name, schema, indexes)`  | creates the collection with `schema` as its validator and one index per `{ keys, unique? }` entry, with `keys` as in `createIndex`. Returns a list of operations, so spread it: `...validatedCollection(...)`           | additive                                                            |
| `dataTransform(name, options)`                | `options`: `run`, `check?`, `invariantId?`                                                                                                                                                                              | data                                                                |

`direction` is `1`, `-1`, `'text'`, `'2dsphere'`, `'2d'`, or `'hashed'`.

`dataTransform` on MongoDB takes no contract argument, and its `check` is an object whose `source` is a callback returning a query for the documents that still need the change. Its other two fields, `filter` and `expect`, are optional and you can leave them out. [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration#the-same-pattern-on-mongodb) shows a filled-in example.

## See also [#see-also]

* [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration): filling in a planned migration, backfills, and raw SQL
* [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work): what `ops.json` holds and how each operation checks itself
* [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) and [`migration new`](https://www.prisma.io/docs/cli/migration-new): the commands that write `migration.ts`

## Related pages

- [`Error reference`](https://www.prisma.io/docs/orm/reference/error-reference): Every structured error code Prisma ORM can emit, by namespace, with the condition that raises it.
- [`ORM client reference`](https://www.prisma.io/docs/orm/reference/orm-client): Reference for the Prisma ORM client's query, mutation, filter, and aggregate methods.
- [`Pipeline builder reference`](https://www.prisma.io/docs/orm/reference/pipeline-builder): Reference for the Prisma ORM MongoDB pipeline builder's stages, accumulators, expression helpers, and write methods.
- [`Raw queries reference`](https://www.prisma.io/docs/orm/reference/raw-queries): Reference for Prisma ORM raw queries: PostgreSQL raw SQL and MongoDB raw commands.
- [`SQL query builder reference`](https://www.prisma.io/docs/orm/reference/sql-query-builder): Reference for the Prisma ORM SQL query builder's select, mutation, and grouped query methods.

# ORM client reference (/docs/orm/reference/orm-client)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Reference for the Prisma ORM client's query, mutation, filter, and aggregate methods.

Location: ORM > Reference > ORM client reference

The ORM client gives you model-level methods for reading and writing data across PostgreSQL and MongoDB. This page documents every method, its availability on each database, and the behavior that differs between the two. Each method's Remarks say which databases it works on, how it behaves differently on one of them, and where TypeScript rejects something the database itself would accept.

This page assumes your tables already exist. [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) has the packages to install and the `prisma orm init` command. It also covers `prisma db update`, which replaces `prisma migrate dev`, and `prisma contract emit`, which replaces `prisma generate`. [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work) shows how the tables get created. For task-oriented walkthroughs, see the Fundamentals guides: [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data), [Writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data), [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins), and [Transactions](https://www.prisma.io/docs/orm/fundamentals/transactions).

## Example schema [#example-schema]

All examples on this page run against the schema below, except the grouped-aggregate ones, which use a separate `Customer` / `Order` schema shown under [Grouped aggregates](#grouped-aggregates). `contract.prisma` replaces `schema.prisma`, and this page calls it the contract. Running `npx prisma contract emit` compiles it into two generated files: `contract.json`, read at run time, and `contract.d.ts`, read by TypeScript. You import both, as the examples below do. Run `npx prisma contract emit` again after every change to `contract.prisma`. A new project keeps all three files in `src/prisma/`.

**Expand for the example schema**

#### PostgreSQL

```prisma
types {
  Embedding1536 = pgvector.Vector(1536)
}

type Address {
  street  String
  city    String
  zip     String?
  country String
}

enum user_type {
  @@type("pg/text@1")
  admin
  user
}

enum Priority {
  @@type("pg/text@1")
  Low    = "low"
  High   = "high"
  Urgent = "urgent"
}

model User {
  id          Uuid      @id @default(uuid())
  email       String
  displayName String
  createdAt   DateTime  @default(now())
  kind        user_type
  address     Address?
  posts       Post[]
  tasks       Task[]

  @@map("user")
}

model Post {
  id        Uuid           @id @default(uuid())
  title     String
  userId    Uuid
  priority  Priority       @default(Low)
  createdAt DateTime       @default(now())
  embedding Embedding1536?

  user User  @relation(fields: [userId], references: [id])
  tags Tag[]

  @@map("post")
}

model Tag {
  id    Uuid   @id @default(uuid())
  label String @unique

  posts Post[]

  @@map("tag")
}

model PostTag {
  postId Uuid
  tagId  Uuid

  post Post @relation(fields: [postId], references: [id])
  tag  Tag  @relation(fields: [tagId], references: [id])

  @@id([postId, tagId])
  @@map("post_tag")
}

model Task {
  id          Uuid     @id @default(uuid())
  title       String
  description String?
  status      String   @default("open")
  type        String
  userId      Uuid
  createdAt   DateTime @default(now())

  user User @relation(fields: [userId], references: [id])

  @@discriminator(type)
  @@map("task")
}

model Bug {
  severity     String
  stepsToRepro String?
  @@base(Task, "bug")
  @@map("bug")
}

model Feature {
  priority      String
  targetRelease String?
  @@base(Task, "feature")
  @@map("feature")
}
```

#### MongoDB

```prisma
enum UserRole {
  @@type("mongo/string@1")
  Admin  = "admin"
  Author = "author"
  Reader = "reader"
}

type Address {
  street  String
  city    String
  zip     String?
  country String
}

model User {
  id      ObjectId @id @map("_id")
  name    String
  email   String
  bio     String?
  role    UserRole
  address Address?
  posts   Post[]
  @@map("users")
}

model Post {
  id        ObjectId @id @map("_id")
  title     String
  content   String
  kind      String
  authorId  ObjectId
  createdAt Date
  author    User @relation(fields: [authorId], references: [id])
  @@discriminator(kind)
  @@index([authorId])
  @@index([createdAt(sort: Desc), authorId])
  @@map("posts")
}

model Article {
  summary   String
  @@base(Post, "article")
  @@unique([summary])
}

model Tutorial {
  difficulty String
  duration   Int32
  @@base(Post, "tutorial")
}
```

Some parts of the schema the examples rely on:

* The `types` block at the top gives a name to a type from an extension package, so your models can use that name. `Embedding1536` comes from the pgvector extension, and `pgvector.` is that package's prefix. See [PostgreSQL](#postgresql) for the extra line it needs when you create the client.

* `@@map("user")` sets the table or collection name. Without it, the table name is the model name exactly as written, `User`.

* On MongoDB, `id ObjectId @id @map("_id")` renames the field to `_id` everywhere: you filter on `_id`, and the returned document has an `_id` key. That is why the MongoDB examples never say `id`.

* `Uuid` is a built-in type for a PostgreSQL `uuid` column. You do not import it. `@default(uuid())` fills the id in when you insert a row.

* `@@type("pg/text@1")` on an `enum` block stores the enum as a text column. The `@1` is the version of that storage format, and only version 1 exists today, so write it exactly like that. The MongoDB form of the same attribute is `@@type("mongo/string@1")`. This page calls an enum written this way a text-backed enum.

* A `native_enum` block stores the members as a PostgreSQL enum type, created with `CREATE TYPE`. Prisma ORM 7 stored every `enum` this way, so a database that Prisma ORM 7 created already has these types, and you keep them by declaring each one with `native_enum`, as [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) shows. A plain `enum` block in Prisma ORM 8 is stored as text. Give every `native_enum` member a value, because a member with no value is rejected. A field that uses it is typed `pg.enum(Priority)`. This page calls an enum written this way a native enum. The two sort differently; see [`orderBy()`](#orderby).

  ```prisma
  native_enum Priority {
    Low    = "low"
    High   = "high"
    Urgent = "urgent"
  }

  model Post {
    id       Uuid              @id @default(uuid())
    priority pg.enum(Priority)
  }
  ```

* An enum member's stored value is the string after `=`, or the member name when there is no `=`. That string is what you pass to `.eq()`. So `Urgent = "urgent"` is matched by `.eq('urgent')`, and a bare `admin` member is matched by `.eq('admin')`.

* A variant is a model that reuses another model's fields and rows. `@@base(Task, "bug")` makes `Bug` a variant of `Task`. Its second argument, `"bug"`, is the value stored in the discriminator column for a `Bug` row. `@@discriminator(type)` names that column. `db.orm.public.Task.variant('Bug')` returns only the `Bug` rows. Pass the model name, `'Bug'`, not the string in `@@base`.

* `PostTag` is required. To join `Post.tags Tag[]` and `Tag.posts Post[]`, write a third model with one foreign key to each side and an `@@id` of exactly those two columns. Prisma ORM finds it for you, and neither `Post` nor `Tag` names it. A pair of list fields with no such model is rejected. See [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins#many-to-many).

* On PostgreSQL, a `DateTime` field comes back as a `Temporal.Instant`, the standard JavaScript object for a point in time. A filter on that field takes the same type, so you can pass a value straight back in.

## Setting up the client [#setting-up-the-client]

Create a client with `postgres(...)` or `mongo(...)`, then read and write your models through `db.orm`. The same `db` also has a query builder, `db.sql` on PostgreSQL and `db.query` on MongoDB, plus `db.raw` for raw queries. This page covers none of those three: see [Advanced queries](https://www.prisma.io/docs/orm/fundamentals/advanced-queries). Create `db` once per process, and close it with `await db.close()` when the process shuts down. The two databases have different entry points, and they name the models differently.

### PostgreSQL [#postgresql]

Create a PostgreSQL client with `postgres(...)`. `db.orm` holds your models by model name, grouped by database schema: `db.orm.public.User`, `db.orm.public.Post`. `public` is the PostgreSQL schema your tables are in unless you put them in another one. Import types from `./contract.d`, which resolves to `contract.d.ts`.

```typescript
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

const db = postgres<Contract>({ contractJson, url: process.env.DATABASE_URL });

const users = await db.orm.public.User.all();
```

If your contract uses a type from an extension package, pass that package to `extensions` when you create the client. The example schema's `Embedding1536` type comes from pgvector, so it needs this:

```typescript
import pgvector from '@prisma/orm-extension-pgvector/runtime';

const db = postgres<Contract>({
  contractJson,
  url: process.env.DATABASE_URL,
  extensions: [pgvector],
});
```

To give a model your own methods on top of the built-in ones, import `Collection` from `@prisma/orm-postgres/orm-client`, subclass it, and register the subclass with `orm(...)` from that same package. You still create the client with `postgres(...)`. `orm(...)` takes two things from it: the `runtime` argument, which is what `await client.connect()` gives you, and the `context` argument, which is `client.context`. The code is under [Custom `Collection` subclass](#custom-collection-subclass).

### MongoDB [#mongodb]

Create a MongoDB client with `mongo(...)`. `db.orm` holds your models by collection name, with no schema in between. The collection name is the one you set with `@@map`, or the model name exactly as written when you did not set one. The example schema maps `User` to `users`, so it is `db.orm.users`, and `Post` is `db.orm.posts`. `dbName` is the MongoDB database name.

```typescript
import mongo from '@prisma/orm-mongo/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

const db = mongo<Contract>({ contractJson, url: process.env.MONGODB_URL, dbName: 'app' });

const users = await db.orm.users.all();
```

## Query-building methods [#query-building-methods]

These methods narrow a query, and each returns a collection. On this page, a collection is the query object you chain more methods on, such as `db.orm.public.User` or `db.orm.public.User.where(...)`. When this page says "a MongoDB collection", it means that query object. MongoDB itself calls its store of documents a collection too, and the name is the same one. You run the query with a [read method](#read-terminals) such as `all()` or `first()`. MongoDB supports fewer of these methods than PostgreSQL, and each method's Remarks say which databases it works on.

Some examples import a filter helper you can use on its own. On PostgreSQL those come from `@prisma/orm-postgres/orm-client`, on MongoDB from `@prisma/orm-mongo/query-ast/execution`. See [Filter conditions and operators](#filter-conditions-and-operators).

The examples below use these ids, which stand for rows inserted before the query runs:

```typescript
const aliceId = '00000000-0000-4000-8000-000000000001';
const carolId = '00000000-0000-4000-8000-000000000003';
const postId = '00000000-0000-4000-8000-000000000010';
const acmeId = '00000000-0000-4000-8000-000000000020';
```

### `where()` [#where]

Restrict a query to rows matching a filter.

#### Remarks [#remarks]

* Available for PostgreSQL and MongoDB, but the accepted filter shapes differ.
* On PostgreSQL, `where()` takes either a callback that calls an operator on a column (`u.email.eq(...)`) or an object of field-and-value pairs that must match exactly.
* On MongoDB, `where()` takes either an object of field-and-value pairs that must match exactly or a `MongoFieldFilter`. The object form can only test for equality. For anything else, such as greater-than, use `MongoFieldFilter` (see [MongoFieldFilter](#mongofieldfilter)).
* Calling `where()` more than once on the same query requires a row to match all of the filters.
* `.eq()` is one operator of many. [Filter conditions and operators](#filter-conditions-and-operators), further down this page, lists them all for both databases.

#### Options [#options]

| Argument | Type                                                                                                 | Required | Description                      |
| -------- | ---------------------------------------------------------------------------------------------------- | -------- | -------------------------------- |
| `filter` | A callback that calls an operator on a column, a shorthand object, or (MongoDB) a `MongoFieldFilter` | Yes      | The condition rows must satisfy. |

#### Return type [#return-type]

| Return type  | Example                         | Description                                                                                             |
| ------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `Collection` | `db.orm.public.User.where(...)` | A collection narrowed by the filter. Chain more methods on it, then run it with a read or write method. |

#### Examples [#examples]

##### Callback form with a column operator (PostgreSQL) [#callback-form-with-a-column-operator-postgresql]

```typescript
const admins = await db.orm.public.User.where((u) => u.kind.eq('admin')).all();
```

##### Shorthand object form [#shorthand-object-form]

  

#### PostgreSQL

```typescript
const bob = await db.orm.public.User.where({ email: 'bob@example.com' }).first();
```

#### MongoDB

```typescript
const authors = await db.orm.users.where({ role: 'author' }).all();
```

##### Chaining `where()` calls (ANDed) [#chaining-where-calls-anded]

```typescript
const carolUrgentPosts = await db.orm.public.Post.where({ userId: carolId })
  .where((p) => p.priority.eq('urgent'))
  .all();
```

##### `MongoFieldFilter` expression (MongoDB) [#mongofieldfilter-expression-mongodb]

```typescript
import { MongoFieldFilter } from '@prisma/orm-mongo/query-ast/execution';

const alice = await db.orm.users.where(MongoFieldFilter.eq('email', 'alice@example.com')).first();

const recentPosts = await db.orm.posts
  .where(MongoFieldFilter.gte('createdAt', new Date('2024-01-02T00:00:00.000Z')))
  .all();
```

For a task-oriented guide to filtering, see [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data#filter-records).

### `select()` [#select]

Return only the scalar fields you name.

#### Remarks [#remarks-1]

* Available for PostgreSQL and MongoDB.
* On PostgreSQL, `select()` narrows the returned row shape at the type level: fields you didn't select are absent from the result type.
* On MongoDB, `select()` changes what the database returns but not the TypeScript type. Only the fields you named come back. The type still lists every field on the model. Read a field you did not name and you get `undefined`, because the returned document does not carry it.

#### Options [#options-1]

| Argument    | Type                   | Required | Description                             |
| ----------- | ---------------------- | -------- | --------------------------------------- |
| `...fields` | Field names (`string`) | Yes      | One or more scalar field names to keep. |

#### Return type [#return-type-1]

| Return type  | Example                                    | Description                                 |
| ------------ | ------------------------------------------ | ------------------------------------------- |
| `Collection` | `db.orm.public.User.select('id', 'email')` | A collection projected to the named fields. |

#### Examples [#examples-1]

##### Project to a subset of fields [#project-to-a-subset-of-fields]

  

#### PostgreSQL

```typescript
const summaries = await db.orm.public.User.select('id', 'email').orderBy((u) => u.email.asc()).all();
// summaries[0] is { id, email }, with no displayName
```

#### MongoDB

```typescript
const summaries = await db.orm.users.select('name', 'email').all();
```

### `include()` [#include]

Eagerly load a relation onto the returned rows.

#### Remarks [#remarks-2]

* Available for PostgreSQL and MongoDB, with differences noted below.
* On PostgreSQL, `include(relationName, refineFn?)` loads both to-one and to-many relations. The optional callback receives the related rows as a collection, so you can filter, order, limit, and aggregate them. See [Refinements, aggregates, and combine](#refinements-aggregates-and-combine).
* On MongoDB, wrap the `_id` of a related document loaded by `include()` in `String(...)` before you compare it. It comes back as an `ObjectId` object, while a document's own `_id` comes back as a hex string.
* On MongoDB, `include()` loads a relation that is stored as a reference. It takes the relation name and nothing else, and TypeScript rejects a second argument.

#### Options [#options-2]

| Argument       | Type                                                                | Required | Description                                                               |
| -------------- | ------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------- |
| `relationName` | `string`                                                            | Yes      | The relation to load.                                                     |
| `refineFn`     | A callback that returns the narrowed relation or an aggregate of it | No       | PostgreSQL only. Narrows the loaded relation, or reduces it to one value. |

#### Return type [#return-type-2]

| Return type  | Example                               | Description                                        |
| ------------ | ------------------------------------- | -------------------------------------------------- |
| `Collection` | `db.orm.public.User.include('posts')` | A collection whose rows carry the loaded relation. |

#### Examples [#examples-2]

##### To-one relation (PostgreSQL) [#to-one-relation-postgresql]

```typescript
const posts = await db.orm.public.Post.include('user').where({ id: postId }).all();
// posts[0].user is the related User
```

##### To-many relation (PostgreSQL) [#to-many-relation-postgresql]

```typescript
const users = await db.orm.public.User.include('posts').where({ id: aliceId }).all();
// users[0].posts is an array of the user's posts
```

##### Reference relation (MongoDB) [#reference-relation-mongodb]

```typescript
const posts = await db.orm.posts.include('author').where({ title: 'Hello world' }).all();
// posts[0].author._id is an ObjectId; compare it as String(posts[0].author._id)
```

For a task-oriented guide to loading related records, see [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins).

### Refinements, aggregates, and combine [#refinements-aggregates-and-combine]

On PostgreSQL, the callback you pass to `include()` receives the related rows as a collection. This page calls that callback a refinement, which is the word in the heading above. You can filter, order, and paginate the related rows in it, and you can also reduce them to a single value, or use `combine()` to return several results at once. To count or sum a whole model instead of a relation, see [Grouped aggregates](#grouped-aggregates), where `aggregate((agg) => ({ n: agg.count() }))` counts every row.

#### Remarks [#remarks-3]

* PostgreSQL only. On MongoDB, `include()` takes no callback, and `count`, `sum`, `avg`, `min`, `max`, and `combine` do not exist on a collection.
* On PostgreSQL, those six are only callable **inside** an `include()` callback. Called anywhere else, they throw an error whose `code` is `ORM.INCLUDE_INVALID`.
* `sum()` and `avg()` take a numeric column: an integer, a floating-point number, or a decimal. They also take an interval or a `Time` column, the time-of-day type. They do not take a date or a timestamp, and TypeScript rejects a date or timestamp field name here.
* `min()` and `max()` take more: numeric and text columns, dates, times, timestamps, intervals, IP addresses, and text arrays. They do not take a boolean, a `uuid`, binary data, a bit string, or JSON.
* `count()` returns a `number`. With no argument it counts rows; with a field name it counts rows where that field is not null. `countBigInt()` returns a `bigint` instead, for a count too large for a JavaScript `number`.
* `sum()` over an integer column returns a `number`. A total too large for a `number` throws an error whose `code` is `RUNTIME.DECODE_FAILED`. Use `sumBigInt(field)` for totals that large. It returns a `bigint`.
* `avg()` over an integer column returns a JavaScript floating-point `number`. `avgDecimal(field)` returns the exact average as a decimal string. Pass that string to a decimal library, or call `Number(...)` on it when a floating-point value is fine.
* When a to-many relation has no rows, `sum()`, `avg()`, `min()`, and `max()` come back as `null`, not `0`.
* `combine(shape)` takes an object. You choose the keys. Call `posts.combine({ ... })`, and inside the object write `posts` again for each value. The `posts` inside the object is the same collection the callback received, with nothing chained on it yet. A value that chains more methods on `posts` comes back as an array of rows. A value that is an aggregate, such as `posts.count()`, comes back as that single value.

#### Options [#options-3]

| Argument                                         | Type                                       | Required | Description                                                                      |
| ------------------------------------------------ | ------------------------------------------ | -------- | -------------------------------------------------------------------------------- |
| `where()` / `orderBy()` / `limit()` / `offset()` | Chained on the nested collection           | No       | Refine which related rows load.                                                  |
| `count()`                                        | Aggregate, no arguments                    | No       | Reduces the relation to a row count.                                             |
| `sum(field)` / `avg(field)`                      | Aggregate over a numeric field             | No       | Reduces the relation to one number.                                              |
| `min(field)` / `max(field)`                      | Aggregate over a sortable field            | No       | Reduces the relation to its smallest or largest value, in the column's own type. |
| `combine(shape)`                                 | Object of named collections and aggregates | No       | Returns several results under one relation key.                                  |

#### Return type [#return-type-3]

| Return type                                                 | Example                              | Description                                                                           |
| ----------------------------------------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------- |
| The narrowed relation, a single value, or an object of both | `include('posts', (p) => p.count())` | The relation key on each row holds the callback's result instead of the related rows. |

#### Examples [#examples-3]

##### Filter, order, and limit within a relation (PostgreSQL) [#filter-order-and-limit-within-a-relation-postgresql]

```typescript
const users = await db.orm.public.User.include('posts', (posts) =>
  posts
    .where((p) => p.priority.eq('low'))
    .orderBy((p) => p.createdAt.desc())
    .limit(1),
)
  .where({ id: aliceId })
  .all();
```

##### Reduce a relation to a count (PostgreSQL) [#reduce-a-relation-to-a-count-postgresql]

```typescript
const users = await db.orm.public.User.include('posts', (posts) => posts.count())
  .where({ id: aliceId })
  .all();
// users[0].posts is the number 2
```

##### `sum()` / `avg()` over a numeric relation (PostgreSQL) [#sum--avg-over-a-numeric-relation-postgresql]

This example uses the `Customer` and `Order` models, which are in the separate schema shown under [Grouped aggregates](#grouped-aggregates).

```typescript
const customers = await db.orm.public.Customer.include('orders', (orders) => orders.sum('amount'))
  .where({ id: acmeId })
  .all();
// customers[0].orders is 1500

const avgCustomers = await db.orm.public.Customer.include('orders', (orders) => orders.avg('amount'))
  .where({ id: acmeId })
  .all();
// avgCustomers[0].orders is 300
```

##### `combine()` multiple sub-views (PostgreSQL) [#combine-multiple-sub-views-postgresql]

```typescript
const users = await db.orm.public.User.include('posts', (posts) =>
  posts.combine({
    recent: posts.orderBy((p) => p.createdAt.desc()).limit(1),
    total: posts.count(),
  }),
)
  .where({ id: aliceId })
  .all();
// users[0].posts.total is 2; users[0].posts.recent is a one-element array
```

> [!NOTE]
> `min()`
> 
>  and
> 
> `max()`
> 
>  over a date column
> 
> `min('createdAt')` over a `DateTime` column compiles and returns a `Temporal.Instant`, the standard JavaScript object for a point in time. Not every JavaScript engine has `Temporal` yet. Check with `typeof Temporal === 'undefined'`, and if yours does not, install `temporal-polyfill` and add `import 'temporal-polyfill/full/global'`.
> 
> `sum('createdAt')` and `avg('createdAt')` do not compile.

### `orderBy()` [#orderby]

Sort the result set.

#### Remarks [#remarks-4]

* Available for PostgreSQL and MongoDB, with different argument shapes.
* On PostgreSQL, `orderBy()` takes a callback that returns `.asc()` or `.desc()` on one column. Pass an array of such callbacks to sort by more than one column.
* On PostgreSQL, the callback can also sort by a field of a related record, for a relation to one record and one relation deep, as in `(p) => p.user.displayName.asc()`.
* On PostgreSQL, the callback can also sort by the number of related records, for a relation to many records, as in `(u) => u.posts.count().desc()`. `count()` takes an optional filter, the same one `some()` takes.
* On PostgreSQL, `.asc()` and `.desc()` take `{ nulls: "first" }` or `{ nulls: "last" }`. Without it, PostgreSQL puts nulls last for `.asc()` and first for `.desc()`.
* On MongoDB, `orderBy()` takes an object instead: `{ field: 1 }` sorts ascending and `{ field: -1 }` sorts descending.
* The example schema declares `Priority` text-backed, so on PostgreSQL it sorts by its stored text: `'high'`, then `'low'`, then `'urgent'`. A native enum column sorts in the order its members are declared instead, so the same members in a `native_enum Priority` block sort `Low`, `High`, `Urgent`. Use a native enum when the sort order matters.

#### Options [#options-4]

| Argument | Type                                                                                                                                 | Required | Description                       |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------- | --------------------------------- |
| `sort`   | Callback `(fields) => f.field.asc() \| .desc()`, an array of such callbacks (PostgreSQL), or a `{ field: 1 \| -1 }` object (MongoDB) | Yes      | The sort key(s) and direction(s). |

#### Return type [#return-type-4]

| Return type  | Example                           | Description                            |
| ------------ | --------------------------------- | -------------------------------------- |
| `Collection` | `db.orm.public.Post.orderBy(...)` | A collection with an ordering applied. |

#### Examples [#examples-4]

##### Ascending and descending [#ascending-and-descending]

  

#### PostgreSQL

```typescript
const newestFirst = await db.orm.public.Post.where({ userId: aliceId })
  .orderBy((p) => p.createdAt.desc())
  .all();
```

#### MongoDB

```typescript
const newestFirst = await db.orm.posts.orderBy({ createdAt: -1 }).all();
```

##### Multiple sort keys (PostgreSQL) [#multiple-sort-keys-postgresql]

```typescript
const byPriorityThenDate = await db.orm.public.Post.orderBy([
  (p) => p.priority.asc(),
  (p) => p.createdAt.asc(),
]).all();
// Priority is text-backed here, so it sorts as 'high', 'low', 'urgent'
```

### `limit()` [#limit]

Limit the number of returned rows.

#### Remarks [#remarks-5]

* Available for PostgreSQL and MongoDB.

#### Options [#options-5]

| Argument | Type     | Required | Description                       |
| -------- | -------- | -------- | --------------------------------- |
| `count`  | `number` | Yes      | Maximum number of rows to return. |

#### Return type [#return-type-5]

| Return type  | Example                       | Description                           |
| ------------ | ----------------------------- | ------------------------------------- |
| `Collection` | `db.orm.public.Post.limit(2)` | A collection limited to `count` rows. |

#### Examples [#examples-5]

##### Limit the result set [#limit-the-result-set]

  

#### PostgreSQL

```typescript
const firstTwo = await db.orm.public.Post.orderBy((p) => p.createdAt.asc()).limit(2).all();
```

#### MongoDB

```typescript
const firstOne = await db.orm.posts.orderBy({ createdAt: 1 }).limit(1).all();
```

### `offset()` [#offset]

Offset into the ordered result set.

#### Remarks [#remarks-6]

* Available for PostgreSQL and MongoDB.
* Combine with `orderBy()` and `limit()` for pagination.

#### Options [#options-6]

| Argument | Type     | Required | Description             |
| -------- | -------- | -------- | ----------------------- |
| `count`  | `number` | Yes      | Number of rows to skip. |

#### Return type [#return-type-6]

| Return type  | Example                        | Description                          |
| ------------ | ------------------------------ | ------------------------------------ |
| `Collection` | `db.orm.public.Post.offset(2)` | A collection offset by `count` rows. |

#### Examples [#examples-6]

##### Offset into the result set [#offset-into-the-result-set]

  

#### PostgreSQL

```typescript
const page2 = await db.orm.public.Post.orderBy((p) => p.createdAt.asc()).offset(2).limit(2).all();
```

#### MongoDB

```typescript
const secondPost = await db.orm.posts.orderBy({ createdAt: 1 }).offset(1).limit(1).all();
```

##### Related records, counts, and nulls (PostgreSQL) [#related-records-counts-and-nulls-postgresql]

```typescript
const byAuthor = await db.orm.public.Post.orderBy([
  (p) => p.user.displayName.asc(),
  (p) => p.id.asc(),
]).all();

const mostPosts = await db.orm.public.User.orderBy((u) => u.posts.count().desc()).all();

const described = await db.orm.public.Task.orderBy((t) => t.description.desc({ nulls: "last" })).all();
```

### `cursor()` [#cursor]

Resume pagination from a known position.

#### Remarks [#remarks-7]

* PostgreSQL only. `cursor()` does not exist on a MongoDB collection.
* Every sort in the `orderBy()` must be a plain column of the model. A sort by a related record, a count, an extension operation such as a vector distance, or a sort with `nulls` makes `cursor()` throw an error whose `code` is `ORM.ARGUMENT_INVALID`. Page such a query with `limit()` and `offset()`.
* Always call `orderBy()` before `cursor()`. TypeScript rejects the call if you do not. Nothing checks this while the query runs, so without the `orderBy()` the cursor is ignored and every row comes back.
* The cursor object must name every column the `orderBy()` sorts on. Leave one out and running the query throws an error whose `code` is `ORM.CURSOR_VALUE_MISSING`. With two sort columns, give both keys. The cursor compares the sort columns in order: first by the first column, then by the second for rows that tie on the first.

#### Options [#options-7]

| Argument | Type                                              | Required | Description                   |
| -------- | ------------------------------------------------- | -------- | ----------------------------- |
| `values` | Object of the `orderBy()` key(s) and their values | Yes      | The position to resume after. |

#### Return type [#return-type-7]

| Return type  | Example                                    | Description                                      |
| ------------ | ------------------------------------------ | ------------------------------------------------ |
| `Collection` | `db.orm.public.Post.cursor({ createdAt })` | A collection resuming after the cursor position. |

#### Examples [#examples-7]

##### Resume pagination (PostgreSQL) [#resume-pagination-postgresql]

```typescript
const page1 = await db.orm.public.Post.orderBy((p) => p.createdAt.asc()).limit(2).all();
const last = page1[page1.length - 1];

const page2 = await db.orm.public.Post.orderBy((p) => p.createdAt.asc())
  .cursor({ createdAt: last.createdAt })
  .limit(2)
  .all();
```

### `distinct()` [#distinct]

Remove duplicate rows, comparing only the fields you name.

#### Remarks [#remarks-8]

* PostgreSQL only. `distinct()` does not exist on a MongoDB collection.
* You do not need `select()`. `distinct('priority')` keeps one whole row per distinct `priority` value, whatever the query returns.
* Which of the tied rows it keeps is not defined. Call `orderBy()` first to choose, as [`distinctOn()`](#distincton) does.

#### Options [#options-8]

| Argument    | Type                   | Required | Description                   |
| ----------- | ---------------------- | -------- | ----------------------------- |
| `...fields` | Field names (`string`) | Yes      | The fields to deduplicate on. |

#### Return type [#return-type-8]

| Return type  | Example                                   | Description                                                   |
| ------------ | ----------------------------------------- | ------------------------------------------------------------- |
| `Collection` | `db.orm.public.Post.distinct('priority')` | A collection with duplicate rows removed on the named fields. |

#### Examples [#examples-8]

##### Deduplicate on a field (PostgreSQL) [#deduplicate-on-a-field-postgresql]

```typescript
const priorities = await db.orm.public.Post.distinct('priority').all();
// priorities holds one whole Post row per distinct priority value
```

### `distinctOn()` [#distincton]

Keep the first row per key according to `orderBy()`.

#### Remarks [#remarks-9]

* PostgreSQL only. `distinctOn()` does not exist on a MongoDB collection.
* Call `orderBy()` first, so that "the first row per key" means something. TypeScript rejects the call if you do not.
* Start the `orderBy()` with the same columns you pass to `distinctOn()`, as the example does. Sort by anything else first and the query fails in the database. If one of those first sorts is not a plain column, the call throws an error whose `code` is `ORM.ARGUMENT_INVALID`; a sort by a related record or a count may follow them.

#### Options [#options-9]

| Argument    | Type                   | Required | Description                                |
| ----------- | ---------------------- | -------- | ------------------------------------------ |
| `...fields` | Field names (`string`) | Yes      | The key field(s) to keep the first row of. |

#### Return type [#return-type-9]

| Return type  | Example                                   | Description                           |
| ------------ | ----------------------------------------- | ------------------------------------- |
| `Collection` | `db.orm.public.Post.distinctOn('userId')` | A collection keeping one row per key. |

#### Examples [#examples-9]

##### First row per key (PostgreSQL) [#first-row-per-key-postgresql]

```typescript
const latestPerUser = await db.orm.public.Post.orderBy([(p) => p.userId.asc(), (p) => p.createdAt.desc()])
  .distinctOn('userId')
  .all();
// latestPerUser holds one post per userId: the newest one, because of the orderBy
```

### `variant()` [#variant]

Narrow a model to one of the variants declared with `@@base`.

#### Remarks [#remarks-10]

* Available for PostgreSQL and MongoDB.
* Pass the variant's model name, such as `'Bug'`, not the string in its `@@base` attribute. On MongoDB you pass the model name too, even though the accessor before it is the collection name.
* On PostgreSQL, a variant that sets its own `@@map`, as `Bug` and `Feature` do, is stored in its own table. Read [`createAndCount()`](#createandcount) and [`upsert()`](#upsert) before you write to such a variant.
* On MongoDB, every variant is a document in the one collection, told apart by the field named in `@@discriminator`.

#### Options [#options-10]

| Argument      | Type     | Required | Description                    |
| ------------- | -------- | -------- | ------------------------------ |
| `variantName` | `string` | Yes      | The model name of the variant. |

#### Return type [#return-type-10]

| Return type                           | Example                             | Description                                     |
| ------------------------------------- | ----------------------------------- | ----------------------------------------------- |
| `Collection`, narrowed to the variant | `db.orm.public.Task.variant('Bug')` | A collection holding only rows of that variant. |

#### Examples [#examples-10]

##### Narrow to a variant [#narrow-to-a-variant]

  

#### PostgreSQL

```typescript
const bugs = await db.orm.public.Task.variant('Bug').all();
```

#### MongoDB

```typescript
const tutorials = await db.orm.posts.variant('Tutorial').all();
```

## Read methods [#read-terminals]

A read method runs the query and gives you the rows. `all()` and `first()` are available on both databases, while `aggregate()` and `groupBy()` are PostgreSQL only and are documented under [Grouped aggregates](#grouped-aggregates).

There is no `count()` method on either database, so on PostgreSQL, count with `aggregate((a) => ({ n: a.count() }))`. On MongoDB, counting takes two steps: `db.query`, the [pipeline builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#mongodb-pipeline-builder), builds the pipeline, and `runtime.query(...)` runs it.

```typescript
const built = db.query.from('posts').count('total').build();
const runtime = await db.runtime();
const [counted] = await runtime.query(built); // counted.total is the count
```

For a task-oriented walkthrough, see [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data).

### `all()` [#all]

Resolve the query to every matching row.

#### Remarks [#remarks-11]

* Available for PostgreSQL and MongoDB.
* `all()` returns an [`AsyncIterableResult`](#asynciterableresult): you can `await` it to collect an array, or use `for await` to stream rows one at a time.
* `await`ing a result you have already `await`ed is safe. You get the same array back, and the query does not run again. Each result can be used one way only, so awaiting it and then looping it with `for await`, or the reverse, throws an error whose `code` is `RUNTIME.ITERATOR_CONSUMED`. See [Single consumption and mode switching](#single-consumption-and-mode-switching).
* `orderBy()` is written differently on each database. See [`orderBy()`](#orderby).

#### Options [#options-11]

`all()` takes no required arguments.

#### Return type [#return-type-11]

| Return type                | Example                          | Description                                                       |
| -------------------------- | -------------------------------- | ----------------------------------------------------------------- |
| `AsyncIterableResult<Row>` | `await db.orm.public.User.all()` | Awaitable to `Row[]`, or iterable with `for await` for streaming. |

`Row` is the model's row type, from the emitted `contract.d.ts`.

#### Examples [#examples-11]

##### Await to collect an array [#await-to-collect-an-array]

  

#### PostgreSQL

```typescript
const users = await db.orm.public.User.all();
```

#### MongoDB

```typescript
const users = await db.orm.users.all();
```

##### Stream rows one at a time [#stream-rows-one-at-a-time]

  

#### PostgreSQL

```typescript
for await (const user of db.orm.public.User.orderBy((u) => u.email.asc()).all()) {
  console.log(user.email);
}
```

#### MongoDB

```typescript
for await (const post of db.orm.posts.orderBy({ createdAt: 1 }).all()) { // 1 ascending, -1 descending
  console.log(post.title);
}
```

For Prisma ORM 7 users, `findMany` maps onto `all()`:

```diff
- const users = await prisma.user.findMany({ where: { kind: 'admin' } });
+ const users = await db.orm.public.User.where({ kind: 'admin' }).all();
```

### `first()` [#first]

Resolve the query to the first matching row, or `null` if none matches.

#### Remarks [#remarks-12]

* Available for PostgreSQL and MongoDB.
* On PostgreSQL, `first()` accepts an inline filter: a shorthand object or a callback (`first((p) => p.priority.eq('urgent'))`). An inline filter is added to any earlier `where()` call, and both have to match.
* On MongoDB, `first()` takes no filter argument. Filter with `where(...)` first, then call `first()`.

#### Options [#options-12]

| Name     | Type                                           | Required | Description                                |
| -------- | ---------------------------------------------- | -------- | ------------------------------------------ |
| `filter` | Shorthand object or callback (PostgreSQL only) | No       | An inline filter applied before resolving. |

#### Return type [#return-type-12]

| Return type   | Example                               | Description                        |
| ------------- | ------------------------------------- | ---------------------------------- |
| `Row \| null` | `await db.orm.public.User.first(...)` | The first matching row, or `null`. |

#### Examples [#examples-12]

##### Match by an inline filter (PostgreSQL) [#match-by-an-inline-filter-postgresql]

```typescript
const alice = await db.orm.public.User.first({ email: 'alice@example.com' });
const urgentPost = await db.orm.public.Post.first((p) => p.priority.eq('urgent'));
```

##### Match with a prior `where()` (MongoDB) [#match-with-a-prior-where-mongodb]

```typescript
const bob = await db.orm.users.where({ name: 'Bob' }).first();
```

For Prisma ORM 7 users, `findUnique` and `findFirst` map onto `first()`:

```diff
- const alice = await prisma.user.findUnique({ where: { email } });
+ const alice = await db.orm.public.User.first({ email });
- const alice = await prisma.user.findUniqueOrThrow({ where: { email } });
+ const alice = await db.orm.public.User.where({ email }).all().firstOrThrow();
```

`first()` returns `null` on no match and does not check that only one row matched. `findUniqueOrThrow` and `findFirstOrThrow` both map onto `all().firstOrThrow()`, as the last line above shows.

`firstOrThrow()` is a method on the result that `all()` gives you, so calling it is not a second use of that result. It reads every matching row into memory and returns the first one, and it throws an error whose `code` is `RUNTIME.NO_ROWS` when nothing matched.

### Custom `Collection` subclass [#custom-collection-subclass]

On PostgreSQL you can subclass `Collection` to add your own methods to a model, and register the subclass when you create the client.

#### Remarks [#remarks-13]

* PostgreSQL only. You cannot subclass a collection on MongoDB.
* `db.orm` cannot use your subclass. Call the `orm(...)` function with a `collections` object to get a second accessor with the same methods as `db.orm.public`. Use that accessor for the models you subclassed, and keep `db.orm.public` for every other model. Your existing `db.orm.public.X` calls keep working.
* `client` in the example below is what `postgres(...)` returns, the same object [Setting up the client](#setting-up-the-client) calls `db`. The example creates one so that it runs on its own.
* `Collection<Contract, 'Task'>` takes two type arguments: your contract type, and the name of the model this collection is for.
* A method that returns `this.variant('Bug')` gives back a collection narrowed to the `Bug` model. It is chainable, so you finish it with `all()`, `first()`, or any other method.

#### Examples [#examples-13]

##### Register a subclass with a domain method (PostgreSQL) [#register-a-subclass-with-a-domain-method-postgresql]

```typescript
// postgres() comes from /runtime; Collection and orm() come from /orm-client.
import postgres from '@prisma/orm-postgres/runtime';
import { Collection, orm } from '@prisma/orm-postgres/orm-client';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

class TaskCollection extends Collection<Contract, 'Task'> {
  bugs() {
    return this.variant('Bug');
  }
  features() {
    return this.variant('Feature');
  }
}

const client = postgres<Contract>({ contractJson, url: process.env.DATABASE_URL });
const runtime = await client.connect();

const tasks = orm({
  runtime,
  context: client.context,
  collections: { Task: TaskCollection },
}).public; // .public is the PostgreSQL schema

const bugs = await tasks.Task.bugs().all();
const features = await tasks.Task.features().all();
```

## Write methods [#mutation-terminals]

A write method changes the database. `create`, `createAll`, `createAndCount`, `update`, `updateAll`, `updateAndCount`, `delete`, `deleteAll`, `deleteAndCount`, and `upsert` are available on both databases, and the differences between the two are listed under each method.

For Prisma ORM 7 users: `createMany` is `createAndCount()`, which returns the count as a number instead of `{ count }`, and `createManyAndReturn` is `createAll()`. In the same way, `updateMany` is `updateAndCount()` and `updateManyAndReturn` is `updateAll()`. `deleteMany` is `deleteAndCount()`, and `deleteAll()` returns the deleted rows, which no Prisma ORM 7 method did. `count` is [`aggregate()`](#grouped-aggregates) on PostgreSQL, or the two steps shown under [Read methods](#read-terminals) on MongoDB. `skipDuplicates: true` is now `{ onConflict: 'skip' }`, which you pass to [`createAll()`](#createall) or [`createAndCount()`](#createandcount) on PostgreSQL as a second argument.

To catch one of the errors named below, wrap the call in `try` and `catch`, then compare `error.code` with the string given here. For a task-oriented walkthrough, see [Writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data). On MongoDB, a write method rejects a chain that already has `orderBy()`, `limit()`, or `offset()` on it, and every write except `updateAll()` and `deleteAll()` also rejects `include()`. Both throw an error whose `code` is `ORM.OPERATION_UNSUPPORTED`. For grouping several writes into one unit, see [Transactions](https://www.prisma.io/docs/orm/fundamentals/transactions).

> [!WARNING]
> Filter before you update or delete
> 
> Always call `where()` before an update or a delete. On MongoDB the six update and delete methods and `upsert()` check for a filter and throw an error whose `code` is `ORM.WHERE_MISSING`, with a message naming the method you called, such as `updateAll() requires a .where() filter. Call .where() before .updateAll()`. On PostgreSQL, these methods do not compile without a `where()`, but nothing checks at run time. If a call without a filter does reach the database, `update()` and `delete()` change a single row and you cannot predict which one, and `updateAll()` and `deleteAll()` change every row.

The examples below use `aliceId`, `bobId`, `carolId`, `postId`, `tagId`, `tutorialId`, and `userId` for the ids of rows that already exist. Substitute your own.

### `create()` [#create]

Insert a single row and return it.

#### Remarks [#remarks-14]

* Available for PostgreSQL and MongoDB.
* On PostgreSQL, you may leave out any field your contract gives a default, including the id. Passing an explicit id is accepted. Nullable fields can be left out too. Every other field is required.
* On MongoDB, `_id` is the only field you can leave out. Give every other field a value, and write `null` for a field you want empty.
* On MongoDB, `create()` returns the values you passed plus the `_id` the server assigned, not the stored document. Read the row back if you need a value the database filled in. On PostgreSQL the returned row is read from the database already.
* On PostgreSQL, `create()` can create or link related rows in the same transaction. Nest `create()` on the side that does not hold the foreign key, and `connect()` on the side that does.
* Nested `create()` and `connect()` are not available on MongoDB.

#### Options [#options-13]

| Name             | Type                   | Required | Description                                                                          |
| ---------------- | ---------------------- | -------- | ------------------------------------------------------------------------------------ |
| The row's fields | Object of field values | Yes      | The row to insert. Pass the object as the only argument. There is no `data` wrapper. |

On PostgreSQL, that object can also carry a `create` or `connect` callback for a related row, as shown below. `create()` and `connect()` each take one object or an array of objects, on any relation. `disconnect()` takes an array, and on a many-to-many relation the array is required.

#### Return type [#return-type-13]

| Return type | Example                               | Description       |
| ----------- | ------------------------------------- | ----------------- |
| `Row`       | `await db.orm.public.Tag.create(...)` | The inserted row. |

#### Examples [#examples-14]

##### Insert a single row [#insert-a-single-row]

  

#### PostgreSQL

```typescript
const tag = await db.orm.public.Tag.create({ label: 'typescript-2' });
```

#### MongoDB

```typescript
const user = await db.orm.users.create({
  name: 'Carol',
  email: 'carol@example.com',
  bio: null,
  role: 'reader',
  address: null,
});
// user._id is the server-assigned id
```

##### Nested `create()` on the side without the foreign key (PostgreSQL) [#nested-create-on-a-child-owned-relation-postgresql]

```typescript
const author = await db.orm.public.User.create({
  email: 'dana@example.com',
  displayName: 'Dana',
  kind: 'user',
  posts: (posts) => posts.create([{ title: 'Dana post one' }]),
});
```

##### Nested `connect()` on the side with the foreign key (PostgreSQL) [#nested-connect-on-a-parent-owned-relation-postgresql]

```typescript
const post = await db.orm.public.Post.create({
  title: 'Connected to Bob',
  user: (user) => user.connect({ id: bobId }),
});
```

For Prisma ORM 7 users, `create()` drops the `data` wrapper:

```diff
- const tag = await prisma.tag.create({ data: { label: 'typescript-2' } });
+ const tag = await db.orm.public.Tag.create({ label: 'typescript-2' });
```

### `createAll()` [#createall]

Insert multiple rows and return them.

#### Remarks [#remarks-15]

* Available for PostgreSQL and MongoDB.
* Returns an [`AsyncIterableResult`](#asynciterableresult): `await` for an array, or `for await` to stream inserted rows.
* On PostgreSQL every row is inserted by one statement before the first row reaches you. Stopping the loop early does not undo an insert.
* To skip each row that would break a unique constraint, instead of failing the whole insert, pass `{ onConflict: 'skip' }` as the second argument. The result then holds only the rows the database wrote. This replaces `skipDuplicates: true` from Prisma ORM 7.
* `onConflict` works on PostgreSQL, and on SQLite through the experimental `@prisma/orm-sqlite` package. On MongoDB, `createAll()` takes only the rows, so a second argument is a type error.
* By default, a row is skipped when it breaks any unique constraint. To check only one constraint, list its fields in `conflictOn`. In the example schema, `Tag.label` is unique, so `conflictOn: ['label']` skips a tag whose label already exists. A row that breaks a different unique constraint is then not skipped: the database rejects it, and the whole insert fails, so no row is written.
* `onConflict` does not work on a variant stored in its own table, such as `Bug`, which maps to `bug` while its base model `Task` maps to `task`. Passing it there throws an error whose `code` is `ORM.OPERATION_UNSUPPORTED`. For such a variant, call `createAll()` with only the rows. A row that breaks a unique constraint then makes the call fail instead of being skipped.
* If your contract was emitted before `8.0.0-rc.12`, run `npx prisma contract emit` again before you use `onConflict`. Otherwise the call throws an error whose `code` is `ORM.CAPABILITY_MISSING`.

#### Options [#options-14]

| Name            | Type                                  | Required | Description                                                         |
| --------------- | ------------------------------------- | -------- | ------------------------------------------------------------------- |
| First argument  | Array of row objects                  | Yes      | The rows to insert. There is no `data` wrapper.                     |
| Second argument | `{ onConflict: 'skip', conflictOn? }` | No       | Skip rows that break a unique constraint. Not available on MongoDB. |

`conflictOn` is an array of field names, such as `['label']`. [`upsert()`](#upsert) also takes a `conflictOn`, but there it is an object of field values, such as `{ label: 'typescript' }`.

#### Return type [#return-type-14]

| Return type                | Example                                    | Description                          |
| -------------------------- | ------------------------------------------ | ------------------------------------ |
| `AsyncIterableResult<Row>` | `await db.orm.public.Tag.createAll([...])` | Awaitable to `Row[]`, or streamable. |

#### Examples [#examples-15]

##### Insert and collect [#insert-and-collect]

  

#### PostgreSQL

```typescript
const created = await db.orm.public.Tag.createAll([{ label: 'alpha' }, { label: 'beta' }]);

// Skip rows whose label already exists instead of failing.
const added = await db.orm.public.Tag.createAll([{ label: 'alpha' }, { label: 'gamma' }], {
  onConflict: 'skip',
  conflictOn: ['label'],
});
// added holds only the gamma row
```

#### MongoDB

```typescript
const created = await db.orm.users.createAll([
  { name: 'Dana', email: 'dana@example.com', bio: null, role: 'author', address: null },
  { name: 'Eve', email: 'eve@example.com', bio: null, role: 'reader', address: null },
]);
```

### `createAndCount()` [#createandcount]

Insert rows and return how many were inserted, without reading them back.

#### Remarks [#remarks-16]

* Available for PostgreSQL and MongoDB.
* On PostgreSQL, `createAndCount()` does not work on a variant that is stored in its own table, meaning its `@@map` names a different table than its base model does. `Bug` in the [example schema](#example-schema) is one: it maps to `bug` while `Task` maps to `task`. Use `createAll()` instead.
* Calling it on such a variant throws an error whose `code` is `ORM.OPERATION_UNSUPPORTED`, with the message `createAndCount() is not supported for MTI variant "Bug" on model "Task". Use createAll() instead.` MTI in the message means multi-table inheritance, the variant stored in its own table described above.
* On MongoDB, a variant is one document in one collection, so `createAndCount()` works on a variant as usual.
* It returns the number of rows the database inserted. With `{ onConflict: 'skip' }`, the skipped rows are not counted. The option works as on [`createAll()`](#createall).

#### Options [#options-15]

| Name            | Type                                  | Required | Description                                                         |
| --------------- | ------------------------------------- | -------- | ------------------------------------------------------------------- |
| First argument  | Array of row objects                  | Yes      | The rows to insert. There is no `data` wrapper.                     |
| Second argument | `{ onConflict: 'skip', conflictOn? }` | No       | Skip rows that break a unique constraint. Not available on MongoDB. |

`conflictOn` is an array of field names, as on [`createAll()`](#createall).

#### Return type [#return-type-15]

| Return type | Example                                         | Description                 |
| ----------- | ----------------------------------------------- | --------------------------- |
| `number`    | `await db.orm.public.Tag.createAndCount([...])` | The count of inserted rows. |

#### Examples [#examples-16]

##### Insert and count [#insert-and-count]

  

#### PostgreSQL

```typescript
const inserted = await db.orm.public.Tag.createAndCount([{ label: 'epsilon' }, { label: 'zeta' }]);
// 2
```

#### MongoDB

```typescript
const inserted = await db.orm.posts.variant('Tutorial').createAndCount([
  {
    title: 'Variant createAndCount',
    content: 'body',
    authorId: aliceId,
    createdAt: new Date('2024-02-01T00:00:00.000Z'),
    difficulty: 'beginner',
    duration: 10,
  },
]);
// 1
```

### `update()` [#update]

Update the matched row and return it, or `null` if none matches.

#### Remarks [#remarks-17]

* Available for PostgreSQL and MongoDB. Requires a prior `where()` (see the warning at the top of this section).

* On MongoDB, `update()` takes an object of field values, or a callback that returns field operations, such as `(p) => [p.content.set('Rewritten')]`. See [Field update operations](#field-update-operations).

* On MongoDB, the update input covers the base model's fields only. Putting a field declared on a variant in the update, such as `duration` on `Tutorial`, makes TypeScript complain even though the update runs correctly. Put `// @ts-expect-error` on the line directly above the line TypeScript flags. When the complaint goes away, TypeScript reports the comment itself as unused, so delete it then. The same is true of `updateAll()` and `updateAndCount()`.

  ```typescript
  // @ts-expect-error duration is a Tutorial field, not a Post field
  .update((t) => [t.duration.inc(10)]);
  ```

* Take care on PostgreSQL: `update()` takes an object of field values only, and passing a function instead writes nothing, reports nothing, and returns `null`.

* On PostgreSQL, `update()` can also relink related rows. `connect()` points the foreign key at a different row, and `disconnect()` removes a many-to-many link without deleting either row.

* Returns `null` when no row matches. On PostgreSQL it also returns `null` when the object you pass is empty and has no keys at all. An object whose values already match the row is different: that update runs and returns the row.

* On PostgreSQL, [`select()`](#select) and [`include()`](#include) before `.update()` choose which fields and relations come back on the returned row. They change nothing about what is written.

#### Options [#options-16]

| Name        | Type                                                              | Required | Description                                                                              |
| ----------- | ----------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------- |
| The changes | Object of field values, or on MongoDB a field-operations callback | Yes      | What to set on the matched row, passed as the only argument. There is no `data` wrapper. |

On PostgreSQL that object can also carry `connect` or `disconnect` for a related row, as shown below.

#### Return type [#return-type-16]

| Return type   | Example                                           | Description                                 |
| ------------- | ------------------------------------------------- | ------------------------------------------- |
| `Row \| null` | `await db.orm.public.User.where(...).update(...)` | The updated row, or `null` if none matched. |

#### Examples [#examples-17]

##### Update with a data object [#update-with-a-data-object]

  

#### PostgreSQL

```typescript
const updated = await db.orm.public.User.where({ id: bobId }).update({ displayName: 'Bob Updated' });
```

#### MongoDB

```typescript
const updated = await db.orm.users.where({ _id: bobId }).update({ bio: 'Now with a bio' });
```

##### Field-operations callback (MongoDB) [#field-operations-callback-mongodb]

```typescript
const updated = await db.orm.posts
  .where({ _id: postId })
  .update((p) => [p.title.set('Updated title'), p.content.set('Rewritten')]);
```

##### Nested `connect()` relinks a foreign key (PostgreSQL) [#nested-connect-relinks-a-foreign-key-postgresql]

```typescript
const relinked = await db.orm.public.Post.where({ id: postId }).update({
  user: (user) => user.connect({ id: carolId }),
});
```

##### Nested `disconnect()` unlinks a many-to-many row (PostgreSQL) [#nested-disconnect-unlinks-a-many-to-many-row-postgresql]

```typescript
const updated = await db.orm.public.Post.where({ id: postId })
  .select('id', 'title')
  .include('tags', (tag) => tag.select('id', 'label').orderBy((t) => t.label.asc()))
  .update({
    tags: (tag) => tag.disconnect([{ id: tagId }]),
  });
// only the join-table row is removed. The Tag row itself still exists
```

For Prisma ORM 7 users, `update()` moves the filter into `where()` and drops the `data` wrapper:

```diff
- const updated = await prisma.user.update({ where: { id: bobId }, data: { displayName: 'Bob Updated' } });
+ const updated = await db.orm.public.User.where({ id: bobId }).update({ displayName: 'Bob Updated' });
```

### `updateAll()` [#updateall]

Update every matching row and collect the results.

#### Remarks [#remarks-18]

* Available for PostgreSQL and MongoDB. Call `where()` first. Without a filter this changes every row. See the warning at the top of this section.
* On PostgreSQL, `updateAll()` runs as one statement, so every matching row changes together.
* On MongoDB, `updateAll()` is not a single operation, and two things follow. If a document begins matching your filter while the call is running, it is updated but not included in the returned rows. If someone else changes a matched document while the call is running, you get their version back, not yours.
* Prisma ORM has no `db.transaction()` on MongoDB, so you cannot avoid this from the client. To control it, share one `MongoClient` with the MongoDB driver and group the writes in one of the driver's own sessions, shown under [Transactions on MongoDB](https://www.prisma.io/docs/orm/fundamentals/transactions#transactions-on-mongodb).

#### Options [#options-17]

| Name        | Type                                                              | Required | Description                                                                                |
| ----------- | ----------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------ |
| The changes | Object of field values, or on MongoDB a field-operations callback | Yes      | What to set on every matched row, passed as the only argument. There is no `data` wrapper. |

#### Return type [#return-type-17]

| Return type                | Example                                              | Description       |
| -------------------------- | ---------------------------------------------------- | ----------------- |
| `AsyncIterableResult<Row>` | `await db.orm.public.Post.where(...).updateAll(...)` | The updated rows. |

#### Examples [#examples-18]

##### Update all matching rows [#update-all-matching-rows]

  

#### PostgreSQL

```typescript
const updated = await db.orm.public.Post.where({ userId: aliceId }).updateAll({ priority: 'urgent' });
```

#### MongoDB

```typescript
const updated = await db.orm.users.where({ role: 'author' }).updateAll({ role: 'admin' });
// see the remark above: this is not one operation
```

### `updateAndCount()` [#updateandcount]

Update every matching row and return the count.

#### Remarks [#remarks-19]

* Available for PostgreSQL and MongoDB. Call `where()` first. Without a filter this changes every row. See the warning at the top of this section.
* On MongoDB the count leaves out documents that already held the new values. On PostgreSQL it counts every matched row.

#### Options [#options-18]

| Name        | Type                                                              | Required | Description                                                                                |
| ----------- | ----------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------ |
| The changes | Object of field values, or on MongoDB a field-operations callback | Yes      | What to set on every matched row, passed as the only argument. There is no `data` wrapper. |

#### Return type [#return-type-18]

| Return type | Example                                                   | Description                |
| ----------- | --------------------------------------------------------- | -------------------------- |
| `number`    | `await db.orm.public.Post.where(...).updateAndCount(...)` | The count of updated rows. |

#### Examples [#examples-19]

##### Update and count [#update-and-count]

  

#### PostgreSQL

```typescript
const count = await db.orm.public.Post.where({ userId: carolId }).updateAndCount({ priority: 'low' });
```

#### MongoDB

```typescript
const count = await db.orm.users.where({ role: 'author' }).updateAndCount({ role: 'admin' });
```

### `delete()` [#delete]

Remove the matched row and return it, or `null` if none matches.

#### Remarks [#remarks-20]

* Available for PostgreSQL and MongoDB. Requires a prior `where()` (see the section warning above). Returns `null` when no row matches.

#### Options [#options-19]

`delete()` takes no required arguments. Filter with `where()` first.

#### Return type [#return-type-19]

| Return type   | Example                                       | Description                                 |
| ------------- | --------------------------------------------- | ------------------------------------------- |
| `Row \| null` | `await db.orm.public.Tag.where(...).delete()` | The deleted row, or `null` if none matched. |

#### Examples [#examples-20]

##### Delete a row [#delete-a-row]

  

#### PostgreSQL

```typescript
const created = await db.orm.public.Tag.create({ label: 'throwaway' });
const deleted = await db.orm.public.Tag.where({ id: created.id }).delete();
```

#### MongoDB

```typescript
const deleted = await db.orm.users.where({ _id: userId }).delete();
```

For Prisma ORM 7 users, `delete()` moves the filter into `where()`:

```diff
- const deleted = await prisma.tag.delete({ where: { id } });
+ const deleted = await db.orm.public.Tag.where({ id }).delete();
```

### `deleteAll()` [#deleteall]

Remove every matching row and collect the results.

#### Remarks [#remarks-21]

* Available for PostgreSQL and MongoDB. Call `where()` first. Without a filter this deletes every row. See the warning at the top of this section.
* Every matching row is deleted before the first row reaches you. Stopping the loop early does not save any of them.

#### Options [#options-20]

`deleteAll()` takes no required arguments. Filter with `where()` first.

#### Return type [#return-type-20]

| Return type                | Example                                           | Description       |
| -------------------------- | ------------------------------------------------- | ----------------- |
| `AsyncIterableResult<Row>` | `await db.orm.public.Post.where(...).deleteAll()` | The deleted rows. |

#### Examples [#examples-21]

##### Delete all matching rows [#delete-all-matching-rows]

  

#### PostgreSQL

```typescript
const deleted = await db.orm.public.Post.where({ userId: carolId }).deleteAll();
```

#### MongoDB

```typescript
const deleted = await db.orm.users.where({ role: 'reader' }).deleteAll();
```

### `deleteAndCount()` [#deleteandcount]

Remove every matching row and return the count.

#### Remarks [#remarks-22]

* Available for PostgreSQL and MongoDB. Call `where()` first. Without a filter this deletes every row. See the warning at the top of this section. Returns `0` when no row matches.

#### Options [#options-21]

`deleteAndCount()` takes no required arguments. Filter with `where()` first.

#### Return type [#return-type-21]

| Return type | Example                                                | Description                |
| ----------- | ------------------------------------------------------ | -------------------------- |
| `number`    | `await db.orm.public.Post.where(...).deleteAndCount()` | The count of deleted rows. |

#### Examples [#examples-22]

##### Delete and count [#delete-and-count]

  

#### PostgreSQL

```typescript
const count = await db.orm.public.Post.where({ userId: carolId }).deleteAndCount();
```

#### MongoDB

```typescript
const count = await db.orm.users.where({ role: 'reader' }).deleteAndCount();
```

### `upsert()` [#upsert]

Insert a row if none matches, otherwise update the existing row.

#### Remarks [#remarks-23]

* On MongoDB, call `where()` first. The filter decides which document is updated.
* On PostgreSQL, `upsert()` never reads the filters. A `where()` before it is ignored, without an error. `conflictOn` decides which row counts as already existing.
* `conflictOn` names the unique column that decides insert or update, such as `conflictOn: { label: 'typescript' }`. Only the column name is used. The value is required by the type and is then ignored, so pass any value of the right type.
* For a unique constraint on several columns together, name every one of those columns, as in `conflictOn: { orgId: '', email: '' }`. The set you name has to match one `@@unique` constraint.
* When a row is inserted on PostgreSQL, the `create` side is used as you wrote it.
* When a row is inserted on MongoDB, a field that appears in both `create` and `update` takes the `update` value.
* On MongoDB, the `update` side takes an object of field values or a field-operations callback.
* On PostgreSQL, `upsert()` does not work on a variant stored in its own table, the same restriction as [`createAndCount()`](#createandcount). It throws an error whose `code` is `ORM.OPERATION_UNSUPPORTED`, with the message `upsert() is not supported for MTI variant "Bug" on model "Task". Use createAll() instead.`
* There is no upsert for such a variant. Read the row with `first()`, then call `create()` or `update()`.
* On MongoDB, the `_id` on the returned row is a hex string, not the driver's `ObjectId`.

#### Options [#options-22]

| Name         | Type                                                              | Required | Description                                                 |
| ------------ | ----------------------------------------------------------------- | -------- | ----------------------------------------------------------- |
| `create`     | Object of field values                                            | Yes      | The row to insert if none matches.                          |
| `update`     | Object of field values, or on MongoDB a field-operations callback | Yes      | The changes to apply if a row matches.                      |
| `conflictOn` | Object naming the unique column or columns, PostgreSQL only       | No       | What decides insert or update. Omit to use the primary key. |

#### Return type [#return-type-22]

| Return type | Example                               | Description                  |
| ----------- | ------------------------------------- | ---------------------------- |
| `Row`       | `await db.orm.public.Tag.upsert(...)` | The inserted or updated row. |

#### Examples [#examples-23]

##### Insert or update (PostgreSQL) [#insert-or-update-postgresql]

```typescript
// Insert: no existing row has label 'brand-new', so the row is inserted
// exactly as the create side describes it.
const inserted = await db.orm.public.Tag.upsert({
  create: { label: 'brand-new' },
  update: { label: 'brand-new-updated' },
  conflictOn: { label: 'brand-new' }, // only the column name `label` is used
});

// Update: a row with label 'typescript' already exists, so the update runs against it.
const updated = await db.orm.public.Tag.upsert({
  create: { label: 'typescript' },
  update: { label: 'typescript-renamed' },
  conflictOn: { label: 'typescript' },
});
```

##### Insert or update (MongoDB) [#insert-or-update-mongodb]

```typescript
const user = await db.orm.users.where({ email: 'newperson@example.com' }).upsert({
  create: {
    name: 'New Person',
    email: 'newperson@example.com',
    bio: null,
    role: 'reader',
    address: null,
  },
  update: { bio: 'set on upsert' },
});
// on insert, bio is 'set on upsert': the `update` value wins on MongoDB
```

##### Field-operations callback on the update side (MongoDB) [#field-operations-callback-on-the-update-side-mongodb]

```typescript
const post = await db.orm.posts
  .variant('Tutorial')
  .where({ _id: tutorialId })
  .upsert({
    create: {
      title: 'Should not be used',
      content: 'unused',
      authorId: bobId,
      createdAt: new Date('2024-01-01T00:00:00.000Z'),
      difficulty: 'beginner',
      duration: 0,
    },
    update: (t) => [t.content.set('Updated content')],
  });
```

For Prisma ORM 7 users, `upsert()` replaces the `where` argument with `conflictOn` (PostgreSQL):

```diff
- const tag = await prisma.tag.upsert({
-   where: { label: 'typescript' },
-   update: { label: 'typescript-renamed' },
-   create: { label: 'typescript' },
- });
+ const tag = await db.orm.public.Tag.upsert({
+   update: { label: 'typescript-renamed' },
+   create: { label: 'typescript' },
+   conflictOn: { label: 'typescript' },
+ });
```

## Grouped aggregates [#grouped-aggregates]

These methods exist only on PostgreSQL collections. `aggregate()` treats every row the query matches as one group, while `groupBy().aggregate()` aggregates per group and `having()` filters those groups. A MongoDB model's collection has none of them, so to aggregate on MongoDB, use the pipeline builder, which is Prisma ORM's API for MongoDB's aggregation pipeline and is described in [MongoDB: Pipeline builder](https://www.prisma.io/docs/orm/fundamentals/advanced-queries#mongodb-pipeline-builder).

The examples below use a separate `Customer` / `Order` schema, where `Order.amount` is a numeric column:

**Expand for the aggregate example schema**

```prisma
model Customer {
  id      Uuid   @id @default(uuid())
  name    String
  segment String

  orders Order[]

  @@map("customer")
}

model Order {
  id         Uuid     @id @default(uuid())
  customerId Uuid
  channel    String
  amount     Int
  quantity   Int?
  placedAt   DateTime @default(now())

  customer Customer @relation(fields: [customerId], references: [id])

  @@map("order")
}
```

### `aggregate()` [#aggregate]

Compute aggregates over the rows the query matches. `aggregate()` runs the query, so you `await` it directly instead of calling `.all()`.

#### Remarks [#remarks-24]

* PostgreSQL only. Not available on MongoDB.
* `count()` counts rows and returns a number, `0` when no rows match.
* `count(field)` counts the rows where that field is not null.
* To count or sum the related rows of each parent row, use the `include()` callback instead; see [Refinements, aggregates, and combine](#refinements-aggregates-and-combine).
* `sum()`, `avg()`, `min()`, and `max()` return `null`, not `0`, when no rows match. Handle the `null`.
* A `limit()` or `offset()` earlier in the chain is applied first. The aggregate then covers only the rows they kept.
* What `sum()` and `avg()` give you back depends on the column type, as the table below shows.

| Column type     | `sum()` returns  | `avg()` returns  | Exact variant                 |
| --------------- | ---------------- | ---------------- | ----------------------------- |
| `Int`, `BigInt` | `number \| null` | `number \| null` | `sumBigInt()`, `avgDecimal()` |
| `Decimal`       | `string \| null` | `string \| null` | `avgDecimal()`                |

Use `sumBigInt()` when the total can pass `Number.MAX_SAFE_INTEGER`, because a `sum()` whose total passes it throws an error whose `code` is `RUNTIME.DECODE_FAILED`, thrown when the query result is read. Use `avgDecimal()` when you need the exact mean as a string, such as `'10.3333333333333333'`. Over a `Decimal` column `sum()` and `avg()` are already exact, and `sumBigInt()` is not available.

#### Options [#options-23]

| Argument   | Type                                               | Required | Description                                                                        |
| ---------- | -------------------------------------------------- | -------- | ---------------------------------------------------------------------------------- |
| `selector` | Callback `(agg) => ({ total: agg.sum('amount') })` | Yes      | The aggregates to compute. Each key you return becomes a key of the result object. |

The callback's `agg` argument gives you `count()`, `count(field)`, `sum(field)`, `avg(field)`, `min(field)`, and `max(field)`, plus `countBigInt()`, `sumBigInt(field)`, and `avgDecimal(field)`. `agg.countBigInt()` counts the same rows as `agg.count()` and returns a `bigint`.

#### Return type [#return-type-23]

| Return type | Example         | Description                                                                                   |
| ----------- | --------------- | --------------------------------------------------------------------------------------------- |
| Object      | `{ total: 10 }` | One key per key you returned from the callback. `sum`, `avg`, `min`, and `max` can be `null`. |

#### Examples [#examples-24]

##### Count (PostgreSQL) [#count-postgresql]

```typescript
const stats = await db.orm.public.Order.aggregate((agg) => ({
  total: agg.count(),
  withQuantity: agg.count('quantity'), // rows where quantity is not null
}));
// { total: 10, withQuantity: 8 }
```

##### Sum and average (PostgreSQL) [#sum-and-average-postgresql]

```typescript
const stats = await db.orm.public.Order.where({
  customerId: '20000000-0000-0000-0000-000000000001',
}).aggregate((agg) => ({
  totalAmount: agg.sum('amount'),
  avgAmount: agg.avg('amount'),
}));
// { totalAmount: 900, avgAmount: 300 }
```

##### Min and max (PostgreSQL) [#min-and-max-postgresql]

```typescript
const stats = await db.orm.public.Order.aggregate((agg) => ({
  cheapest: agg.min('amount'),
  priciest: agg.max('amount'),
}));
// { cheapest: 10, priciest: 500 }
```

##### Counts and totals past JavaScript's precision limit (PostgreSQL) [#counts-and-totals-past-javascripts-precision-limit-postgresql]

```typescript
const exact = await db.orm.public.Order.aggregate((agg) => ({
  rows: agg.countBigInt(),
  total: agg.sumBigInt('amount'),
  average: agg.avgDecimal('amount'),
}));
// { rows: 10n, total: 1500n, average: '150.0000000000000000' }
```

##### `null` over an empty set (PostgreSQL) [#null-over-an-empty-set-postgresql]

```typescript
const stats = await db.orm.public.Order.where((o) => o.amount.gt(999_999)).aggregate((agg) => ({
  total: agg.sum('amount'),
  average: agg.avg('amount'),
  count: agg.count(),
}));
// { total: null, average: null, count: 0 }
```

For Prisma ORM 7 users, `aggregate()` takes a selector callback instead of `_sum`/`_avg` keys:

```diff
- const stats = await prisma.order.aggregate({ _sum: { amount: true }, _avg: { amount: true } });
+ const stats = await db.orm.public.Order.aggregate((agg) => ({ total: agg.sum('amount'), average: agg.avg('amount') }));
```

### `groupBy()` [#groupby]

Group rows by one or more fields, then aggregate per group.

#### Remarks [#remarks-25]

* PostgreSQL only. Not available on MongoDB.
* Pass field names as separate arguments: `groupBy('customerId', 'channel')`.
* `groupBy(...)` returns a `GroupedCollection`. You cannot `await` it. Call `.aggregate(...)` on it, which runs the query and gives you one row per group. Each row holds the grouping fields, typed as they are on your model, plus the keys you returned from the aggregate callback.
* Chain order: `where(...)` comes before `groupBy(...)` and filters the rows that get grouped. After `groupBy(...)` come `having(...)` and `orderBy(...)`, then `limit(...)` and `offset(...)`. `aggregate(...)` comes last.
* `orderBy(...)` on a grouped collection sorts the groups by a field you grouped on. You cannot sort groups by an aggregate value. To do that, write the query with the SQL query builder instead. See [Advanced queries](https://www.prisma.io/docs/orm/fundamentals/advanced-queries).
* `limit(n)` and `offset(n)` take a slice of the groups, and both require an `orderBy(...)` before them. Without one they are a TypeScript error.

#### Options [#options-24]

| Argument    | Type                               | Required | Description             |
| ----------- | ---------------------------------- | -------- | ----------------------- |
| `...fields` | One or more field names (`string`) | Yes      | The fields to group by. |

#### Return type [#return-type-24]

| Return type         | Example                                     | Description                            |
| ------------------- | ------------------------------------------- | -------------------------------------- |
| `GroupedCollection` | `db.orm.public.Order.groupBy('customerId')` | Not a promise. Call `.aggregate(...)`. |

#### Examples [#examples-25]

##### Group and aggregate (PostgreSQL) [#group-and-aggregate-postgresql]

```typescript
const perCustomer = await db.orm.public.Order.groupBy('customerId').aggregate((agg) => ({
  orderCount: agg.count(),
  totalAmount: agg.sum('amount'),
}));
// one row per customer, each { customerId, orderCount, totalAmount }
```

##### Sort and page the groups (PostgreSQL) [#sort-and-page-the-groups-postgresql]

```typescript
const firstTwoChannels = await db.orm.public.Order.groupBy('channel')
  .orderBy((group) => group.channel.desc()) // desc() sorts descending, asc() ascending
  .limit(2)
  .aggregate((agg) => ({ orderCount: agg.count() }));
```

For Prisma ORM 7 users, `groupBy()` chains into `aggregate()` instead of taking a `by` array with aggregate keys:

```diff
- const perCustomer = await prisma.order.groupBy({ by: ['customerId'], _sum: { amount: true } });
+ const perCustomer = await db.orm.public.Order.groupBy('customerId').aggregate((agg) => ({ totalAmount: agg.sum('amount') }));
```

### `having()` [#having]

Filter groups by an aggregate comparison.

#### Remarks [#remarks-26]

* PostgreSQL only. Not available on MongoDB. Call it on the result of `groupBy()`.
* The `having()` callback gives you `count()`, `count(field)`, `sum(field)`, `avg(field)`, `min(field)`, and `max(field)`. Call a comparison on the result: `h.sum('amount').gt(1000)`. The comparisons are `eq`, `neq`, `gt`, `lt`, `gte`, and `lte`.
* For more than one condition, call `.having(...)` again. The conditions are combined with AND.
* You cannot refer to a key you returned from `aggregate()` here. Write the aggregate out again in `having()`.

#### Options [#options-25]

| Argument    | Type                                       | Required | Description                          |
| ----------- | ------------------------------------------ | -------- | ------------------------------------ |
| `predicate` | Callback `(h) => h.sum('amount').gt(1000)` | Yes      | The condition each group must match. |

#### Return type [#return-type-25]

| Return type         | Example                                                 | Description                            |
| ------------------- | ------------------------------------------------------- | -------------------------------------- |
| `GroupedCollection` | `db.orm.public.Order.groupBy('customerId').having(...)` | Not a promise. Call `.aggregate(...)`. |

#### Examples [#examples-26]

##### Filter groups by a sum (PostgreSQL) [#filter-groups-by-a-sum-postgresql]

```typescript
const bigSpenders = await db.orm.public.Order.groupBy('customerId')
  .having((h) => h.sum('amount').gt(1000))
  .aggregate((agg) => ({ totalAmount: agg.sum('amount') }));
```

## Filter conditions and operators [#filter-conditions-and-operators]

A condition says which rows match. You write one inside `where()`, and inside a relation filter such as `u.posts.some(...)`. If you call `where()` more than once, the conditions are ANDed, and one call can take the object form and the next the callback form. PostgreSQL and MongoDB write conditions differently.

* **PostgreSQL** compares a field with a method on that field, such as `u.email.eq(...)`, inside a callback. You name the callback's argument yourself, so the `u` and `p` below are only names. To combine conditions, import `and`, `or`, `not`, and `all` from `@prisma/orm-postgres/orm-client`.
* **MongoDB** has no callback form. `where()` takes either the shorthand object or a filter such as `MongoFieldFilter.eq('name', 'Alice')`. The full list is under [`MongoFieldFilter`](#mongofieldfilter). Import `MongoFieldFilter`, `MongoAndExpr`, and `MongoOrExpr` from `@prisma/orm-mongo/query-ast/execution`. To combine conditions, use `.and()`, `.not()`, and `MongoOrExpr.of([...])`, described under [Combinators](#combinators).

### Scalar comparisons (PostgreSQL) [#scalar-comparisons-postgresql]

Comparison methods on a field.

#### Remarks [#remarks-27]

* PostgreSQL. Which comparison methods a field has depends on its type. Autocomplete shows which ones apply.
* `isNull()` and `isNotNull()` are on every field.
* `eq`, `neq`, `in`, and `notIn` are on a field whose values can be compared for equality.
* `gt`, `lt`, `gte`, and `lte` are on a field whose values can be ordered.
* `like` and `ilike` are on a text field.
* `String` fields and text-backed enums have all of them. A [native enum](#example-schema) field, typed `pg.enum(...)` in the contract, has all but `like` and `ilike`, because PostgreSQL has no pattern match for an `enum` type. `Int`, `BigInt`, `Float`, `Decimal`, `Uuid`, and `DateTime` fields also have all but `like` and `ilike`. A `Boolean` field has only the equality methods, `isNull()`, and `isNotNull()`. A `Json` field has only `isNull()` and `isNotNull()`.
* `like()` matches a SQL pattern case-sensitively. `ilike()` matches the same pattern case-insensitively.
* `in([])` matches no rows. `notIn([])` matches every row.

#### Options [#options-26]

| Method                                                  | Type               | Description                                      |
| ------------------------------------------------------- | ------------------ | ------------------------------------------------ |
| `eq(value)` / `neq(value)`                              | Exact value        | Equality / inequality.                           |
| `gt(value)` / `lt(value)` / `gte(value)` / `lte(value)` | Ordered value      | Ordered comparisons.                             |
| `like(pattern)` / `ilike(pattern)`                      | SQL `LIKE` pattern | Case-sensitive / case-insensitive pattern match. |
| `in(values)` / `notIn(values)`                          | Array of values    | Membership / exclusion.                          |
| `isNull()` / `isNotNull()`                              | No argument        | NULL checks.                                     |

#### Examples [#examples-27]

##### Equality and inequality (PostgreSQL) [#equality-and-inequality-postgresql]

```typescript
const alice = await db.orm.public.User.where((u) => u.email.eq('alice@example.com')).first();
const notAlice = await db.orm.public.User.where((u) => u.email.neq('alice@example.com')).all();
```

##### Ordered comparisons (PostgreSQL) [#ordered-comparisons-postgresql]

```typescript
const after = await db.orm.public.Post.where((p) =>
  p.createdAt.gt(Temporal.Instant.from('2024-01-02T10:00:00.000Z')),
).all();
// gte() is the same comparison, including the boundary value.
```

##### Pattern matching (PostgreSQL) [#pattern-matching-postgresql]

```typescript
const matches = await db.orm.public.User.where((u) => u.email.like('%@example.com')).all(); // case-sensitive
const caseInsensitive = await db.orm.public.User.where((u) => u.email.ilike('%@EXAMPLE.COM')).all();
```

##### Membership and NULL checks (PostgreSQL) [#membership-and-null-checks-postgresql]

```typescript
const lowOrHigh = await db.orm.public.Post.where((p) => p.priority.in(['low', 'high'])).all();
const notLowOrHigh = await db.orm.public.Post.where((p) => p.priority.notIn(['low', 'high'])).all();
const withoutDescription = await db.orm.public.Task.where((t) => t.description.isNull()).all(); // Task.description is String? in the example schema
```

### Full-text search (PostgreSQL) [#full-text-search]

PostgreSQL full-text search on a text field.

#### Remarks [#remarks-28]

* PostgreSQL. A text field has `fullTextMatches(query, options?)` to filter and `fullTextRank(query, options?)` to sort by relevance.

* The [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder) has both, as `fns.fullTextMatches(column, query)` and `fns.fullTextRank(column, query)`. It also has `fns.fullTextHeadline(column, query)`, which returns the matching text with each match marked. Use the SQL query builder when you want that text in your results, because the ORM's `select()` takes only field names.

* The `query` argument is a parsed search query, which PostgreSQL calls a `tsquery`. Passing a plain string is a type error. Build the query with one of these functions from `@prisma/orm-postgres/target/full-text`: `websearchToTsquery(text)` reads text the way a web search box does: the user puts a phrase in quotes, writes `or` between choices, and puts `-` before a word to leave it out. `plaintoTsquery(text)` requires every word, and `phrasetoTsquery(text)` requires the words in order.

* `toTsquery(text)` reads PostgreSQL's own search syntax, in which `&` means and, `|` means or, `!` means not, and `:*` after a word matches any word that starts with it. Text that breaks this syntax makes the query fail when it runs, so never pass user input to `toTsquery()`.

* To add an operator to user text, such as `:*` for a prefix match while the user types, use the `tsquery` template tag from the same package: `` tsquery`${term}:*` ``. Text inside `${}` is searched as plain words, so the user's text cannot add operators of its own. When it holds several words, they must appear next to each other and in that order, and `:*` applies to each word, so `` tsquery`${'new y'}:*` `` finds `new` followed by a word that starts with `y`. Do not put quotes around the `${}` yourself.

* `language` is the language whose rules PostgreSQL uses to match words, so that in `english` a search for `run` also finds `running`. It defaults to `english`. Pass the same `language` to `fullTextMatches()` or `fullTextRank()` and to the function that builds the query, as in the example below. The tag takes it as `` tsquery({ language: 'german' })`${input}:*` ``.

  ```typescript title="src/search-posts.ts (excerpt)"
  const q = websearchToTsquery(input, { language: 'german' });
  const posts = await db.orm.public.Post.where((p) => p.title.fullTextMatches(q, { language: 'german' })).all();
  ```

* Add [`@@fullTextIndex`](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#full-text-indexes) to the model, with the same `language`, so PostgreSQL can use an index for the search. Without it the query still works, but PostgreSQL reads every row. The attribute takes the one field to index and a `name:` for the index:

  ```prisma title="src/prisma/contract.prisma (excerpt)"
  model Post {
    id    Uuid   @id @default(uuid())
    title String

    @@fullTextIndex([title], name: "post_title_search", language: "german")
    @@map("post")
  }
  ```

  Then run `npx prisma contract emit` and create the index the way you apply any other contract change: `npx prisma db update` while you are iterating, or `npx prisma migration plan` followed by `npx prisma db migrate`. See [How migrations work](https://www.prisma.io/docs/orm/migrations/how-migrations-work).

* A native enum field, typed `pg.enum(...)` in the contract, has no full-text operations.

#### Options [#options-27]

| Method                             | Options                                     | Description                                  |
| ---------------------------------- | ------------------------------------------- | -------------------------------------------- |
| `fullTextMatches(query, options?)` | `language`                                  | Matches rows whose field matches `query`.    |
| `fullTextRank(query, options?)`    | `language`, `normalization`, `coverDensity` | The relevance of the match, for `orderBy()`. |

* `normalization` sets how the length of the text changes the rank. It is a whole number from 0 to 63, made by adding PostgreSQL's flags together. The default, 0, ignores length. `2` divides the rank by the length of the text, so of two titles with the same matches, the shorter one ranks higher. The PostgreSQL manual lists every flag under [Ranking search results](https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-RANKING).
* `coverDensity: true` also counts how close together the matching words are, so a row where they appear near each other ranks higher.

#### Examples [#examples-28]

##### Search and sort by relevance [#search-and-sort-by-relevance]

```typescript title="src/search-posts.ts"
import { tsquery, websearchToTsquery } from '@prisma/orm-postgres/target/full-text';

const q = websearchToTsquery('"Prisma ORM" -draft');
const posts = await db.orm.public.Post.select('id', 'title')
  .where((p) => p.title.fullTextMatches(q))
  .orderBy((p) => p.title.fullTextRank(q).desc())
  .limit(10)
  .all();

const suggestions = await db.orm.public.Post.select('id', 'title')
  .where((p) => p.title.fullTextMatches(tsquery`${input}:*`))
  .limit(5)
  .all();
```

### Combinators [#combinators]

Combine or negate conditions.

#### Remarks [#remarks-29]

* On PostgreSQL, import `and`, `or`, `not`, and `all` from `@prisma/orm-postgres/orm-client`. You call them as functions, as in `and(a, b)`. They are not methods on a field.
* On PostgreSQL, `and(...)` and `or(...)` take any number of conditions, so `and(a, b, c)` is fine. `not(...)` takes one.
* On PostgreSQL, `all()` takes no arguments and returns a condition that matches every row. This `all()` is not the `.all()` you call at the end of a chain to run the query.
* On MongoDB, call `.and(other)` and `.not()` on a condition you already built, as in `MongoFieldFilter.eq('name', 'Alice').and(...)`. There is no `.or()` method. To OR conditions, build `MongoOrExpr.of([...])`.
* On MongoDB, `.and(other)` takes exactly one condition. For three, chain it: `a.and(b).and(c)`. You can also write all three at once with `MongoAndExpr.of([a, b, c])`. `MongoAndExpr` and `MongoOrExpr` come from the same module as `MongoFieldFilter`.

#### Examples [#examples-29]

##### `and` / `or` / `not` (PostgreSQL) [#and--or--not-postgresql]

```typescript
import { and, or, not } from '@prisma/orm-postgres/orm-client';
const both = await db.orm.public.Post.where((p) =>
  and(p.priority.eq('low'), p.userId.eq('00000000-0000-0000-0000-000000000003')),
).all();
const either = await db.orm.public.Post.where((p) => or(p.priority.eq('urgent'), p.priority.eq('high'))).all();
const negated = await db.orm.public.Post.where((p) => not(p.priority.eq('low'))).all();
```

##### `all` (PostgreSQL) [#all-postgresql]

```typescript
import { all } from '@prisma/orm-postgres/orm-client';
const everyPost = await db.orm.public.Post.where(() => all()).all();
```

##### `and` / `or` / `not` (MongoDB) [#and--or--not-mongodb]

```typescript
import { MongoAndExpr, MongoFieldFilter, MongoOrExpr } from '@prisma/orm-mongo/query-ast/execution';

const both = await db.orm.users
  .where(MongoFieldFilter.eq('role', 'author').and(MongoFieldFilter.eq('name', 'Alice')))
  .all();
const either = await db.orm.users
  .where(MongoOrExpr.of([MongoFieldFilter.eq('name', 'Alice'), MongoFieldFilter.eq('name', 'Bob')]))
  .all();
const negated = await db.orm.users.where(MongoFieldFilter.eq('name', 'Alice').not()).all();
const bothAtOnce = await db.orm.users
  .where(MongoAndExpr.of([MongoFieldFilter.eq('role', 'author'), MongoFieldFilter.eq('name', 'Alice')]))
  .all();
```

##### AND of two ORs (MongoDB) [#and-of-two-ors-mongodb]

```typescript
const authorsNamedAliceOrBob = await db.orm.users
  .where(
    MongoOrExpr.of([MongoFieldFilter.eq('name', 'Alice'), MongoFieldFilter.eq('name', 'Bob')]).and(
      MongoOrExpr.of([MongoFieldFilter.eq('role', 'author'), MongoFieldFilter.eq('role', 'editor')]),
    ),
  )
  .all();
```

### Relation filters (PostgreSQL) [#relation-filters-postgresql]

Filter parents by their related rows.

#### Remarks [#remarks-30]

* PostgreSQL. `some()`, `every()`, and `none()` are methods on a to-many relation, which is a relation that holds many related rows, such as `User.posts`.
* Each of the three takes either a callback or a plain object of equality matches: `u.posts.some((p) => p.priority.eq('urgent'))` and `u.posts.some({ priority: 'urgent' })` mean the same thing.
* `some()` with no argument matches parents with at least one related row.
* A user with no posts matches `every()`.
* `not(u.posts.some(...))` and `u.posts.none(...)` match the same rows. Prefer `none(...)`.
* All three are also methods on a to-one relation, such as `Post.user`, which holds a single related row. There `some()` means the related row matches, and `none()` means it does not. `every()` matches when the related row matches, and also when there is no related row.

#### Examples [#examples-30]

##### `some` / `every` / `none` (PostgreSQL) [#some--every--none-postgresql]

```typescript
const withUrgentPost = await db.orm.public.User.where((u) => u.posts.some((p) => p.priority.eq('urgent'))).all();
const withAnyTag = await db.orm.public.Tag.where((t) => t.posts.some()).all();
const allLowPriority = await db.orm.public.User.where((u) => u.posts.every((p) => p.priority.eq('low'))).all();
const noUrgentPost = await db.orm.public.User.where((u) => u.posts.none((p) => p.priority.eq('urgent'))).all();
```

##### To-one relation predicate (PostgreSQL) [#to-one-relation-predicate-postgresql]

```typescript
const postsByAlice = await db.orm.public.Post.where((p) => p.user.some({ email: 'alice@example.com' })).all();
const postsByAnyoneElse = await db.orm.public.Post.where((p) => p.user.none({ email: 'alice@example.com' })).all();
```

For Prisma ORM 7 users, `some()` and `none()` on a to-one relation replace `is` and `isNot`:

```diff
- const postsByAlice = await prisma.post.findMany({ where: { user: { is: { email: 'alice@example.com' } } } });
+ const postsByAlice = await db.orm.public.Post.where((p) => p.user.some({ email: 'alice@example.com' })).all();
```

### Shorthand object filter [#shorthand-object-filter]

A plain object of equality matches, ANDed together.

#### Remarks [#remarks-31]

* Available for PostgreSQL and MongoDB.
* Multiple keys are combined with implicit AND. A key set to `undefined` is skipped.
* On PostgreSQL, a key set to `null` becomes an IS NULL check. On MongoDB it matches documents where the field is null and documents where the field is missing.
* On PostgreSQL, the shorthand object cannot filter a field whose type cannot be compared for equality, such as `Json`. Using that field as a key compiles, but fails at run time with an error whose `code` is `ORM.FILTER_UNSUPPORTED`. Use the callback form, which has whatever methods that type does support. On a `Json` field those are `isNull()` and `isNotNull()`.

#### Examples [#examples-31]

##### Shorthand object [#shorthand-object]

  

#### PostgreSQL

```typescript
const row = await db.orm.public.Post.where({
  userId: '00000000-0000-0000-0000-000000000001',
  priority: 'high',
}).first();
```

#### MongoDB

```typescript
const alice = await db.orm.users.where({ name: 'Alice', role: 'author' }).first();
```

### `MongoFieldFilter` [#mongofieldfilter]

Helpers that build one MongoDB filter condition. Use them for anything other than equality on a top-level field, which `.where({ name: 'Alice' })` already covers. Chaining two of them, as in `.where(a).where(b)`, joins them with AND. For OR, see [Combinators](#combinators).

#### Remarks [#remarks-32]

* MongoDB. Import from `@prisma/orm-mongo/query-ast/execution`. `MongoExistsExpr` is in the same module.
* The helpers are `of`, `eq`, `neq`, `gt`, `lt`, `gte`, `lte`, `in`, `nin`, `isNull`, and `isNotNull`. Each returns one filter, which you can pass straight to `.where()` or hold in a variable. There is no `ne`; use `neq`.
* `of(field, operator, value)`: pass the MongoDB operator as a string, including the `$`, for example `'$regex'`. Use it for operators the named helpers do not cover, such as `MongoFieldFilter.of('tags', '$size', 3)` on an array field `tags`. A misspelled operator such as `'$regexp'` is not caught until the query runs.
* `isNull(field)` matches documents where the field is `null` and documents where the field is missing. `isNotNull(field)` matches everything else. To test only whether a field is present, use `MongoExistsExpr.exists(field)` or `MongoExistsExpr.notExists(field)`. Those two are all `MongoExistsExpr` offers.
* There is no `regex`, `elemMatch`, `all`, or `size` helper. Write those operators through `of`.

#### Options [#options-28]

| Method                                                                              | Type                                    | Description                                                                              |
| ----------------------------------------------------------------------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------- |
| `of(field, operator, value)`                                                        | Field + MongoDB operator string + value | Any operator, including the `$`, such as `'$regex'`.                                     |
| `eq(field, value)` / `neq(field, value)`                                            | Field + value                           | Equality / inequality.                                                                   |
| `gt(field, value)` / `lt(field, value)` / `gte(field, value)` / `lte(field, value)` | Field + value                           | Greater than, less than, greater or equal, less or equal.                                |
| `in(field, values)` / `nin(field, values)`                                          | Field + array                           | Membership / exclusion.                                                                  |
| `isNull(field)` / `isNotNull(field)`                                                | Field                                   | `isNull` matches a `null` value or a missing field. `isNotNull` matches everything else. |

#### Examples [#examples-32]

##### Comparison helpers (MongoDB) [#comparison-helpers-mongodb]

```typescript
import { MongoFieldFilter } from '@prisma/orm-mongo/query-ast/execution';

const alice = await db.orm.users.where(MongoFieldFilter.eq('name', 'Alice')).first();
const notAlice = await db.orm.users.where(MongoFieldFilter.neq('name', 'Alice')).all();
const strictlyAfter = await db.orm.posts
  .where(MongoFieldFilter.gt('createdAt', new Date('2024-01-01T10:00:00.000Z')))
  .all();
```

##### Membership and null checks (MongoDB) [#membership-and-null-checks-mongodb]

```typescript
const articlesOrTutorials = await db.orm.posts
  .where(MongoFieldFilter.in('kind', ['article', 'tutorial']))
  .all();
const notArticles = await db.orm.posts.where(MongoFieldFilter.nin('kind', ['article'])).all();
const noBio = await db.orm.users.where(MongoFieldFilter.isNull('bio')).all();
const hasBio = await db.orm.users.where(MongoFieldFilter.isNotNull('bio')).all();
```

##### An operator written as a string, and `$exists` (MongoDB) [#an-operator-written-as-a-string-and-exists-mongodb]

```typescript
import { MongoExistsExpr, MongoFieldFilter } from '@prisma/orm-mongo/query-ast/execution';

const matching = await db.orm.posts.where(MongoFieldFilter.of('title', '$regex', '^Hello')).all();
const withBioField = await db.orm.users.where(MongoExistsExpr.exists('bio')).all();
```

### Dot-notation into an embedded object (MongoDB) [#dot-notation-into-an-embedded-object-mongodb]

Filter into a field of an object stored inside the document, rather than in its own collection, using a dot path.

#### Remarks [#remarks-33]

* MongoDB. Use `MongoFieldFilter.eq('address.city', 'San Francisco')` for a dotted path. It takes the path as a plain `string` and needs no cast.
* You can also write `.where({ 'address.city': 'San Francisco' })`. That object form runs correctly, but it does not type-check. `.where()` only knows your model's top-level field names, so you must cast.

#### Examples [#examples-33]

##### Dot-notation path (MongoDB) [#dot-notation-path-mongodb]

```typescript
import { MongoFieldFilter } from '@prisma/orm-mongo/query-ast/execution';

const usersInSf = await db.orm.users.where(MongoFieldFilter.eq('address.city', 'San Francisco')).all();
```

`MongoFieldFilter.eq` is the recommended form, because the object form needs a cast, and the cast drops type checking for every key in that object:

```typescript
const usersInSf = await db.orm.users
  .where({ 'address.city': 'San Francisco' } as unknown as Record<string, unknown>)
  .all();
```

## Field update operations [#field-update-operations]

On MongoDB, `update()`, `updateAll()`, `updateAndCount()`, and `upsert()` take a callback in place of a data object. The callback gets one argument, the update builder, written `u` in these examples, and returns an array of the operations you want. `updateAndCount()` takes the callback in the same place as `update()`, while `upsert()` takes it as its `update` key, beside `create`. PostgreSQL has no callback form: pass an object to [`update()`](#update) instead.

* For a top-level field, read it off the update builder as a property: `u.bio.set('Hello')`.
* For a field inside an embedded object, call the update builder as a function with the dot path: `u('address.city').set('San Francisco')`. The `upsert()` callback cannot use a dot path. Given one, `upsert()` throws an error whose `code` is `ORM.OPERATION_UNSUPPORTED`. Set the whole embedded object on its top-level field instead, as in `u.address.set({ street: '1 Market St', city: 'San Francisco', zip: '94105', country: 'US' })`. Give every field of the embedded object, including the optional ones.

All four methods require `.where()`, and without one they throw an error whose `code` is `ORM.WHERE_MISSING`. `.where({})` does not satisfy that rule, because an empty object adds no condition. To change every document, pass a filter that matches them all, such as `MongoFieldFilter.isNotNull('_id')`. A `_id` filter takes the hex string that a read gives you back, as the examples below show. On `upsert()`, `.where()` picks the document to update, exactly as on `update()`, and the full example is under [`upsert()`](#upsert). `update()` returns the updated document, or `null` when nothing matched, and `updateAll()` returns an [`AsyncIterableResult`](#asynciterableresult) of the changed documents. [`updateAndCount()`](#updateandcount) exists on both databases, and it returns the number of changed documents.

### Available operations (MongoDB) [#available-operations-mongodb]

#### Remarks [#remarks-34]

* MongoDB only. These are the four operations the update builder gives you for single-value fields: `set()`, `unset()`, `inc()`, and `mul()`. The four array operations follow under [Array operations](#array-operations-mongodb-unverified).
  * `set(value)` assigns a field.
  * `unset()` removes a field.
  * `inc(n)` increments a numeric field. TypeScript offers `inc` and `mul` on numeric fields only. Applied to a missing field, `inc` sets the field to `n`.
  * `mul(n)` multiplies a numeric field. Applied to a missing field, it sets the field to `0` whatever `n` is.
* After `variant(...)`, `u.duration.inc(10)` is a type error even though it runs correctly. Put `// @ts-expect-error` on the line directly above the line TypeScript flags. When the type error goes away, TypeScript reports the comment as unused, so delete the comment then.

#### Examples [#examples-34]

These examples use the MongoDB accessors from [Setting up the client](#setting-up-the-client).

##### `set()` (MongoDB) [#set-mongodb]

Return as many operations as you want, and they are applied together, in one write.

```typescript
const updated = await db.orm.users
  .where({ _id: '6650f1c2a1b2c3d4e5f60002' })
  .update((u) => [u.bio.set('Set via field op'), u.name.set('Bob R.')]);
// A field inside the embedded `address` object, by dot path:
const moved = await db.orm.users.where({ _id: '6650f1c2a1b2c3d4e5f60002' }).update((u) => [u('address.city').set('San Francisco')]);
```

##### `inc()` and `mul()` (MongoDB) [#inc-and-mul-mongodb]

`duration` is declared on `Tutorial`, not on the base `Post` model, so each `.update(...)` line that touches it needs its own `// @ts-expect-error` directly above it.

```typescript
const incremented = await db.orm.posts
  .variant('Tutorial')
  .where({ _id: '6650f1c2a1b2c3d4e5f60003' })
  // @ts-expect-error duration is a Tutorial field, not a Post field
  .update((u) => [u.duration.inc(10)]);

const multiplied = await db.orm.posts
  .variant('Tutorial')
  .where({ _id: '6650f1c2a1b2c3d4e5f60003' })
  // @ts-expect-error duration is a Tutorial field, not a Post field
  .update((u) => [u.duration.mul(3)]);
```

##### `unset()` (MongoDB) [#unset-mongodb]

```typescript
const updated = await db.orm.users.where({ _id: '6650f1c2a1b2c3d4e5f60001' }).update((u) => [u.bio.unset()]);
const changed = await db.orm.users.where({ _id: '6650f1c2a1b2c3d4e5f60002' }).updateAndCount((u) => [u.bio.unset()]);
```

### Operations that do not exist (MongoDB) [#operations-that-do-not-exist-mongodb]

> [!WARNING]
> No
> 
> `min`
> 
> ,
> 
> `max`
> 
> ,
> 
> `rename`
> 
> , or
> 
> `currentDate`
> 
>  field operations
> 
> The update builder implements eight operations, and only these eight: `set`, `unset`, `inc`, `mul`, `push`, `pull`, `addToSet`, and `pop`. `min`, `max`, `rename`, and `currentDate` are absent from the API, and TypeScript rejects them: `rename` is not a property of `u.bio`.

### Array operations (MongoDB) [#array-operations-mongodb-unverified]

#### Remarks [#remarks-35]

* MongoDB. `push()`, `pull()`, `addToSet()`, and `pop()` are available on the update builder. `push(value)` appends one element. `addToSet(value)` appends it only if it is not already there. `pop(1)` removes the last element, and `pop(-1)` removes the first.
* `pull(match)` removes every element equal to the argument. If the array holds objects, pass part of an object to remove every element that matches it, as in `u.tags.pull({ kind: 'draft' })`.
* These operations need an array field, declared with `[]` in your contract, as in `tags String[]`. Applied to any other field, the write fails. There is no `error.code` to match, because the error is MongoDB's own.
* The four lines below are separate calls because one update cannot apply two operations to the same field. One update can still change two different fields, such as pushing to `tags` and setting `bio`. The example schema has no array field, so these four lines assume `tags String[]` on `User` and will not run against the schema on this page.

```typescript
await db.orm.users.where({ _id: '6650f1c2a1b2c3d4e5f60001' }).update((u) => [u.tags.push('admin')]);
await db.orm.users.where({ _id: '6650f1c2a1b2c3d4e5f60001' }).update((u) => [u.tags.addToSet('admin')]);
await db.orm.users.where({ _id: '6650f1c2a1b2c3d4e5f60001' }).update((u) => [u.tags.pull('draft')]);
await db.orm.users.where({ _id: '6650f1c2a1b2c3d4e5f60001' }).update((u) => [u.tags.pop(1)]);
```

## Result types [#result-types]

### Model and result types [#model-and-result-types]

`contract.d.ts` exports a type for every model, under `Models`. On PostgreSQL the schema is part of the name: `Models.public_User`. The same file exports a `models` constant, so `typeof models.public.User` is the same type. A model type lists every scalar field and every relation, and no query returns exactly that, so three types derive what a query does return:

* `Scalars<M>` is the model without its relations. It is what `all()` and `first()` return when you do not call `select()` or `include()`.
* `Shape<M, Spec>` is a row with the fields and relations you choose. In `Spec`, `"+"` names the scalar fields and relations to keep, `"-"` names scalar fields to drop, and any other key is a relation with its own nested spec. If `"+"` names only relations, every scalar field stays. A relation named in `"+"` comes with all of its scalar fields and none of its own relations.
* `ResultType<typeof query>` is one row of a query you have already written.

Import `Scalars` and `Shape` from `@prisma/orm-postgres/family-contract/types`, or `@prisma/orm-mongo/family-contract/types` on MongoDB. Import `ResultType` from `@prisma/orm-postgres/components/runtime`. A contract emitted before `8.0.0-rc.10` has no `Models`; run `npx prisma contract emit` again after upgrading.

```typescript
import type { Models } from './contract.d';
import type { Scalars, Shape } from '@prisma/orm-postgres/family-contract/types';
import type { ResultType } from '@prisma/orm-postgres/components/runtime';

type UserRow = Scalars<Models.public_User>;
// every scalar field of User, no posts and no tasks

type UserResponse = Shape<Models.public_User, { '-': 'email'; posts: { '+': 'id' | 'title' } }>;
// every scalar field of User except email, plus posts as an array of { id, title }

const usersWithPosts = db.orm.public.User.include('posts');
type UserWithPosts = ResultType<typeof usersWithPosts>;
// the same type as Shape<Models.public_User, { '+': 'posts' }>
```

Use `Shape` to declare a function's return type once, and TypeScript checks the body at the `return`. A wrong field name, a relation under `"-"`, or a scalar field in `"+"` next to a `"-"` is a compile error on that key. For Prisma ORM 7 users, these replace `Prisma.User` and `Prisma.UserGetPayload<...>`.

### `AsyncIterableResult` [#asynciterableresult]

The methods `all()` / `createAll()` / `updateAll()` / `deleteAll()` return an `AsyncIterableResult`. You can use it two ways:

* `await` the result (or call `.toArray()`) to get every row in one array.
* Loop over it with `for await ... of` to take rows one at a time.

`createAll()`, `updateAll()`, and `deleteAll()` exist on PostgreSQL as well as MongoDB, and [Write methods](#mutation-terminals) documents what each one takes, with examples. If you need the type by name, import it from `@prisma/orm-postgres/components/runtime` on PostgreSQL, or from `@prisma/orm-mongo/components/runtime` on MongoDB.

#### Single consumption and mode switching [#single-consumption-and-mode-switching]

Each result is read once, one way:

* Re-`await`ing (or calling `.toArray()` on) a result you already awaited is **safe**. It returns the same array.
* Looping a result a second time with `for await` throws an error whose `code` is `RUNTIME.ITERATOR_CONSUMED`. So does switching from one way to the other, such as awaiting a result and then looping it. The message contains `already been consumed`. To recognise the error, import `isRuntimeError` from `@prisma/orm-postgres/components/runtime` on PostgreSQL, or from `@prisma/orm-mongo/components/runtime` on MongoDB, and check `error.code`.

PostgreSQL and MongoDB behave the same here, and the example below uses the PostgreSQL accessor. On MongoDB the same methods are on `db.orm.users`, see [Setting up the client](#setting-up-the-client). `all()` returns the result object straight away, and the `await` is what runs the query, so the example holds the result in a variable.

```typescript
import { isRuntimeError } from '@prisma/orm-postgres/components/runtime';
const result = db.orm.public.User.all();
const first = await result;
const again = await result.toArray(); // safe: same array

try {
  for await (const user of result) {
  }
} catch (error) {
  if (isRuntimeError(error) && error.code === 'RUNTIME.ITERATOR_CONSUMED') {
    // the result was already read as an array
  }
}
```

### Aggregate result shapes [#aggregate-result-shapes]

* `aggregate((agg) => ({ ... }))` resolves to a **single object** keyed by your aliases. `agg` is the callback's argument, and it carries the aggregate functions. `db.orm.public.Order.aggregate((agg) => ({ total: agg.count() }))` resolves to one object, such as `{ total: 10 }`.
* [Grouped aggregates](#grouped-aggregates) documents `aggregate()`, `groupBy()` with more than one field, and every function `agg` gives you. The bullets here cover only the shape of what you get back.
* `groupBy(...).aggregate((agg) => ({ ... }))` resolves to an **array**, one object per group. Each object carries the fields you grouped by plus your aliases. `db.orm.public.Order.groupBy('customerId').aggregate((agg) => ({ orderCount: agg.count(), totalAmount: agg.sum('amount') }))` resolves to `[{ customerId, orderCount, totalAmount }, ...]`.
* `count()` is always a `number` (`0` over an empty set). `sum()`, `avg()`, `min()`, and `max()` resolve to `null`, not `0`, over an empty result set.

## Related pages

- [`Error reference`](https://www.prisma.io/docs/orm/reference/error-reference): Every structured error code Prisma ORM can emit, by namespace, with the condition that raises it.
- [`Migration API`](https://www.prisma.io/docs/orm/reference/migration-api): Every method and helper a migration.ts can use: the Migration class, the PostgreSQL operations, the column and constraint helpers, rawSql, and the MongoDB operations.
- [`Pipeline builder reference`](https://www.prisma.io/docs/orm/reference/pipeline-builder): Reference for the Prisma ORM MongoDB pipeline builder's stages, accumulators, expression helpers, and write methods.
- [`Raw queries reference`](https://www.prisma.io/docs/orm/reference/raw-queries): Reference for Prisma ORM raw queries: PostgreSQL raw SQL and MongoDB raw commands.
- [`SQL query builder reference`](https://www.prisma.io/docs/orm/reference/sql-query-builder): Reference for the Prisma ORM SQL query builder's select, mutation, and grouped query methods.

# Pipeline builder reference (/docs/orm/reference/pipeline-builder)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Reference for the Prisma ORM MongoDB pipeline builder's stages, accumulators, expression helpers, and write methods.

Location: ORM > Reference > Pipeline builder reference

The pipeline builder gives you a typed way to build MongoDB aggregation pipelines. You reach it through `db.query`, chain aggregation stages onto a starting collection, and finish the chain with the call that builds the query. It is the MongoDB counterpart to the [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder): a lower-level API for the queries the [ORM client](https://www.prisma.io/docs/orm/reference/orm-client) doesn't express.

Everything the builder produces becomes a MongoDB aggregation pipeline. There is no `find()` or `distinct()` here, so use `db.orm` or [`rawCommand()`](#rawcommand) for those. To fetch a single document, filter and then `limit(1)`. Use the ORM client (`db.orm`) for everyday reads and writes across models and relations. Reach for the pipeline builder when you need to group documents, to join another collection and keep transforming the result, or to write the result into a collection (`$out` and `$merge`). This page documents every stage, accumulator, expression helper, and write method.

> [!NOTE]
> This is the MongoDB pipeline builder
> 
> The pipeline builder targets MongoDB only. PostgreSQL has no pipeline builder: use the [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder) for PostgreSQL joins and aggregates, and the [ORM client](https://www.prisma.io/docs/orm/reference/orm-client) for everyday queries on either database.

## Example schema [#example-schema]

The examples run against the schema below, the same MongoDB schema as the [ORM client](https://www.prisma.io/docs/orm/reference/orm-client) page. `Article` and `Tutorial` are two kinds of `Post`, stored in one `posts` collection and told apart by the value of the `kind` field. `@@base(Post, "article")` and `@@discriminator(kind)` set that up. See [`@@base`](https://www.prisma.io/docs/orm/reference/orm-client#variant) on the ORM client page. `@@type("mongo/string@1")` says the enum is stored as a MongoDB string, and `@1` is the version of that type id, always `@1` today. None of that matters to a pipeline: `kind` is an ordinary field you can filter and group on.

**Expand for the example schema**

```prisma
enum UserRole {
  @@type("mongo/string@1")
  Admin  = "admin"
  Author = "author"
  Reader = "reader"
}

type Address {
  street  String
  city    String
  zip     String?
  country String
}

model User {
  id      ObjectId @id @map("_id")
  name    String
  email   String
  bio     String?
  role    UserRole
  address Address?
  posts   Post[]
  @@map("users")
}

model Post {
  id        ObjectId @id @map("_id")
  title     String
  content   String
  kind      String
  authorId  ObjectId
  createdAt Date
  author    User @relation(fields: [authorId], references: [id])
  @@discriminator(kind)
  @@index([authorId])
  @@index([createdAt(sort: Desc), authorId])
  @@map("posts")
}

model Article {
  summary   String
  @@base(Post, "article")
  @@unique([summary])
}

model Tutorial {
  difficulty String
  duration   Int32
  @@base(Post, "tutorial")
}
```

## Entry points [#entry-points]

Every pipeline starts with `db.query.from('posts')`, naming the collection to aggregate over. It ends with a call that turns the chain into a query you can run, and between them you chain stages.

`db` is the client you create with `mongo(...)`, whose `dbName` option is the name of the MongoDB database to use. See [Transactions and runtime](https://www.prisma.io/docs/orm/reference/transactions-and-runtime#mongooptions) for every option and for how to create the client. Three Prisma ORM import paths appear on this page: `@prisma/orm-mongo/runtime` holds the `mongo()` client, `@prisma/orm-mongo/query-builder` holds `mongoQuery`, `fn`, `acc`, and `expr`, and `@prisma/orm-mongo/query-ast/execution` holds the `Mongo*Stage` classes, `MongoAggFieldRef`, and `MongoFieldFilter`. Every example holds the built query in a variable named `plan`.

Prisma ORM 8 renames `schema.prisma` to `contract.prisma`. Run `npx prisma contract emit` before any code on this page compiles: it writes `contract.json`, used at run time, and `contract.d.ts`, used for types. The example below imports `contract.json` with `with { type: 'json' }`, which works with the TypeScript settings `prisma orm init` writes for you. [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) has the setup steps.

### `from()` [#from]

Enter the pipeline builder on a collection.

#### Remarks [#remarks]

* `from()` takes the collection name, the same name you use on `db.orm` (`'posts'`, `'users'`), not the model name `Post`. The collection name is the model's `@@map` value, or the model name exactly as written when there is no `@@map`.
* Passing an unknown collection name throws right away, with an error whose `code` is `ORM.MODEL_UNKNOWN` and whose message is `Unknown root: "<name>". Valid roots: ...` (the message says root; it means the collection name).
* `from()` returns a builder you chain stages onto. Call `insertOne()` and `insertMany()` on `from()` directly, before any stage.
* You can build the same pipelines without a client. `import { mongoQuery } from '@prisma/orm-mongo/query-builder'`, then `mongoQuery({ contractJson }).from('posts')`. Import `contractJson` the same way the example below does. `mongoQuery` only builds queries. It never runs one, so you still need a client's `runtime` to get results. Use it in tests, or to build a query once and run it through any client you like.

#### Options [#options]

| Name         | Type                               | Required | Description                       |
| ------------ | ---------------------------------- | -------- | --------------------------------- |
| `collection` | Collection name (`string` literal) | Yes      | The collection to aggregate over. |

#### Return type [#return-type]

| Return type      | Example                  | Description                                                  |
| ---------------- | ------------------------ | ------------------------------------------------------------ |
| Pipeline builder | `db.query.from('posts')` | A builder you chain stages onto, then finish with `build()`. |

#### Examples [#examples]

##### Enter the builder on a collection [#enter-the-builder-on-a-collection]

```typescript
import mongo from '@prisma/orm-mongo/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

const db = mongo<Contract>({ contractJson, url: process.env.MONGODB_URL, dbName: 'app' });
const runtime = await db.runtime();

const plan = db.query.from('posts').build();
const posts = await runtime.query(plan);
```

### Building and executing a pipeline [#building-and-executing-a-pipeline]

`build()` returns the built query, which the examples hold in a variable named `plan`. Nothing runs until you pass it to `runtime.query(...)`. Every later example reuses the `db` and `runtime` from the example above.

#### Remarks [#remarks-1]

* On MongoDB, `db.runtime()` returns a promise, so you must await it: `const runtime = await db.runtime()`. Hold it in a variable and reuse it.
* `await` that call for an array of documents, or write `for await (const doc of runtime.query(plan)) { ... }` to take one document at a time.
* There is no `db.execute` on the MongoDB client.
* **Read results are decoded.** If every stage in your pipeline is one of `match()`, `sort()`, `limit()`, `skip()`, `sample()`, `project()`, `addFields()`, and `vectorSearch()`, `_id` comes back as a hex string. If any stage is not in that list, including `lookup()` and `group()`, every document comes back raw, with each value as MongoDB stores it. An `_id` that MongoDB generated is then an `ObjectId` object from the `mongodb` package, the MongoDB driver Prisma ORM uses. Compare those ids as strings, as [`lookup()`](#lookup) shows. A `DateTime` field comes back as a JavaScript `Date` either way.

#### Examples [#examples-1]

##### Execute through the client [#execute-through-the-client]

```typescript
const plan = db.query.from('posts').sort({ createdAt: 1 }).build();
const posts = await runtime.query(plan);
```

## Pipeline stages [#pipeline-stages]

Stages transform the documents flowing through the pipeline. Chain them in order; each stage's output feeds the next. The `(f) => ...` callbacks reference the current document's fields, one property per field.

### `match()` [#match]

Filter documents by a predicate.

#### Remarks [#remarks-2]

* `match()` takes a callback whose `f` argument has one property per field, and returns a filter expression (`(f) => f.kind.eq('tutorial')`).
* Scalar fields expose these filter operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `exists`, and `type`. They work like the MongoDB query operators of the same name (`$ne`, `$gt`, `$in`, `$exists`, `$type`, and so on).
* To compare two computed values rather than a field against a constant, wrap the comparison in `expr(...)`: `match((f) => expr(fn.gt(fn.year(f.createdAt), fn.literal(2023))))`. `fn` holds the helpers that build expressions, one per MongoDB operator. `expr()` wraps one of those values so `match()` accepts it. The `fn.*` helpers take expressions, not plain values, so wrap every constant in `fn.literal()`. See [Expression helpers](#expression-helpers).

Where each form goes. `.node` is the raw MongoDB expression inside an `fn.*` value:

| Call site                                                                         | What you pass                             |
| --------------------------------------------------------------------------------- | ----------------------------------------- |
| `project()`, `addFields()`, `redact()`, and the arguments of an accumulator       | The `fn.*` value itself.                  |
| The condition argument of `fn.cond()`, and the stages that take an options object | The `.node` property of the `fn.*` value. |
| `match()`                                                                         | The `fn.*` value wrapped in `expr(...)`.  |

#### Options [#options-1]

| Name        | Type                               | Required | Description                           |
| ----------- | ---------------------------------- | -------- | ------------------------------------- |
| `predicate` | Callback `(f) => FilterExpression` | Yes      | The condition documents must satisfy. |

#### Return type [#return-type-1]

| Return type      | Example                             | Description                                                                                |
| ---------------- | ----------------------------------- | ------------------------------------------------------------------------------------------ |
| Filtered builder | `db.query.from('posts').match(...)` | A builder narrowed by the filter, chainable into more stages, write methods, or `build()`. |

#### Examples [#examples-2]

##### Filter by a field [#filter-by-a-field]

```typescript
const plan = db.query
  .from('posts')
  .match((f) => f.kind.eq('tutorial'))
  .build();
const tutorials = await runtime.query(plan);
```

##### Aggregation-expression predicate [#aggregation-expression-predicate]

```typescript
import { fn, expr } from '@prisma/orm-mongo/query-builder';

const plan = db.query
  .from('posts')
  .match((f) => expr(fn.gt(fn.year(f.createdAt), fn.literal(2023))))
  .build();
const recent = await runtime.query(plan);
```

> [!WARNING]
> `_id`
> 
>  equality filters do not work through the pipeline builder
> 
> Filtering by `_id` equality inside `match()` **never matches any document**: neither a hex string (`f._id.eq('507f...')`) nor an `ObjectId` matches. There is no supported way to filter by `_id` equality through the typed pipeline builder. To fetch one document by its id, use the [ORM client](https://www.prisma.io/docs/orm/reference/orm-client), which converts the hex string for you, while the pipeline builder does not convert it:
> 
> ```typescript
> const postId = '6650f1c2a1b2c3d4e5f60003';
> const post = await db.orm.posts.where({ _id: postId }).first();
> ```
>
> For an `_id` filter inside a pipeline, use [`rawCommand()`](#rawcommand), which places a real `ObjectId` directly in a raw pipeline document.

### `sort()` [#sort]

Order documents by a field spec.

#### Remarks [#remarks-3]

* `sort()` takes a plain object spec: `{ field: 1 }` ascending, `{ field: -1 }` descending. Multiple keys sort in the order they appear.

#### Options [#options-2]

| Name   | Type                   | Required | Description                       |
| ------ | ---------------------- | -------- | --------------------------------- |
| `spec` | `{ [field]: 1 \| -1 }` | Yes      | The sort key(s) and direction(s). |

#### Return type [#return-type-2]

| Return type      | Example                                          | Description                         |
| ---------------- | ------------------------------------------------ | ----------------------------------- |
| Pipeline builder | `db.query.from('posts').sort({ createdAt: -1 })` | A builder with an ordering applied. |

#### Examples [#examples-3]

##### Sort descending [#sort-descending]

```typescript
const plan = db.query.from('posts').sort({ createdAt: -1 }).build();
const newestFirst = await runtime.query(plan);
```

### `limit()` [#limit]

Cap the number of documents.

#### Remarks [#remarks-4]

* Combine `sort()` then `limit(1)` to fetch a single document: the pipeline builder has no `first()`.

#### Options [#options-3]

| Name    | Type     | Required | Description                            |
| ------- | -------- | -------- | -------------------------------------- |
| `count` | `number` | Yes      | Maximum number of documents to return. |

#### Return type [#return-type-3]

| Return type      | Example                           | Description                             |
| ---------------- | --------------------------------- | --------------------------------------- |
| Pipeline builder | `db.query.from('posts').limit(1)` | A builder limited to `count` documents. |

#### Examples [#examples-4]

##### Fetch a single document [#fetch-a-single-document]

```typescript
const plan = db.query.from('posts').sort({ createdAt: 1 }).limit(1).build();
const [oldest] = await runtime.query(plan);
```

### `skip()` [#skip]

Offset into the sorted result set.

#### Options [#options-4]

| Name    | Type     | Required | Description                  |
| ------- | -------- | -------- | ---------------------------- |
| `count` | `number` | Yes      | Number of documents to skip. |

#### Return type [#return-type-4]

| Return type      | Example                          | Description                            |
| ---------------- | -------------------------------- | -------------------------------------- |
| Pipeline builder | `db.query.from('posts').skip(1)` | A builder offset by `count` documents. |

#### Examples [#examples-5]

##### Paginate [#paginate]

```typescript
const plan = db.query.from('posts').sort({ createdAt: 1 }).skip(1).build();
const afterFirst = await runtime.query(plan);
```

### `sample()` [#sample]

Draw a random subset of documents.

#### Options [#options-5]

| Name   | Type     | Required | Description                    |
| ------ | -------- | -------- | ------------------------------ |
| `size` | `number` | Yes      | Number of documents to sample. |

#### Return type [#return-type-5]

| Return type      | Example                            | Description                         |
| ---------------- | ---------------------------------- | ----------------------------------- |
| Pipeline builder | `db.query.from('posts').sample(1)` | A builder emitting a random subset. |

#### Examples [#examples-6]

##### Random subset [#random-subset]

```typescript
const plan = db.query.from('posts').sample(1).build();
const oneRandom = await runtime.query(plan);
```

### `addFields()` [#addfields]

Compute new fields and attach them to each document.

#### Remarks [#remarks-5]

* `addFields()` takes a callback returning an object of new field names to computed [expression-helper](#expression-helpers) values. Existing fields are preserved.

#### Options [#options-6]

| Name   | Type                                        | Required | Description                |
| ------ | ------------------------------------------- | -------- | -------------------------- |
| `spec` | Callback `(f) => ({ [field]: Expression })` | Yes      | The new fields to compute. |

#### Return type [#return-type-6]

| Return type      | Example                                 | Description                                     |
| ---------------- | --------------------------------------- | ----------------------------------------------- |
| Pipeline builder | `db.query.from('posts').addFields(...)` | A builder whose documents carry the new fields. |

#### Examples [#examples-7]

##### Attach a computed field [#attach-a-computed-field]

```typescript
import { fn } from '@prisma/orm-mongo/query-builder';

const plan = db.query
  .from('posts')
  .addFields((f) => ({ shoutTitle: fn.toUpper(f.title) }))
  .build();
const withShout = await runtime.query(plan);
```

### `lookup()` [#lookup]

Join documents from another collection (`$lookup`).

#### Remarks [#remarks-6]

* `lookup()` takes a callback that builds the join with `from(collection).on((local, foreign) => ({ local, foreign })).as(name)`: the other collection, the two fields to match on, and the name of the output array field.
* The object returned by `on()` has two fixed keys, `local` and `foreign`. Write `({ local: local.authorId, foreign: foreign._id })`.
* The joined documents arrive in an array under the `as` name. When nothing matches, that array is empty.
* A joined document's `_id` and the `_id` of the document it was joined to are both `ObjectId` objects, and two `ObjectId` objects are never `===` even when they hold the same id. Compare them as strings: `String(post.author[0]._id) === String(post.authorId)`.

#### Options [#options-7]

| Name      | Type                                                   | Required | Description             |
| --------- | ------------------------------------------------------ | -------- | ----------------------- |
| `builder` | Callback `(from) => from(collection).on(...).as(name)` | Yes      | The join specification. |

#### Return type [#return-type-7]

| Return type      | Example                              | Description                                       |
| ---------------- | ------------------------------------ | ------------------------------------------------- |
| Pipeline builder | `db.query.from('posts').lookup(...)` | A builder whose documents carry the joined array. |

#### Examples [#examples-8]

##### Join a foreign collection [#join-a-foreign-collection]

```typescript
const plan = db.query
  .from('posts')
  .match((f) => f.title.eq('Hello world'))
  .lookup((from) =>
    from('users')
      .on((local, foreign) => ({ local: local.authorId, foreign: foreign._id }))
      .as('author'),
  )
  .build();
const withAuthor = await runtime.query(plan);
```

### `project()` [#project]

Reshape each document.

#### Remarks [#remarks-7]

* `project()` has two forms. A **key-list** form narrows to the named fields (`project('title', 'kind')`); `_id` is retained implicitly even when not listed.
* A **callback** form computes a projection spec (`project((f) => ({ title: 1, shout: fn.toUpper(f.title) }))`). Write `1` to keep a field, or an expression to compute it. There is no `0` form here: the callback form cannot drop a field.

#### Options [#options-8]

| Name        | Type                                             | Required      | Description                   |
| ----------- | ------------------------------------------------ | ------------- | ----------------------------- |
| `...fields` | Field names (`string`)                           | Key-list form | The fields to keep.           |
| `spec`      | Callback `(f) => ({ [field]: 1 \| Expression })` | Callback form | The projection specification. |

#### Return type [#return-type-8]

| Return type      | Example                                           | Description                             |
| ---------------- | ------------------------------------------------- | --------------------------------------- |
| Pipeline builder | `db.query.from('posts').project('title', 'kind')` | A builder projected to the given shape. |

#### Examples [#examples-9]

##### Key-list form [#key-list-form]

```typescript
const plan = db.query.from('posts').project('title', 'kind').build();
const trimmed = await runtime.query(plan);
```

##### Callback form [#callback-form]

```typescript
import { fn } from '@prisma/orm-mongo/query-builder';

const plan = db.query
  .from('posts')
  .project((f) => ({ title: 1, shout: fn.toUpper(f.title) }))
  .build();
const projected = await runtime.query(plan);
```

### `unwind()` [#unwind]

Unroll an array field into one document per element.

#### Remarks [#remarks-8]

* `unwind(field, { preserveNullAndEmptyArrays? })` maps to MongoDB's `$unwind`. Name the field holding the array. TypeScript accepts any field of the document; nothing checks that it holds an array.

#### Options [#options-9]

| Name                                 | Type                  | Required | Description                                                                 |
| ------------------------------------ | --------------------- | -------- | --------------------------------------------------------------------------- |
| `field`                              | Field name (`string`) | Yes      | The array field to unroll.                                                  |
| `options.preserveNullAndEmptyArrays` | `boolean`             | No       | Keep documents whose array is null, missing, or empty. Defaults to `false`. |

#### Return type [#return-type-9]

| Return type      | Example                                 | Description                                        |
| ---------------- | --------------------------------------- | -------------------------------------------------- |
| Pipeline builder | `db.query.from('posts').unwind('tags')` | A builder emitting one document per array element. |

#### Examples [#examples-10]

##### Unroll an array field [#unroll-an-array-field]

This example needs a `tags String[]` field on `Post`, which the example schema does not have.

```typescript
const plan = db.query
  .from('posts')
  .match((f) => f.title.eq('Hello world'))
  .unwind('tags')
  .sort({ tags: 1 })
  .build();
const perTag = await runtime.query(plan);
```

### `group()` [#group]

Group documents by a key and compute per-group aggregates.

#### Remarks [#remarks-9]

* `group()` takes a callback that receives **only** the `f` argument, one property per field (`(f) => ...`), and returns a spec object. The spec's `_id` sets the grouping key; every other key must be an **accumulator**.
* `acc` holds the accumulators `group()` accepts, such as a count or a sum, documented under [Accumulators](#accumulators). Import it and use it inside the callback, **not** as a second callback argument: `import { acc } from '@prisma/orm-mongo/query-builder'`, then `acc.count()`, `acc.push(f.title)`. The callback takes one argument; there is no `(f, acc) => ...` form.
* A `_id: null` key groups the whole collection into a single bucket.
* A non-accumulator value for a non-`_id` key throws as soon as you call `group()`, with an error whose `code` is `ORM.ARGUMENT_INVALID`: `group() field "<name>" must use an accumulator (e.g. acc.sum(), acc.count()). Got "<kind>" expression.` A `null` value for a key other than `_id` throws with the same code and the message `group() field "<name>" must not be null. Only _id can be null.`

#### Options [#options-10]

| Name   | Type                                                               | Required | Description                                  |
| ------ | ------------------------------------------------------------------ | -------- | -------------------------------------------- |
| `spec` | Callback `(f) => ({ _id: keyExpression \| null, [alias]: acc.* })` | Yes      | The grouping key and per-group accumulators. |

#### Return type [#return-type-10]

| Return type      | Example                             | Description                                |
| ---------------- | ----------------------------------- | ------------------------------------------ |
| Pipeline builder | `db.query.from('posts').group(...)` | A builder emitting one document per group. |

#### Examples [#examples-11]

##### Group by a field [#group-by-a-field]

```typescript
import { acc } from '@prisma/orm-mongo/query-builder';

const plan = db.query
  .from('posts')
  .group((f) => ({
    _id: f.authorId,
    postCount: acc.count(),
    titles: acc.push(f.title),
  }))
  .build();
const perAuthor = await runtime.query(plan);
```

##### Group the whole collection [#group-the-whole-collection]

```typescript
import { acc } from '@prisma/orm-mongo/query-builder';

const plan = db.query
  .from('posts')
  .group((f) => ({ _id: null, total: acc.count(), latest: acc.max(f.createdAt) }))
  .build();
const [summary] = await runtime.query(plan);
```

For Prisma ORM 7 users, `groupBy` becomes a `group()` stage on the pipeline builder:

```diff
- const perAuthor = await prisma.post.groupBy({ by: ['authorId'], _count: true });
+ const perAuthor = await runtime.query(
+   db.query.from('posts').group((f) => ({ _id: f.authorId, postCount: acc.count() })).build(),
+ );
```

### `replaceRoot()` [#replaceroot]

Promote a computed sub-document to the top level.

#### Remarks [#remarks-10]

* `replaceRoot()` takes a callback returning an expression that evaluates to an object. A bare scalar is rejected by MongoDB at runtime (`'newRoot' expression must evaluate to an object`).
* A common pattern is to promote the first element of a `lookup()` array with `fn.arrayElemAt(f.author, fn.literal(0))`.

#### Options [#options-11]

| Name   | Type                                 | Required | Description                          |
| ------ | ------------------------------------ | -------- | ------------------------------------ |
| `spec` | Callback `(f) => documentExpression` | Yes      | The document to promote to the root. |

#### Return type [#return-type-11]

| Return type      | Example                                   | Description                                              |
| ---------------- | ----------------------------------------- | -------------------------------------------------------- |
| Pipeline builder | `db.query.from('posts').replaceRoot(...)` | A builder whose documents are the promoted sub-document. |

#### Examples [#examples-12]

##### Promote a looked-up document [#promote-a-looked-up-document]

```typescript
import { fn } from '@prisma/orm-mongo/query-builder';

const plan = db.query
  .from('posts')
  .match((f) => f.title.eq('Hello world'))
  .lookup((from) =>
    from('users')
      .on((local, foreign) => ({ local: local.authorId, foreign: foreign._id }))
      .as('author'),
  )
  .replaceRoot((f) => fn.arrayElemAt(f.author, fn.literal(0)))
  .build();
const authors = await runtime.query(plan);
```

### `count()` [#count]

Reduce the pipeline to a single document holding the count. It is not `acc.count()`, which counts the documents in one group inside `group()`.

#### Options [#options-12]

| Name    | Type     | Required | Description                          |
| ------- | -------- | -------- | ------------------------------------ |
| `field` | `string` | Yes      | The output field name for the count. |

#### Return type [#return-type-12]

| Return type      | Example                                 | Description                                       |
| ---------------- | --------------------------------------- | ------------------------------------------------- |
| Pipeline builder | `db.query.from('posts').count('total')` | A builder emitting one `{ [field]: n }` document. |

#### Examples [#examples-13]

##### Count documents [#count-documents]

```typescript
const plan = db.query.from('posts').count('total').build();
const [{ total }] = await runtime.query(plan);
```

### `sortByCount()` [#sortbycount]

Group by an expression and sort descending by group size.

#### Remarks [#remarks-11]

* `sortByCount()` takes a callback returning the grouping expression. It emits one document per distinct value, each `{ _id, count }`, sorted by `count` descending.

#### Options [#options-13]

| Name         | Type                         | Required | Description                      |
| ------------ | ---------------------------- | -------- | -------------------------------- |
| `expression` | Callback `(f) => expression` | Yes      | The value to group and count by. |

#### Return type [#return-type-13]

| Return type      | Example                                             | Description                                    |
| ---------------- | --------------------------------------------------- | ---------------------------------------------- |
| Pipeline builder | `db.query.from('posts').sortByCount((f) => f.kind)` | A builder emitting `{ _id, count }` documents. |

#### Examples [#examples-14]

##### Count occurrences of a field value [#count-occurrences-of-a-field-value]

```typescript
const plan = db.query
  .from('posts')
  .sortByCount((f) => f.kind)
  .build();
const byKind = await runtime.query(plan);
```

### `redact()` [#redact]

Keep or prune documents (and sub-documents) based on an expression.

#### Remarks [#remarks-12]

* `redact()` maps to MongoDB's `$redact`, whose expression must evaluate to one of MongoDB's `$$` variables: `$$KEEP`, `$$DESCEND`, or `$$PRUNE`.
* Write those variables with `f.rawPath('$KEEP')` and `f.rawPath('$PRUNE')`. `f.rawPath(path)` names a field or a MongoDB `$$` variable by its raw string, with no checking against your model, and it prefixes `$` to the string you give it. There is no expression helper for a `$$` variable, and `fn.literal(...)` cannot stand in: the server rejects both `fn.literal('KEEP')` and `fn.literal('$$KEEP')`.
* For which `fn.*` values need their `.node` property here, see the table under [`match()`](#match). For anything more involved, use [`rawCommand()`](#rawcommand), where you write the `$redact` stage with `$$KEEP` and `$$PRUNE` directly.

#### Options [#options-14]

| Name   | Type                         | Required | Description                                                      |
| ------ | ---------------------------- | -------- | ---------------------------------------------------------------- |
| `spec` | Callback `(f) => expression` | Yes      | An expression evaluating to `$$KEEP`, `$$DESCEND`, or `$$PRUNE`. |

#### Return type [#return-type-14]

| Return type      | Example                              | Description                                   |
| ---------------- | ------------------------------------ | --------------------------------------------- |
| Pipeline builder | `db.query.from('posts').redact(...)` | A builder that keeps or prunes each document. |

#### Examples [#examples-15]

##### Keep tutorials and prune everything else [#keep-tutorials-and-prune-everything-else]

```typescript
import { fn } from '@prisma/orm-mongo/query-builder';

const plan = db.query
  .from('posts')
  .redact((f) =>
    fn.cond(fn.eq(f.kind, fn.literal('tutorial')).node, f.rawPath('$KEEP'), f.rawPath('$PRUNE')),
  )
  .build();
const tutorials = await runtime.query(plan);
```

### Option-object stages [#option-object-stages]

Several stages take a single MongoDB stage options object rather than a typed `(f) => ...` callback. Each one carries the same meaning it has in MongoDB. Where an option below is called a raw expression, it wants a MongoDB expression object rather than a typed builder value: build one with the `fn.*` helpers and pass its `.node` property, or name a field with `MongoAggFieldRef.of('duration')`, which is already a raw expression and takes no `.node`.

#### Remarks [#remarks-13]

* `bucket({ groupBy, boundaries, default_?, output? })` sorts documents into the ranges you name. `default` is a reserved word in JavaScript, so the key is `default_`. `groupBy` is a raw expression.
* `bucketAuto({ groupBy, buckets, output?, granularity? })` sorts them into a given number of ranges, chosen so each holds about the same number of documents. `groupBy` is a raw expression. `granularity` is a string that MongoDB reads as the series it rounds the bucket boundaries to. Prisma ORM passes it through unchanged, accepts any string, and MongoDB rejects the ones it does not know.
* `geoNear({ near, distanceField, spherical?, maxDistance?, minDistance?, query?, key?, distanceMultiplier?, includeLocs? })` sorts documents by their distance from a point and writes that distance into `distanceField`. `near` is the point to measure from, and Prisma ORM passes it through to MongoDB unchanged.
* `graphLookup({ from, startWith, connectFromField, connectToField, as, maxDepth?, depthField?, restrictSearchWithMatch? })` follows links from document to document through one collection and collects what it reaches into `as`. `startWith` is a raw expression.
* `setWindowFields({ partitionBy?, sortBy?, output })` computes a value for each document from the documents around it, such as a running total. `partitionBy` is a raw expression. `output` is an object mapping each new field name to `{ operator, window? }`, where `operator` is a raw expression, usually an accumulator: `{ runningTotal: { operator: MongoAggAccumulator.sum(MongoAggFieldRef.of('duration')), window: { documents: ['unbounded', 0] } } }`.
* `densify({ field, partitionByFields?, range })` adds documents to fill the gaps in a sequence of numbers or dates. `range` is `{ step, unit?, bounds }`, where `bounds` is `'full'`, `'partition'`, or a pair of start and end values.
* `fill({ partitionBy?, partitionByFields?, sortBy?, output })` replaces missing or null values with a value you choose. `partitionBy` is a raw expression. `output` is an object mapping each field name to `{ method }` or `{ value }`, where `value` is an expression and `method` is a string that Prisma ORM passes through to MongoDB unchanged.
* `facet(facets)` takes an object mapping each output field name to an array of stages.
* `unionWith(collection, pipeline?)` takes a collection name and an optional array of stages.
* The stages you pass to `facet` and `unionWith` are classes, one class per MongoDB stage, named `Mongo<Stage>Stage`. Import them, along with `MongoAggFieldRef` and `MongoAggAccumulator`, from `@prisma/orm-mongo/query-ast/execution`. Each class takes the same arguments as the MongoDB stage it builds. The three used below are `MongoCountStage(field)`, `MongoSortStage(spec)`, and `MongoLimitStage(n)`.

#### Examples [#examples-16]

##### Concatenate another collection with `unionWith()` [#concatenate-another-collection-with-unionwith]

```typescript
const plan = db.query.from('posts').unionWith('users').build();
const combined = await runtime.query(plan);
```

##### Run several sub-pipelines with `facet()` [#run-several-sub-pipelines-with-facet]

`MongoFieldFilter` is the filter class from `@prisma/orm-mongo/query-ast/execution`. See [MongoFieldFilter](https://www.prisma.io/docs/orm/reference/orm-client#mongofieldfilter) on the ORM client page for its methods, such as `gt` and `in`.

```typescript
import { MongoCountStage, MongoFieldFilter, MongoLimitStage, MongoMatchStage, MongoSortStage } from '@prisma/orm-mongo/query-ast/execution';

const plan = db.query
  .from('posts')
  .facet({
    totalCount: [new MongoCountStage('count')],
    newest: [new MongoSortStage({ createdAt: -1 }), new MongoLimitStage(2)],
    tutorials: [
      new MongoMatchStage(MongoFieldFilter.eq('kind', 'tutorial')),
      new MongoCountStage('count'),
    ],
  })
  .build();
const [facets] = await runtime.query(plan);
// facets.totalCount is [{ count: <number of posts> }]; facets.newest is the two newest posts
```

##### Sort into ranges with `bucket()` [#sort-into-ranges-with-bucket]

`MongoAggFieldRef.of()` takes any field path as a string and does not check it against your models. `duration` is a field on `Tutorial`, so posts without it fall into the `Other` bucket.

```typescript
import { MongoAggFieldRef } from '@prisma/orm-mongo/query-ast/execution';

const plan = db.query
  .from('posts')
  .bucket({
    groupBy: MongoAggFieldRef.of('duration'),
    boundaries: [0, 15, 60],
    default_: 'Other',
  })
  .build();
const buckets = await runtime.query(plan);
// one document per bucket, each { _id: <lower boundary>, count: n }
```

### Atlas-only stages [#atlas-only-stages]

`search()`, `searchMeta()`, and `vectorSearch()` build MongoDB Atlas Search stages (`$search`, `$searchMeta`, `$vectorSearch`).

#### Remarks [#remarks-14]

* These stages need MongoDB Atlas. Nothing stops you from building them against a database that is not on Atlas. The error only appears when you run the query.
* `search(config, index?)` takes an Atlas Search operator object, for example `{ text: { query: 'hello', path: 'title' } }`, and an optional `index`, which names the Atlas Search index to use.
* `searchMeta(config, index?)` takes the same two arguments and returns counts and facets instead of documents.
* `vectorSearch({ index, path, queryVector, numCandidates, limit, filter? })` takes the index name, the field holding the vectors, the vector to search for as an array of numbers, how many candidates to consider, how many documents to return, and an optional filter object.

#### Return type [#return-type-15]

| Return type      | Example                                                                      | Description                                                           |
| ---------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| Pipeline builder | `db.query.from('posts').search({ text: { query: 'hello', path: 'title' } })` | A builder with an Atlas Search stage. Executes only on MongoDB Atlas. |

## Accumulators [#accumulators]

Accumulators compute per-group values inside a [`group()`](#group) stage. `_id: null` in the examples below means one group holding every document. Import them from `@prisma/orm-mongo/query-builder`:

```typescript
import { acc } from '@prisma/orm-mongo/query-builder';
```

The builder exposes nineteen accumulators:

| Accumulator                          | Signature                        | Description                                                           |
| ------------------------------------ | -------------------------------- | --------------------------------------------------------------------- |
| `acc.count()`                        | `count()`                        | Number of documents in the group.                                     |
| `acc.sum(expr)`                      | `sum(expression)`                | Sum of the expression across the group.                               |
| `acc.avg(expr)`                      | `avg(expression)`                | Average of the expression.                                            |
| `acc.min(expr)`                      | `min(expression)`                | Minimum value.                                                        |
| `acc.max(expr)`                      | `max(expression)`                | Maximum value.                                                        |
| `acc.first(expr)`                    | `first(expression)`              | Value from the first document in the group.                           |
| `acc.last(expr)`                     | `last(expression)`               | Value from the last document in the group.                            |
| `acc.push(expr)`                     | `push(expression)`               | Array of the expression's value from every document.                  |
| `acc.addToSet(expr)`                 | `addToSet(expression)`           | Array of distinct values.                                             |
| `acc.firstN({ input, n })`           | `firstN({ input, n })`           | First `n` values.                                                     |
| `acc.lastN({ input, n })`            | `lastN({ input, n })`            | Last `n` values.                                                      |
| `acc.maxN({ input, n })`             | `maxN({ input, n })`             | The `n` largest values.                                               |
| `acc.minN({ input, n })`             | `minN({ input, n })`             | The `n` smallest values.                                              |
| `acc.top({ output, sortBy })`        | `top({ output, sortBy })`        | The `output` value from the document that sorts first under `sortBy`. |
| `acc.bottom({ output, sortBy })`     | `bottom({ output, sortBy })`     | The `output` value from the document that sorts last under `sortBy`.  |
| `acc.topN({ output, sortBy, n })`    | `topN({ output, sortBy, n })`    | The `output` values from the first `n` documents under `sortBy`.      |
| `acc.bottomN({ output, sortBy, n })` | `bottomN({ output, sortBy, n })` | The `output` values from the last `n` documents under `sortBy`.       |
| `acc.stdDevPop(expr)`                | `stdDevPop(expression)`          | Population standard deviation.                                        |
| `acc.stdDevSamp(expr)`               | `stdDevSamp(expression)`         | Sample standard deviation.                                            |

* `firstN`, `lastN`, `maxN`, and `minN` take `{ input, n }`. `input` is the expression whose values you collect.
* `top` and `bottom` take `{ output, sortBy }`. `topN` and `bottomN` take the same two plus `n`.
* `output` is the expression whose value you want back from each chosen document. `sortBy` is a plain object such as `{ createdAt: 1 }`, where `1` sorts ascending and `-1` sorts descending. Its keys are plain strings because they name fields, not values.
* Wherever a signature takes `n`, wrap the number: write `n: fn.literal(2)`, not `n: 2`. `fn.literal` comes from the [expression helpers](#expression-helpers) below.

**Put a `sort()` before the `group()` when you use `acc.first()` or `acc.last()`.** Without one, the document MongoDB calls first is arbitrary and can change between runs.

#### Examples [#examples-17]

##### `count()` and `sum()` [#count-and-sum]

`acc.sum(fn.literal(1))` adds 1 for each document, which counts them. To add up a field instead, pass the field, as in `acc.sum(f.views)` on a collection with a numeric `views` field. The example schema's `posts` has no such field, so that call needs a collection of your own.

```typescript
import { acc, fn } from '@prisma/orm-mongo/query-builder';

const plan = db.query.from('posts')
  .group((f) => ({ _id: null, total: acc.count(), counted: acc.sum(fn.literal(1)) })).build();
const [{ total, counted }] = await runtime.query(plan);
// { total: 2, counted: 2 }
```

##### `avg()`, `min()`, and `max()` [#avg-min-and-max]

```typescript
const plan = db.query.from('posts')
  .group((f) => ({ _id: null, earliest: acc.min(f.createdAt), avgYear: acc.avg(fn.year(f.createdAt)) }))
  .build();
const [stats] = await runtime.query(plan);
// { earliest: <Date>, avgYear: 2024 }
```

##### `first()` and `last()` [#first-and-last]

```typescript
const plan = db.query.from('posts').sort({ createdAt: 1 })
  .group((f) => ({ _id: null, firstTitle: acc.first(f.title), lastTitle: acc.last(f.title) }))
  .build();
const [{ firstTitle, lastTitle }] = await runtime.query(plan);
// { firstTitle: 'Hello world', lastTitle: 'Tutorial one' }
```

##### `push()` and `addToSet()` [#push-and-addtoset]

Both take one expression: `group((f) => ({ _id: null, allTitles: acc.push(f.title), distinctKinds: acc.addToSet(f.kind) }))`. `allTitles` holds one entry per document, while `distinctKinds` holds each value once.

##### `firstN()` (an `N`-variant) [#firstn-an-n-variant]

```typescript
const plan = db.query.from('posts').sort({ createdAt: 1 })
  .group((f) => ({
    _id: null,
    firstTwo: acc.firstN({ input: f.title, n: fn.literal(2) }),
    newestTitle: acc.top({ output: f.title, sortBy: { createdAt: -1 } }), // the title string, not a document
  }))
  .build();
const [{ firstTwo, newestTitle }] = await runtime.query(plan);
// firstTwo is ['Hello world', 'Tutorial one']
```

## Expression helpers [#expression-helpers]

Expression helpers (`fn.*`) build the computed values used inside stages like `addFields()`, `project()`, `group()` accumulators, and `match()` (via `expr()`). Inside a stage, write `f.title` or `fn.toUpper(...)`, never `'hello'` or `3` on their own, so wrap a constant in `fn.literal('hello')`. The update operators on the [write methods](#write-methods) and the `MongoFieldFilter` methods work the other way round: they take ordinary JavaScript values, so write `f.bio.set('hello')`, not `f.bio.set(fn.literal('hello'))`. Import the helpers from `@prisma/orm-mongo/query-builder`:

```typescript
import { fn } from '@prisma/orm-mongo/query-builder';
```

Each helper is the camelCase name of the MongoDB aggregation operator without its `$` prefix, so `$toUpper` is `fn.toUpper` and `$dateToString` is `fn.dateToString`. Five helpers are named differently:

| MongoDB operator     | Helper                           |
| -------------------- | -------------------------------- |
| `$in`                | `fn.isIn`                        |
| `$type`              | `fn.typeOf`                      |
| `$toString`          | `fn.toString_`                   |
| `$first` and `$last` | `fn.firstElem` and `fn.lastElem` |

The first three are renamed because `in` and `typeof` are reserved words in JavaScript and `toString` is already a method on every JavaScript object.

Here is every helper. Anything missing from this list has no helper, including `$and`, `$or`, `$not`, `$switch`, `$ifNull`, `$map`, `$reduce`, and `$filter`.

| Group                   | Helpers                                                                                                                                                        |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Arithmetic              | `add`, `subtract`, `multiply`, `divide`                                                                                                                        |
| Strings                 | `concat`, `toLower`, `toUpper`, `substr`, `substrBytes`, `trim`, `ltrim`, `rtrim`, `split`, `strLenCP`, `strLenBytes`, `replaceOne`, `replaceAll`              |
| Regular expressions     | `regexMatch`, `regexFind`, `regexFindAll`                                                                                                                      |
| Dates                   | `year`, `month`, `dayOfMonth`, `hour`, `minute`, `second`, `millisecond`, `dateToString`, `dateFromString`, `dateDiff`, `dateAdd`, `dateSubtract`, `dateTrunc` |
| Comparison              | `cmp`, `eq`, `ne`, `gt`, `gte`, `lt`, `lte`                                                                                                                    |
| Arrays                  | `size`, `arrayElemAt`, `concatArrays`, `firstElem`, `lastElem`, `isIn`, `indexOfArray`, `isArray`, `reverseArray`, `slice`, `zip`, `range`                     |
| Sets                    | `setUnion`, `setIntersection`, `setDifference`, `setEquals`, `setIsSubset`, `anyElementTrue`, `allElementsTrue`                                                |
| Type conversion         | `typeOf`, `convert`, `toInt`, `toLong`, `toDouble`, `toDecimal`, `toString_`, `toObjectId`, `toBool`, `toDate`                                                 |
| Objects                 | `objectToArray`, `arrayToObject`, `getField`, `setField`                                                                                                       |
| Constants and branching | `literal`, `cond`                                                                                                                                              |

`fn.literal(value)` wraps a constant so MongoDB reads it as a value and not as the name of a field. `.node` is the raw MongoDB expression inside an `fn.*` value, and a field reference such as `f.title` has one too. Passing an `expr(...)` value where `.node` is expected throws a `TypeError`. This table is the whole rule for when to write `.node`:

| Call site                                                                                                                                 | What you pass                            |
| ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| `project()`, `addFields()`, `redact()`, and the arguments of an accumulator                                                               | The `fn.*` value itself.                 |
| The condition argument of `fn.cond()`                                                                                                     | Its `.node` property.                    |
| `f.stage.set()`, `f.stage.replaceRoot()`, and `f.stage.replaceWith()`, documented under [Update operation forms](#update-operation-forms) | The `.node` property.                    |
| The `groupBy`, `startWith`, and `partitionBy` options of `bucket()`, `bucketAuto()`, `graphLookup()`, `setWindowFields()`, and `fill()`   | The `.node` property.                    |
| `match()`                                                                                                                                 | The `fn.*` value wrapped in `expr(...)`. |

`expr()` is what lets a `match()` filter compare computed values. Import it beside `fn`:

```typescript
import { expr, fn } from '@prisma/orm-mongo/query-builder';

const plan = db.query.from('posts').match((f) => expr(fn.gt(fn.year(f.createdAt), fn.literal(2024)))).build();
```

For OR, AND, or NOT, pass `match()` a filter you build yourself instead of a callback:

```typescript
import { MongoAndExpr, MongoFieldFilter, MongoOrExpr } from '@prisma/orm-mongo/query-ast/execution';

const kindFilter = MongoOrExpr.of([
  MongoFieldFilter.eq('kind', 'tutorial'),
  MongoFieldFilter.eq('kind', 'guide'),
]);
const plan = db.query.from('posts').match(kindFilter).build();
const rows = await runtime.query(plan);
// rows are the documents whose kind is either tutorial or guide
```

#### Remarks [#remarks-15]

* There is no `fn.*` helper for OR, AND, or NOT. In a `match()` filter, build the filter yourself: `MongoOrExpr.of([...])` is OR, `MongoAndExpr.of([...])` is AND, and `.not()` on any filter is NOT. The example above shows OR.
* Each entry in those lists is a `MongoFieldFilter`, which has `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `isNull`, and `isNotNull`. These are the same filter methods the ORM client uses, described under [Combinators](https://www.prisma.io/docs/orm/reference/orm-client#combinators). A filter you build yourself names the field as a string, as in `MongoFieldFilter.eq('kind', 'tutorial')`, and nothing checks that string against your model.
* "Not equal" has two spellings on this page. The filter method is `MongoFieldFilter.neq` and the expression helper is `fn.ne`.
* Inside a computed value in `project()` or `addFields()` there is no way to write OR, AND, or NOT. Write that stage yourself with [`pipe()`](#pipe), or write the whole command with [`rawCommand()`](#rawcommand).
* `fn.slice(array, ...rest)` and `fn.range(start, end, step)` take positional arguments, and so does every helper not listed in the table below. This page does not give the positional order for those helpers. Look each one up in [MongoDB's aggregation operator reference](https://www.mongodb.com/docs/manual/reference/operator/aggregation/). Each argument is an expression from the `f` argument or a `fn.literal(...)` value.
* **`fn.toObjectId()` cannot take a `fn.literal()` value.** `fn.toObjectId(fn.literal(id))` throws a `TypeError`. There is no way to turn a string id into an `ObjectId` inside a pipeline. Build the `ObjectId` in your own code instead and put it in a raw `$match` with [`rawCommand()`](#rawcommand), as the last example on this page does.

These helpers take one object of named arguments instead of positional ones:

| Helper                                                 | Arguments                                               |
| ------------------------------------------------------ | ------------------------------------------------------- |
| `fn.dateDiff`                                          | `{ startDate, endDate, unit, timezone?, startOfWeek? }` |
| `fn.dateTrunc`                                         | `{ date, unit, binSize?, timezone?, startOfWeek? }`     |
| `fn.dateAdd`                                           | `{ startDate, unit, amount, timezone? }`                |
| `fn.dateSubtract`                                      | The same keys as `fn.dateAdd`.                          |
| `fn.dateToString`                                      | `{ date, format?, timezone?, onNull? }`                 |
| `fn.dateFromString`                                    | `{ dateString, format?, timezone?, onError?, onNull? }` |
| `fn.trim`, `fn.ltrim`, and `fn.rtrim`                  | `{ input, chars? }`                                     |
| `fn.regexMatch`, `fn.regexFind`, and `fn.regexFindAll` | `{ input, regex, options? }`                            |
| `fn.replaceOne` and `fn.replaceAll`                    | `{ input, find, replacement }`                          |
| `fn.zip`                                               | `{ inputs, useLongestLength?, defaults? }`              |
| `fn.getField`                                          | `{ field, input? }`                                     |
| `fn.setField`                                          | `{ field, input, value }`                               |
| `fn.convert`                                           | `{ input, to, onError?, onNull? }`                      |

In `fn.convert`, `to` takes any MongoDB type name written as an expression, such as `fn.literal('int')` or `fn.literal('objectId')`.

#### Examples [#examples-18]

##### Arithmetic in a projection [#arithmetic-in-a-projection]

```typescript
const plan = db.query.from('posts')
  .project((f) => ({ title: 1, computed: fn.add(fn.literal(1), fn.multiply(fn.literal(2), fn.literal(3))) }))
  .build();
const rows = await runtime.query(plan);
// computed is 7 for every document
```

##### String composition [#string-composition]

`project((f) => ({ shout: fn.concat(fn.toUpper(f.title), fn.literal('!')) }))` puts the title in upper case next to a `!`.

##### Branch with `cond()` [#branch-with-cond]

```typescript
const plan = db.query.from('posts')
  .project((f) => ({
    title: 1,
    label: fn.cond(fn.eq(f.kind, fn.literal('tutorial')).node, fn.literal('is-tutorial'), fn.literal('not-tutorial')),
  }))
  .build();
const rows = await runtime.query(plan);
```

### `pipe()` [#pipe]

Append an arbitrary raw pipeline stage the typed methods don't cover.

#### Remarks [#remarks-16]

* `pipe(stage)` appends a raw stage that you construct yourself, and keeps the row type you already had. The stages are the `Mongo*Stage` classes, one per MongoDB stage, from `@prisma/orm-mongo/query-ast/execution`. The class name is `Mongo`, then the stage name without its `$`, then `Stage`, so `$unwind` is `MongoUnwindStage`. The example below uses `MongoMatchStage` and `MongoCountStage`. The same module exports `MongoFieldFilter`, which builds the filter a `MongoMatchStage` takes.
* `pipe<NewShape>(stage)` declares the row type the rows have after that stage. `NewShape` is a type you write yourself, as at the end of the example below.
* After a `pipe()` stage the TypeScript type no longer describes the rows. They come back exactly as MongoDB returns them, so a date is a `Date` and an `_id` that MongoDB generated is an `ObjectId` from the `mongodb` package, the driver Prisma ORM runs your queries through.
* Prefer a typed stage where one exists. `pipe()` adds one raw stage to a typed chain, and [`rawCommand()`](#rawcommand) replaces the whole command.

#### Examples [#examples-19]

##### Append a raw stage [#append-a-raw-stage]

```typescript
import { MongoCountStage, MongoFieldFilter, MongoMatchStage } from '@prisma/orm-mongo/query-ast/execution';

const plan = db.query.from('posts')
  .pipe(new MongoMatchStage(MongoFieldFilter.eq('kind', 'tutorial'))).build();
const rows = await runtime.query(plan);

type Counted = { total: number };
const countPlan = db.query.from('posts').pipe<Counted>(new MongoCountStage('total')).build();
```

## Read methods [#read-terminals]

Finish a read chain with `build()`, then run the built query with `runtime.query(...)`.

### `build()` and `aggregate()` [#build-and-aggregate]

Compile the pipeline into a query you can run.

#### Remarks [#remarks-17]

* Write `build()`. `aggregate()` is another name for the same method. Neither runs the query: pass the result to `runtime.query(...)` to fetch documents.

## Write methods [#write-methods]

The pipeline builder can write, not just read. Write methods are available at three points: on the root collection, after a `match()` filter, and at the end of any pipeline, where `out()` and `merge()` write the output into a collection. A write method returns the built query on its own, so there is no `build()` call after one. The examples below name that built query `plan`.

Updater callbacks (the `(f) => [...]` argument to the update methods) must return an **array** of operations. This is a firm rule:

* Always return an array. Returning a bare operation, `f.bio.set('x')` rather than `[f.bio.set('x')]`, throws as soon as you call the write method.
* An empty array throws an error whose `code` is `ORM.MUTATION_DATA_MISSING`: `Updater returned no operations. Return at least one update from the callback ...`.
* An updater is either all operator form or all pipeline form. Operator form calls an operator on a field, as in `f.bio.set(value)`. Pipeline form can read other fields of the same document, and it calls `f.stage.*`. Type `f.stage` exactly: `stage` is not a placeholder for a stage name. You cannot mix the two in one updater. TypeScript rejects the mixed array, and at run time it throws an error whose `code` is `ORM.ARGUMENT_INVALID`: `Cannot mix ...`.
* Applying the same operator to the same field twice in one updater throws an error whose `code` is `ORM.ARGUMENT_INVALID`: `Update spec collision: ...`.

### Root-level writes [#root-level-writes]

`insertOne`, `insertMany`, `updateAll`, `deleteAll`, and `upsertOne` are available on the collection you name in `from(...)`, before you add any stage.

#### Remarks [#remarks-18]

* These return a built query. Run it with `runtime.query(...)`.
* Write results are result objects, not documents: `insertOne` gives `{ insertedId }`, `insertMany` gives `{ insertedIds, insertedCount }`, the update methods and `upsertOne` give `{ matchedCount, modifiedCount }`, plus `upsertedCount` and `upsertedId` when an upsert inserted a document, and the delete methods give `{ deletedCount }`. A write returns one result object, as the single row of the result, which is why every example here reads it with `const [result] = ...`.
* The document you pass to `insertOne` / `insertMany` is a plain record. TypeScript requires no particular field, and the builder does not check the record against your contract. You can leave nullable fields out. The examples below pass `null` for them to make the document shape explicit.
* You can leave `_id` out and let MongoDB assign one.
* **On the way in, values are stored exactly as you pass them, so pass a `Date` for a date field and an `ObjectId` from the `mongodb` package for an id field.** Nothing turns a string into either. This is the write direction only. Reads are decoded as the first half of this page describes.
* [`match()`](#match) filter values follow the same rule as the values you insert. The one value you cannot filter on this way is `_id`. An `_id` filter written in `match()` never matches anything, so use [`rawCommand()`](#rawcommand) instead. The [`match()`](#match) warning gives the detail, and the last example on this page shows the form that works.
* `insertMany([])` throws an error whose `code` is `ORM.MUTATION_DATA_MISSING`.

#### Examples [#examples-20]

##### `insertOne()` and `insertMany()` [#insertone-and-insertmany]

```typescript
const onePlan = db.query.from('users')
  .insertOne({ name: 'Carol', email: 'carol@example.com', bio: null, role: 'author', address: null });
const [insertOneResult] = await runtime.query(onePlan);
// { insertedId: <ObjectId> }

const manyPlan = db.query.from('users').insertMany([
  { name: 'Carol', email: 'carol@example.com', bio: null, role: 'author', address: null },
  { name: 'Dave', email: 'dave@example.com', bio: null, role: 'reader', address: null },
]);
const [insertManyResult] = await runtime.query(manyPlan);
// { insertedIds: [<ObjectId>, <ObjectId>], insertedCount: 2 }
```

##### `updateAll()` (array-of-ops updater) [#updateall-array-of-ops-updater]

`db.query.from('users').updateAll((f) => [f.bio.set('everyone now has bio')])` builds the update. Pass it to `runtime.query(...)` to run it.

##### `deleteAll()` [#deleteall]

`db.query.from('users').deleteAll()` builds a delete for every document. Pass it to `runtime.query(...)` and read `deletedCount` from the single result object.

##### `upsertOne()` on the root (filter, then updater) [#upsertone-on-the-root-filter-then-updater]

`upsertOne(filterCallback, updaterCallback)`. The first callback returns the filter, and the second returns the array of update operations.

```typescript
const plan = db.query.from('users')
  .upsertOne((f) => f.email.eq('erin@example.com'), (f) => [f.name.set('Erin'), f.email.set('erin@example.com')]);
const [result] = await runtime.query(plan);
// inserts when no document matches: result.upsertedId is defined
```

### Writes after `match()` [#writes-after-match]

After a `match()` filter, `updateMany`, `updateOne`, `deleteMany`, `deleteOne`, `upsertOne`, `findOneAndUpdate`, and `findOneAndDelete` write against the matched documents.

#### Remarks [#remarks-19]

* The `match()` filter supplies the write's filter, so you do not repeat it.
* After `match()`, `upsertOne()` takes the updater callback only (the filter comes from `match()`).
* `updateOne` / `deleteOne` affect at most one matching document. `updateMany` / `deleteMany` affect all matches. Which document that is, this builder gives you no way to choose.
* `findOneAndUpdate()` and `findOneAndDelete()` return the document exactly as the `mongodb` driver gives it, so its `_id` is an `ObjectId` from the `mongodb` package even though the TypeScript type says `string`. To get the id as a string, write `String(result._id)`.
* `findOneAndUpdate()` and `findOneAndDelete()` are offered straight after `match()` and nowhere else. TypeScript withdraws them after every other stage, `sort()` and `skip()` included. If a cast gets one past TypeScript after a `skip()`, it throws an error whose `code` is `ORM.OPERATION_UNSUPPORTED`.

#### Examples [#examples-21]

##### `updateMany()` and `updateOne()` [#updatemany-and-updateone]

```typescript
const manyPlan = db.query.from('users').match((f) => f.role.eq('author'))
  .updateMany((f) => [f.bio.set('matched-many')]);
await runtime.query(manyPlan);

const onePlan = db.query.from('users').match((f) => f.email.eq('alice@example.com'))
  .updateOne((f) => [f.bio.set('single-update')]);
const [result] = await runtime.query(onePlan);
// { matchedCount: 1, modifiedCount: 1 }
```

##### `deleteMany()` and `deleteOne()` [#deletemany-and-deleteone]

```typescript
const plan = db.query.from('users').match((f) => f.role.eq('author')).deleteMany();
const [result] = await runtime.query(plan);
// { deletedCount: 2 }
```

##### `upsertOne()` after `match()` (updater only) [#upsertone-after-match-updater-only]

`db.query.from('users').match((f) => f.email.eq('alice@example.com')).upsertOne((f) => [f.bio.set('upserted via match')])` builds the upsert. On a hit, `result.modifiedCount` is 1.

##### `findOneAndUpdate()` and `returnDocument` [#findoneandupdate-and-returndocument]

`findOneAndUpdate()` returns the matched document. Its second argument is optional and takes `returnDocument`, which controls which version you get back: `'before'` returns the document before the update, `'after'` returns it after. The default is `'after'`. The same argument takes `upsert`, which defaults to `false` and inserts a document when nothing matches.

```typescript
const plan = db.query.from('users').match((f) => f.email.eq('alice@example.com'))
  .findOneAndUpdate((f) => [f.bio.set('changed')], { returnDocument: 'before' });
const [beforeDoc] = await runtime.query(plan);
// beforeDoc.bio is the value from before the update
```

> [!WARNING]
> The option is
> 
> `returnDocument`
> 
> , not
> 
> `returnNewDocument`
> 
> Use `returnDocument: 'before' | 'after'`. `returnNewDocument` is not a valid option name, so TypeScript rejects it and suggests `returnDocument`. If a cast gets it past TypeScript, the unknown key is ignored and you silently get the default `'after'`.

##### `findOneAndDelete()` [#findoneanddelete]

`db.query.from('users').match((f) => f.email.eq('alice@example.com')).findOneAndDelete()` builds the delete. Its single result row is the removed document.

### Update operation forms [#update-operation-forms]

Inside an updater callback, each operation targets a field. There are two mutually exclusive forms.

#### Remarks [#remarks-20]

* **Operator form**: call an operator on the `f` argument, one operator per field. There are fourteen, in the table below.
* **Pipeline form**: aggregation-pipeline update stages through `f.stage.*`, for example `f.stage.set({ bio: f.name.node })`. The four stages are `set`, `unset`, `replaceRoot`, and `replaceWith`.
* The two forms cannot be mixed in a single updater (see the write-methods intro). An updater is entirely operator form or entirely pipeline form.

Operator form takes these arguments:

| Operator             | What you pass                                                                                         |
| -------------------- | ----------------------------------------------------------------------------------------------------- |
| `set(value)`         | The new value.                                                                                        |
| `unset()`            | Nothing. Removes the field.                                                                           |
| `rename(newName)`    | The new field name, as a string.                                                                      |
| `inc(amount)`        | A number to add. A negative number subtracts.                                                         |
| `mul(factor)`        | A number to multiply the stored value by.                                                             |
| `min(value)`         | A value, written only if it is lower than the stored one.                                             |
| `max(value)`         | A value, written only if it is higher than the stored one.                                            |
| `push(value)`        | One value to append to an array field.                                                                |
| `addToSet(value)`    | One value, appended only if the array does not already hold it.                                       |
| `pop(direction)`     | `1` removes the last element, `-1` the first. The argument is optional and defaults to `1`.           |
| `pull(value)`        | The value to remove from an array field.                                                              |
| `pullAll(values)`    | An array of values to remove.                                                                         |
| `currentDate()`      | Nothing. Writes the current date.                                                                     |
| `setOnInsert(value)` | A value written only when an upsert inserts a new document, so it does nothing outside `upsertOne()`. |

#### Examples [#examples-22]

##### Operator form [#operator-form]

```typescript
const plan = db.query.from('users').match((f) => f.role.eq('author'))
  .updateMany((f) => [f.bio.set('operator form')]);
await runtime.query(plan);
// on a collection with a numeric views field and an array tags field (posts has neither):
// updateMany((f) => [f.views.inc(1), f.tags.push('mongodb')])
```

##### Pipeline form (`f.stage.*`) [#pipeline-form-fstage]

```typescript
const plan = db.query.from('users').match((f) => f.role.eq('author'))
  .updateMany((f) => [f.stage.set({ bio: f.name.node })]);
await runtime.query(plan);
// each author's bio is set to that author's own name
```

### Pipeline write methods: `out()` and `merge()` [#pipeline-write-terminals-out-and-merge]

`out()` and `merge()` write the pipeline's output into a collection (`$out` / `$merge`).

#### Remarks [#remarks-21]

* `out(collection)` writes the pipeline output into a destination collection, replacing its contents. Pass a second argument, the database name as a string, to write into a different database: `out('users_snapshot', 'archive')`.
* `merge({ into })` writes the pipeline output into a target collection, merging with existing documents. `into` is a collection name or `{ db, coll }`. The options object also takes `on`, which is one field name as a string or several as an array of strings, plus `whenMatched` and `whenNotMatched`.
* `whenMatched` takes `'replace'`, `'keepExisting'`, `'merge'`, or `'fail'`, or an array of update stages, which are `MongoAddFieldsStage`, `MongoProjectStage`, and `MongoReplaceRootStage` objects from `@prisma/orm-mongo/query-ast/execution`. `MongoAddFieldsStage` takes one object of field names and expressions, as in `new MongoAddFieldsStage({ ... })`. `whenNotMatched` takes `'insert'`, `'discard'`, or `'fail'`. A misspelled value fails at the database rather than in TypeScript.
* Both end the chain. They return a built query you run with `runtime.query(...)`, and that call returns an empty array, because the output goes to the destination collection and not to your program.

#### Examples [#examples-23]

##### Write the output with `out()` [#write-the-output-with-out]

`db.query.from('users').out('users_snapshot')` builds the write. After you pass it to `runtime.query(...)`, the `users_snapshot` collection holds the pipeline output.

##### Merge with `merge()` [#merge-with-merge]

```typescript
const plan = db.query.from('users')
  .merge({ into: 'users_archive', on: 'email', whenMatched: 'merge', whenNotMatched: 'insert' });
await runtime.query(plan);
```

## `rawCommand()` [#rawcommand]

Run a raw MongoDB aggregate command through the pipeline builder.

#### Remarks [#remarks-22]

* `db.query.rawCommand(command)` takes a command you build yourself, for example `new RawAggregateCommand(collection, pipeline)`, and sends it as you wrote it. The rows come back as `unknown`, so you type them yourself.
* Use it for anything the typed builder cannot express, including `_id` equality filters (see the [`match()`](#match) warning) and MongoDB's `$redact` stage.
* For the full raw MongoDB API (raw collection methods, untyped writes, and rows that come back as the driver gives them), see [Raw queries](https://www.prisma.io/docs/orm/reference/raw-queries).

#### Examples [#examples-24]

##### Run a raw aggregate pipeline [#run-a-raw-aggregate-pipeline]

```typescript
import { RawAggregateCommand } from '@prisma/orm-mongo/query-ast/execution';

const plan = db.query.rawCommand(new RawAggregateCommand('posts', [{ $count: 'total' }]));
const rows = await runtime.query(plan);
// [{ total: 2 }]
```

##### Filter by `_id` (the way that works) [#filter-by-_id-the-way-that-works]

```typescript
import { ObjectId } from 'mongodb';

const plan = db.query.rawCommand(
  new RawAggregateCommand('posts', [{ $match: { _id: new ObjectId(postId) } }]),
);
const rows = await runtime.query(plan);
// a real ObjectId in a raw pipeline document matches correctly
```

## Related pages

- [`Error reference`](https://www.prisma.io/docs/orm/reference/error-reference): Every structured error code Prisma ORM can emit, by namespace, with the condition that raises it.
- [`Migration API`](https://www.prisma.io/docs/orm/reference/migration-api): Every method and helper a migration.ts can use: the Migration class, the PostgreSQL operations, the column and constraint helpers, rawSql, and the MongoDB operations.
- [`ORM client reference`](https://www.prisma.io/docs/orm/reference/orm-client): Reference for the Prisma ORM client's query, mutation, filter, and aggregate methods.
- [`Raw queries reference`](https://www.prisma.io/docs/orm/reference/raw-queries): Reference for Prisma ORM raw queries: PostgreSQL raw SQL and MongoDB raw commands.
- [`SQL query builder reference`](https://www.prisma.io/docs/orm/reference/sql-query-builder): Reference for the Prisma ORM SQL query builder's select, mutation, and grouped query methods.

# Raw queries reference (/docs/orm/reference/raw-queries)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Reference for Prisma ORM raw queries: PostgreSQL raw SQL and MongoDB raw commands.

Location: ORM > Reference > Raw queries reference

Raw queries are the way out when the typed APIs can't express the query you need. Reach for a typed API first: the [ORM client](https://www.prisma.io/docs/orm/reference/orm-client) for everyday reads and writes, the [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder) for PostgreSQL joins and aggregates, and the [pipeline builder](https://www.prisma.io/docs/orm/reference/pipeline-builder) for MongoDB aggregation. When none of them reaches the SQL clause or MongoDB command you need, drop down to raw.

There are two kinds of raw query: **PostgreSQL raw SQL** (the `fns.raw` tagged template for fragments and the `db.raw.sql` tag for whole statements) and **MongoDB raw commands** (`db.raw.collection(...)` and `db.query.rawCommand(...)`).

## PostgreSQL raw SQL [#postgresql-raw-sql]

Raw SQL comes in two forms.

A **raw fragment** is a piece of SQL you put inside a builder query. Write it as a tagged template with `fns.raw` and pass it to a `select()`, `where()`, `orderBy()`, or `update()` call. The rest of the query stays typed.

A **whole raw statement** is a complete SQL statement written with `db.raw.sql`. If it returns rows, end it with `.returnsRow(spec).build()`, where the spec is a column list [defined below](#the-client-level-dbrawsql-tag), and pass the result to `runtime.query(...)`. If it does not, end it with `.affectedCount().build()` and pass the result to `runtime.execute(...)`.

> [!WARNING]
> Only
> 
> `.returnsRow()`
> 
>  converts values for you
> 
> A type id such as `pg/text@1` tells Prisma ORM what JavaScript type a column should become, and the property is named `codecId`. `.returnsRow(spec)` names a type id for every column of a whole `db.raw.sql` statement, so you get real JavaScript values back. A fragment's `.returns(...)` does not convert anything: it only tells TypeScript what type to expect, so the value is whatever the `pg` package, the PostgreSQL driver underneath, gives you. For a `text` or an `integer` column that is already a JavaScript string or number, while a `numeric` column arrives as a string. A date column gets no conversion by Prisma ORM, so you get the `pg` package's own value for that column.

The examples in this section run against the `user` / `post` schema from the SQL query builder page. See its [example schema](https://www.prisma.io/docs/orm/reference/sql-query-builder#example-schema) for the full model definitions. As on that page, create the client with `postgres(...)` and reach tables through `db.sql.public`, which is keyed by table name (the model name exactly as written, unless the model sets the `@@map` attribute, which renames a table). `db.runtime()` gives you the connection that runs a built query.

```ts
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };
const db = postgres<Contract>({ contractJson, url: process.env.DATABASE_URL });
const runtime = db.runtime();
const aliceId = '00000000-0000-4000-8000-000000000001';
```

### `fns.raw` in a projection [#fnsraw-in-a-projection]

A projection is the `select()` list. A `select()` callback receives two arguments: `f`, with one property per column, and `fns`, with the expression helpers. `fns.raw` is a tagged template. Write a SQL fragment, interpolate columns and values with `${...}`, and declare the fragment's result type with `.returns(typeId)`. See [`select()`](https://www.prisma.io/docs/orm/reference/sql-query-builder#select) for every form it accepts.

```ts
const plan = db.sql.public.user
  .select('id')
  .select('upperEmail', (f, fns) => fns.raw`UPPER(${f.email})`.returns('pg/text@1'))
  .where((f, fns) => fns.eq(f.id, aliceId))
  .build();
const rows = await runtime.query(plan);
// rows === [{ id: aliceId, upperEmail: 'ALICE@EXAMPLE.COM' }]
```

`.returns(...)` only tells TypeScript what to expect: it does not cast the value in SQL and it does not change how the `pg` package reads it. It takes a type id string, or an object of the form `{ codecId, nullable }`. See [Binding a bare value with `param()`](#binding-a-bare-value-with-param) for the type ids you are most likely to write, and the SQL query builder's [`fns.raw` and `.returns()`](https://www.prisma.io/docs/orm/reference/sql-query-builder#fnsraw-and-returns) for the full treatment.

### `fns.raw` as a `where()` predicate [#fnsraw-as-a-where-predicate]

`where()`'s callback returns a boolean expression, the same thing the comparison helpers such as `fns.eq(...)` return. A raw fragment that declares `.returns('pg/bool@1')` is itself a boolean expression, so you can pass it straight to `where()` without wrapping it in `fns.eq(...)`.

```ts
const plan = db.sql.public.user
  .select('id', 'email')
  .where((f, fns) => fns.raw`LENGTH(${f.email}) > 15`.returns('pg/bool@1'))
  .build();
const rows = await runtime.query(plan);
// only users whose email is longer than 15 characters
```

### Interpolating a typed expression [#interpolating-a-typed-expression]

You can interpolate another expression, such as a comparison, a column reference, or another raw fragment. The expression itself goes into the fragment, not its rendered SQL, so it stays type-checked. An interpolated value is sent as a query parameter, never pasted into the SQL. A column or table name cannot be interpolated as a string, because a string becomes a parameter. When the column is chosen at run time, pick it in your own code from a fixed set of columns you control, and choose the matching `fns.raw` fragment or `select()` call for each one.

```ts
const plan = db.sql.public.user
  .select('id', 'kind')
  .select('kindLabel', (f, fns) => fns.raw`CASE WHEN ${fns.eq(f.kind, 'admin')} THEN 'admin' ELSE 'regular user' END`.returns('pg/text@1'))
  .build();
const rows = await runtime.query(plan);
// each row's kindLabel is 'admin' or 'regular user'
```

### Binding a bare value with `param()` [#binding-a-bare-value-with-param]

Interpolate a plain `number`, `string`, `boolean`, `bigint`, or `Uint8Array` directly. For anything else, such as a point in time or a decimal you want stored as `numeric`, wrap the value in `param(value, { codecId })` and name the type id yourself. Import `param` from `@prisma/orm-postgres/relational-core/expression`.

A bare value that you do interpolate directly gets the type id Prisma ORM picks from its JavaScript type:

| The value you interpolate                           | The type id it gets                               |
| --------------------------------------------------- | ------------------------------------------------- |
| a whole `number` from `-2147483648` to `2147483647` | `pg/int4@1`                                       |
| a larger whole `number`, up to `9007199254740991`   | `pg/int8number@1`, which reads back as a `number` |
| any other `number`, including a fractional one      | `pg/float8@1`                                     |
| a `bigint`                                          | `pg/int8@1`, which reads back as a `bigint`       |
| a `string`                                          | `pg/text@1`                                       |
| a `boolean`                                         | `pg/bool@1`                                       |
| a `Uint8Array`                                      | `pg/bytea@1`                                      |

A type id is `pg/`, a name, and `@1`. The name is usually the PostgreSQL type, and a few carry a suffix that says which JavaScript type you get, such as `pg/int8number@1` for a `number` and `pg/timestamptz-temporal@1` for a `Temporal.Instant`. Between those two, pick `pg/int8@1` when the value can exceed 2^53. Three more you are likely to write are `pg/uuid@1`, `pg/numeric@1`, and `pg/jsonb@1`. Those are the common ones, not the whole set. For any column, `db.sql.public.<table>.columns.<column>.codecId` is its id, and the same ids are in `contract.json` under `storage.namespaces.<schema>.entries.table.<table>.columns.<column>.codecId`. A point in time is the case `param()` exists for, and `pg/timestamptz-temporal@1` takes a `Temporal.Instant`, the standard JavaScript object for a point in time, not a `Date`. `Temporal` is a global in Node.js 26.8.2 and later, and on earlier versions you install `temporal-polyfill` and add `import 'temporal-polyfill/full/global'`.

```ts
import { param } from '@prisma/orm-postgres/relational-core/expression';

const cutoff = param(Temporal.Instant.from('2024-01-01T00:00:00Z'), { codecId: 'pg/timestamptz-temporal@1' });
const plan = db.sql.public.user
  .select('id', 'email')
  .where((f, fns) => fns.raw`${f.createdAt} > ${cutoff}`.returns('pg/bool@1'))
  .build();
const rows = await runtime.query(plan);
// users created after the start of 2024
```

### Declaring a nullable result [#declaring-a-nullable-result]

The object form of `.returns()` declares a nullable result. Use it when a fragment can evaluate to SQL `NULL`, so the result type is `T | null`.

```ts
const plan = db.sql.public.user
  .select('id')
  .select('adminName', (f, fns) => fns.raw`CASE WHEN ${fns.eq(f.kind, 'admin')} THEN ${f.displayName} END`.returns({ codecId: 'pg/text@1', nullable: true }))
  .build();
const rows = await runtime.query(plan);
// adminName is the displayName for admins, null for everyone else
```

### The client-level `db.raw.sql` tag [#the-client-level-dbrawsql-tag]

`db.raw` is the client's raw API, beside `db.sql` and `db.orm`. On PostgreSQL it holds `sql`, the same tagged template as `fns.raw`. On MongoDB it holds `collection(...)` instead, which the [MongoDB raw commands](#mongodb-raw-commands) section covers. Unlike `fns.raw`, `db.raw.sql` works outside a builder callback, and it has the extra methods that turn a whole statement into a query you can run.

Use `.returns(...)` to build an expression ahead of time and pass it to the object form of [`select()`](https://www.prisma.io/docs/orm/reference/sql-query-builder#select), which names each output column:

```ts
const serverNow = db.raw.sql`now()`.returns('pg/timestamptz-temporal@1');
const plan = db.sql.public.user
  .select((f) => ({ id: f.id, serverNow }))
  .where((f, fns) => fns.eq(f.id, aliceId))
  .build();
const rows = await runtime.query(plan);
```

Use `.returnsRow(spec)` to run a whole statement and get converted rows back. The spec names the columns of every returned row, and each entry is either a column from your contract or a type id. A column such as `db.sql.public.user.columns.id` brings its own conversion, nullability, and TypeScript type. Write a type id for a column your contract has no match for, and the object form `{ codecId: 'pg/text@1', nullable: true }` when that column can be `NULL`, as a `LEFT JOIN` column can. If a returned row has no column your spec names, the query throws an error whose `code` is `RUNTIME.RAW_ROW_COLUMN_MISSING`. A failing statement throws a `SqlQueryError` whose `sqlState` is the PostgreSQL error code for the failure, such as `23505` for a unique-constraint violation.

```ts
const user = db.sql.public.user;
const post = db.sql.public.post;

const plan = db.raw.sql`
  SELECT u.id, u.email, count(p.id) AS "postCount"
  FROM "user" u
  LEFT JOIN "post" p ON p."userId" = u.id
  GROUP BY u.id, u.email
  ORDER BY count(p.id) DESC, u.email ASC
  LIMIT ${10}
`
  .returnsRow({ id: user.columns.id, email: user.columns.email, postCount: 'pg/int8@1' })
  .build();

const rows = await runtime.query(plan);
// row.email is a string; row.postCount is a bigint
```

Use `.affectedCount()`, which takes no spec, for a statement that returns no rows. Pass the built query to `runtime.execute(...)`, which resolves to `{ affectedRows }`, the number of rows the statement changed. You can also run a built raw query inside a transaction: [`db.transaction()`](https://www.prisma.io/docs/orm/reference/transactions-and-runtime#dbtransactioncallback) gives you a `tx`, and `tx.query(...)` and `tx.execute(...)` take the same built queries as `runtime.query(...)` and `runtime.execute(...)` do.

```ts
const plan = db.raw.sql`
  UPDATE "post"
  SET priority = ${'urgent'}
  WHERE "userId" IN (SELECT id FROM "user" WHERE kind = ${'admin'})
`.affectedCount().build();

const stats = await runtime.execute(plan);
// stats.affectedRows
```

You can nest a `.returnsRow()` query inside another: that is how you write a subquery or a CTE, which is a `WITH` query. Interpolate it before `.build()`, and call `.build()` on the outer one only. Its `.returns` property holds its declared columns, so `outer.returnsRow({ postCount: inner.returns.postCount })` reuses a declaration. You cannot nest a statement that ends with `.affectedCount()`, because it produces no rows. You can nest an `UPDATE ... RETURNING`, because it does.

> [!NOTE]
> Three names look alike
> 
> `.returns(typeId)` is a method on a fragment, `.returnsRow(spec)` is a method on a statement, and `.returns` is a property on the object `.returnsRow()` gives you.

```ts
const authorsWithPosts = db.raw.sql`
  SELECT p."userId" AS "userId", count(*) AS "postCount"
  FROM "post" p
  GROUP BY p."userId"
  HAVING count(*) >= ${3}
`.returnsRow({ userId: post.columns.userId, postCount: 'pg/int8@1' });

const plan = db.raw.sql`
  WITH active AS (${authorsWithPosts})
  SELECT u.email, active."postCount"
  FROM active
  JOIN "user" u ON u.id = active."userId"
  ORDER BY active."postCount" DESC, u.email ASC
`.returnsRow({ email: user.columns.email, postCount: authorsWithPosts.returns.postCount }).build();
```

### Unsupported interpolation [#unsupported-interpolation]

Interpolation accepts columns, expressions, `param(...)` values, raw queries that return rows, and the bare types `number`, `bigint`, `string`, `boolean`, and `Uint8Array`. Interpolating anything else, such as a `Date`, is rejected by TypeScript when you compile. In plain JavaScript the tagged template throws as soon as you call it, with an error whose `code` is `RUNTIME.RAW_SQL_UNSUPPORTED_INTERPOLATION` and this message:

```
unsupported JS value type for raw-SQL interpolation: wrap this value in `param(...)` with an explicit codec
```

To bind any value whose type is not in the list, wrap it in [`param(value, { codecId })`](#binding-a-bare-value-with-param) with the right type id. For a `Date`, convert it to a `Temporal.Instant` first and bind that.

## MongoDB raw commands [#mongodb-raw-commands]

`db.raw.collection(collectionName)` returns an object with nine methods for running MongoDB commands directly against a collection. The collection name is the one your contract declares (`'users'`, `'posts'`), the same name the ORM client uses (`db.orm.users`). MongoDB has no schemas, so there is no `public` segment here and none on `db.orm`. There is no raw `find()`, so use `aggregate<Row>()` with a `$match` stage. MongoDB has no transactions in Prisma ORM, so a raw command cannot run inside one. See [Transactions (MongoDB)](https://www.prisma.io/docs/orm/reference/transactions-and-runtime#transactions-mongodb).

Each of these nine methods builds a command: call `.build()` on it, then run every one of them with `runtime.query(...)`, including the writes. The raw collection methods all run through `query()`. A write returns a one-element array, so destructure it with `const [result] = ...`.

> [!WARNING]
> MongoDB raw results are native BSON values
> 
> Nothing on the MongoDB side of this page is converted for you. An `_id` comes back as it is stored: one that MongoDB generated is an `ObjectId` instance from the `mongodb` package, the MongoDB driver underneath, not a hex string. Compare one with `String(row._id) === aliceId`. Raw filters take native BSON values too, so build ids with that package's `ObjectId` class. The write methods give you the counts and ids under the `mongodb` package's own key names, `{ insertedId }`, `{ matchedCount, modifiedCount, upsertedCount, upsertedId }`, and `{ deletedCount }`, and you read those keys directly.

The examples in this section run against the `users` / `posts` schema from the pipeline builder page. See its [example schema](https://www.prisma.io/docs/orm/reference/pipeline-builder#example-schema) for the full model definitions. Create the client with `mongo(...)`, get the connection that runs a built query from `await db.runtime()`, and declare the two example ids once:

```ts
import mongo from '@prisma/orm-mongo/runtime';
import { ObjectId } from 'mongodb';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };
const db = mongo<Contract>({ contractJson, url: process.env.MONGODB_URL, dbName: 'app' });
const runtime = await db.runtime();
const aliceId = '6539a1f2c3d4e5f60718293a';
const bobId = '6539a1f2c3d4e5f60718293b';
```

### `aggregate<Row>()` [#aggregaterow]

Run a raw aggregation pipeline against a collection. The type parameter says what each returned row looks like. The pipeline stages are raw MongoDB documents, sent as you wrote them, so a filter on `_id` with a real `ObjectId` matches.

```ts
const plan = db.raw.collection('posts').aggregate<{ _id: unknown; title: string }>([{ $match: { title: 'Hello world' } }]).build();
const [row] = await runtime.query(plan);
// row.title === 'Hello world'; row._id is a raw ObjectId
```

### `insertOne()` and `insertMany()` [#insertone-and-insertmany]

Insert one or many documents. Both return the `mongodb` package's own insert result, with `ObjectId` instances for the generated ids. `insertMany()`'s `insertedIds` is a plain array of `ObjectId`, in the order you passed the documents.

```ts
const users = db.raw.collection('users');
const onePlan = users.insertOne({ name: 'Dave', email: 'dave@example.com', role: 'author' }).build();
const [oneResult] = await runtime.query(onePlan);
// { insertedId: <ObjectId> }

const manyPlan = users.insertMany([{ name: 'Eve', email: 'eve@example.com', role: 'author' }, { name: 'Frank', email: 'frank@example.com', role: 'author' }]).build();
const [manyResult] = await runtime.query(manyPlan);
// { insertedCount: 2, insertedIds: [<ObjectId>, <ObjectId>] }
```

### `updateOne()` and `updateMany()` [#updateone-and-updatemany]

Update one or every matching document. The first argument is a raw filter document, and the second is either an update document such as `{ $set: ... }` or an aggregation pipeline, which is an array of stages. Both return `{ matchedCount, modifiedCount, upsertedCount, upsertedId }`.

#### Update document form [#update-document-form]

```ts
const plan = db.raw.collection('users').updateOne({ _id: new ObjectId(aliceId) }, { $set: { bio: 'Updated bio' } }).build();
const [result] = await runtime.query(plan);
// { matchedCount: 1, modifiedCount: 1, ... }
```

#### Pipeline form [#pipeline-form]

An array update is a full aggregation-pipeline update, so a stage can reference the document's other fields.

```ts
const plan = db.raw.collection('users').updateMany({ role: 'author' }, [{ $set: { bio: { $concat: ['bio for ', '$name'] } } }]).build();
const [result] = await runtime.query(plan);
// { matchedCount: 2, modifiedCount: 2, ... }
```

### `deleteOne()` and `deleteMany()` [#deleteone-and-deletemany]

Delete one or every matching document. Both return `{ deletedCount }`.

```ts
const onePlan = db.raw.collection('users').deleteOne({ _id: new ObjectId(bobId) }).build();
const [oneResult] = await runtime.query(onePlan);
// { deletedCount: 1 }

const manyPlan = db.raw.collection('users').deleteMany({ role: 'author' }).build();
const [manyResult] = await runtime.query(manyPlan);
// { deletedCount: 2 }
```

### `findOneAndUpdate()` [#findoneandupdate]

Atomically update a matching document and return the document as it was before the update. When no document matches and `upsert` is `true`, the update inserts one.

#### Remarks [#remarks]

* `findOneAndUpdate()` accepts only `{ upsert }` as its third argument. It cannot sort, and it cannot give you the document as it is after the update. TypeScript rejects `sort` or `returnDocument` in the options object.

To sort, or to read the document after the update, build the command yourself and run it through `db.query.rawCommand(...)`. `new RawFindOneAndUpdateCommand(...)` takes six arguments:

* `collection`: the collection name. Required.
* `filter`: the filter document. Required.
* `update`: an update document, or an array of aggregation-pipeline stages. Required.
* `upsert`: a boolean. Optional, and `false` when you leave it out.
* `sort`: a record of field name to `1` or `-1`. Optional.
* `returnDocument`: `'before'` or `'after'`. Optional. Leave it out and you get the document as it was before the update.

```ts
import { RawFindOneAndUpdateCommand } from '@prisma/orm-mongo/query-ast/execution';

// collection, filter, update, upsert, sort, returnDocument
const command = new RawFindOneAndUpdateCommand('users', { _id: new ObjectId(aliceId) }, { $inc: { count: 1 } }, true, { count: -1 }, 'after');
const [updated] = await runtime.query(db.query.rawCommand(command));
```

##### Upsert counter pattern [#upsert-counter-pattern]

`findOneAndUpdate()` returns the document as it was **before** your update. The first call creates the document, so there is nothing to return and you get `[]`. The second call returns `count: 1`, which is the value before that call added one. The example schema has no counter collection, so `users` stands in for one here. MongoDB allows a plain string `_id`, so `'pageViews'` is a valid id. The advice to build ids with `ObjectId` applies to ids MongoDB generated.

```ts
const filter = { _id: 'pageViews' };
const update = { $inc: { count: 1 }, $setOnInsert: { _id: 'pageViews' } };
const counter = db.raw.collection('users');
const bump = () => runtime.query(counter.findOneAndUpdate(filter, update, { upsert: true }).build());
const first = await bump(); // [], because the insert has no earlier version
const second = await bump(); // [{ ..., count: 1 }], the version before the second increment
const third = await bump(); // [{ ..., count: 2 }]
```

### `findOneAndDelete()` [#findoneanddelete]

Atomically delete a matching document and return it. The yielded row is the raw matched document itself, not a wrapper object, so its `_id` is a raw `ObjectId`.

```ts
const plan = db.raw.collection('users').findOneAndDelete({ _id: new ObjectId(aliceId) }).build();
const [deleted] = await runtime.query(plan);
// deleted is the removed document, and its _id is a raw ObjectId
const isAlice = String(deleted._id) === aliceId; // true
```

## `db.query.rawCommand()` [#dbqueryrawcommand]

`db.query.rawCommand(command)` runs a raw MongoDB command, sent exactly as you wrote it. See the [pipeline builder](https://www.prisma.io/docs/orm/reference/pipeline-builder). It returns a built query already, so do not call `.build()` on it. Unlike `aggregate<Row>()` it has no row type parameter, so its rows come back as `unknown` and you cast them yourself.

```ts
import { RawAggregateCommand } from '@prisma/orm-mongo/query-ast/execution';

const plan = db.query.rawCommand(new RawAggregateCommand('posts', [{ $count: 'total' }]));
const rows = (await runtime.query(plan)) as { total: number }[];
// [{ total: 2 }]
```

`rawCommand()` is the way out when the typed pipeline builder can't express a query, such as filtering by `_id` equality. The command you pass is sent unchanged, so a real `ObjectId` in a pipeline document matches. `aggregate<Row>()` on `db.raw.collection()` handles `_id` filtering too, and it gives you a row type, so use `rawCommand()` when you are already working in `db.query` and need one raw command there. For the full treatment see the pipeline builder's [`rawCommand()`](https://www.prisma.io/docs/orm/reference/pipeline-builder#rawcommand) section.

```ts
const plan = db.query.rawCommand(new RawAggregateCommand('posts', [{ $match: { _id: new ObjectId('6539a1f2c3d4e5f60718293c') } }]));
const rows = await runtime.query(plan);
```

## Related pages

- [`Error reference`](https://www.prisma.io/docs/orm/reference/error-reference): Every structured error code Prisma ORM can emit, by namespace, with the condition that raises it.
- [`Migration API`](https://www.prisma.io/docs/orm/reference/migration-api): Every method and helper a migration.ts can use: the Migration class, the PostgreSQL operations, the column and constraint helpers, rawSql, and the MongoDB operations.
- [`ORM client reference`](https://www.prisma.io/docs/orm/reference/orm-client): Reference for the Prisma ORM client's query, mutation, filter, and aggregate methods.
- [`Pipeline builder reference`](https://www.prisma.io/docs/orm/reference/pipeline-builder): Reference for the Prisma ORM MongoDB pipeline builder's stages, accumulators, expression helpers, and write methods.
- [`SQL query builder reference`](https://www.prisma.io/docs/orm/reference/sql-query-builder): Reference for the Prisma ORM SQL query builder's select, mutation, and grouped query methods.

# SQL query builder reference (/docs/orm/reference/sql-query-builder)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Reference for the Prisma ORM SQL query builder's select, mutation, and grouped query methods.

Location: ORM > Reference > SQL query builder reference

The SQL query builder builds typed queries from a table, with one method per SQL clause: `select()`, `innerJoin()`, `groupBy()`, and the rest. It is closer to SQL than the [ORM client](https://www.prisma.io/docs/orm/reference/orm-client) is, and the same `db` gives you both. Reach for it when you need a join, aggregate, or SQL feature the ORM client doesn't expose, or when you want direct control over the generated SQL.

Some methods work only on some databases, and some fail only when the query runs. For a task-oriented guide to when and how to reach for the builder, see [Advanced queries](https://www.prisma.io/docs/orm/fundamentals/advanced-queries).

> [!NOTE]
> The builder for SQL databases
> 
> The SQL query builder targets SQL databases; PostgreSQL and SQLite are supported today. MongoDB has no SQL builder: use the [ORM client](https://www.prisma.io/docs/orm/reference/orm-client) for MongoDB queries, and the [pipeline builder](https://www.prisma.io/docs/orm/reference/pipeline-builder) for aggregation pipelines.

## Example schema [#example-schema]

The examples run against the schema below and use the `user`, `post`, `post_tag`, and `tag` tables. The grouped-query examples use a separate `customer` and `order` schema, shown under [Grouped queries](#grouped-queries). `PostTag` is the join table. The two list fields and the `PostTag` model together are how Prisma ORM 8 declares a many-to-many, which [Relations and joins](https://www.prisma.io/docs/orm/fundamentals/relations-and-joins#many-to-many) explains. For the schema syntax itself, see [Contract authoring](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax).

**Expand for the example schema**

```prisma
types {
  Embedding1536 = pgvector.Vector(1536)
}

type Address {
  street  String
  city    String
  zip     String?
  country String
}

enum user_type {
  @@type("pg/text@1")
  admin
  user
}

enum Priority {
  @@type("pg/text@1")
  Low    = "low"
  High   = "high"
  Urgent = "urgent"
}

model User {
  id          Uuid      @id @default(uuid())
  email       String
  displayName String
  createdAt   DateTime  @default(now())
  kind        user_type
  address     Address?
  posts       Post[]
  tasks       Task[]

  @@map("user")
}

model Post {
  id        Uuid           @id @default(uuid())
  title     String
  userId    Uuid
  priority  Priority       @default(Low)
  createdAt DateTime       @default(now())
  embedding Embedding1536?

  user User  @relation(fields: [userId], references: [id])
  tags Tag[]

  @@map("post")
}

model Tag {
  id    Uuid   @id @default(uuid())
  label String @unique

  posts Post[]

  @@map("tag")
}

model PostTag {
  postId Uuid
  tagId  Uuid

  post Post @relation(fields: [postId], references: [id])
  tag  Tag  @relation(fields: [tagId], references: [id])

  @@id([postId, tagId])
  @@map("post_tag")
}

model Task {
  id          Uuid     @id @default(uuid())
  title       String
  description String?
  status      String   @default("open")
  type        String
  userId      Uuid
  createdAt   DateTime @default(now())

  user User @relation(fields: [userId], references: [id])

  @@discriminator(type)
  @@map("task")
}

model Bug {
  severity     String
  stepsToRepro String?
  @@base(Task, "bug")
  @@map("bug")
}

model Feature {
  priority      String
  targetRelease String?
  @@base(Task, "feature")
  @@map("feature")
}
```

## Entry points [#entry-points]

In Prisma ORM 8 your `schema.prisma` is called `contract.prisma`. [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) gets you from a Prisma ORM 7 project to that file, and has the rest of the setup steps. Install the client with `npm install @prisma/orm-postgres`. Run `npx prisma contract emit` to write `contract.json` and `contract.d.ts` beside `contract.prisma`. The examples below assume your own file is in `src/prisma/`, next to those two files, and they write the type import path as `./contract.d`, exactly like that.

You build queries from the client's `sql` property. Create a Postgres client with `postgres(...)`, then reach tables through `db.sql.public`. `public` is the PostgreSQL schema your tables are in. To put a model's table in another PostgreSQL schema, such as `auth`, wrap the model in a `namespace auth { ... }` block in your contract, and you then reach its table through `db.sql.auth` instead. See [Namespaces](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#namespaces).

Table accessors are keyed by table name, not model name. A table name is the model's `@@map` value, or the model name exactly as written when the model has no `@@map`. In the example schema, the `User` model is mapped to `user`, so you write `db.sql.public.user`. The `PostTag` model for the join table is mapped to `post_tag`, so you write `db.sql.public.post_tag`. Column names are the field names unless a field sets `@map`, and for a field that does, you write the `@map` name everywhere in the builder. A field declared `userId Uuid @map("user_id")` is `select('user_id')` and `f.user_id`, and each row you get back has a `user_id` key.

### The `db.sql` builder [#the-dbsql-facet]

`db.runtime()` returns the connection that runs a built query. On PostgreSQL it is synchronous, so no `await` is needed. Hold it in a variable and reuse it. When your app shuts down, close the client with [`db.close()`](https://www.prisma.io/docs/orm/reference/transactions-and-runtime#close).

A `select()`, `insert()`, `update()`, or `delete()` call starts a query. [`build()`](#build) turns the chain into a query object, which the examples name `plan`. Nothing touches the database until you pass that object to `runtime.query(...)`. You can run the same built query more than once.

```ts
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

const db = postgres<Contract>({ contractJson, url: process.env.DATABASE_URL });
const runtime = db.runtime();

const plan = db.sql.public.user.select('id', 'email').build();
const users = await runtime.query(plan);
```

The example schema's `Embedding1536` column is a pgvector type, so a client for that schema also needs pgvector in `extensions`, as [Built-in functions](#built-in-functions) shows.

SQLite works the same way: create the client with `sqlite(...)` from `@prisma/orm-sqlite/runtime`. SQLite has no schemas, so there is no `public` in the path and the same table is `db.sql.user`. Of the SELECT methods on this page, `lateralJoin()`, `outerLateralJoin()`, and `distinctOn()` are not available on SQLite, but every other one is. The rest of this page shows PostgreSQL and writes the root as `db.sql.public`.

### Table access [#table-access]

Every table on `db.sql.public` exposes the query-building methods.

```ts
db.sql.public.user.select('id', 'email'); // start a SELECT
db.sql.public.tag.insert([{ label: 'typescript' }]); // start an INSERT
```

### Aliasing a query with `.as()` [#aliasing-a-query-with-as]

Call `.as(alias)` on a `SELECT` chain before `build()` to use that query as a subquery. The aliased query is then something you can pass to `innerJoin()`, `outerLeftJoin()`, and the other join methods. Do not call `.as()` inside a [`lateralJoin()`](#lateraljoin) callback. For the example, see [Subquery via `.as()`](#subquery-via-as).

## SELECT queries [#select-queries]

These methods build and refine a `SELECT`. They chain, and you resolve the query with [`build()`](#build) followed by `runtime.query(...)`. Chain the methods in any order, with two exceptions: a join must come before any call that names the joined table's columns, and the columns you pass to `distinctOn()` must be the first sort keys in `orderBy()`. `SelectQuery` in the tables below is the type they return.

The set of column names a query can use is its scope: it starts as the columns of the table you began with, and every join adds the joined table's columns to it.

The `where()`, `select()`, `orderBy()`, `update()`, and other callback forms receive two arguments. The first is `f`, which has one property per column in scope. After a join, every column is on `f` under its table name, such as `f.user.email` or `f.post.id`. A column name that only one table has is also on `f` directly. The second is `fns`, an object of [expression helpers](#expressions-and-functions) such as `fns.eq()` and `fns.raw`. For an enum column you pass the value stored in the database, which is the string after `=`, so `High = "high"` is matched by `fns.eq(f.priority, 'high')`. A member with no `=`, such as `admin` in `user_type`, is matched by its own name, `fns.eq(f.kind, 'admin')`.

### `select()` [#select]

Reduce each row to a chosen set of columns or computed expressions.

#### Options [#options]

`select()` has three forms:

| Form                  | Signature                                    | Description                                                                                                           |
| --------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Column names          | `select('col', 'col2', ...)`                 | Keep the named columns. A name that is not in the query's scope throws an error whose `code` is `ORM.COLUMN_UNKNOWN`. |
| Aliased expression    | `select(alias, (f, fns) => expr)`            | Add one computed column under `alias`.                                                                                |
| Object of expressions | `select((f, fns) => ({ alias: expr, ... }))` | Add several computed columns at once. The row type is inferred from the object's shape.                               |

Every form adds to what the query already returns: calling `select()` a second time never replaces the first call's columns, whichever form you use. To return fewer columns, start a new query instead.

A computed expression's result type comes from `.returns(...)` on `fns.raw`, or from the `fns.*` function you called. Every `fns.raw` fragment needs `.returns()`. A type id is `pg/` plus the PostgreSQL type name plus a version, always `@1` today, such as `pg/int4@1` or `pg/uuid@1`. A few use a longer name, such as `pg/timestamptz-temporal@1` for `DateTime`. The common ones are `pg/text@1`, `pg/int4@1`, `pg/int8@1`, `pg/float8@1`, `pg/bool@1`, `pg/uuid@1`, and `pg/timestamptz-temporal@1`. The full list is what your contract uses. Read any column's id from `db.sql.public.<table>.columns.<column>.codecId`, and see [Binding a bare value with `param()`](https://www.prisma.io/docs/orm/reference/raw-queries#binding-a-bare-value-with-param) for which JavaScript type becomes which id. See [`fns.raw` and `.returns()`](#fnsraw-and-returns).

#### Return type [#return-type]

| Return type   | Example                                    | Description                                                                     |
| ------------- | ------------------------------------------ | ------------------------------------------------------------------------------- |
| `SelectQuery` | `db.sql.public.user.select('id', 'email')` | A query projected to the named columns or expressions, chainable and buildable. |

#### Examples [#examples]

The examples on this page use these ids, which stand for rows that exist:

```ts
const aliceId = '00000000-0000-4000-8000-000000000001';
const carolId = '00000000-0000-4000-8000-000000000003';
const helloWorldId = '00000000-0000-4000-8000-000000000010';
const untaggedPostId = '00000000-0000-4000-8000-000000000011';
const newestPostId = '00000000-0000-4000-8000-000000000012';
```

##### Project a subset of columns [#project-a-subset-of-columns]

```ts
const plan = db.sql.public.user.select('id', 'email').build();
const rows = await runtime.query(plan);
// rows[0] is { id, email }, with no displayName
```

##### Add an aliased computed column [#add-an-aliased-computed-column]

```ts
const plan = db.sql.public.user
  .select('id', 'displayName')
  .select('emailLength', (f, fns) => fns.raw`LENGTH(${f.email})`.returns('pg/int4@1'))
  .where((f, fns) => fns.eq(f.id, aliceId))
  .build();
const rows = await runtime.query(plan);
```

##### Project multiple computed columns at once [#project-multiple-computed-columns-at-once]

```ts
const plan = db.sql.public.user
  .select((f, fns) => ({
    id: f.id,
    upperEmail: fns.raw`UPPER(${f.email})`.returns('pg/text@1'),
    emailLength: fns.raw`LENGTH(${f.email})`.returns('pg/int4@1'),
  }))
  .where((f, fns) => fns.eq(f.id, aliceId))
  .build();
const rows = await runtime.query(plan);
// rows === [{ id: aliceId, upperEmail: 'ALICE@EXAMPLE.COM', emailLength: 17 }]
```

### `where()` [#where]

Restrict a query to rows matching an expression.

#### Options [#options-1]

| Name        | Type                     | Required | Description                                                                                                              |
| ----------- | ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `predicate` | `(f, fns) => Expression` | Yes      | A boolean expression built from `f` and `fns`. Combine comparisons with `fns.and(...)` and `fns.or(...)`, nested freely. |

#### Return type [#return-type-1]

| Return type   | Example                                      | Description                        |
| ------------- | -------------------------------------------- | ---------------------------------- |
| `SelectQuery` | `db.sql.public.post.select('id').where(...)` | A query narrowed by the predicate. |

#### Examples [#examples-1]

##### Combine comparisons with `and()` and `or()` [#combine-comparisons-with-and-and-or]

```ts
const plan = db.sql.public.post
  .select('id', 'title', 'priority')
  .where((f, fns) =>
    fns.or(
      fns.and(fns.eq(f.userId, aliceId), fns.eq(f.priority, 'high')),
      fns.eq(f.userId, carolId),
    ),
  )
  .build();
const rows = await runtime.query(plan);
```

### `innerJoin()` [#innerjoin]

Combine matching rows from two tables. Every column is then on `f` under its table name, such as `f.user.email` or `f.post.id`. A column name that only one table has is also on `f` directly.

#### Options [#options-2]

| Name    | Type                                                                                            | Required | Description                    |
| ------- | ----------------------------------------------------------------------------------------------- | -------- | ------------------------------ |
| `other` | A table (`db.sql.public.<table>`) or an aliased subquery ([`.as()`](#aliasing-a-query-with-as)) | Yes      | The table or subquery to join. |
| `on`    | `(f, fns) => Expression`                                                                        | Yes      | The join condition.            |

#### Return type [#return-type-2]

| Return type   | Example                                                 | Description                                                                                 |
| ------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `SelectQuery` | `db.sql.public.post.innerJoin(db.sql.public.user, ...)` | A query over the joined tables, with both tables' columns in scope under their table names. |

#### Examples [#examples-2]

##### Join posts to their authors [#join-posts-to-their-authors]

```ts
const plan = db.sql.public.post
  .innerJoin(db.sql.public.user, (f, fns) => fns.eq(f.post.userId, f.user.id))
  .select((f) => ({ postId: f.post.id, authorEmail: f.user.email }))
  .where((f, fns) => fns.eq(f.post.id, helloWorldId))
  .build();
const rows = await runtime.query(plan);
// rows === [{ postId: helloWorldId, authorEmail: 'alice@example.com' }]
```

### `outerLeftJoin()`, `outerRightJoin()`, `outerFullJoin()` [#outerleftjoin-outerrightjoin-outerfulljoin]

Keep unmatched rows from one or both sides, filling the missing side's columns with `null`. Each takes the same `(other, on)` arguments and returns a `SelectQuery` as [`innerJoin()`](#innerjoin) does. `outerLeftJoin()` is SQL's `LEFT OUTER JOIN` and keeps every left-table row. `outerRightJoin()` is `RIGHT OUTER JOIN` and keeps every right-table row. `outerFullJoin()` is `FULL OUTER JOIN` and keeps unmatched rows from both sides.

#### Examples [#examples-3]

##### Left join keeps rows with no match [#left-join-keeps-rows-with-no-match]

```ts
const plan = db.sql.public.post
  .outerLeftJoin(db.sql.public.post_tag, (f, fns) => fns.eq(f.post.id, f.post_tag.postId))
  .select((f) => ({ postId: f.post.id, tagId: f.post_tag.tagId }))
  .where((f, fns) => fns.eq(f.post.id, untaggedPostId))
  .build();
const rows = await runtime.query(plan);
// rows === [{ postId: untaggedPostId, tagId: null }]
```

### `lateralJoin()` [#lateraljoin]

Correlate a per-row subquery against the outer row: for each outer row, the joined subquery can reference that row's columns. Use it for a query such as the newest post for each user.

#### Remarks [#remarks]

* **Availability:** PostgreSQL only. On SQLite TypeScript rejects the call. If you cast, or call it from plain JavaScript, it throws an error whose `code` is `ORM.CAPABILITY_MISSING`.
* The callback receives a `lateral` builder. Start its subquery with `lateral.from(otherTable)`, then chain the usual `SELECT` methods. Inside the callback, the outer table's columns are on `f` under its table name, such as `f.user.id`, so the subquery can filter on the outer row.
* Return the query chain **directly** from the callback. Do **not** call `.as(...)` on it. The first argument of `lateralJoin()` already names the subquery.
* Every column is on `f` under its table name, and a column name that only one table has is also on `f` directly. Outside the callback, the subquery's columns are under the alias you gave it, such as `f.latestPost.id`. Inside the callback, the joined table is still `post`, so the same column is `f.post.id`. Because both tables have `id` and `createdAt`, a bare `select('id')` or `orderBy((f) => f.createdAt, ...)` throws.
* `outerLateralJoin(alias, callback)` is the `LEFT JOIN LATERAL` form: same arguments, and rows with no match keep the outer row.

#### Options [#options-3]

| Name    | Type                       | Required | Description                                                                                       |
| ------- | -------------------------- | -------- | ------------------------------------------------------------------------------------------------- |
| `alias` | `string`                   | Yes      | Names the subquery. Address its columns as `f.<alias>.<col>` in later `select()`/`where()` calls. |
| `build` | `(lateral) => SelectQuery` | Yes      | Builds the correlated subquery. Return the query chain directly.                                  |

#### Return type [#return-type-3]

| Return type   | Example                                             | Description                                                         |
| ------------- | --------------------------------------------------- | ------------------------------------------------------------------- |
| `SelectQuery` | `db.sql.public.user.lateralJoin('latestPost', ...)` | A query with the lateral subquery's columns in scope under `alias`. |

#### Examples [#examples-4]

##### Each user's most recent post [#each-users-most-recent-post]

```ts
const plan = db.sql.public.user
  .lateralJoin('latestPost', (lateral) =>
    lateral
      .from(db.sql.public.post)
      .select((f) => ({ id: f.post.id, title: f.post.title }))
      .where((f, fns) => fns.eq(f.post.userId, f.user.id))
      .orderBy((f) => f.post.createdAt, { direction: 'desc' })
      .limit(1),
  )
  .select((f) => ({ userId: f.user.id, latestPostId: f.latestPost.id }))
  .where((f, fns) => fns.eq(f.user.id, aliceId))
  .build();
const rows = await runtime.query(plan);
// rows === [{ userId: aliceId, latestPostId: newestPostId }]
```

### `orderBy()` [#orderby]

Sort the result set by a column or a computed expression, in a direction you choose.

#### Options [#options-4]

| Name                | Type                                               | Required | Description                              |
| ------------------- | -------------------------------------------------- | -------- | ---------------------------------------- |
| `key`               | Column name (`string`) or `(f, fns) => Expression` | Yes      | The column or computed value to sort by. |
| `options.direction` | `'asc' \| 'desc'`                                  | No       | Sort direction.                          |

TypeScript also accepts a `nulls` option, but it does nothing, and no `NULLS FIRST` or `NULLS LAST` reaches the SQL. To put nulls last, sort by a computed value first, then by the column:

```ts
db.sql.public.task
  .select('id', 'description')
  .orderBy((f, fns) => fns.raw`CASE WHEN ${f.description} IS NULL THEN 1 ELSE 0 END`.returns('pg/int4@1'))
  .orderBy('description', { direction: 'asc' });
```

#### Return type [#return-type-4]

| Return type   | Example                                                    | Description                                                                      |
| ------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `SelectQuery` | `db.sql.public.user.select('email').orderBy('email', ...)` | A query with the sort key applied. Call `orderBy()` again to add secondary keys. |

#### Examples [#examples-5]

##### Sort by a column [#sort-by-a-column]

```ts
const plan = db.sql.public.user.select('id', 'email').orderBy('email', { direction: 'asc' }).build();
const rows = await runtime.query(plan);
```

##### Sort by a computed value [#sort-by-a-computed-value]

```ts
const plan = db.sql.public.user
  .select('id', 'email')
  .orderBy((f, fns) => fns.raw`LENGTH(${f.email})`.returns('pg/int4@1'), { direction: 'asc' })
  .build();
const rows = await runtime.query(plan);
```

### `distinct()` [#distinct]

De-duplicate identical projected rows (`SELECT DISTINCT`).

#### Return type [#return-type-5]

| Return type   | Example                                            | Description                                     |
| ------------- | -------------------------------------------------- | ----------------------------------------------- |
| `SelectQuery` | `db.sql.public.post.select('priority').distinct()` | A query returning only distinct projected rows. |

#### Examples [#examples-6]

##### De-duplicate projected rows [#de-duplicate-projected-rows]

```ts
const plan = db.sql.public.post.select('priority').distinct().build();
const rows = await runtime.query(plan);
// distinct priorities: ['high', 'low', 'urgent']
```

### `distinctOn()` [#distincton]

Keep the first row per distinct key, according to the query's `orderBy()` (`DISTINCT ON`).

#### Remarks [#remarks-1]

* **Availability:** PostgreSQL only. On SQLite TypeScript rejects the call. If you cast, or call it from plain JavaScript, it throws an error whose `code` is `ORM.CAPABILITY_MISSING`.
* Sort keys that come after the `distinctOn()` columns in `orderBy()` decide which row is kept.

#### Options [#options-5]

| Name      | Type                    | Required | Description                                       |
| --------- | ----------------------- | -------- | ------------------------------------------------- |
| `...keys` | Column names (`string`) | Yes      | The columns whose distinct combinations are kept. |

#### Return type [#return-type-6]

| Return type   | Example                                                    | Description                                     |
| ------------- | ---------------------------------------------------------- | ----------------------------------------------- |
| `SelectQuery` | `db.sql.public.post.select('userId').distinctOn('userId')` | A query keeping the first row per distinct key. |

#### Examples [#examples-7]

##### First post per user by date [#first-post-per-user-by-date]

```ts
const plan = db.sql.public.post
  .select('id', 'userId', 'createdAt')
  .orderBy('userId', { direction: 'asc' })
  .orderBy('createdAt', { direction: 'asc' })
  .distinctOn('userId')
  .build();
const rows = await runtime.query(plan);
// one row per user, each the earliest post by createdAt
```

### `limit()` and `offset()` [#limit-and-offset]

Cap the number of returned rows and skip rows in the ordered result set.

#### Options [#options-6]

| Method      | Argument                          | Description              |
| ----------- | --------------------------------- | ------------------------ |
| `limit(n)`  | `number`, or a numeric expression | Return at most `n` rows. |
| `offset(n)` | `number`, or a numeric expression | Skip the first `n` rows. |

#### Return type [#return-type-7]

| Return type   | Example                                    | Description                                 |
| ------------- | ------------------------------------------ | ------------------------------------------- |
| `SelectQuery` | `db.sql.public.user.select('id').limit(2)` | A query with the row cap or offset applied. |

#### Examples [#examples-8]

##### Page through results [#page-through-results]

```ts
const plan = db.sql.public.user
  .select('id')
  .orderBy('email', { direction: 'asc' })
  .limit(1)
  .offset(1)
  .build();
const rows = await runtime.query(plan);
```

### Subquery via `.as()` [#subquery-via-as]

Call `.as(alias)` on a `SELECT` chain before `build()` to use it as a subquery. Pass the result to any join method as the `other` argument. `SELECT` queries and [grouped queries](#grouped-queries) have `.as()`, but queries started with `insert()`, `update()`, or `delete()` do not, so you cannot join against the rows they return.

#### Options [#options-7]

| Name    | Type     | Required | Description                                                                  |
| ------- | -------- | -------- | ---------------------------------------------------------------------------- |
| `alias` | `string` | Yes      | Names the subquery. Address its columns as `f.<alias>.<col>` after the join. |

#### Return type [#return-type-8]

| Return type | Example                                   | Description                                                                                                           |
| ----------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Subquery    | `db.sql.public.post.select(...).as('hp')` | A subquery you pass as a join's `other` argument. You cannot call `build()` on it. Join it into an outer query first. |

#### Examples [#examples-9]

##### Join against a subquery [#join-against-a-subquery]

```ts
const highPriorityPosts = db.sql.public.post
  .select('id', 'userId')
  .where((f, fns) => fns.eq(f.priority, 'high'))
  .as('hp');

const plan = db.sql.public.user
  .innerJoin(highPriorityPosts, (f, fns) => fns.eq(f.user.id, f.hp.userId))
  .select((f) => ({ userId: f.user.id, postId: f.hp.id }))
  .build();
const rows = await runtime.query(plan);
```

## Grouped queries [#grouped-queries]

Grouping starts with [`groupBy()`](#groupby), which turns a select query into a `GroupedQuery`. Write your aggregates in `select()` first, then call `groupBy()`. After that you can add `having()`, `orderBy()`, `limit()`, `offset()`, and `distinct()`.

The examples below use an extra table, `order`, whose `amount` column is an integer:

```prisma
model Order {
  id         Uuid     @id @default(uuid())
  customerId Uuid
  amount     Int
  placedAt   DateTime @default(now())

  @@map("order")
}
```

### `groupBy()` [#groupby]

Group rows by one or more columns or by a computed expression, producing one row per distinct group.

#### Options [#options-8]

| Form        | Signature                     | Description                 |
| ----------- | ----------------------------- | --------------------------- |
| Field names | `groupBy('col', 'col2', ...)` | Group by the named columns. |
| Expression  | `groupBy((f, fns) => expr)`   | Group by a computed value.  |

#### Return type [#return-type-9]

| Return type    | Example                                                          | Description                                                              |
| -------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `GroupedQuery` | `db.sql.public.order.select('customerId').groupBy('customerId')` | A grouped query supporting `having()`, aggregates, ordering, and limits. |

#### Examples [#examples-10]

##### Group by a column with a count [#group-by-a-column-with-a-count]

The examples below reuse the `runtime` created here, and name each built query `plan`, the object `build()` returns.

```ts
const runtime = db.runtime();

const plan = db.sql.public.order
  .select('customerId')
  .select('orderCount', (f, fns) => fns.count(f.id))
  .groupBy('customerId')
  .build();
const rows = await runtime.query(plan);
// rows === [{ customerId: '<a customer id>', orderCount: 5 }]
```

> [!NOTE]
> What the aggregates give you back
> 
> * A `count()` or integer `sum()` result larger than 2^53 - 1 throws an error whose `code` is `RUNTIME.DECODE_FAILED`. Use `countBigInt()` or `sumBigInt(field)` when totals can get that large.
> * `avg()` is computed as a floating-point `number`, so a long decimal is rounded. Use `avgDecimal(field)` when you need the exact figure.
> * Every error this page names is an `Error` with a `code` property, so check for one as below.

```ts
try { await runtime.query(plan); } catch (error) {
  if (error instanceof Error && 'code' in error && error.code === 'RUNTIME.DECODE_FAILED') { /* the count is too big for a number */ }
}
```

##### Group by a computed value [#group-by-a-computed-value]

```ts
const plan = db.sql.public.order
  .select('yearPlaced', (f, fns) => fns.raw`EXTRACT(YEAR FROM ${f.placedAt})`.returns('pg/numeric@1'))
  .select('orderCount', (f, fns) => fns.count(f.id))
  .groupBy('yearPlaced')
  .build();
const rows = await runtime.query(plan);
// rows === [{ yearPlaced: '2024', orderCount: 10 }]. PostgreSQL computes EXTRACT as numeric, which arrives as the string '2024'. Write Number(row.yearPlaced) for 2024.
```

Annotate with the type PostgreSQL computes, not the type you want. Here `pg/numeric@1` types `yearPlaced` as `string`, which is what you receive, while `.returns('pg/int4@1')` would type it `number` and still hand you a string. `.groupBy('yearPlaced')` groups by the alias given to the selected value. To group by the expression itself, repeat the fragment inside `groupBy()`, `.returns()` and all:

```ts
  .groupBy((f, fns) => fns.raw`EXTRACT(YEAR FROM ${f.placedAt})`.returns('pg/numeric@1'))
```

A name that is neither a column of the table you started from nor an alias you selected throws an error whose `code` is `ORM.COLUMN_UNKNOWN`, at the moment you call `groupBy()`. If you select a column you did not group or aggregate, the query fails when it runs, not when you build it, and that failure comes back as PostgreSQL's own error, not a Prisma ORM code.

### `having()` [#having]

Filter groups by an aggregate comparison. Build the predicate from the aggregate functions (`fns.count`, `fns.sum`, `fns.avg`, `fns.min`, `fns.max`) and the comparison functions, comparing against a JavaScript literal.

#### Remarks [#remarks-2]

* Compare against a plain JavaScript number, as in `fns.gt(fns.count(), 1)`. Passing a `bigint` literal such as `1n` throws an error whose `code` is `RUNTIME.ENCODE_FAILED` when the query runs. `fns.countBigInt()` and `fns.sumBigInt()` are the other way round: compare those against a `bigint` literal, as in `fns.gt(fns.countBigInt(), 1n)`.
* Do not use a selected alias in `having()`. TypeScript will let you, but PostgreSQL rejects it and the query fails when it runs. Write the aggregate again instead.

#### Options [#options-9]

| Name        | Type                     | Required | Description                                                                                   |
| ----------- | ------------------------ | -------- | --------------------------------------------------------------------------------------------- |
| `predicate` | `(f, fns) => Expression` | Yes      | A boolean expression over aggregate functions, for example `fns.gt(fns.sum(f.amount), 1000)`. |

#### Return type [#return-type-10]

| Return type    | Example                                                                      | Description                                                    |
| -------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------- |
| `GroupedQuery` | `db.sql.public.order.select('customerId').groupBy('customerId').having(...)` | A grouped query filtered to the groups matching the predicate. |

#### Examples [#examples-11]

##### Filter groups by a sum threshold [#filter-groups-by-a-sum-threshold]

```ts
const plan = db.sql.public.order
  .select('customerId')
  .select('totalAmount', (f, fns) => fns.sum(f.amount))
  .groupBy('customerId')
  .having((f, fns) => fns.gt(fns.sum(f.amount), 1000))
  .build();
const rows = await runtime.query(plan); // only the customer whose orders sum over 1000, with totalAmount 1500
```

##### Compare with `count()`, `avg()`, `min()`, `max()` [#compare-with-count-avg-min-max]

```ts
const plan = db.sql.public.order
  .select('customerId')
  .select('avgAmount', (f, fns) => fns.avg(f.amount))
  .select('exactAvg', (f, fns) => fns.avgDecimal(f.amount))
  .select('minAmount', (f, fns) => fns.min(f.amount))
  .select('maxAmount', (f, fns) => fns.max(f.amount))
  .groupBy('customerId')
  .having((f, fns) => fns.and(fns.gt(fns.count(), 1), fns.gt(fns.avg(f.amount), 100)))
  .build();
const rows = await runtime.query(plan); // avgAmount is 300, exactAvg is the exact string '300.0000000000000000', minAmount is 100, maxAmount is 500
```

### Ordering and limiting a grouped query [#ordering-and-limiting-a-grouped-query]

A `GroupedQuery` supports the same `orderBy()`, `limit()`, `offset()`, `distinct()`, and [`distinctOn()`](#distincton) methods as a `SelectQuery`. Sort by an aggregate alias to order groups. A name that is neither a column of the table you started from nor an alias you selected throws an error whose `code` is `ORM.COLUMN_UNKNOWN`, at the moment you call `orderBy()`.

#### Examples [#examples-12]

##### Order groups by total, keep the top one [#order-groups-by-total-keep-the-top-one]

```ts
const plan = db.sql.public.order
  .select('customerId')
  .select('totalAmount', (f, fns) => fns.sum(f.amount))
  .groupBy('customerId')
  .orderBy('totalAmount', { direction: 'desc' })
  .limit(1)
  .build();
const rows = await runtime.query(plan); // the single highest-spending customer
```

## Mutations [#mutations]

> [!WARNING]
> An update or delete with no
> 
> `where()`
> 
>  hits every row
> 
> `where()` is optional on `update()` and `delete()`: leave it out and every row in the table is changed, with no warning.

Mutations start from a table with `insert()`, `update()`, or `delete()`, and end with [`build()`](#build). Add [`returning()`](#returning) to get the affected rows back. Run a mutation with no `returning()` using `runtime.execute(plan)`, which resolves to `{ affectedRows }`. With `returning()`, run it with `runtime.query(plan)`. The examples below go back to this page's example models, so they use `db.sql.public.tag` and `db.sql.public.user` again.

### `insert()` [#insert]

Insert one or more rows in a single statement.

#### Remarks [#remarks-3]

* `insert()` always takes an **array**. A single-row insert is a one-element array. There is no separate single-row overload. An empty array throws an error whose `code` is `ORM.MUTATION_DATA_MISSING`.
* Leave a column out and the `@default(...)` in `contract.prisma` is applied. Prisma ORM generates `@default(uuid())` and `@default(now())` values when you call `build()`, not when the query runs. The built query then holds fixed values, so running it twice inserts the same id twice, which fails on a unique column. Call `.build()` again for each insert.
* There is no `ON CONFLICT` and no upsert here. For "insert or update", use the ORM client's [`upsert()`](https://www.prisma.io/docs/orm/reference/orm-client#upsert) or write the statement with [`db.raw.sql`](https://www.prisma.io/docs/orm/reference/raw-queries).

#### Options [#options-10]

| Name   | Type                 | Required | Description                                                 |
| ------ | -------------------- | -------- | ----------------------------------------------------------- |
| `rows` | Array of row objects | Yes      | The rows to insert. Every column is optional in TypeScript. |

PostgreSQL still rejects a missing required column that has no default. Never call `.returns()` or [`param()`](#param) on an insert value.

#### Return type [#return-type-11]

| Return type   | Example                           | Description                                                                |
| ------------- | --------------------------------- | -------------------------------------------------------------------------- |
| `InsertQuery` | `db.sql.public.tag.insert([...])` | An insert query. Buildable directly, or chain [`returning()`](#returning). |

#### Examples [#examples-13]

##### Insert a single row [#insert-a-single-row]

```ts
const plan = db.sql.public.tag.insert([{ label: 'single-row-tag' }]).build();
await runtime.execute(plan); // execute runs a write that returns no rows. id is filled in from @default(uuid())
```

##### Insert multiple rows in one statement [#insert-multiple-rows-in-one-statement]

```ts
const plan = db.sql.public.tag.insert([{ label: 'multi-row-a' }, { label: 'multi-row-b' }]).build();
await runtime.execute(plan);
```

### `returning()` [#returning]

Return columns from the rows affected by an `insert()`, `update()`, or `delete()`.

#### Remarks [#remarks-4]

* **Availability:** PostgreSQL and SQLite.
* `returning()` takes column names only. There is no `returning('*')`, and you cannot return a computed expression.

#### Options [#options-11]

| Name         | Type                    | Required | Description                                   |
| ------------ | ----------------------- | -------- | --------------------------------------------- |
| `...columns` | Column names (`string`) | Yes      | The columns to return from each affected row. |

#### Return type [#return-type-12]

| Return type    | Example                                                    | Description                                                                                                            |
| -------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Mutation query | `db.sql.public.tag.insert([...]).returning('id', 'label')` | The mutation query, which now gives you back those columns from each affected row. Run it with `query`, not `execute`. |

#### Examples [#examples-14]

##### Return the inserted row [#return-the-inserted-row]

```ts
const plan = db.sql.public.tag.insert([{ label: 'returned-tag' }]).returning('id', 'label').build();
const rows = await runtime.query(plan); // rows === [{ id: '<the generated uuid>', label: 'returned-tag' }]
```

### `update()` [#update]

Update matched rows. Set columns with a values object, or derive new values from existing columns with an expression callback. Choose the rows with `where()`, and use [`returning()`](#returning) to get the updated rows.

#### Options [#options-12]

`update()` accepts a values object or an expression callback, but you cannot mix the two forms in one call.

| Form                | Signature                             | Description                                                |
| ------------------- | ------------------------------------- | ---------------------------------------------------------- |
| Values object       | `update({ col: value, ... })`         | Set columns to fixed values.                               |
| Expression callback | `update((f, fns) => ({ col: expr }))` | Set columns to expressions computed from existing columns. |

Every value the callback returns must be an expression. To set a column to a fixed value in the callback form, wrap that value in a `fns.raw` fragment, as the second example below does.

#### Return type [#return-type-13]

| Return type   | Example                              | Description                                                                  |
| ------------- | ------------------------------------ | ---------------------------------------------------------------------------- |
| `UpdateQuery` | `db.sql.public.user.update({ ... })` | An update query. Chain `where()` and optionally [`returning()`](#returning). |

#### Examples [#examples-15]

##### Update with a values object [#update-with-a-values-object]

```ts
const plan = db.sql.public.user
  .update({ displayName: 'Bobby' })
  .where((f, fns) => fns.eq(f.email, 'bob@example.com'))
  .returning('id', 'displayName')
  .build();
const rows = await runtime.query(plan); // one row, with displayName now 'Bobby'
```

##### Derive a value from an existing column [#derive-a-value-from-an-existing-column]

```ts
const plan = db.sql.public.user
  .update((f, fns) => ({
    displayName: fns.raw`UPPER(${f.displayName})`.returns('pg/text@1'),
    email: fns.raw`${'carol@archived.example.com'}`.returns('pg/text@1'),
  }))
  .where((f, fns) => fns.eq(f.email, 'carol@example.com'))
  .returning('id', 'displayName')
  .build();
const rows = await runtime.query(plan); // one row, with displayName now 'CAROL' and a fixed new email
```

### `delete()` [#delete]

Delete matched rows. `delete()` takes no arguments. Choose the rows with `where()`, and use [`returning()`](#returning) to get the deleted rows back.

#### Return type [#return-type-14]

| Return type   | Example                      | Description                                                                 |
| ------------- | ---------------------------- | --------------------------------------------------------------------------- |
| `DeleteQuery` | `db.sql.public.tag.delete()` | A delete query. Chain `where()` and optionally [`returning()`](#returning). |

#### Examples [#examples-16]

##### Delete and return the removed row [#delete-and-return-the-removed-row]

```ts
const plan = db.sql.public.tag
  .delete()
  .where((f, fns) => fns.eq(f.label, 'to-delete'))
  .returning('id', 'label')
  .build();
const rows = await runtime.query(plan); // one row, the tag that was deleted
```

### `param()` [#param]

Give a value its type by hand, for a value with no column to take the type from, such as a literal inside `fns.raw`. `param()` works in any query, not only in mutations.

#### Remarks [#remarks-5]

* Import `param` from `@prisma/orm-postgres/relational-core/expression`.
* Values passed to `insert()`, `update()`, and comparison functions such as `fns.eq(f.col, value)` each take their type from the column they are used with, so you rarely need `param()`. Reach for it when the type the builder would pick is not the one the column needs. Inside `fns.raw` no column lends its type, so a bare string becomes `pg/text@1` and a value compared there with a `uuid` column needs `param(id, { codecId: 'pg/uuid@1' })`. A `Temporal.Instant` cannot be interpolated bare at all.
* The option is called `codecId`, but it takes the same type id used everywhere else on this page. [Binding a bare value with `param()`](https://www.prisma.io/docs/orm/reference/raw-queries#binding-a-bare-value-with-param) lists the type id each kind of JavaScript value gets, which is where to look for a date, a uuid, a boolean, or an array.

#### Options [#options-13]

| Name           | Type     | Required | Description                                                  |
| -------------- | -------- | -------- | ------------------------------------------------------------ |
| `value`        | `T`      | Yes      | The value to bind.                                           |
| `opts.codecId` | `string` | Yes      | The type id to send the value as, for example `'pg/text@1'`. |

#### Return type [#return-type-15]

| Return type | Example                                            | Description                                          |
| ----------- | -------------------------------------------------- | ---------------------------------------------------- |
| `ParamRef`  | `param('%@example.com', { codecId: 'pg/text@1' })` | A bound-parameter reference usable inside `fns.raw`. |

#### Examples [#examples-17]

##### Bind a literal inside a raw fragment [#bind-a-literal-inside-a-raw-fragment]

```ts
import { param } from '@prisma/orm-postgres/relational-core/expression';

const targetId = param('11111111-1111-1111-1111-111111111111', { codecId: 'pg/uuid@1' });
const plan = db.sql.public.user
  .select('id', 'email')
  .where((f, fns) => fns.raw`${f.id} = ${targetId}`.returns('pg/bool@1'))
  .build();
const rows = await runtime.query(plan);
```

## Expressions and functions [#expressions-and-functions]

Callback forms receive `fns` alongside the `f` argument. `fns` is an object of helper functions: comparisons, boolean combinations, aggregates, and raw SQL.

### Built-in functions [#built-in-functions]

These exist on every database:

| Category   | Functions                                                                |
| ---------- | ------------------------------------------------------------------------ |
| Comparison | `eq(a, b)`, `ne(a, b)`, `gt(a, b)`, `gte(a, b)`, `lt(a, b)`, `lte(a, b)` |
| Membership | `in(expr, values)`, `notIn(expr, values)`                                |
| Boolean    | `and(...predicates)`, `or(...predicates)`                                |
| Existence  | `exists(subquery)`, `notExists(subquery)`                                |
| Raw SQL    | ``raw`...`.returns(typeId)``                                             |

For `in()` and `notIn()`, `values` is an array or a subquery. All four of `in()`, `notIn()`, `exists()`, and `notExists()` take a select query that you do not call `build()` on.

```ts
const named = db.sql.public.user
  .select('id', 'email')
  .where((f, fns) => fns.in(f.email, ['bob@example.com', 'carol@example.com']))
  .build();

const authorsById = db.sql.public.user
  .select('id', 'email')
  .where((f, fns) => fns.in(f.id, db.sql.public.post.select('userId')))
  .build();

const authors = db.sql.public.user
  .select('id', 'email')
  .where((f, fns) => fns.exists(db.sql.public.post.select('id').where((inner, innerFns) => innerFns.eq(inner.post.userId, f.user.id))))
  .build();
```

Which aggregate functions exist depends on your database, and PostgreSQL gives you these eight. The contract type is the one you write in `contract.prisma`, and the PostgreSQL type is in brackets:

| Function                               | Returns                                                                                                                                           |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `count()` / `count(field)`             | `number`. With no argument it counts rows. With a field it counts that field's non-null values                                                    |
| `countBigInt()` / `countBigInt(field)` | `bigint`. Use it when the count can pass [2^53 - 1](#group-by-a-column-with-a-count)                                                              |
| `sum(field)`                           | `number` over an `Int` (`int4`) or `BigInt` (`int8`) column. A string over `Decimal` or `Numeric` (`numeric`), a `number` over `Float` (`float8`) |
| `sumBigInt(field)`                     | `bigint`. The sum over an integer column that can pass [2^53 - 1](#group-by-a-column-with-a-count)                                                |
| `avg(field)`                           | `number` over an `Int` (`int4`) or `Float` (`float8`) column                                                                                      |
| `avgDecimal(field)`                    | An exact decimal string. The version of `avg` that does not round                                                                                 |
| `min(field)`                           | The input column's own type. A `VarChar` column gives a `String` (`text`)                                                                         |
| `max(field)`                           | The input column's own type. A `VarChar` column gives a `String` (`text`)                                                                         |

On PostgreSQL, `fns` also has `ilike(expr, pattern)`, a case-insensitive SQL `LIKE` match for text columns, as in `fns.ilike(f.displayName, '%alice%')`. There is no `fns.like`, so write a case-sensitive `LIKE` in a [`fns.raw`](#fnsraw-and-returns) fragment that returns a boolean:

```ts title="src/find-users.ts"
const plan = db.sql.public.user
  .select('id', 'displayName')
  .where((f, fns) => fns.raw`${f.displayName} LIKE ${'%Alice%'}`.returns('pg/bool@1'))
  .build();
```

`ilike` does not work on a `native_enum` column, typed `pg.enum(...)`, because PostgreSQL cannot pattern-match an enum type. Passing one is a type error. See [Enums](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#enums).

Full-text search on PostgreSQL uses `fns.fullTextMatches(column, query)` to filter, `fns.fullTextRank(column, query)` to score, and `fns.fullTextHeadline(column, query)` to return the matching text with each match marked. Build `query` from the search text with `fns.websearchToTsquery(text)`, `fns.plaintoTsquery(text)`, `fns.phrasetoTsquery(text)`, or `fns.toTsquery(text)`, or with the `tsquery` template tag from `@prisma/orm-postgres/target/full-text`. Never pass user input to `fns.toTsquery()`, because text that breaks PostgreSQL's search syntax makes the query fail when it runs; use `fns.websearchToTsquery()` or the `tsquery` tag for user input. [Full-text search](https://www.prisma.io/docs/orm/reference/orm-client#full-text-search) on the ORM client reference explains what each of these does, and the index that lets PostgreSQL search without reading every row.

Each of the three full-text functions takes an options object as its last argument, and each accepts `language`. Pass the same `language` to the function that builds `query`, as in `fns.fullTextMatches(f.title, fns.websearchToTsquery(q, { language: 'german' }), { language: 'german' })`. `fullTextRank` also takes `normalization` and `coverDensity`, which the ORM client reference describes. `fullTextHeadline` also takes these options:

* `startSel` and `stopSel`: the text put before and after each match. PostgreSQL uses `<b>` and `</b>` when you leave them out.
* `maxWords` and `minWords`: the longest and shortest headline, in words. `minWords` must be lower than `maxWords`.
* `highlightAll: true`: return the whole text with every match marked, instead of a short excerpt around the matches.

This query returns each matching post with its rank and a headline that marks the matches with `<mark>`:

```ts title="src/search-posts.ts"
const q = 'prisma orm';
const plan = db.sql.public.post
  .select('id', 'title')
  .select('rank', (f, fns) => fns.fullTextRank(f.title, fns.websearchToTsquery(q)))
  .select('headline', (f, fns) =>
    fns.fullTextHeadline(f.title, fns.websearchToTsquery(q), { startSel: '<mark>', stopSel: '</mark>' }),
  )
  .where((f, fns) => fns.fullTextMatches(f.title, fns.websearchToTsquery(q)))
  .orderBy((f, fns) => fns.fullTextRank(f.title, fns.websearchToTsquery(q)), { direction: 'desc' })
  .limit(10)
  .build();

const results = await runtime.query(plan);
// { id: string; title: string; rank: number; headline: string }[]
```

`rank` is a `number`, and a higher rank is a better match. `headline` is a `string`: the title with each match between `<mark>` and `</mark>`.

pgvector is the PostgreSQL extension for vector columns. If your contract uses a pgvector type, such as `Embedding1536` in the example schema, pass pgvector in `extensions` when you create the client, because without it `postgres(...)` throws an error whose `code` is `RUNTIME.MISSING_EXTENSION_PACK`:

```ts title="src/prisma/db.ts"
import pgvector from '@prisma/orm-extension-pgvector/runtime';

const db = postgres<Contract>({
  contractJson,
  url: process.env.DATABASE_URL,
  extensions: [pgvector],
});
```

`fns` then also has `fns.cosineDistance(a, b)`, which returns the cosine distance between two vectors as a `number`. Each argument is a vector column or an array of numbers, as in `fns.cosineDistance(f.embedding, queryEmbedding)`. See [Extension types](https://www.prisma.io/docs/orm/contract-authoring/psl-syntax#extension-types).

### `fns.raw` and `.returns()` [#fnsraw-and-returns]

Write a raw SQL fragment as a tagged template, and interpolate columns, typed expressions, and bare JavaScript values with `${...}`. For a bare value, the builder picks the type id from its JavaScript type. [Binding a bare value with `param()`](https://www.prisma.io/docs/orm/reference/raw-queries#binding-a-bare-value-with-param) lists which JavaScript type becomes which type id, and shows how to choose a different one with `param(...)`. Call `.returns(typeId)` to declare the fragment's result type.

#### Options [#options-14]

| Name               | Type                                 | Required    | Description                                                                                                                                      |
| ------------------ | ------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| SQL fragment       | Tagged template                      | Yes         | The raw SQL, with `${...}` interpolations for columns and values.                                                                                |
| `.returns(typeId)` | `string`, or `{ codecId, nullable }` | Yes, always | Declares the result type, for example `'pg/int4@1'`, `'pg/text@1'`. For a fragment used as a `where()` predicate, write `.returns('pg/bool@1')`. |

#### Remarks [#remarks-6]

* **Always call `.returns()`.** Nothing in the builder accepts a fragment without it.
* **`.returns()` only tells TypeScript what type to expect.** It does not convert the value. Convert the value in JavaScript, or run the statement with [`db.raw.sql` and `.returnsRow()`](https://www.prisma.io/docs/orm/reference/raw-queries), which does decode.
* Use `fns.raw` for any SQL feature without a dedicated helper: `COALESCE`, `CAST`, `LENGTH`, `UPPER`, `EXTRACT`, and so on. There is no `fns.coalesce` and no `fns.cast`.

#### Examples [#examples-18]

##### Compute a column with a SQL function [#compute-a-column-with-a-sql-function]

```ts
const plan = db.sql.public.user
  .select('emailLength', (f, fns) => fns.raw`LENGTH(${f.email})`.returns('pg/int4@1'))
  .build();
```

## Compiling and executing [#compiling-and-executing]

### `build()` [#build]

Compile a query so you can run it.

#### Remarks [#remarks-7]

* `build()` takes **zero arguments** on every query type: select, insert, update, delete, and grouped. You supply parameter values where you write them, inside `insert([...])`, a `where()` callback, or a [`param()`](#param) call.

#### Return type [#return-type-16]

| Return type | Example                                   | Description                                                                                                             |
| ----------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Built query | `db.sql.public.user.select('id').build()` | A query you run with `runtime.query(...)`. You can get the TypeScript type of one row with [`ResultType`](#resulttype). |

### Running a built query [#executing-a-plan]

Run a built query with `runtime`, which is `db.runtime()`.

| Call                    | What you get                                                                                                                 |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `runtime.query(plan)`   | Rows. `await` it for an array of rows (`Row[]`), or `for await` over it to take one row at a time.                           |
| `runtime.execute(plan)` | `{ affectedRows }`.                                                                                                          |
| Which one               | `query` for anything that returns rows, which means a `SELECT` or a write with `returning()`. `execute` for everything else. |

### `ResultType` [#resulttype]

Recover a built query's row type at the type level.

#### Remarks [#remarks-8]

* Import `ResultType` from `@prisma/orm-postgres/components/runtime`. It works with the ORM client as well as the SQL builder.
* `ResultType<typeof plan>` is **one row**, not an array. `await runtime.query(plan)` resolves to `Row[]`, but `ResultType<typeof plan>` is `Row`.
* It also works on ORM queries: `ResultType<typeof db.orm.public.User.include('posts')>`. `db.orm` is keyed by model name, so the model is `User` there and the table is `user` under `db.sql`. See [Model and result types](https://www.prisma.io/docs/orm/reference/orm-client#model-and-result-types).

#### Examples [#examples-19]

##### Recover the row type from a built query [#recover-the-row-type-from-a-plan]

```ts
import type { ResultType } from '@prisma/orm-postgres/components/runtime';

const plan = db.sql.public.user.select('id', 'email').build();
type Row = ResultType<typeof plan>; // { id: string; email: string }

const rows = await runtime.query(plan); // Row[]
```

### Streaming vs. collecting [#streaming-vs-collecting]

`await runtime.query(plan)` collects every row into an array, which is the common case and what every example on this page uses. You can also loop the same result with `for await` to handle one row at a time. On PostgreSQL every row is loaded before the loop starts, so `for await` saves nothing there. Use `await`.

Keep the result in a variable, as in `const result = runtime.query(plan)`, and you can `await result` as many times as you like. You cannot mix `await` and `for await` on the same result, and you cannot `for await` it twice. Either one throws an error whose `code` is `RUNTIME.ITERATOR_CONSUMED`. See [`AsyncIterableResult`](https://www.prisma.io/docs/orm/reference/orm-client#asynciterableresult).

## Related pages

- [`Error reference`](https://www.prisma.io/docs/orm/reference/error-reference): Every structured error code Prisma ORM can emit, by namespace, with the condition that raises it.
- [`Migration API`](https://www.prisma.io/docs/orm/reference/migration-api): Every method and helper a migration.ts can use: the Migration class, the PostgreSQL operations, the column and constraint helpers, rawSql, and the MongoDB operations.
- [`ORM client reference`](https://www.prisma.io/docs/orm/reference/orm-client): Reference for the Prisma ORM client's query, mutation, filter, and aggregate methods.
- [`Pipeline builder reference`](https://www.prisma.io/docs/orm/reference/pipeline-builder): Reference for the Prisma ORM MongoDB pipeline builder's stages, accumulators, expression helpers, and write methods.
- [`Raw queries reference`](https://www.prisma.io/docs/orm/reference/raw-queries): Reference for Prisma ORM raw queries: PostgreSQL raw SQL and MongoDB raw commands.

# Transactions and runtime reference (/docs/orm/reference/transactions-and-runtime)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Reference for the Prisma ORM client lifecycle, transactions, prepared statements, and execution options.

Location: ORM > Reference > Transactions and runtime reference

Prisma ORM 8 renames `schema.prisma` to `contract.prisma`. Run `npx prisma contract emit`, which writes two files next to it: `contract.json`, which your app imports, and `contract.d.ts`, which gives you the TypeScript types. A new project keeps all three files in `src/prisma/`. Every client you create needs `contract.json`. The query you came for, `prisma.user.findMany({ where })`, is now `db.orm.public.User.where(...).all()`. [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) lists the packages to install, the commands to run, and the rest of the renamed calls.

`db` is the client that `postgres(...)` or `mongo(...)` returns. `db.runtime()` gives you the object that actually runs queries, and that object is called the runtime.

Create, connect, and close the client, run transactions, prepare statements, and set per-query execution options, on PostgreSQL and MongoDB. For a task-oriented walkthrough, see the Fundamentals guide to [Transactions](https://www.prisma.io/docs/orm/fundamentals/transactions). For the ways to query inside a transaction, see the [ORM client reference](https://www.prisma.io/docs/orm/reference/orm-client), the [SQL query builder reference](https://www.prisma.io/docs/orm/reference/sql-query-builder), and the [raw queries reference](https://www.prisma.io/docs/orm/reference/raw-queries).

Transactions are not available on MongoDB. To run one there, pass your own `MongoClient` with the `mongoClient` option and use the driver's `session.withTransaction(...)`, which [Transactions on MongoDB](https://www.prisma.io/docs/orm/fundamentals/transactions#transactions-on-mongodb) shows in code.

## Client lifecycle on PostgreSQL [#client-lifecycle-on-postgresql]

Create a PostgreSQL client with `postgres(...)`, connect it to get a runtime, run queries, and close it when you are done.

### `postgres(options)` [#postgresoptions]

Create a PostgreSQL client.

#### Remarks [#remarks]

* Import `contract.json` and pass it as `contractJson`, as every example below does. Pass `contract` only if you already hold a contract object; most code passes `contractJson`. Supply exactly one.
* The `<Contract>` type argument is what types `db.orm` and `db.sql`. `contract.d.ts` exports it under the name `Contract`. Pass it yourself whenever you pass `contractJson`, because TypeScript cannot read a type out of a JSON file. It is inferred only when you use the `contract` option.
* Tell the client which database to use in one of three ways: `url`, `pg`, or `binding`. A `binding` wraps any of the three choices in one object, with a `kind` field saying which it is: `{ kind: 'url', url }`, `{ kind: 'pgPool', pool }`, or `{ kind: 'pgClient', client }`. Use it when your code picks the source at run time. Pass exactly one of `url`, `pg`, and `binding`, or leave all three out and pass one to [`connect()`](#connect).
* When you pass a `pg` pool or client, you own it: call `db.close()` first, then close it yourself with `pool.end()`. When you pass a `url`, the client creates the pool and closes it. Set that pool's timeouts with `poolOptions`, which has no effect on a pool you supply yourself.
* Some types come from a PostgreSQL extension, such as a `pgvector.Vector(1536)` type in your `contract.prisma`. Run `npm install @prisma/orm-extension-pgvector` first. Then `import pgvector from '@prisma/orm-extension-pgvector/runtime'` and pass `extensions: [pgvector]`.
* A middleware is an object with a name and one or more hooks, such as `{ name: 'no-big-deletes', beforeQuery: (query) => { if (query.sql.includes('DELETE')) throw new Error('blocked') } }`. Throw from a hook to block the query. The hooks are `beforeCompile`, `beforeQuery`, `beforeExecute`, `interceptQuery`, `interceptExecute`, `onRow`, `afterQuery`, and `afterExecute`. See [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works).
* Migrations record in your database which contract it matches. With `verifyMarker: 'onFirstUse'`, the default, the first query checks that record and logs a warning on a mismatch, then runs anyway. If you see the warning, run `npx prisma db update`. `verifyMarker: false` skips the check.
* `postgres(options)` does not open a connection. The client opens one on first use, so [`connect()`](#connect) is optional: call it to open the connection up front and fail early.

#### Options [#options]

Pass exactly one of `url`, `pg`, and `binding`.

| Name                        | Type                                                                                 | Required | Description                                                                                                                                              |
| --------------------------- | ------------------------------------------------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `contractJson` / `contract` | JSON contract or contract value                                                      | Yes      | The contract. Supply exactly one.                                                                                                                        |
| `url`                       | `string`                                                                             | See note | A PostgreSQL connection string.                                                                                                                          |
| `pg`                        | `Pool` or `Client` from the `pg` package                                             | See note | An existing `pg` instance to use. You close it yourself.                                                                                                 |
| `binding`                   | `{ kind: 'url' \| 'pgPool' \| 'pgClient', ... }`                                     | See note | The same three choices in one object.                                                                                                                    |
| `poolOptions`               | `{ connectionTimeoutMillis?: number; idleTimeoutMillis?: number }`                   | No       | Timeouts for the pool the client creates from `url` (defaults `20000` / `30000`).                                                                        |
| `extensions`                | Array of extension runtimes, the default export of each package's `/runtime` subpath | No       | The PostgreSQL extensions your contract's types need. Install each package, then import its `/runtime` subpath and put the default export in this array. |
| `middleware`                | Array of middleware                                                                  | No       | Code that runs around every query. See [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works).                                                     |
| `verifyMarker`              | `'onFirstUse'` or `false`                                                            | No       | Whether the first query checks that the database was set up for this contract. Defaults to `'onFirstUse'`.                                               |

#### Return type [#return-type]

| Return type      | Example                                     | Description                                                        |
| ---------------- | ------------------------------------------- | ------------------------------------------------------------------ |
| `PostgresClient` | `postgres<Contract>({ contractJson, url })` | A client that has not connected yet. Its members are listed below. |

* `.orm` holds your models by model name. See the [ORM client reference](https://www.prisma.io/docs/orm/reference/orm-client).
* `.sql` is the SQL query builder, keyed by PostgreSQL schema, then by table name: `db.sql.public.tag`. The table name is the model's `@@map` value, or the model name exactly as written when the model sets no `@@map`. See the [SQL query builder reference](https://www.prisma.io/docs/orm/reference/sql-query-builder). Write raw SQL with ``db.raw.sql`...` ``, as the [raw queries reference](https://www.prisma.io/docs/orm/reference/raw-queries) shows.
* `.enums` holds the enum values from your contract, by PostgreSQL schema: `db.enums.public.Role`. `.nativeEnums` holds the values of enum types that exist in PostgreSQL itself, created with `CREATE TYPE`, also by schema. Look the type up by name in brackets: `db.nativeEnums.auth['AalLevel'].values` is `['aal1', 'aal2', 'aal3']`.
* `.contract` is the contract as an object. [`connect()`](#connect), [`runtime()`](#runtime), [`transaction()`](#dbtransactioncallback), [`prepare()`](#dbpreparedeclaration-callback), and [`close()`](#close) are documented on this page.

#### Examples [#examples]

##### Create a client from a connection string [#create-a-client-from-a-connection-string]

```typescript
import postgres from '@prisma/orm-postgres/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

const db = postgres<Contract>({ contractJson, url: process.env.DATABASE_URL! });
```

These examples assume the file is beside `contract.json` in `src/prisma/`, so from anywhere else, change the relative paths. Write `./contract.d` exactly like that, with no extension. It resolves under `preserve` or `esnext` with `bundler`, the settings `prisma orm init` writes, and under `nodenext` as CommonJS; under `nodenext`, `node18`, or `node20` as ES modules it does not, and the upgrade guide covers that case. The line `import contractJson from './contract.json' with { type: 'json' }` needs Node.js 22.18 or newer and TypeScript 5.9 or newer. In `tsconfig.json` it needs `resolveJsonModule: true` and one of these `module` settings, each with its `moduleResolution`: `preserve` with `bundler`, `esnext` with `bundler`, or `nodenext` with `nodenext`. `node18` and `node20` also work, with `moduleResolution` left unset. `prisma orm init` writes `preserve` and `bundler` into new projects. When `module` is `nodenext` and `package.json` has no `"type": "module"`, TypeScript treats the file as CommonJS, and there the import is `import contractJson from './contract.json';` with no `with` part. The [Prisma ORM 7 to 8 upgrade guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#26-set-up-tsconfigjson-for-the-prisma-orm-8-client) walks through which setting fits which kind of project. TypeScript types every `process.env` value as possibly undefined, so the examples write `!` after it, the same way `prisma orm init` does.

##### Bind to an existing `pg` pool [#bind-to-an-existing-pg-pool]

```typescript
import postgres from '@prisma/orm-postgres/runtime';
import { Pool } from 'pg';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

const pool = new Pool({ connectionString: process.env.DATABASE_URL! });
const db = postgres<Contract>({ contractJson, pg: pool });
```

### `connect()` [#connect]

Open a connection and return a runtime.

#### Remarks [#remarks-1]

* Returns a `Promise<Runtime>`. The runtime is the connected object that runs queries. It has these calls:
  * `runtime.query(built)` runs a built query and returns its rows. A built query is the object you get from `.build()` at the end of a builder or raw chain. See [Running a built query](https://www.prisma.io/docs/orm/reference/sql-query-builder#executing-a-plan).
  * `runtime.execute(built)` runs a built query that returns no rows, such as an insert, and returns `{ affectedRows }`. See [Running a built query](https://www.prisma.io/docs/orm/reference/sql-query-builder#executing-a-plan).
  * `runtime.connection()` takes one connection out of the pool so that several queries run on the same connection. It returns a promise, and you put the connection back with `connection.release()`: `const connection = await runtime.connection(); try { await connection.query(built) } finally { await connection.release() }`. See [Manual connection and transaction control](#manual-connection-and-transaction-control).
  * `runtime.prepare(declaration, callback)` prepares a statement you run many times with different values. The client has a `prepare()` too, and the two do the same thing. See [Prepared statements (PostgreSQL)](#prepared-statements-postgresql).
  * `runtime.telemetry()` reports how the most recent query went. See [`runtime.telemetry()`](#runtimetelemetry).
* `connect()` takes the same database options as `postgres(...)`, so a client you created without one can be given its database here: `await db.connect({ url: process.env.DATABASE_URL! })`, or `await db.connect({ binding: { kind: 'url', url } })`.
* Every error has a `code` property, and the [error reference](https://www.prisma.io/docs/orm/reference/error-reference) lists them all. Catch the error and compare `error.code` with the value shown here, for example `if (error.code === 'DRIVER.NOT_CONNECTED')`.
* Call `connect()` before any query, or not at all. Running a query connects the client, so a `connect()` after that rejects with an error whose `code` is `DRIVER.ALREADY_CONNECTED`. So does a second `connect()`.

#### Return type [#return-type-1]

| Return type        | Example                              | Description            |
| ------------------ | ------------------------------------ | ---------------------- |
| `Promise<Runtime>` | `const runtime = await db.connect()` | The connected runtime. |

#### Examples [#examples-1]

##### Connect and run a query [#connect-and-run-a-query]

```typescript
const runtime = await db.connect();
const tags = await runtime.query(db.sql.public.tag.select('id', 'label').build());
```

### `runtime()` [#runtime]

Get the current runtime synchronously.

#### Remarks [#remarks-2]

* On PostgreSQL, `runtime()` is **synchronous**: it returns the `Runtime` directly, not a promise. You can call it before connecting, because the client connects on first use.

#### Return type [#return-type-2]

| Return type | Example                        | Description                          |
| ----------- | ------------------------------ | ------------------------------------ |
| `Runtime`   | `const runtime = db.runtime()` | The runtime, returned synchronously. |

### `close()` [#close]

Close the client and release its pool.

#### Remarks [#remarks-3]

* Returns a `Promise<void>`. `close()` is safe to call at any time.
* After `close()`, `connect()` rejects and `runtime()` throws an error whose `code` is `DRIVER.NOT_CONNECTED` (`Postgres client is closed`).

#### Return type [#return-type-3]

| Return type     | Example            | Description                         |
| --------------- | ------------------ | ----------------------------------- |
| `Promise<void>` | `await db.close()` | Resolves when the client is closed. |

#### Examples [#examples-2]

##### Close when finished [#close-when-finished]

```typescript
const db = postgres<Contract>({ contractJson, url: process.env.DATABASE_URL! });
const admins = await db.orm.public.User.where((u) => u.kind.eq('admin')).all();
await db.close();
```

### `await using` (automatic disposal) [#await-using-automatic-disposal]

The client implements `Symbol.asyncDispose`, so `await using` closes it automatically at the end of its block.

#### Remarks [#remarks-4]

* Disposal fires at the end of the **block** the `await using` declaration lives in, not on the next line. Scope the client to the block where you need it. After the block exits, the client is closed the same way `close()` closes it: a later `connect()` rejects with an error whose `code` is `DRIVER.NOT_CONNECTED`.
* `await using` needs `@types/node` installed, or `"esnext.disposable"` added to the `lib` array in your `tsconfig.json`.

#### Examples [#examples-3]

##### Close automatically with `await using` [#close-automatically-with-await-using]

```typescript
{
  await using db = postgres<Contract>({ contractJson, url: process.env.DATABASE_URL! });
  const tags = await db.runtime().query(db.sql.public.tag.select('id', 'label').build());
} // db is closed here
```

## Client lifecycle on MongoDB [#client-lifecycle-on-mongodb]

Create a MongoDB client with `mongo(...)`. The entry point and several lifecycle details differ from PostgreSQL, most notably that `runtime()` is asynchronous.

### `mongo(options)` [#mongooptions]

Create a MongoDB client.

#### Remarks [#remarks-5]

* Pass the contract with `contractJson` or `contract` (supply exactly one), the same way as on PostgreSQL.
* Tell the client which database to use in one of four ways: `url`, `uri`, `mongoClient`, or `binding`. A `binding` wraps the choices in one object, with a `kind` field saying which it is: `{ kind: 'url', url, dbName }` or `{ kind: 'mongoClient', client, dbName }`. Use it when your code picks the source at run time, and use the `url` kind for a `uri`. Pass exactly one of the four, or leave all four out and pass one to [MongoDB `connect()`](#connect-1). `dbName` is separate and does not count as one of the four, so `{ url, dbName }` is allowed.
* With `url`, the database name comes from the path of the connection string, as in `mongodb://host:27017/app`. Add `dbName` to override that name, or when the string has no name in its path. `uri` takes the same kind of string, and always needs `dbName`.
* **Client ownership**: with `url` or `uri`, Prisma ORM creates the underlying `MongoClient` and closes it on `close()`. With `mongoClient`, you supplied the client, so Prisma ORM does **not** close it. Because `close()` leaves your client open, you can use one `MongoClient` both through Prisma ORM and in code you write against the `mongodb` package directly. You close that client yourself.
* `mongo(options)` does not open a connection. The runtime is built on first use, or explicitly via [MongoDB `connect()`](#connect-1).

#### Options [#options-1]

Pass exactly one of `url`, `uri`, `mongoClient`, and `binding`. `dbName` is separate, and `uri` and `mongoClient` both require it.

| Name                        | Type                                    | Required | Description                                                                                                                       |
| --------------------------- | --------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `contractJson` / `contract` | JSON contract or contract value         | Yes      | The contract. Supply exactly one.                                                                                                 |
| `url`                       | `string`                                | See note | A `mongodb://` or `mongodb+srv://` string, with the database name in its path.                                                    |
| `uri` + `dbName`            | `string` + `string`                     | See note | The same kind of string, plus the database name, which is required here.                                                          |
| `mongoClient` + `dbName`    | `MongoClient` + `string`                | See note | An existing `MongoClient` you own, plus the database name.                                                                        |
| `binding`                   | `{ kind: 'url' \| 'mongoClient', ... }` | See note | The same choices in one object.                                                                                                   |
| `middleware`                | Array of middleware                     | No       | Code that runs around every query. See [How middleware works](https://www.prisma.io/docs/orm/middleware/how-middleware-works).                              |
| `mode`                      | `'strict'` or `'permissive'`            | No       | Defaults to `'strict'`. Prisma ORM ignores this value. It is passed through to your middleware so your own code can branch on it. |

#### Return type [#return-type-4]

| Return type   | Example                                          | Description                                                                                                                                                         |
| ------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MongoClient` | `mongo<Contract>({ contractJson, url, dbName })` | A client that has not connected yet. This is Prisma ORM's own type. The `mongodb` driver has a class of the same name, so when you import both, name this one `db`. |

* `.orm` holds your models by collection name, with no `.public` in the path: `db.orm.users`. The collection name is the model's `@@map` value, or the model name exactly as written when the model sets no `@@map`. The [example schema](https://www.prisma.io/docs/orm/reference/orm-client#example-schema) sets `@@map("users")` on `User`, which is why the key here is `users`. See the [ORM client reference](https://www.prisma.io/docs/orm/reference/orm-client).
* `.query` is the pipeline builder, which builds MongoDB aggregation pipelines. See the [pipeline builder reference](https://www.prisma.io/docs/orm/reference/pipeline-builder). `.raw` sends raw MongoDB commands. See the [raw queries reference](https://www.prisma.io/docs/orm/reference/raw-queries).
* `.enums` holds the enum values from your contract, and `.contract` is the contract as an object. [MongoDB `connect()`](#connect-1), [MongoDB `runtime()`](#runtime-1), and [MongoDB `close()`](#close-1) are documented below.

#### Examples [#examples-4]

##### Create a client from a connection string [#create-a-client-from-a-connection-string-1]

```typescript
import mongo from '@prisma/orm-mongo/runtime';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

const db = mongo<Contract>({ contractJson, url: process.env.MONGODB_URL!, dbName: 'app' });
```

##### Share an existing `MongoClient` [#share-an-existing-mongoclient]

```typescript
import mongo from '@prisma/orm-mongo/runtime';
import { MongoClient } from 'mongodb';
import type { Contract } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };

// `MongoClient` here is the driver's class; the `db` below is Prisma ORM's own MongoClient type
const client = new MongoClient(process.env.MONGODB_URL!);
const db = mongo<Contract>({ contractJson, mongoClient: client, dbName: 'app' });
```

### `connect()` [#connect-1]

Open a connection and return a runtime.

#### Remarks [#remarks-6]

* Returns a `Promise<MongoRuntime>`. Call `connect()` before any query, or not at all. Running a query connects the client, so a `connect()` after that rejects with an error whose `code` is `DRIVER.ALREADY_CONNECTED`. So does a second `connect()`.
* `connect()` takes the same database options as `mongo(...)`, so a client you created without one can be given its database here: `await db.connect({ url: process.env.MONGODB_URL!, dbName: 'app' })`.

#### Return type [#return-type-5]

| Return type             | Example                              | Description                                                   |
| ----------------------- | ------------------------------------ | ------------------------------------------------------------- |
| `Promise<MongoRuntime>` | `const runtime = await db.connect()` | The connected runtime (`query`, `execute`, and `close` only). |

### `runtime()` [#runtime-1]

Get the runtime.

#### Remarks [#remarks-7]

* On MongoDB, `runtime()&#x60; returns a &#x2A;*`Promise<MongoRuntime>`**: you must `await` it. PostgreSQL's `runtime()` is synchronous, so write `await db.runtime()` on MongoDB and `db.runtime()` on PostgreSQL.
* `MongoRuntime` has `query`, `execute`, and `close` only. It has no `connection()`, `prepare()`, or `telemetry()`. See [Transactions (MongoDB)](#transactions-mongodb) and [Execution options and results](#execution-options-and-results).

#### Return type [#return-type-6]

| Return type             | Example                              | Description                           |
| ----------------------- | ------------------------------------ | ------------------------------------- |
| `Promise<MongoRuntime>` | `const runtime = await db.runtime()` | The runtime, resolved asynchronously. |

### `runtime.query()` [#runtimequery]

Run a built query through the runtime.

#### Remarks [#remarks-8]

* `(await db.runtime()).query(built)` runs any built MongoDB query, including one built by the [pipeline builder](https://www.prisma.io/docs/orm/reference/pipeline-builder) (`db.query`).
* Returns an [`AsyncIterableResult`](#asynciterableresult), which holds the rows the query returns: `await` it for an array, or `for await` to read the rows one at a time as they arrive.
* For an update or delete command, use `runtime.execute(built)`, which returns `{ affectedRows }`. Other commands throw an error whose `code` is `RUNTIME.MONGO_STATISTICS_UNSUPPORTED`. There is no `execute()` on the client itself.

#### Return type [#return-type-7]

| Return type                | Example                                   | Description             |
| -------------------------- | ----------------------------------------- | ----------------------- |
| `AsyncIterableResult<Row>` | `await (await db.runtime()).query(built)` | The built query's rows. |

#### Examples [#examples-5]

##### Run a query built by the pipeline builder [#run-a-pipeline-builder-plan]

```typescript
// 'posts' is the collection name, the same key you use on `db.orm`
const built = db.query.from('posts').build();
const posts = await (await db.runtime()).query(built);
```

### `close()` [#close-1]

Close the client.

#### Remarks [#remarks-9]

* Always call `db.close()`. `runtime.close()` leaves the client looking open, and later calls fail.
* Returns a `Promise<void>`. After `close()`, any further use rejects with an error whose `code` is `DRIVER.NOT_CONNECTED` (`Mongo client is closed`). That covers `db.runtime()` and ORM access such as `db.orm.users.first()`, since both go through the same runtime. When you supplied a `mongoClient`, `close()` does not close your client (see [`mongo(options)`](#mongooptions)).

#### Return type [#return-type-8]

| Return type     | Example            | Description                         |
| --------------- | ------------------ | ----------------------------------- |
| `Promise<void>` | `await db.close()` | Resolves when the client is closed. |

#### Examples [#examples-6]

##### Use after close throws [#use-after-close-throws]

```typescript
await db.close();
await db.runtime(); // rejects with DRIVER.NOT_CONNECTED
```

### `await using` (automatic disposal) [#await-using-automatic-disposal-1]

The MongoDB client implements `Symbol.asyncDispose` too, so `await using` closes it at the end of its block.

#### Remarks [#remarks-10]

* Disposal fires at the end of the block, exactly as on PostgreSQL. After the block exits, a later `connect()` rejects with an error whose `code` is `DRIVER.NOT_CONNECTED`.

#### Examples [#examples-7]

##### Close automatically with `await using` [#close-automatically-with-await-using-1]

```typescript
{
  await using db = mongo<Contract>({ contractJson, url: process.env.MONGODB_URL!, dbName: 'app' });
  await db.connect();
  // ... run queries ...
} // db is closed here
```

## Transactions (PostgreSQL) [#transactions-postgresql]

A transaction groups several writes into one unit: they all commit together, or they all roll back. Use `db.transaction(...)` in application code. If you are writing a function that takes a runtime as a parameter instead of the client, use `withTransaction(...)`. If you need to run several statements on one connection, get a connection with `runtime.connection()` and call `commit()` or `rollback()` yourself.

### `db.transaction(callback)` [#dbtransactioncallback]

Run a callback inside a transaction. The transaction commits when the callback returns and rolls back when it throws.

#### Remarks [#remarks-11]

* Query through `tx`, not `db`. `tx.orm` holds your models. Build queries with `tx.sql`, then run them with `tx.query(...)` to get rows back, or `tx.execute(...)` when the write returns no rows. `tx.execute(...)` resolves to `{ affectedRows }`, the number of rows the statement changed. Every call on `tx` uses the same transaction connection, and queries on `db` run outside the transaction.
* `db.transaction(...)` takes the callback and nothing else. There are no `isolationLevel`, `timeout`, or `maxWait` options, and Prisma ORM offers no way to set the isolation level. Nothing retries a failed transaction for you. Write the retry loop yourself. A transaction has no time limit. PostgreSQL's `idle_in_transaction_session_timeout` ends one that sits idle between statements, and on PostgreSQL 17 and later `transaction_timeout` caps its total length. Set either in your connection string or server configuration. See the [fundamentals transactions guide](https://www.prisma.io/docs/orm/fundamentals/transactions#options-and-isolation-level).
* To put a time limit on the queries inside a transaction, pass a `signal` to each `tx.query(...)` and `tx.execute(...)` call, as the example below does. See [`RuntimeExecuteOptions`](#runtimeexecuteoptions).
* `tx` has no `transaction()` method, so transactions do not nest. If a helper you call starts its own transaction, change it to take `tx` as a parameter instead. `TransactionContext`, imported from `@prisma/orm-postgres/family-runtime`, has `query` and `execute` only, so a helper typed with it cannot use `tx.orm` or `tx.sql`: `async function addTag(tx: TransactionContext) { ... }`. There is no exported type for the full `tx`, so derive it: `type Tx = Parameters<Parameters<typeof db.transaction>[0]>[0]`.
* `tx.sql` is a full SQL builder, keyed the same way as `db.sql`: use `tx.sql.public.<table>`, where `public` is the PostgreSQL schema.
* Reads inside the transaction see the transaction's own uncommitted writes.
* `tx.enums` and `tx.nativeEnums` are the same enum accessors the client has, and `.values` is the list of an enum's members.
* The callback's return value passes through as the result of `db.transaction(...)`.
* `tx.query(...)` returns an [`AsyncIterableResult`](#asynciterableresult) that works only while the transaction is open. Read it inside the callback. A result you return and then read after the transaction has ended rejects with an error whose `code` is `RUNTIME.TRANSACTION_CLOSED`. To act on a code, catch the error and compare `error.code` with the string. Every code is listed in the [error reference](https://www.prisma.io/docs/orm/reference/error-reference).

#### Options [#options-2]

| Name       | Type                 | Required | Description                                                                                        |
| ---------- | -------------------- | -------- | -------------------------------------------------------------------------------------------------- |
| `callback` | `(tx) => Promise<R>` | Yes      | The transactional work. `tx` exposes `orm`, `sql`, `query`, `execute`, `enums`, and `nativeEnums`. |

#### Return type [#return-type-9]

| Return type  | Example                                   | Description                                                               |
| ------------ | ----------------------------------------- | ------------------------------------------------------------------------- |
| `Promise<R>` | `await db.transaction(async (tx) => ...)` | Whatever the callback returns, so `R` is your callback's own return type. |

#### Examples [#examples-8]

##### Commit several writes atomically [#commit-several-writes-atomically]

```typescript
await db.transaction(async (tx) => {
  await tx.orm.public.Tag.create({ label: 'tx-commit-a' });
  await tx.orm.public.Tag.create({ label: 'tx-commit-b' });
});
// both tags exist now
```

##### Roll back when the callback throws [#roll-back-when-the-callback-throws]

```typescript
try {
  await db.transaction(async (tx) => {
    await tx.orm.public.Tag.create({ label: 'tx-rollback' });
    throw new Error('deliberate rollback');
  });
} catch {
  // the tag was rolled back and does not exist
}
```

##### Read your own uncommitted writes [#read-your-own-uncommitted-writes]

```typescript
const { createdId, found } = await db.transaction(async (tx) => {
  const created = await tx.orm.public.Tag.create({ label: 'tx-ryow' });
  const found = await tx.orm.public.Tag.where({ label: 'tx-ryow' }).first();
  return { createdId: created.id, found };
});
// found.id === createdId
```

##### Run a SQL builder query with `tx.sql` and `tx.execute` [#run-a-sql-builder-plan-with-txsql-and-txexecute]

```typescript
await db.transaction(async (tx) => {
  const signal = AbortSignal.timeout(5000); // give this statement five seconds
  await tx.execute(
    tx.sql.public.tag.insert([{ id: crypto.randomUUID(), label: 'tx-sql-insert' }]).build(),
    { signal },
  );
});
```

> [!WARNING]
> An escaped
> 
> `AsyncIterableResult`
> 
>  throws after the transaction ends
> 
> Collect the rows inside the callback by awaiting the result there, and return the array instead. A result is tied to the transaction connection, so if you return one from the callback and read it after the transaction has committed, it rejects with an error whose `code` is `RUNTIME.TRANSACTION_CLOSED`, before yielding any row.
> 
> ```typescript
> const escaped = await db.transaction(async (tx) => {
>   await tx.orm.public.Tag.create({ label: 'tx-escape' });
>   return { rows: tx.query(tx.sql.public.tag.select('label').build()) };
> });
>
> await escaped.rows.toArray(); // rejects with RUNTIME.TRANSACTION_CLOSED
> ```

For Prisma ORM 7 users, an array of queries becomes a callback:

```diff
- const [user, post] = await prisma.$transaction([
-   prisma.user.create({ data: { email, displayName } }),
-   prisma.post.create({ data: { title, userId } }),
- ]);
+ const { user, post } = await db.transaction(async (tx) => {
+   const user = await tx.orm.public.User.create({ email, displayName, kind: 'user' });
+   const post = await tx.orm.public.Post.create({ title, userId: user.id });
+   return { user, post };
+ });
```

The callback form does something the array form never could: one query's result (here `user.id`) can feed the next query in the same transaction.

### `withTransaction(runtime, callback)` [#withtransactionruntime-callback]

A transaction helper you import directly. Use it when you are writing a function that takes a runtime as a parameter instead of the client.

#### Remarks [#remarks-12]

* Imported from `@prisma/orm-postgres/family-runtime`, along with the `Runtime` type.
* The callback receives a transaction handle whose only methods are `query` and `execute`. Unlike `db.transaction(...)`'s `tx`, it has no `.orm` or `.sql`. Pass a SQL builder into your function as well, such as the client's `db.sql`, and build your queries with that.
* Commits on return, rolls back on throw, the same as `db.transaction(...)`.

#### Options [#options-3]

| Name       | Type                 | Required | Description                                                 |
| ---------- | -------------------- | -------- | ----------------------------------------------------------- |
| `runtime`  | `Runtime`            | Yes      | The runtime to open the transaction on.                     |
| `callback` | `(tx) => Promise<R>` | Yes      | The transactional work. `tx` exposes `query` and `execute`. |

#### Return type [#return-type-10]

| Return type  | Example                                             | Description                    |
| ------------ | --------------------------------------------------- | ------------------------------ |
| `Promise<R>` | `await withTransaction(runtime, async (tx) => ...)` | Whatever the callback returns. |

#### Examples [#examples-9]

##### Commit two writes with `withTransaction` [#commit-two-writes-with-withtransaction]

```typescript
import { withTransaction, type Runtime } from '@prisma/orm-postgres/family-runtime';

async function addTags(runtime: Runtime, sql: typeof db.sql) {
  return withTransaction(runtime, async (tx) => {
    await tx.execute(sql.public.tag.insert([{ id: crypto.randomUUID(), label: 'wt-commit-1' }]).build());
    await tx.execute(sql.public.tag.insert([{ id: crypto.randomUUID(), label: 'wt-commit-2' }]).build());
  });
}

await addTags(db.runtime(), db.sql);
```

### Manual connection and transaction control [#manual-connection-and-transaction-control]

The lowest level: acquire a connection, open a transaction on it, commit or roll back yourself, and return the connection to the pool. Use it when you need several statements on one connection, such as a read and then a write with no transaction around them.

#### Remarks [#remarks-13]

* `runtime.connection()` returns a dedicated connection. `connection.transaction()` opens a transaction on it. Run built queries with `transaction.query(...)` for rows or `transaction.execute(...)` for writes that return no rows, then call `transaction.commit()` or `transaction.rollback()`. Always `release()` the connection when done, to return it to the pool. Commit or roll back on every path first, then release: the examples nest a `try` for the transaction inside the `try` whose `finally` releases the connection, so a statement that throws neither leaves the transaction open nor leaks the connection.
* `connection.destroy()` throws that connection away instead of returning it to the pool. Use `destroy()` only for a connection you no longer trust.

#### Options [#options-4]

| Method                                            | Type | Description                                                     |
| ------------------------------------------------- | ---- | --------------------------------------------------------------- |
| `runtime.connection()`                            | none | Returns a `Promise` of a dedicated connection.                  |
| `connection.transaction()`                        | none | Returns a `Promise` of a transaction on that connection.        |
| `transaction.commit()` / `transaction.rollback()` | none | Commit or discard the transaction.                              |
| `connection.release()`                            | none | Return the connection to the pool.                              |
| `connection.destroy()`                            | none | Throw this connection away instead of returning it to the pool. |

#### Examples [#examples-10]

##### Commit manually, then release [#commit-manually-then-release]

```typescript
const runtime = db.runtime();
const connection = await runtime.connection();
try {
  await connection.query(db.sql.public.tag.select('id').limit(1).build()); // a read on this connection
  const transaction = await connection.transaction();
  try {
    await transaction.execute(
      db.sql.public.tag.insert([{ id: crypto.randomUUID(), label: 'manual-commit' }]).build(),
    );
    await transaction.commit();
  } catch (error) {
    await transaction.rollback();
    throw error;
  }
} finally {
  await connection.release();
}
```

##### Roll back manually, then release [#roll-back-manually-then-release]

```typescript
const connection = await runtime.connection();
try {
  const transaction = await connection.transaction();
  try {
    await transaction.execute(
      db.sql.public.tag.insert([{ id: crypto.randomUUID(), label: 'manual-rollback' }]).build(),
    );
  } finally {
    await transaction.rollback();
  }
} finally {
  await connection.release();
}
```

##### Throw a connection away with `destroy()` [#throw-a-connection-away-with-destroy]

```typescript
const connection = await runtime.connection();
await connection.destroy();
// the runtime stays healthy and opens a replacement connection on the next query
```

## Transactions (MongoDB) [#transactions-mongodb]

> [!NOTE]
> MongoDB transactions are not available in Prisma ORM yet
> 
> There is no `db.transaction(...)` on the MongoDB client, and the MongoDB runtime has no `connection()`, `prepare()`, or `telemetry()`: it has `query`, `execute`, and `close` and nothing else. Single-document write operations are atomic on their own, while multi-document transactions through Prisma ORM are planned, not shipped. To run one today, create your own `MongoClient`, pass it as the `mongoClient` option when you create the client, and group the writes in `session.withTransaction(...)`, as the [Fundamentals transactions guide](https://www.prisma.io/docs/orm/fundamentals/transactions#transactions-on-mongodb) shows. The reading rules under [`AsyncIterableResult`](#asynciterableresult) apply to MongoDB too.

## Prepared statements (PostgreSQL) [#prepared-statements-postgresql]

A prepared statement compiles a query once against a declaration of its parameters, then runs it repeatedly with different values. Prepared statements are not available on MongoDB.

### `runtime.prepare(declaration, callback)` [#runtimepreparedeclaration-callback]

Prepare a statement from a runtime.

#### Remarks [#remarks-14]

* The declaration maps each parameter name to a type id, for example `{ label: 'pg/text@1' }`. Use `db.sql.public.<table>.columns.<column>.codecId` to get any column's id. The [table on the raw queries page](https://www.prisma.io/docs/orm/reference/raw-queries#binding-a-bare-value-with-param) lists the common ones.
* The callback takes one argument, the declared `params`, and returns the built query, which is what `.build()` gives you. `SqlQueryPlan` in the tables below is the type of a built query. Build it with a SQL builder you already hold, such as `db.sql`. In the `where((f, fns) => ...)` calls below, `f` holds the table's columns and `fns` holds the comparison functions.
* A declared parameter that the callback never uses is rejected at prepare time with an error whose `code` is `RUNTIME.PREPARE_UNUSED_PARAM`, with `details.unused` listing the parameter names you declared but did not use. The rejection happens at `prepare()`, before any execution.
* The resulting `PreparedStatement` runs via `ps.query(target, params)`; see [`PreparedStatement.query`](#preparedstatementquerytarget-params).

#### Options [#options-5]

| Name          | Type                                 | Required | Description                                |
| ------------- | ------------------------------------ | -------- | ------------------------------------------ |
| `declaration` | Object mapping param name to type id | Yes      | The statement's parameters.                |
| `callback`    | `(params) => SqlQueryPlan`           | Yes      | Builds the query from the declared params. |

#### Return type [#return-type-11]

| Return type                  | Example                                                          | Description                    |
| ---------------------------- | ---------------------------------------------------------------- | ------------------------------ |
| `Promise<PreparedStatement>` | `await runtime.prepare({ label: 'pg/text@1' }, (params) => ...)` | A reusable prepared statement. |

#### Examples [#examples-11]

##### Prepare and run a statement [#prepare-and-run-a-statement]

```typescript
const runtime = db.runtime();
const ps = await runtime.prepare({ label: 'pg/text@1' }, (params) =>
  db.sql.public.tag.select('id', 'label').where((f, fns) => fns.eq(f.label, params.label)).limit(1).build(),
);

const typescript = await ps.query(runtime, { label: 'typescript' });
const missing = await ps.query(runtime, { label: 'does-not-exist' });
// typescript has one row; missing has none
```

##### An unused declared parameter is rejected at prepare time [#an-unused-declared-parameter-is-rejected-at-prepare-time]

```typescript
await runtime.prepare({ label: 'pg/text@1', unused: 'pg/int4@1' }, (params) =>
  db.sql.public.tag.select('id', 'label').where((f, fns) => fns.eq(f.label, params.label)).limit(1).build(),
);
// rejects with RUNTIME.PREPARE_UNUSED_PARAM, details: { unused: ['unused'] }
```

### `db.prepare(declaration, callback)` [#dbpreparedeclaration-callback]

Prepare a statement on the client itself.

#### Remarks [#remarks-15]

* The callback takes one argument, the declared `params`, as it does on `runtime.prepare(...)`. Build the query with the client's own `db.sql` or `db.orm`.
* The callback can return a built SQL query, or an ORM query that ends in `.prepared.all()`, `.prepared.first()`, or `.prepared.aggregate(...)`. `.prepared` always goes right before that last call, so a grouped aggregate is written `db.orm.public.Post.groupBy('userId').prepared.aggregate((agg) => ({ posts: agg.count() }))`.
* The ORM query is built once. `db.prepare(...)` resolves to a prepared query, here called `ps`, and you run it with `ps.query(db.runtime(), values)`, where `values` holds a value for each declared parameter. A connection or a transaction also works in place of `db.runtime()`. Each run uses the new values and returns what the same call without `.prepared` returns:
  * `all()` returns the rows, as an [`AsyncIterableResult`](#asynciterableresult) that you `await` for an array.
  * `first()` returns a promise of one row, or of `null` when no row matches.
  * `aggregate(...)` returns a promise of the aggregate object.
  * `groupBy(...)` followed by `aggregate(...)` returns a promise of an array with one object per group.
* `prepare()` starts the connection itself. Call `db.runtime()` for the runtime. `db.connect()` would throw an error whose `code` is `DRIVER.ALREADY_CONNECTED`, because `prepare()` already connected.

#### Options [#options-6]

| Name          | Type                                               | Required | Description                                                           |
| ------------- | -------------------------------------------------- | -------- | --------------------------------------------------------------------- |
| `declaration` | Object mapping param name to type id               | Yes      | The statement's parameters.                                           |
| `callback`    | `(params) => SqlQueryPlan` or a prepared ORM query | Yes      | Builds the query from the declared params, with `db.sql` or `db.orm`. |

#### Return type [#return-type-12]

| Return type                  | Example                                                     | Description                    |
| ---------------------------- | ----------------------------------------------------------- | ------------------------------ |
| `Promise<PreparedStatement>` | `await db.prepare({ label: 'pg/text@1' }, (params) => ...)` | A reusable prepared statement. |

#### Examples [#examples-12]

##### Prepare a SQL builder query off the client [#prepare-a-sql-builder-query-off-the-client]

```typescript
const ps = await db.prepare({ label: 'pg/text@1' }, (params) =>
  db.sql.public.tag.select('id', 'label').where((f, fns) => fns.eq(f.label, params.label)).limit(1).build(),
);

const rows = await ps.query(db.runtime(), { label: 'typescript' });
```

##### Prepare an ORM read and an aggregate [#prepare-an-orm-read-and-an-aggregate]

```typescript title="src/prepared-reads.ts"
const byLabel = await db.prepare({ label: 'pg/text@1' }, (params) =>
  db.orm.public.Tag.select('id', 'label').prepared.first({ label: params.label }),
);
const tag = await byLabel.query(db.runtime(), { label: 'typescript' });
// { id: '...', label: 'typescript' }, or null

const countTags = await db.prepare({}, () =>
  db.orm.public.Tag.prepared.aggregate((agg) => ({ total: agg.count() })),
);
const { total } = await countTags.query(db.runtime(), {});
```

In an ORM query, a prepared parameter works in `where(...)` filters, in the callback you pass to `include(...)`, and in `.limit(...)` and `.offset(...)`, so the same statement can page through results. Declare a page size or offset as `'pg/int4@1'`, as in `{ take: 'pg/int4@1' }`, and pass `params.take` to `.limit(...)`. A text type id such as `'pg/text@1'`, or a nullable one such as `{ codecId: 'pg/int4@1', nullable: true }`, is a type error there.

### `PreparedStatement.query(target, params)` [#preparedstatementquerytarget-params]

Run a prepared statement against a target, with the parameter values.

#### Remarks [#remarks-16]

* A query that returns rows prepares into a `PreparedStatement`, which you run with `query(...)`. Some queries return a row count instead of rows. End the query with `.affectedCount()`. Preparing one gives you a `PreparedExecution`, which you run with `execute(target, params)`. It resolves to `{ affectedRows }`. See the [raw queries reference](https://www.prisma.io/docs/orm/reference/raw-queries):

  ```typescript
  const archive = await runtime.prepare({ label: 'pg/text@1' }, (params) =>
    db.raw.sql`UPDATE "tag" SET label = 'archived' WHERE label = ${params.label}`.affectedCount().build(),
  );

  const { affectedRows } = await archive.execute(runtime, { label: 'stale' });
  ```

* You must pass `target`. It is the runtime, connection, or transaction the statement runs on. One prepared statement runs against any of them.

* A prepared statement has no `close()` method and nothing to dispose. Hold one for as long as you like and reuse it.

#### Options [#options-7]

| Name     | Type                                    | Required | Description                    |
| -------- | --------------------------------------- | -------- | ------------------------------ |
| `target` | `Runtime`, connection, or transaction   | Yes      | Where to run the statement.    |
| `params` | Object of the declared parameter values | Yes      | The values for this execution. |

#### Return type [#return-type-13]

| Return type                | Example                              | Description                                            |
| -------------------------- | ------------------------------------ | ------------------------------------------------------ |
| `AsyncIterableResult<Row>` | `await ps.query(runtime, { label })` | The statement's rows. `await` the result for an array. |

A prepared ORM query from [`db.prepare(...)`](#dbpreparedeclaration-callback) is different: its `query(...)` returns what the same ORM call returns, so a prepared `first()` gives a promise of one row or `null`.

#### Examples [#examples-13]

##### Run one prepared statement against a transaction and the runtime [#run-one-prepared-statement-against-a-transaction-and-the-runtime]

```typescript
import { withTransaction } from '@prisma/orm-postgres/family-runtime';

const ps = await runtime.prepare({ label: 'pg/text@1' }, (params) =>
  db.sql.public.tag.select('id', 'label').where((f, fns) => fns.eq(f.label, params.label)).limit(1).build(),
);

const insertedId = await withTransaction(runtime, async (tx) => {
  await tx.execute(db.sql.public.tag.insert([{ id: crypto.randomUUID(), label: 'ps-both-targets' }]).build());
  const inTx = await ps.query(tx, { label: 'ps-both-targets' }); // runs against the transaction
  return inTx[0]!.id;
});

const committed = await ps.query(runtime, { label: 'ps-both-targets' }); // runs against the runtime
// committed[0].id === insertedId
```

## Execution options and results [#execution-options-and-results]

`runtime.query(...)`, `runtime.execute(...)`, `tx.query(...)`, `tx.execute(...)`, `connection.query(...)`, and `connection.execute(...)` all take a `RuntimeExecuteOptions` object as their second argument. A prepared statement takes it as a third argument, after `target` and `params`.

### `RuntimeExecuteOptions` [#runtimeexecuteoptions]

Per-query options for cancellation.

#### Remarks [#remarks-17]

* `signal` is an `AbortSignal` for per-query cancellation. A signal that is **already aborted** when you call `query(...)` rejects before any row is fetched, with an error whose `code` is `RUNTIME.ABORTED`. The error's `cause` is the signal's reason, exactly as you passed it to `controller.abort(...)`.
* An abort that lands after rows have started arriving ends the stream with the same `RUNTIME.ABORTED` error. `details.phase` says where the abort landed.
* Inside `db.transaction(...)` the aborted statement throws, so your callback throws and the transaction rolls back.

#### Options [#options-8]

| Name     | Type                                         | Required | Description                                                                                                          |
| -------- | -------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
| `signal` | `AbortSignal`                                | No       | Per-query cancellation signal.                                                                                       |
| `scope`  | `'runtime' \| 'connection' \| 'transaction'` | No       | A label middleware reads. The runtime sets it; setting it yourself changes only the label, not where the query runs. |

#### Examples [#examples-14]

##### A pre-aborted signal short-circuits [#a-pre-aborted-signal-short-circuits]

```typescript
const controller = new AbortController();
controller.abort(new Error('cancelled'));

await runtime.query(db.sql.public.tag.select('id').limit(1).build(), {
  signal: controller.signal,
});
// rejects with RUNTIME.ABORTED
```

### `runtime.telemetry()` [#runtimetelemetry]

Read telemetry about the most recent query.

#### Remarks [#remarks-18]

* PostgreSQL only. `telemetry()` does not exist on the MongoDB runtime. Read it after a query to log how long that query took and whether it succeeded.
* `telemetry()` returns `null` on a freshly-connected runtime, before any query has run. After a query, it returns an object of the shape `{ lane, target: 'postgres', fingerprint, outcome, durationMs? }`. The object reflects only the **most recent** query, not a running history.
* `lane` says which API built the query, such as `orm-client` for `db.orm` or `raw` for `db.raw.sql`.
* Every run of the same query text shares one `fingerprint`, whatever values you pass, so you can group runs of one query together.
* `outcome` is `'success'` or `'runtime-error'`. `durationMs` is how long the query took. It is optional in the type, and it is set for every query the runtime ran.

#### Return type [#return-type-14]

| Return type                | Example               | Description                                                    |
| -------------------------- | --------------------- | -------------------------------------------------------------- |
| Telemetry object or `null` | `runtime.telemetry()` | The most recent query's telemetry, or `null` before any query. |

#### Examples [#examples-15]

##### Read telemetry before and after a query [#read-telemetry-before-and-after-a-query]

```typescript
const before = runtime.telemetry(); // null

await runtime.query(db.sql.public.tag.select('id').limit(1).build());

const after = runtime.telemetry();
// { lane, target: 'postgres', fingerprint, outcome: 'success', durationMs? }
```

### `AsyncIterableResult` [#asynciterableresult]

[`all()`](https://www.prisma.io/docs/orm/reference/orm-client#all), [`createAll()`](https://www.prisma.io/docs/orm/reference/orm-client#createall), and the runtime's `query(...)` return an `AsyncIterableResult`. `all()` and `query(...)` read rows, and `createAll()` writes rows and returns the ones it wrote. `await` the result to collect an array, or `for await` it to take rows one at a time.

Use `await`, and use `for await` only to handle rows as they arrive. On PostgreSQL it does not reduce memory, because every row is loaded first.

Pick `await` or `for await` for a given result and do not mix the two. Calling `.toArray()` does the same thing as `await`. Re-`await`ing a result you already awaited is safe and returns the same array, but switching between `await` and `for await`, or looping a second time with `for await`, throws an error whose `code` is `RUNTIME.ITERATOR_CONSUMED`. For the full rules on reading a result, shared identically by PostgreSQL and MongoDB, see [`AsyncIterableResult`](https://www.prisma.io/docs/orm/reference/orm-client#asynciterableresult) in the ORM client reference.

## Related pages

- [`Error reference`](https://www.prisma.io/docs/orm/reference/error-reference): Every structured error code Prisma ORM can emit, by namespace, with the condition that raises it.
- [`Migration API`](https://www.prisma.io/docs/orm/reference/migration-api): Every method and helper a migration.ts can use: the Migration class, the PostgreSQL operations, the column and constraint helpers, rawSql, and the MongoDB operations.
- [`ORM client reference`](https://www.prisma.io/docs/orm/reference/orm-client): Reference for the Prisma ORM client's query, mutation, filter, and aggregate methods.
- [`Pipeline builder reference`](https://www.prisma.io/docs/orm/reference/pipeline-builder): Reference for the Prisma ORM MongoDB pipeline builder's stages, accumulators, expression helpers, and write methods.
- [`Raw queries reference`](https://www.prisma.io/docs/orm/reference/raw-queries): Reference for Prisma ORM raw queries: PostgreSQL raw SQL and MongoDB raw commands.

# Prisma 7 (/docs/orm/v7)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma ORM is a next-generation Node.js and TypeScript ORM that provides type-safe database access, migrations, and a visual data editor.

Location: ORM > Prisma 7

Prisma ORM is [open-source](https://github.com/prisma/orm) and consists of:

* [**Prisma Client**](https://www.prisma.io/docs/orm/v7/prisma-client): Auto-generated, type-safe **ORM interface**
* [**Prisma Migrate**](https://www.prisma.io/docs/orm/v7/prisma-migrate): Database migration system
* [**Prisma Studio**](https://www.prisma.io/studio): GUI to view and edit your data

Prisma Client works with any Node.js or TypeScript backend, whether you're deploying to traditional servers, serverless functions, or microservices.

> [!NOTE]
> Try Prisma 8
> 
> Prisma 8 is the current release of Prisma ORM. Start with the [Prisma 8 getting started guide](https://www.prisma.io/docs/getting-started) and share feedback in [Discord](https://pris.ly/discord?utm_source=docs\&utm_medium=inline_text). This section documents Prisma 7, which remains fully supported.

## Get started [#get-started]

- [Quickstart](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres): Prisma ORM 7 with Prisma Postgres in about 5 minutes.

- [Add to an existing project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql): Introspect your database and start querying with Prisma ORM 7.

- [Prisma 8 docs](https://www.prisma.io/docs/orm): The docs for the current major version.

If you're working with a coding agent, copy the prompt below, or start from the [getting started page](https://www.prisma.io/docs) for the full stack.

```text
Add Prisma ORM 7 to this project with my existing database.

If I have not given you a database connection string and none exists in the project, stop and ask.

1. Run `npx prisma@prev init` (Prisma 7). For an existing database, set DATABASE_URL in `.env` and introspect it with `npx prisma@prev db pull`; for a new schema, define models in `prisma/schema.prisma` and run `npx prisma@prev migrate dev --name init`. If migrate dev asks to reset the database, stop and ask me first.
2. Install the driver adapter for the database (Prisma 7 requires one), e.g. `npm install @prisma/adapter-pg` for PostgreSQL, and pass it to `new PrismaClient({ adapter })`. Generate the client with `npx prisma@prev generate` and write one query in an existing code path.
3. Run the query (e.g. with `npx tsx`) and show me the output, the schema, and the query you added.

Current docs: https://www.prisma.io/docs/orm/v7.md and https://www.prisma.io/docs/llms.txt.
```

## Why Prisma ORM [#why-prisma-orm]

Traditional database tools force a tradeoff between **productivity** and **control**. Raw SQL gives full control but is error-prone and lacks type safety. Traditional ORMs improve productivity but abstract too much, leading to the [object-relational impedance mismatch](https://en.wikipedia.org/wiki/Object-relational_impedance_mismatch) and performance pitfalls like the n+1 problem.

Prisma takes a different approach:

* **Type-safe queries** validated at compile time with full autocompletion
* **Thinking in objects** without the complexity of mapping relational data
* **Plain JavaScript objects** returned from queries, not complex model instances
* **Single source of truth** in the Prisma schema for database and application models
* **Healthy constraints** that prevent common pitfalls and anti-patterns

## When to use Prisma [#when-to-use-prisma]

**Prisma is a good fit if you:**

* Build server-side applications (REST, GraphQL, gRPC, serverless)
* Want type safety and editor autocompletion for queries
* Work in a team and want a clear, declarative schema
* Need migrations, querying, and data modeling in one toolkit

**Consider alternatives if you:**

* Need full control over every SQL query (use raw SQL drivers)
* Want a no-code backend (use a BaaS like Supabase or Firebase)
* Need an auto-generated CRUD GraphQL API (use Hasura or PostGraphile)

## How it works [#how-it-works]

### 1. Define your schema [#1-define-your-schema]

The [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) defines your data models and database connection:

```prisma
datasource db {
  provider = "postgresql"
}

generator client {
  provider = "prisma-client"
  output   = "./generated"
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  published Boolean @default(false)
  author    User?   @relation(fields: [authorId], references: [id])
  authorId  Int?
}
```

### 2. Configure your connection [#2-configure-your-connection]

Create a `prisma.config.ts` file in your project root:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 3. Run migrations [#3-run-migrations]

Use [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) to create and apply migrations:

  

#### bun

```bash
bunx prisma@prev migrate dev
```

#### pnpm

```bash
pnpm dlx prisma@prev migrate dev
```

#### yarn

```bash
yarn dlx prisma@prev migrate dev
```

#### npm

```bash
npx prisma@prev migrate dev
```

Or [introspect](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) an existing database:

  

#### bun

```bash
bunx prisma@prev db pull
```

#### pnpm

```bash
pnpm dlx prisma@prev db pull
```

#### yarn

```bash
yarn dlx prisma@prev db pull
```

#### npm

```bash
npx prisma@prev db pull
```

### 4. Query with Prisma Client [#4-query-with-prisma-client]

Generate and use the type-safe client:

  

#### bun

```bash
bun add @prisma/client@7
bunx prisma@prev generate
```

#### pnpm

```bash
pnpm add @prisma/client@7
pnpm dlx prisma@prev generate
```

#### yarn

```bash
yarn add @prisma/client@7
yarn dlx prisma@prev generate
```

#### npm

```bash
npm install @prisma/client@7
npx prisma@prev generate
```

```ts
import { PrismaClient } from "./generated/client";
// Import the driver adapter for your specific database (example uses PostgreSQL)
import { PrismaPg } from "@prisma/adapter-pg";

// Initialize the adapter according to your driver's requirements
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });

// Pass the adapter instance to PrismaClient
const prisma = new PrismaClient({ adapter });

// Find all users with their posts
const users = await prisma.user.findMany({
  include: { posts: true },
});

// Create a user with a post
const user = await prisma.user.create({
  data: {
    email: "alice@prisma.io",
    posts: {
      create: { title: "Hello World" },
    },
  },
});
```

> [!NOTE]
> Prisma 7 Connection Requirements
> 
> Starting with **Prisma 7**, providing a [driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers) is mandatory for direct database connections. This change standardizes database connectivity across Node.js, Serverless, and Edge environments.
> 
> Hosted Prisma Accelerate connections are retiring on December 1, 2026. If your Prisma Postgres application still uses a hosted `prisma+postgres://` URL, [switch to pooled TCP or the Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/switch-from-accelerate).
> 
> To ensure compatibility:
> 
> * **Install an adapter:** Use the specific package for your database (e.g., `@prisma/adapter-pg`, `@prisma/adapter-mariadb`, etc.).
> * **Enable ESM:** Your `package.json` must include `"type": "module"`.
> 
> For detailed instructions, see the [V7 Upgrade Guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v7).

## Next steps [#next-steps]

* [**Prisma schema**](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) - Learn the schema language
* [**Prisma Client**](https://www.prisma.io/docs/orm/v7/prisma-client) - Explore the query API

## Related pages

- [`Coming from Prisma ORM 7`](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7): What each Prisma ORM 7 schema attribute, command, and query is called in Prisma ORM 8, and what is not available.
- [`Core concepts`](https://www.prisma.io/docs/orm/core-concepts): The ideas every Prisma ORM command and API builds on: contracts, emitting, plans, the database signature, codecs, and the migration graph.
- [`Extensions`](https://www.prisma.io/docs/orm/extensions): Every package that plugs into Prisma ORM: database packages, column types, indexes, query operations, and middleware, by Prisma and the community.
- [`Overview`](https://www.prisma.io/docs/orm/data-modeling): Describe the data your application needs with models, primary keys, scalar fields, and relations.
- [`Prisma ORM`](https://www.prisma.io/docs/orm/v6): Learn about Prisma ORM

# Backups (/docs/postgres/database/backups)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Manage and restore database backups in Prisma Postgres

Location: Postgres > Database > Backups

## Overview [#overview]

On [Starter, Pro, and Business plans](https://www.prisma.io/pricing), Prisma Postgres automatically creates snapshots of your database to support recovery and backup workflows. Navigate to the **Backups** tab of your Prisma Postgres instance in the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres) to view and re-instantiate your available backups.

Snapshots are created *daily*, but only on days when the database has activity. Depending on your plan, you will see a different number of available snapshots:

| Plan     | Snapshot retention |
| -------- | ------------------ |
| Starter  | Last 7 days        |
| Pro      | Last 7 days        |
| Business | Last 30 days       |

Database changes or events that occurred after the most recent snapshot may not be restored.

For more details about backup availability and plan-specific features, visit our [pricing page](https://www.prisma.io/pricing).

> [!NOTE]
> In the future, Prisma Postgres will provide more fine-grained backup mechanisms based on user specific configurations and with point-in-time restore functionality.

## Manually creating a backup file via `pg_dump` [#manually-creating-a-backup-file-via-pg_dump]

If you would like to create a backup file of your database, you can use `pg_dump` with a [direct connection](https://www.prisma.io/docs/postgres/database/connecting-to-your-database). This is useful for migrating data between databases or creating a local copy of your database.

## Prerequisites [#prerequisites]

Before you begin, make sure you have:

* **Node.js** installed (version 16 or higher).
* **PostgreSQL CLI Tools** (`pg_dump`) for creating backups. Use Postgres version 17 as Prisma Postgres is based on this version.
* A **direct connection string** for your Prisma Postgres database.

## 1. Install PostgreSQL command-line tools [#1-install-postgresql-command-line-tools]

To create backups, ensure you have the PostgreSQL command-line tools installed. Run the following commands based on your operating system:

  

#### macOS

```bash
brew install postgresql@17
which pg_dump
which pg_restore
```

#### Windows

```bash
# Download from the official PostgreSQL website:
# https://www.postgresql.org/download/windows/
# During installation, select "Command Line Tools".
# Then verify with:

where pg_dump
where pg_restore
```

#### Linux

```bash
sudo apt-get update
sudo apt-get install postgresql-client-17
which pg_dump
which pg_restore
```

> [!NOTE]
> If you installed PostgreSQL but still see a "command not found" error for `pg_dump` or `pg_restore`, ensure your installation directory is in your system's `PATH` environment variable.

### 2. Creating the Backup with `pg_dump` [#2-creating-the-backup-with-pg_dump]

Get your direct connection string by following [Connecting to your database](https://www.prisma.io/docs/postgres/database/connecting-to-your-database).

You can now dump the database by running the following command and using your own connection string:

```bash
pg_dump --dbname="postgres://USER:PASSWORD@db.prisma.io:5432/?sslmode=require" > ./mydatabase.bak
```

This will create your backup file named `mydatabase.bak` in the current directory.

## Related pages

- [`Connect to Prisma Postgres without Accelerate`](https://www.prisma.io/docs/postgres/database/switch-from-accelerate): Replace a hosted Prisma Postgres Accelerate connection without moving your database or data
- [`Connecting to your database`](https://www.prisma.io/docs/postgres/database/connecting-to-your-database): Choose the right Prisma Postgres connection string for your runtime, tool, and workload.
- [`Connection pooling`](https://www.prisma.io/docs/postgres/database/connection-pooling): Use Prisma Postgres connection pooling for concurrent application traffic.
- [`Extensions`](https://www.prisma.io/docs/postgres/database/postgres-extensions): Enable and use standard PostgreSQL extensions with Prisma Postgres.
- [`Query Insights`](https://www.prisma.io/docs/postgres/database/query-insights): Inspect slow queries, connect Prisma calls to SQL, and apply focused fixes with Prisma Postgres.

# Connecting to your database (/docs/postgres/database/connecting-to-your-database)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Choose the right Prisma Postgres connection string for your runtime, tool, and workload.

Location: Postgres > Database > Connecting to your database

Every Prisma Postgres database has two connection strings: **pooled** for application traffic, **direct** for migrations and admin tooling. This page covers how to get them, where each one goes, and the recommended setup for common runtimes.

For pooling behavior, limits, and timeouts, see [Connection pooling](https://www.prisma.io/docs/postgres/database/connection-pooling).

## Get your connection strings [#get-your-connection-strings]

1. Open your project in the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres).
2. Select your database.
3. Click **Connect to your database**.
4. Click **Generate new connection string**.
5. Copy both the **pooled** and **direct** connection strings.

![Animated walkthrough of generating a connection string in Prisma Console: navigating to the database, clicking Connect, generating a new connection string, and copying the result.](https://www.prisma.io/img/postgres/connection-string.gif)

## Connection string format [#connection-string-format]

Both strings share the same credentials. The only difference is the hostname:

```bash title=".env"
# Pooled — routes through the connection pooler
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/?sslmode=require"

# Direct — connects straight to the database
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/?sslmode=require"
```

| Part       | Description                                               |
| ---------- | --------------------------------------------------------- |
| `USER`     | Database user (generated in Console)                      |
| `PASSWORD` | Database password (generated in Console)                  |
| Host       | `pooled.db.prisma.io` (pooled) or `db.prisma.io` (direct) |
| Port       | `5432`                                                    |
| `sslmode`  | Always `require` - SSL is mandatory                       |

## Which connection to use [#which-connection-to-use]

| If you are...                                                                               | Use        | Why                                                                  |
| ------------------------------------------------------------------------------------------- | ---------- | -------------------------------------------------------------------- |
| Running application queries (API handlers, workers, functions)                              | **Pooled** | Safer under concurrency. Reuses a small set of database connections. |
| Running migrations, introspection, `pg_dump`, `pg_restore`, Prisma Studio, or admin tooling | **Direct** | These workflows need session continuity or should bypass the pooler. |
| Using `LISTEN/NOTIFY` or session-level `SET` commands                                       | **Direct** | The pooler does not preserve session state across transactions.      |
| Running queries or jobs that may exceed 10 minutes                                          | **Direct** | Pooled connections enforce a 10-minute query timeout.                |

If you swap them, the failure modes are asymmetric. Using the pooled string for migrations produces obvious errors (lock failures, prepared statement errors). Using the direct string for application traffic works at low concurrency but silently exhausts connections under production load. See [Connection pooling](https://www.prisma.io/docs/postgres/database/connection-pooling) for details.

## Recommended setups [#recommended-setups]

### Prisma ORM in Node.js [#prisma-orm-in-nodejs]

Set `DATABASE_URL` to the pooled string for runtime queries. Set `DIRECT_URL` to the direct string so the Prisma CLI (migrations, introspection, Studio) bypasses the pooler.

```bash title=".env"
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/postgres?sslmode=require"
DIRECT_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DIRECT_URL"),
  },
});
```

```ts title="src/db.ts"
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "./generated/prisma/client";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });

export const prisma = new PrismaClient({ adapter });
```

This gives you pooled runtime traffic for application queries and direct CLI access for migrations, introspection, and schema changes.

### Serverless and edge runtimes [#serverless-and-edge-runtimes]

For serverless runtimes that support PostgreSQL over TCP, use the same setup as above but wrap the client in a singleton. Without this, each warm invocation creates a new client and a new connection, which can exhaust your plan's pooled connection limit.

```ts title="src/db.ts"
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "./generated/prisma/client";

const globalForPrisma = globalThis as unknown as {
  prisma?: PrismaClient;
};

export const prisma =
  globalForPrisma.prisma ??
  new PrismaClient({
    adapter: new PrismaPg({
      connectionString: process.env.DATABASE_URL,
    }),
  });

if (process.env.NODE_ENV !== "production") {
  globalForPrisma.prisma = prisma;
}
```

**When TCP is not a good fit:** If your runtime is short-lived, globally distributed, or does not support PostgreSQL TCP connections well, use the [serverless driver (`@prisma/ppg`)](https://www.prisma.io/docs/postgres/database/serverless-driver) instead. It communicates over HTTP and WebSockets rather than TCP and has built in connection pooling. See the [serverless driver docs](https://www.prisma.io/docs/postgres/database/serverless-driver) for setup.

> [!NOTE]
> The serverless driver uses the **direct** connection string but does **not** open a TCP connection to the database. The direct hostname is used for routing only, the transport is HTTP/WebSocket, not PostgreSQL wire protocol.

### PostgreSQL tools and other ORMs [#postgresql-tools-and-other-orms]

Use the **direct** connection string with `psql`, `pg_dump`, `pg_restore`, and GUI tools (TablePlus, DataGrip, DBeaver, Postico):

```bash
psql "postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

For non-Prisma ORMs, see the getting-started guides for [Drizzle](https://www.prisma.io/docs/prisma-postgres/quickstart/drizzle-orm), [Kysely](https://www.prisma.io/docs/prisma-postgres/quickstart/kysely), or [TypeORM](https://www.prisma.io/docs/prisma-postgres/quickstart/typeorm).

## Troubleshooting [#troubleshooting]

### Migrations or db push fail with lock or prepared statement errors [#migrations-or-db-push-fail-with-lock-or-prepared-statement-errors]

The pooled connection string is being used where the direct string is required. Check that `prisma.config.ts` points at `DIRECT_URL` (`db.prisma.io`), not `DATABASE_URL`.

### "Too many connections" [#too-many-connections]

Your application is exceeding the connection limit for your plan. See the [Connection pooling troubleshooting](https://www.prisma.io/docs/postgres/database/connection-pooling#too-many-connections-or-connection-limit-errors) for specific causes and fixes.

### Connection refused or timeout on first connect [#connection-refused-or-timeout-on-first-connect]

Check that your connection string includes `sslmode=require` and uses port `5432`. If you are behind a corporate firewall or VPN that blocks outbound PostgreSQL traffic, you may need to allowlist `*.db.prisma.io` on port 5432, or use the [serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver) which operates over HTTPS.

## Related pages [#related-pages]

* [Connection pooling](https://www.prisma.io/docs/postgres/database/connection-pooling)
* [Serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver)
* [Backups](https://www.prisma.io/docs/postgres/database/backups)

## Related pages

- [`Backups`](https://www.prisma.io/docs/postgres/database/backups): Manage and restore database backups in Prisma Postgres
- [`Connect to Prisma Postgres without Accelerate`](https://www.prisma.io/docs/postgres/database/switch-from-accelerate): Replace a hosted Prisma Postgres Accelerate connection without moving your database or data
- [`Connection pooling`](https://www.prisma.io/docs/postgres/database/connection-pooling): Use Prisma Postgres connection pooling for concurrent application traffic.
- [`Extensions`](https://www.prisma.io/docs/postgres/database/postgres-extensions): Enable and use standard PostgreSQL extensions with Prisma Postgres.
- [`Query Insights`](https://www.prisma.io/docs/postgres/database/query-insights): Inspect slow queries, connect Prisma calls to SQL, and apply focused fixes with Prisma Postgres.

# Connection pooling (/docs/postgres/database/connection-pooling)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Use Prisma Postgres connection pooling for concurrent application traffic.

Location: Postgres > Database > Connection pooling

Prisma Postgres routes application traffic through a tenant-isolated PgBouncer instance running in transactional pool mode. This page covers how pooling works, what limits apply, and when to bypass it. For connection string setup and runtime-specific guidance, see [Connecting to your database](https://www.prisma.io/docs/postgres/database/connecting-to-your-database).

## Connection limits [#connection-limits]

|                        | Free | Starter | Pro | Business |
| ---------------------- | ---- | ------- | --- | -------- |
| **Pooled connections** | 50   | 50      | 250 | 500      |
| **Direct connections** | 10   | 10      | 50  | 100      |

These are concurrent connection limits per plan. 5 direct connections are reserved for platform operations (maintenance, monitoring) and are not available to your workload.

Idle pooled connections are closed after 60 minutes. Compare plans on the [Prisma pricing page](https://www.prisma.io/pricing).

## How the pooler works [#how-the-pooler-works]

```
Application → Connection Proxy → PgBouncer (per tenant, transactional mode) → Database
```

Your application opens a connection to the pooled hostname (`pooled.db.prisma.io`). The pooler multiplexes many client connections onto a smaller number of database connections, assigning a backend connection for the duration of each transaction and returning it to the pool when the transaction completes.

Because PgBouncer operates in transactional mode:

* **Session state does not persist between transactions.** Any `SET` commands, prepared statements, advisory locks, or temporary tables are lost after each transaction boundary. If your workload depends on session state, use a direct connection.
* **Queries are limited to 10 minutes.** Queries exceeding this timeout are terminated. For long-running jobs, use a direct connection.

## When to use each connection type [#when-to-use-each-connection-type]

**Use pooled connections** (`pooled.db.prisma.io`) for all application traffic: API handlers, background workers, serverless functions, edge runtimes.

**Use direct connections** (`db.prisma.io`) for:

* Migrations (`prisma migrate deploy`, `prisma db push`)
* Schema introspection (`prisma db pull`)
* Prisma Studio and admin tooling
* `pg_dump` / `pg_restore`
* `LISTEN` / `NOTIFY`
* Workloads that use session-level `SET` commands or prepared statements outside transactions
* Queries that may exceed 10 minutes

Getting this wrong has asymmetric failure modes. Running migrations through the pooler produces clear errors (lock failures, session state errors). Running application traffic over direct connections works fine at low concurrency but causes silent connection exhaustion under load, the kind of issue that only surfaces in production.

## Troubleshooting [#troubleshooting]

### "Too many connections" or connection limit errors [#too-many-connections-or-connection-limit-errors]

Your application is exceeding the pooled connection limit for your plan. Common causes:

1. **Creating a new database client per request.** Prisma Client should be instantiated once and reused across requests. In serverless environments, instantiate the client outside the handler function so it persists across warm invocations.
2. **Too many concurrent serverless instances.** Each function instance holds its own connection(s). If your platform auto-scales to 200 instances and your plan allows 50 pooled connections, you will hit the limit. Cap concurrency at the platform level or upgrade your plan.
3. **Using the direct hostname for application traffic.** Direct connection limits are much lower (10–100 depending on plan). Switch application traffic to `pooled.db.prisma.io`.

### Migration fails with lock, session, or prepared statement errors [#migration-fails-with-lock-session-or-prepared-statement-errors]

The pooled connection string was used for a migration or admin workflow that requires session continuity. Switch to the direct hostname (`db.prisma.io`) for all Prisma CLI commands and admin tooling.

### Session state not persisting between queries [#session-state-not-persisting-between-queries]

This is expected behavior in transactional pool mode. The pooler returns the backend connection to the pool after each transaction, so `SET` commands, temporary tables, and prepared statements do not carry over. Use a direct connection for session-dependent workloads.

### Query killed after 10 minutes [#query-killed-after-10-minutes]

Pooled connections enforce a 10-minute query timeout. Break the query into smaller batches, or run it over a direct connection where no timeout is enforced.

## Related pages

- [`Backups`](https://www.prisma.io/docs/postgres/database/backups): Manage and restore database backups in Prisma Postgres
- [`Connect to Prisma Postgres without Accelerate`](https://www.prisma.io/docs/postgres/database/switch-from-accelerate): Replace a hosted Prisma Postgres Accelerate connection without moving your database or data
- [`Connecting to your database`](https://www.prisma.io/docs/postgres/database/connecting-to-your-database): Choose the right Prisma Postgres connection string for your runtime, tool, and workload.
- [`Extensions`](https://www.prisma.io/docs/postgres/database/postgres-extensions): Enable and use standard PostgreSQL extensions with Prisma Postgres.
- [`Query Insights`](https://www.prisma.io/docs/postgres/database/query-insights): Inspect slow queries, connect Prisma calls to SQL, and apply focused fixes with Prisma Postgres.

# Database (/docs/postgres/database)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Overview of Prisma Postgres database operations, connections, pooling, backups, and query analysis.

Location: Postgres > Database

This section covers the operational side of Prisma Postgres: how to connect, how pooling works, how to inspect query behavior, and how to manage your database in development and production.

## Start here [#start-here]

* [Connecting to your database](https://www.prisma.io/docs/postgres/database/connecting-to-your-database)
* [Connection pooling](https://www.prisma.io/docs/postgres/database/connection-pooling)
* [Query Insights](https://www.prisma.io/docs/postgres/database/query-insights)

## Operations and maintenance [#operations-and-maintenance]

* [Backups](https://www.prisma.io/docs/postgres/database/backups)
* [PostgreSQL extensions](https://www.prisma.io/docs/postgres/database/postgres-extensions)
* [Serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver)
* [Local Postgres](https://www.prisma.io/docs/local-development/postgres)

## Related pages [#related-pages]

* [Prisma Postgres overview](https://www.prisma.io/docs/postgres)
* [Troubleshooting](https://www.prisma.io/docs/postgres/troubleshooting)
* [FAQ](https://www.prisma.io/docs/postgres/faq)

## Related pages

- [`Best Postgres for AI apps`](https://www.prisma.io/docs/postgres/best-postgres-for-ai-apps): Why Prisma Postgres works well for AI and LLM workloads: built-in pooling, edge connectivity, pgvector, and MCP support.
- [`create-db`](https://www.prisma.io/docs/postgres/npx-create-db): Learn how to provision temporary Prisma Postgres databases with create-db
- [`Error reference`](https://www.prisma.io/docs/postgres/error-reference): Error reference documentation for Prisma Postgres
- [`Import from existing database`](https://www.prisma.io/docs/postgres/import-from-existing-database): Choose the right path to import data from PostgreSQL or MySQL into Prisma Postgres.
- [`Migrate from Early Access`](https://www.prisma.io/docs/postgres/migrate-from-ea-to-ga): Move your Prisma Postgres Early Access database to a new PostgreSQL 17 database with dump and restore.

# Extensions (/docs/postgres/database/postgres-extensions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Enable and use standard PostgreSQL extensions with Prisma Postgres.

Location: Postgres > Database > Extensions

Prisma Postgres supports standard [PostgreSQL extensions](https://www.postgresql.org/docs/current/sql-createextension.html). Extensions add functionality such as vector search, full-text search, fuzzy matching, and cryptographic functions to your database.

## Enabling an extension [#enabling-an-extension]

Enable any [supported extension](#supported-extensions) using standard SQL:

```sql
CREATE EXTENSION IF NOT EXISTS vector;
```

This works from any PostgreSQL client: `psql`, a GUI like TablePlus, a migration file, or a raw SQL query from your application.

The `plpgsql` extension is enabled by default on all Prisma Postgres instances.

## Using extensions with Prisma ORM [#using-extensions-with-prisma-orm]

Prisma ORM doesn't natively support all extension types yet. For extensions that introduce custom types (like `vector` from pgvector), you can use [customized migrations](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations) and [raw SQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql) or [TypedSQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql) to work with them.

The following walkthrough uses pgvector as an example.

### 1. Create an empty migration [#1-create-an-empty-migration]

  

#### bun

```bash
bunx prisma migrate dev --name add-pgvector --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --name add-pgvector --create-only
```

#### yarn

```bash
yarn prisma migrate dev --name add-pgvector --create-only
```

#### npm

```bash
npx prisma migrate dev --name add-pgvector --create-only
```

The `--create-only` flag creates the migration file without applying it, so you can add custom SQL first.

### 2. Add the extension and table to your migration [#2-add-the-extension-and-table-to-your-migration]

Edit the generated migration file to enable the extension and create your table:

```sql
-- prisma/migrations/<timestamp>-add-pgvector/migration.sql
CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE "Document" (
  id SERIAL PRIMARY KEY,
  title TEXT NOT NULL,
  embedding VECTOR(4) -- dimensions depend on your embedding model
);
```

### 3. Apply the migration [#3-apply-the-migration]

  

#### bun

```bash
bunx prisma migrate deploy
```

#### pnpm

```bash
pnpm prisma migrate deploy
```

#### yarn

```bash
yarn prisma migrate deploy
```

#### npm

```bash
npx prisma migrate deploy
```

### 4. Pull the table into your Prisma schema [#4-pull-the-table-into-your-prisma-schema]

Introspect your database to update your Prisma schema with the new table:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

Because Prisma ORM doesn't natively support the `VECTOR` type, it will be represented as [`Unsupported`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#unsupported-types):

```prisma
model Document {
  id        Int                    @id @default(autoincrement())
  title     String
  embedding Unsupported("vector")?
}
```

### 5. Query with raw SQL [#5-query-with-raw-sql]

Use `$executeRaw` or `$queryRaw` to interact with extension-specific types:

```ts
await prisma.$executeRaw`
  INSERT INTO "Document" (title, embedding)
  VALUES ('My Title', '[1,22,1,42]'::vector)
`;
```

You can also use [TypedSQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql) for type-safe queries.

## Supported extensions [#supported-extensions]

**View all supported extensions**

* [`amcheck`](https://www.postgresql.org/docs/current/amcheck.html)
* [`autoinc`](https://www.postgresql.org/docs/current/contrib-spi.html)
* [`bloom`](https://www.postgresql.org/docs/current/bloom.html)
* [`btree_gin`](https://www.postgresql.org/docs/current/btree-gin.html)
* [`btree_gist`](https://www.postgresql.org/docs/current/btree-gist.html)
* [`citext`](https://www.postgresql.org/docs/current/citext.html)
* [`cube`](https://www.postgresql.org/docs/current/cube.html)
* [`dblink`](https://www.postgresql.org/docs/current/dblink.html)
* [`dict_int`](https://www.postgresql.org/docs/current/dict-int.html)
* [`dict_xsyn`](https://www.postgresql.org/docs/current/dict-xsyn.html)
* [`earthdistance`](https://www.postgresql.org/docs/current/earthdistance.html)
* [`file_fdw`](https://www.postgresql.org/docs/current/file-fdw.html)
* [`fuzzystrmatch`](https://www.postgresql.org/docs/current/fuzzystrmatch.html)
* [`hstore`](https://www.postgresql.org/docs/current/hstore.html)
* [`insert_username`](https://www.postgresql.org/docs/current/contrib-spi.html)
* [`intagg`](https://www.postgresql.org/docs/current/intagg.html)
* [`intarray`](https://www.postgresql.org/docs/current/intarray.html)
* [`isn`](https://www.postgresql.org/docs/current/isn.html)
* [`lo`](https://www.postgresql.org/docs/current/lo.html)
* [`ltree`](https://www.postgresql.org/docs/current/ltree.html)
* [`moddatetime`](https://www.postgresql.org/docs/current/contrib-spi.html)
* [`pageinspect`](https://www.postgresql.org/docs/current/pageinspect.html)
* [`pg_buffercache`](https://www.postgresql.org/docs/current/pgbuffercache.html)
* [`pg_freespacemap`](https://www.postgresql.org/docs/current/pgfreespacemap.html)
* [`pg_prewarm`](https://www.postgresql.org/docs/current/pgprewarm.html)
* [`pg_search`](https://pgxn.org/dist/pg_search/)
* [`pg_stat_statements`](https://www.postgresql.org/docs/current/pgstatstatements.html)
* [`pg_surgery`](https://www.postgresql.org/docs/current/pgsurgery.html)
* [`pg_trgm`](https://www.postgresql.org/docs/current/pgtrgm.html)
* [`pg_visibility`](https://www.postgresql.org/docs/current/pgvisibility.html)
* [`pg_walinspect`](https://www.postgresql.org/docs/current/pgwalinspect.html)
* [`pgcrypto`](https://www.postgresql.org/docs/current/pgcrypto.html)
* [`pgrowlocks`](https://www.postgresql.org/docs/current/pgrowlocks.html)
* [`pgstattuple`](https://www.postgresql.org/docs/current/pgstattuple.html)
* [`plpgsql`](https://www.postgresql.org/docs/current/plpgsql.html&#x29; &#x2A;(enabled by default)*
* [`postgres_fdw`](https://www.postgresql.org/docs/current/postgres-fdw.html)
* [`refint`](https://www.postgresql.org/docs/current/contrib-spi.html)
* [`seg`](https://www.postgresql.org/docs/current/seg.html)
* [`sslinfo`](https://www.postgresql.org/docs/current/sslinfo.html)
* [`tablefunc`](https://www.postgresql.org/docs/current/tablefunc.html)
* [`tcn`](https://www.postgresql.org/docs/current/tcn.html)
* [`tsm_system_rows`](https://www.postgresql.org/docs/current/tsm-system-rows.html)
* [`tsm_system_time`](https://www.postgresql.org/docs/current/tsm-system-time.html)
* [`unaccent`](https://www.postgresql.org/docs/current/unaccent.html)
* [`uuid-ossp`](https://www.postgresql.org/docs/current/uuid-ossp.html)
* [`vector`](https://github.com/pgvector/pgvector)
* [`xml2`](https://www.postgresql.org/docs/current/xml2.html)

If you need an extension that is not listed, [request an extension](https://pris.ly/i-want-extensions).

## Limitations [#limitations]

* **Prisma Studio** does not support tables that use custom types from extensions (e.g., `VECTOR`). Queries against those tables will return a deserialization error.
* **Prisma ORM** does not natively support all extension types. Custom types are represented as [`Unsupported`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#unsupported-types) in your schema and must be queried with [raw SQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql).

## Related pages

- [`Backups`](https://www.prisma.io/docs/postgres/database/backups): Manage and restore database backups in Prisma Postgres
- [`Connect to Prisma Postgres without Accelerate`](https://www.prisma.io/docs/postgres/database/switch-from-accelerate): Replace a hosted Prisma Postgres Accelerate connection without moving your database or data
- [`Connecting to your database`](https://www.prisma.io/docs/postgres/database/connecting-to-your-database): Choose the right Prisma Postgres connection string for your runtime, tool, and workload.
- [`Connection pooling`](https://www.prisma.io/docs/postgres/database/connection-pooling): Use Prisma Postgres connection pooling for concurrent application traffic.
- [`Query Insights`](https://www.prisma.io/docs/postgres/database/query-insights): Inspect slow queries, connect Prisma calls to SQL, and apply focused fixes with Prisma Postgres.

# Query Insights (/docs/postgres/database/query-insights)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Inspect slow queries, connect Prisma calls to SQL, and apply focused fixes with Prisma Postgres.

Location: Postgres > Database > Query Insights

Query Insights is built into Prisma Postgres and helps you understand which queries are slow, why they are expensive, and what to change next. It is available in the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres).

For Prisma ORM queries, it connects your Prisma calls to the SQL they generate, including when a single call expands into multiple statements. For raw SQL or queries issued outside Prisma ORM, it still shows full SQL behavior.

## What it shows [#what-it-shows]

The main view gives you a live summary of query activity: average latency, queries per second, and a time-based chart you can scrub through to isolate when a problem occurred.

Below the charts, queries are grouped by statement shape. Each row shows latency, execution count, reads, and when the query was last seen. You can filter by table or sort by any metric to surface the most expensive patterns first.

Selecting a query opens a detail view with a full stat summary, the raw SQL, and an AI-generated analysis explaining why the query is expensive and what to change. The detail view also includes a copyable prompt you can paste into your editor to apply the fix.

## What it helps with [#what-it-helps-with]

Query Insights is most useful for diagnosing N+1 patterns, missing indexes, over-fetching, offset pagination, and repeated queries. In most cases it points you toward one of four fixes: changing the Prisma query shape, adding or adjusting an index, returning fewer fields or rows, or caching repeated work.

## Availability [#availability]

Query Insights is included with Prisma Postgres at no extra cost.

> [!NOTE]
> Query Insights has its own dedicated section with full documentation, examples, and setup instructions. See [Query Insights](https://www.prisma.io/docs/query-insights).

## Related pages

- [`Backups`](https://www.prisma.io/docs/postgres/database/backups): Manage and restore database backups in Prisma Postgres
- [`Connect to Prisma Postgres without Accelerate`](https://www.prisma.io/docs/postgres/database/switch-from-accelerate): Replace a hosted Prisma Postgres Accelerate connection without moving your database or data
- [`Connecting to your database`](https://www.prisma.io/docs/postgres/database/connecting-to-your-database): Choose the right Prisma Postgres connection string for your runtime, tool, and workload.
- [`Connection pooling`](https://www.prisma.io/docs/postgres/database/connection-pooling): Use Prisma Postgres connection pooling for concurrent application traffic.
- [`Extensions`](https://www.prisma.io/docs/postgres/database/postgres-extensions): Enable and use standard PostgreSQL extensions with Prisma Postgres.

# Serverless driver (/docs/postgres/database/serverless-driver)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Connect to Prisma Postgres from serverless and edge environments

Location: Postgres > Database > Serverless driver

The Prisma Postgres serverless driver connects to hosted Prisma Postgres databases over HTTP and WebSockets. Use it with Prisma ORM through [`@prisma/adapter-ppg`](https://www.npmjs.com/package/@prisma/adapter-ppg), or query with raw SQL through [`@prisma/ppg`](https://www.npmjs.com/package/@prisma/ppg).

## Choose a connection method [#choose-a-connection-method]

| Runtime                                                              | Recommended connection                              | Package                                                             |
| -------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------- |
| Conventional Node.js or Bun runtime with PostgreSQL TCP support      | [Pooled TCP](https://www.prisma.io/docs/postgres/database/connection-pooling) | `@prisma/adapter-pg` with `pg`                                      |
| Edge or TCP-constrained runtime with `fetch` and `WebSocket` support | Prisma Postgres serverless driver                   | `@prisma/adapter-ppg` with Prisma ORM, or `@prisma/ppg` for raw SQL |

Use the serverless driver when a conventional PostgreSQL TCP driver cannot run. It also supports streaming, pipelined queries, transactions, batch operations, SQL template literals, and custom type handling.

If your application currently uses a hosted `prisma+postgres://` Accelerate connection, follow [Connect to Prisma Postgres without Accelerate](https://www.prisma.io/docs/postgres/database/switch-from-accelerate).

## Get your connection string [#get-your-connection-string]

The serverless driver accepts the direct Prisma Postgres connection-string format:

```text title="Direct connection string"
postgres://identifier:key@db.prisma.io:5432/postgres?sslmode=require
```

It uses this value as a credential, then communicates with Prisma Postgres over HTTP and WebSockets. It does not open a TCP connection.

In the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres), select your database, choose **Connect to your database**, generate a connection string, and copy the direct value. Do not construct the value by editing another connection string.

If you don't have a Prisma Postgres database, create one using the [`create-db` CLI](https://www.prisma.io/docs/postgres/npx-create-db) tool:

  

#### bun

```bash title="Terminal"
bunx create-db@latest
```

#### pnpm

```bash title="Terminal"
pnpm dlx create-db@latest
```

#### yarn

```bash title="Terminal"
yarn dlx create-db@latest
```

#### npm

```bash title="Terminal"
npx create-db@latest
```

> [!WARNING]
> Keep credentials server-side
> 
> Store `DATABASE_URL` in server-side runtime secrets. Never commit it to source control or include it in code delivered to a browser.

## Installation [#installation]

Install the appropriate package based on your use case:

  

#### With Prisma ORM

  

  <CodeBlockTab value="bun">
    ```bash title="Terminal" 
    bun add @prisma/ppg @prisma/adapter-ppg
    ```

#### pnpm

```bash title="Terminal" 
pnpm add @prisma/ppg @prisma/adapter-ppg
```

#### yarn

```bash title="Terminal" 
yarn add @prisma/ppg @prisma/adapter-ppg
```

#### npm

```bash title="Terminal" 
npm install @prisma/ppg @prisma/adapter-ppg
```
    
  </CodeBlockTab>

#### Raw SQL

  

  <CodeBlockTab value="bun">
    ```bash title="Terminal" 
    bun add @prisma/ppg
    ```

#### pnpm

```bash title="Terminal" 
pnpm add @prisma/ppg
```

#### yarn

```bash title="Terminal" 
yarn add @prisma/ppg
```

#### npm

```bash title="Terminal" 
npm install @prisma/ppg
```
    
  </CodeBlockTab>

## Use with Prisma ORM [#use-with-prisma-orm]

Use the [`PrismaPostgresAdapter`](https://www.npmjs.com/package/@prisma/adapter-ppg) to connect Prisma Client via the serverless driver.

When you generate Prisma Client for an edge runtime, set the generator's [`runtime`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#field-reference) to the deployment target. For example, use `workerd` for Cloudflare Workers, `vercel-edge` for Vercel Edge Functions, or `deno` for Deno:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
  runtime  = "workerd"
}
```

Generate the client, then instantiate it with the serverless driver adapter:

```ts title="src/lib/prisma.ts"
import { PrismaClient } from "../../generated/prisma/client";
import { PrismaPostgresAdapter } from "@prisma/adapter-ppg";

const prisma = new PrismaClient({
  adapter: new PrismaPostgresAdapter({
    connectionString: process.env.DATABASE_URL!,
  }),
});

const users = await prisma.user.findMany();
```

## Query with raw SQL [#query-with-raw-sql]

Use the `prismaPostgres()` high-level API for SQL template literals with automatic parameterization:

```ts title="src/lib/query.ts"
import { prismaPostgres, defaultClientConfig } from "@prisma/ppg";

const ppg = prismaPostgres(defaultClientConfig(process.env.DATABASE_URL!));

type User = { id: number; name: string; email: string };

const users = await ppg.sql<User>`
  SELECT * FROM users WHERE email = ${"user@example.com"}
`.collect();

console.log(users[0].name);
```

### Stream results [#stream-results]

Results are returned as `CollectableIterator<T>`. Stream rows one at a time for constant memory usage, or collect all rows into an array:

```ts title="src/lib/stream.ts"
type User = { id: number; name: string; email: string };

// Stream rows one at a time (constant memory usage)
for await (const user of ppg.sql<User>`SELECT * FROM users`) {
  console.log(user.name);
}

// Or collect all rows into an array
const allUsers = await ppg.sql<User>`SELECT * FROM users`.collect();
```

### Pipeline queries [#pipeline-queries]

Send multiple queries over a single WebSocket connection without waiting for responses. Queries are sent immediately and results arrive in FIFO order:

```ts title="src/lib/pipeline.ts"
import { client, defaultClientConfig } from "@prisma/ppg";

const cl = client(defaultClientConfig(process.env.DATABASE_URL!));
const session = await cl.newSession();

// Send all queries immediately (pipelined)
const [usersResult, ordersResult, productsResult] = await Promise.all([
  session.query("SELECT * FROM users"),
  session.query("SELECT * FROM orders"),
  session.query("SELECT * FROM products"),
]);

session.close();
```

Pipelining reduces network round trips by sending multiple queries before waiting for their responses. The effect on end-to-end latency depends on network conditions and query execution time.

### Parameter streaming [#parameter-streaming]

Parameters over 1KB are automatically streamed without buffering in memory. For large binary parameters, you must use `boundedByteStreamParameter()` which creates a `BoundedByteStreamParameter` object that carries the total byte size, required by the PostgreSQL protocol:

```ts title="src/lib/upload.ts"
import { client, defaultClientConfig, boundedByteStreamParameter, BINARY } from "@prisma/ppg";

const cl = client(defaultClientConfig(process.env.DATABASE_URL!));

// Large binary data (e.g., file content)
const stream = getReadableStream(); // Your ReadableStream source
const totalSize = 1024 * 1024; // Total size must be known in advance

// Create a bounded byte stream parameter
const streamParam = boundedByteStreamParameter(stream, BINARY, totalSize);

// Automatically streamed - constant memory usage
await cl.query("INSERT INTO files (data) VALUES ($1)", streamParam);
```

For `Uint8Array` data, use `byteArrayParameter()`:

```ts title="src/lib/bytes.ts"
import { client, defaultClientConfig, byteArrayParameter, BINARY } from "@prisma/ppg";

const cl = client(defaultClientConfig(process.env.DATABASE_URL!));

const bytes = new Uint8Array([1, 2, 3, 4]);
const param = byteArrayParameter(bytes, BINARY);

await cl.query("INSERT INTO files (data) VALUES ($1)", param);
```

The `boundedByteStreamParameter()` function is provided by the `@prisma/ppg` library and requires the total byte size to be known in advance due to PostgreSQL protocol requirements.

### Transactions and batch operations [#transactions-and-batch-operations]

Transactions automatically handle BEGIN, COMMIT, and ROLLBACK:

```ts title="src/lib/transaction.ts"
const result = await ppg.transaction(async (tx) => {
  await tx.sql.exec`INSERT INTO users (name) VALUES ('Alice')`;
  const users = await tx.sql<User>`SELECT * FROM users WHERE name = 'Alice'`.collect();
  return users[0].name;
});
```

Batch operations execute multiple statements in a single round-trip within an automatic transaction:

```ts title="src/lib/batch.ts"
const [users, affected] = await ppg.batch<[User[], number]>(
  { query: "SELECT * FROM users WHERE id < $1", parameters: [5] },
  { exec: "INSERT INTO users (name) VALUES ($1)", parameters: ["Charlie"] },
);
```

## Type handling [#type-handling]

When using `defaultClientConfig()`, common PostgreSQL types are automatically parsed (`boolean`, `int2`, `int4`, `int8`, `float4`, `float8`, `text`, `varchar`, `json`, `jsonb`, `date`, `timestamp`, `timestamptz`):

```ts title="src/lib/types.ts"
import { prismaPostgres, defaultClientConfig } from "@prisma/ppg";

const ppg = prismaPostgres(defaultClientConfig(process.env.DATABASE_URL!));

// JSON/JSONB automatically parsed
const rows = await ppg.sql<{ data: { key: string } }>`
  SELECT '{"key": "value"}'::jsonb as data
`.collect();
console.log(rows[0].data.key); // "value"

// BigInt parsed to JavaScript BigInt
const bigints = await ppg.sql<{
  big: bigint;
}>`SELECT 9007199254740991::int8 as big`.collect();

// Dates parsed to Date objects
const dates = await ppg.sql<{
  created: Date;
}>`SELECT NOW() as created`.collect();
```

### Custom parsers and serializers [#custom-parsers-and-serializers]

Extend or override the type system with custom parsers (by PostgreSQL OID) and serializers (by type guard):

```ts title="src/lib/custom-parser.ts"
import { client, defaultClientConfig } from "@prisma/ppg";
import type { ValueParser } from "@prisma/ppg";

// Custom parser for UUID type
const uuidParser: ValueParser<string | null> = {
  oid: 2950,
  parse: (value) => (value ? value.toUpperCase() : null),
};

const config = defaultClientConfig(process.env.DATABASE_URL!);
const cl = client({
  ...config,
  parsers: [...(config.parsers ?? []), uuidParser], // Append to defaults
});
```

For custom serializers, place them before defaults so they take precedence:

```ts title="src/lib/custom-serializer.ts"
import { client, defaultClientConfig } from "@prisma/ppg";
import type { ValueSerializer } from "@prisma/ppg";

class Point {
  constructor(
    public x: number,
    public y: number,
  ) {}
}

const pointSerializer: ValueSerializer<Point> = {
  supports: (value: unknown): value is Point => value instanceof Point,
  serialize: (value: Point) => `(${value.x},${value.y})`,
};

const config = defaultClientConfig(process.env.DATABASE_URL!);
const cl = client({
  ...config,
  serializers: [pointSerializer, ...(config.serializers ?? [])], // Your serializer first
});

await cl.query("INSERT INTO locations (point) VALUES ($1)", new Point(10, 20));
```

See the [npm package documentation](https://www.npmjs.com/package/@prisma/ppg) for more details.

## Platform compatibility [#platform-compatibility]

The driver works in server-side environments with `fetch` and `WebSocket` APIs:

| Platform              | HTTP Transport | WebSocket Transport |
| --------------------- | -------------- | ------------------- |
| Cloudflare Workers    | ✅              | ✅                   |
| Vercel Edge Functions | ✅              | ✅                   |
| AWS Lambda            | ✅              | ✅                   |
| Deno Deploy           | ✅              | ✅                   |
| Bun                   | ✅              | ✅                   |
| Node.js 18+           | ✅              | ✅                   |

The package can run in browser environments, but a database connection string is a server credential. Do not use the driver in browser-delivered code. Route browser requests through a server-side endpoint instead.

## Transport modes [#transport-modes]

* **HTTP transport (stateless):** Each query is an independent HTTP request. Best for simple queries and edge functions.
* **WebSocket transport (stateful):** Persistent connection for multiplexed queries. Best for transactions, pipelining, and multiple queries. Create a session with `client().newSession()`.

## API overview [#api-overview]

### `prismaPostgres(config)` [#prismapostgresconfig]

High-level API with SQL template literals, transactions, and batch operations. Recommended for most use cases.

### `client(config)` [#clientconfig]

Low-level API with explicit parameter passing and session management. Use when you need fine-grained control.

See the [npm package](https://www.npmjs.com/package/@prisma/ppg) for complete API documentation.

## Error handling [#error-handling]

Structured error types are provided: `DatabaseError`, `HttpResponseError`, `WebSocketError`, `ValidationError`.

```ts title="src/lib/errors.ts"
import { DatabaseError } from "@prisma/ppg";

try {
  await ppg.sql`SELECT * FROM invalid_table`.collect();
} catch (error) {
  if (error instanceof DatabaseError) {
    console.log(error.code);
  }
}
```

## Connection pooling [#connection-pooling]

The serverless driver uses Prisma Postgres connection pooling by default and requires no additional pool configuration. See the [Prisma Postgres regions](https://www.prisma.io/docs/postgres/faq#what-regions-is-prisma-postgres-available-in).

## Limitations [#limitations]

* Requires a Prisma Postgres instance and does not work with [Local Postgres](https://www.prisma.io/docs/local-development/postgres) databases

## Learn more [#learn-more]

* [`@prisma/ppg` npm package](https://www.npmjs.com/package/@prisma/ppg)
* [prisma/ppg-client GitHub repository](https://github.com/prisma/ppg-client)
* [Prisma Postgres documentation](https://www.prisma.io/docs/postgres)

## Related pages

- [`Backups`](https://www.prisma.io/docs/postgres/database/backups): Manage and restore database backups in Prisma Postgres
- [`Connect to Prisma Postgres without Accelerate`](https://www.prisma.io/docs/postgres/database/switch-from-accelerate): Replace a hosted Prisma Postgres Accelerate connection without moving your database or data
- [`Connecting to your database`](https://www.prisma.io/docs/postgres/database/connecting-to-your-database): Choose the right Prisma Postgres connection string for your runtime, tool, and workload.
- [`Connection pooling`](https://www.prisma.io/docs/postgres/database/connection-pooling): Use Prisma Postgres connection pooling for concurrent application traffic.
- [`Extensions`](https://www.prisma.io/docs/postgres/database/postgres-extensions): Enable and use standard PostgreSQL extensions with Prisma Postgres.

# Alchemy (/docs/postgres/iac/alchemy)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Provision and manage Prisma Postgres projects, databases, and connections with Alchemy.

Location: Postgres > Infrastructure as Code > Alchemy

Use [Alchemy](https://alchemy.run) to manage Prisma Postgres resources directly in your infrastructure code.

Alchemy provides Prisma Postgres resources for:

* Projects
* Databases
* Connections
* Workspace references

## Conceptual model [#conceptual-model]

[Alchemy](https://alchemy.run/) is a TypeScript library that creates and manages infrastructure when you run it.

Instead of a separate declarative config format, you write a normal TypeScript program (commonly `alchemy.run.ts`) and execute it.

Alchemy resources follow lifecycle phases (`create`, `update`, `delete`) and manage provider APIs for you:

* You compose resources in code (`Project`, `Database`, `Connection`).
* Alchemy handles dependency ordering between those resources.
* Resource defaults can include safety behavior, such as delete protection on projects and databases.
* `await app.finalize()` cleans up orphaned resources that are no longer in your program.

This makes it useful when you want infrastructure code that feels close to your application runtime and platform integrations.

## When to use Alchemy [#when-to-use-alchemy]

Alchemy is a strong fit when:

* You are already deploying with Alchemy and want Prisma Postgres in the same graph.
* You want resource composition with first-class platform integrations (for example, Hyperdrive + Workers).
* You prefer lifecycle-driven resource code with safe deletion defaults.

## Typical workflow [#typical-workflow]

If you follow the Alchemy getting started flow, the common lifecycle is:

Create a project scaffold (optional):

  

#### bun

```bash
bunx alchemy@latest create --template typescript
```

#### pnpm

```bash
pnpm dlx alchemy@latest create --template typescript
```

#### yarn

```bash
yarn dlx alchemy@latest create --template typescript
```

#### npm

```bash
npx alchemy@latest create --template typescript
```

Configure provider profiles and credentials:

  

#### bun

```bash
bun run alchemy configure
```

#### pnpm

```bash
pnpm run alchemy configure
```

#### yarn

```bash
yarn alchemy configure
```

#### npm

```bash
npm run alchemy configure
```

Authenticate (required for Cloudflare resources):

  

#### bun

```bash
bun run alchemy login
```

#### pnpm

```bash
pnpm run alchemy login
```

#### yarn

```bash
yarn alchemy login
```

#### npm

```bash
npm run alchemy login
```

Start local development with hot reload:

  

#### bun

```bash
bun run alchemy dev
```

#### pnpm

```bash
pnpm run alchemy dev
```

#### yarn

```bash
yarn alchemy dev
```

#### npm

```bash
npm run alchemy dev
```

Deploy:

  

#### bun

```bash
bun run alchemy deploy
```

#### pnpm

```bash
pnpm run alchemy deploy
```

#### yarn

```bash
yarn alchemy deploy
```

#### npm

```bash
npm run alchemy deploy
```

Tear down:

  

#### bun

```bash
bun run alchemy destroy
```

#### pnpm

```bash
pnpm run alchemy destroy
```

#### yarn

```bash
yarn alchemy destroy
```

#### npm

```bash
npm run alchemy destroy
```

For Prisma Postgres-only resources, `configure`/`login` may not be necessary in every setup. They are typically needed when you also manage Cloudflare resources in the same app.

## Prerequisites [#prerequisites]

* An [Alchemy project](https://alchemy.run/)
* A Prisma service token
* `PRISMA_SERVICE_TOKEN` configured in your environment
* `ALCHEMY_PASSWORD` configured when your resources contain secrets

## Authentication [#authentication]

Alchemy reads Prisma credentials from environment variables by default.

```bash
export PRISMA_SERVICE_TOKEN="prsc_your_token_here"
export ALCHEMY_PASSWORD="choose-a-strong-password"
```

If you need multiple workspaces/accounts, you can override auth per resource with `serviceToken`.

`ALCHEMY_PASSWORD` is used to encrypt/decrypt secret values in Alchemy state.

## Minimal example [#minimal-example]

```ts file=alchemy.run.ts
import alchemy from "alchemy";
import { Connection, Database, Project } from "alchemy/prisma-postgres";

const app = await alchemy("prisma-postgres-example");

const project = await Project("project");

const database = await Database("database", {
  project,
  region: "us-east-1",
});

const connection = await Connection("connection", {
  database,
  name: "app-connection",
});

export const projectId = project.id;
export const databaseId = database.id;
export const host = connection.host;
export const user = connection.user;
export const connectionString = connection.connectionString;
export const prismaConnectionString = connection.prismaConnectionString;

await app.finalize();
```

## Complete example with Hyperdrive + Worker [#complete-example-with-hyperdrive--worker]

```ts file=alchemy.run.ts
import alchemy from "alchemy";
import { Hyperdrive, Worker } from "alchemy/cloudflare";
import { Connection, Database, Project } from "alchemy/prisma-postgres";

const app = await alchemy("prisma-postgres-example");

const project = await Project("project");

const database = await Database("database", {
  project,
  region: "us-east-1",
});

const connection = await Connection("connection", {
  database,
  name: "connection",
});

const db = await Hyperdrive("prisma-postgres", {
  origin: connection.connectionString.unencrypted,
});

export const worker = await Worker("worker", {
  entrypoint: "src/worker.ts",
  bindings: {
    HYPERDRIVE: db,
  },
  compatibilityFlags: ["nodejs_compat"],
});

await app.finalize();
```

```ts file=src/worker.ts
import { Client } from "pg";
import type { worker } from "../alchemy.run.ts";

export default {
  async fetch(_request: Request, env: typeof worker.Env): Promise<Response> {
    const client = new Client({
      connectionString: env.HYPERDRIVE.connectionString,
    });

    try {
      await client.connect();
      const result = await client.query("SELECT * FROM pg_tables");

      return Response.json({
        success: true,
        result: result.rows,
      });
    } catch (error: any) {
      return new Response(`Database error: ${error.message}`, { status: 500 });
    }
  },
};
```

## Working with multiple workspaces [#working-with-multiple-workspaces]

Prisma service tokens are workspace-scoped. You can pass different tokens to different resources:

```ts
import alchemy from "alchemy";
import { Project } from "alchemy/prisma-postgres";

const app = await alchemy("prisma-workspaces");

const workspaceAProject = await Project("workspace-a-project", {
  serviceToken: alchemy.env.PRISMA_SERVICE_TOKEN_WORKSPACE_A,
});

const workspaceBProject = await Project("workspace-b-project", {
  serviceToken: alchemy.env.PRISMA_SERVICE_TOKEN_WORKSPACE_B,
});

await app.finalize();
```

If you need to resolve a workspace by name or id, use `WorkspaceRef`:

```ts
import { WorkspaceRef } from "alchemy/prisma-postgres";

const workspace = await WorkspaceRef("my-workspace");
```

## Deletion behavior [#deletion-behavior]

`Project` and `Database` default to delete protection in Alchemy.

* `Project`: `delete` defaults to `false`
* `Database`: `delete` defaults to `false`

For ephemeral environments, set `delete: true` explicitly:

```ts
const testDatabase = await Database("test-db", {
  project,
  region: "us-east-1",
  delete: true,
});
```

## Common troubleshooting [#common-troubleshooting]

### Missing token [#missing-token]

If resource creation fails with an auth error, confirm `PRISMA_SERVICE_TOKEN` is set for the process running Alchemy.

### Wrong workspace [#wrong-workspace]

Prisma service tokens are workspace-scoped. If resources appear in the wrong workspace, use per-resource `serviceToken` overrides.

## References [#references]

* [Alchemy](https://alchemy.run)
* [Alchemy getting started](https://alchemy.run/getting-started)
* [What is Alchemy?](https://alchemy.run/what-is-alchemy/)
* [Alchemy package on npm](https://www.npmjs.com/package/alchemy)
* [Prisma Postgres](https://www.prisma.io/postgres)

## Related pages

- [`Pulumi`](https://www.prisma.io/docs/postgres/iac/pulumi): Provision and manage Prisma Postgres with Pulumi using the Prisma Terraform provider bridge.
- [`Terraform`](https://www.prisma.io/docs/postgres/iac/terraform): Provision and manage Prisma Postgres projects, databases, and connections using Terraform.

# Pulumi (/docs/postgres/iac/pulumi)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Provision and manage Prisma Postgres with Pulumi using the Prisma Terraform provider bridge.

Location: Postgres > Infrastructure as Code > Pulumi

Use [Pulumi](https://www.pulumi.com/) with the Prisma Postgres Terraform provider through the Pulumi Terraform bridge.

This is the currently supported path for managing Prisma Postgres from Pulumi.

## Conceptual model [#conceptual-model]

Pulumi lets you define infrastructure with a general-purpose language, but still deploys declaratively:

* You write resource code in TypeScript.
* Pulumi builds a dependency graph and previews changes (`pulumi preview`/`pulumi up`).
* Stack state tracks what exists, including secret outputs.

In this guide, Pulumi consumes the Prisma Terraform provider through a generated SDK, so you get typed resources while reusing the same provider capabilities.

## When to use Pulumi [#when-to-use-pulumi]

Pulumi is a strong fit when:

* You want infrastructure and application code in the same language.
* You prefer typed APIs and IDE support over HCL.
* You already use Pulumi stacks for environment management.

## Prerequisites [#prerequisites]

* [Pulumi CLI](https://www.pulumi.com/docs/iac/download-install/)
* A Pulumi TypeScript project (create one with `pulumi new typescript`)
* A Prisma service token (see [REST API authentication docs](https://www.prisma.io/docs/rest-api/authentication#service-tokens))

## 1. Optional: use Bun for dependency installs [#1-optional-use-bun-for-dependency-installs]

If you want Pulumi to use Bun in this project, set this in `Pulumi.yaml`:

```yaml file=Pulumi.yaml
runtime:
  name: nodejs
  options:
    packagemanager: bun
```

## 2. Add the Prisma Postgres provider package [#2-add-the-prisma-postgres-provider-package]

From your Pulumi project directory, run:

```bash
pulumi package add terraform-provider registry.terraform.io/prisma/prisma-postgres 0.2.0
```

This command:

* Generates a local SDK in `sdks/prisma-postgres`
* Adds `packages.prisma-postgres` metadata to `Pulumi.yaml`
* Adds `@pulumi/prisma-postgres` to `package.json` as a local file dependency

### Alternative: local provider binary [#alternative-local-provider-binary]

If you are developing the provider locally, you can also add it from a local binary path:

```bash
pulumi package add terraform-provider /absolute/path/to/terraform-provider-prisma-postgres
```

For most users, the registry form in step 2 is the recommended approach.

## 3. Configure authentication [#3-configure-authentication]

Use one of these methods:

### Option A: environment variable [#option-a-environment-variable]

```bash
export PRISMA_SERVICE_TOKEN="prsc_your_token_here"
```

### Option B: Pulumi config secret [#option-b-pulumi-config-secret]

```bash
pulumi config set prisma-postgres:serviceToken "prsc_your_token_here" --secret
```

## 4. Define resources in `index.ts` [#4-define-resources-in-indexts]

```ts file=index.ts
import * as pulumi from "@pulumi/pulumi";
import * as prismaPostgres from "@pulumi/prisma-postgres";

const project = new prismaPostgres.Project("project", {
  name: "my-app",
});

const database = new prismaPostgres.Database("database", {
  projectId: project.id,
  name: "production",
  region: "us-east-1",
});

const connection = new prismaPostgres.Connection("connection", {
  databaseId: database.id,
  name: "api-key",
});

const availableRegions = prismaPostgres.getRegionsOutput().regions.apply((regions) =>
  regions.filter((r) => r.status === "available").map((r) => `${r.id} (${r.name})`)
);

export const projectId = project.id;
export const databaseId = database.id;
export const connectionString = pulumi.secret(connection.connectionString);
export const directUrl = pulumi.secret(database.directUrl);
export const regions = availableRegions;
```

## 5. Deploy [#5-deploy]

```bash
pulumi up
```

To read secret outputs:

```bash
pulumi stack output connectionString --show-secrets
pulumi stack output directUrl --show-secrets
```

## 6. Clean up [#6-clean-up]

```bash
pulumi destroy
```

## Production notes [#production-notes]

* Store Pulumi state in a managed backend (Pulumi Cloud, S3-compatible backend, etc.).
* Keep service tokens in Pulumi secrets/config or your secret manager, never in source files.
* The generated SDK is a local dependency (`file:sdks/prisma-postgres`), so keep it available in CI/CD.
* Pin the Terraform provider version in `pulumi package add` for reproducible deployments.

## Common troubleshooting [#common-troubleshooting]

### Package add failed [#package-add-failed]

Confirm you're running the command inside a Pulumi project directory containing `Pulumi.yaml`.

### Missing credentials [#missing-credentials]

If provider auth fails, verify either `PRISMA_SERVICE_TOKEN` is set or `prisma-postgres:serviceToken` is configured for the current stack.

### SDK not found in CI [#sdk-not-found-in-ci]

If CI cannot resolve `@pulumi/prisma-postgres`, make sure `sdks/prisma-postgres` exists in the workspace or rerun `pulumi package add` during CI setup.

## References [#references]

* [Pulumi package add](https://www.pulumi.com/docs/iac/cli/commands/pulumi_package_add/)
* [Using any Terraform provider in Pulumi](https://www.pulumi.com/docs/iac/concepts/providers/any-terraform-provider/)
* [Prisma Postgres provider on Terraform Registry](https://registry.terraform.io/providers/prisma/prisma-postgres/latest)
* [Prisma Postgres Terraform provider source](https://github.com/prisma/terraform-provider-prisma-postgres)

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/postgres/iac/alchemy): Provision and manage Prisma Postgres projects, databases, and connections with Alchemy.
- [`Terraform`](https://www.prisma.io/docs/postgres/iac/terraform): Provision and manage Prisma Postgres projects, databases, and connections using Terraform.

# Terraform (/docs/postgres/iac/terraform)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Provision and manage Prisma Postgres projects, databases, and connections using Terraform.

Location: Postgres > Infrastructure as Code > Terraform

Use the [Prisma Postgres Terraform provider](https://registry.terraform.io/providers/prisma/prisma-postgres/latest) to manage projects, databases, and connections with code.

## Conceptual model [#conceptual-model]

Terraform is a desired-state engine:

* You declare the target infrastructure in `.tf` files.
* Terraform computes a plan (`terraform plan`) by comparing config vs current state.
* Terraform applies only the required changes (`terraform apply`) and records the result in state.

For Prisma Postgres, this gives a predictable workflow for creating projects, databases, and connections across environments.

## When to use Terraform [#when-to-use-terraform]

Terraform is a strong fit when:

* You already manage infrastructure in Terraform and want one workflow.
* You prefer explicit `plan` output before applying changes.
* Your team standardizes on HCL modules and Terraform state backends.

## What you can manage [#what-you-can-manage]

The provider currently supports:

* `prisma-postgres_project`
* `prisma-postgres_database`
* `prisma-postgres_connection`
* `prisma-postgres_regions` data source

## Prerequisites [#prerequisites]

* [Terraform](https://developer.hashicorp.com/terraform/install) `>= 1.0`
* A Prisma account and workspace in [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres)
* A Prisma service token (see [REST API authentication docs](https://www.prisma.io/docs/rest-api/authentication#service-tokens))

## 1. Set your service token [#1-set-your-service-token]

Set your token as an environment variable:

```bash
export PRISMA_SERVICE_TOKEN="prsc_your_token_here"
```

## 2. Create `main.tf` [#2-create-maintf]

Create the following Terraform configuration:

```hcl file=main.tf
terraform {
  required_providers {
    prisma-postgres = {
      source = "prisma/prisma-postgres"
    }
  }
}

provider "prisma-postgres" {}

resource "prisma-postgres_project" "main" {
  name = "my-app"
}

resource "prisma-postgres_database" "production" {
  project_id = prisma-postgres_project.main.id
  name       = "production"
  region     = "us-east-1"
}

resource "prisma-postgres_connection" "api" {
  database_id = prisma-postgres_database.production.id
  name        = "api-key"
}

output "connection_string" {
  value     = prisma-postgres_connection.api.connection_string
  sensitive = true
}

output "direct_url" {
  value     = prisma-postgres_database.production.direct_url
  sensitive = true
}
```

## 3. Initialize and apply [#3-initialize-and-apply]

Initialize your working directory:

```bash
terraform init
```

Review and apply:

```bash
terraform plan
terraform apply
```

After apply, retrieve values:

```bash
terraform output -raw connection_string
terraform output -raw direct_url
```

## 4. Clean up (optional) [#4-clean-up-optional]

```bash
terraform destroy
```

## Optional: discover available regions [#optional-discover-available-regions]

If you want to select regions dynamically:

```hcl
data "prisma-postgres_regions" "available" {}

output "available_regions" {
  value = [
    for r in data.prisma-postgres_regions.available.regions : "${r.id} (${r.name})"
    if r.status == "available"
  ]
}
```

## Production notes [#production-notes]

* Store Terraform state in a secure remote backend (for example, S3 + DynamoDB, Terraform Cloud, etc.).
* Treat state as sensitive: even with `sensitive = true`, secret values are still stored in state.
* Keep `PRISMA_SERVICE_TOKEN` in your secret manager or CI secrets, not in code.
* Use separate Terraform workspaces or stacks for `dev`, `staging`, and `prod`.
* Rotate credentials intentionally when required by replacing connection resources.

## Import existing resources [#import-existing-resources]

You can import existing resources into state:

```bash
terraform import prisma-postgres_project.main <project-id>
terraform import prisma-postgres_database.production <database-id>
terraform import prisma-postgres_connection.api <database-id>,<connection-id>
```

Credentials are only returned at creation time and cannot be recovered after import.

## Common troubleshooting [#common-troubleshooting]

### Missing token [#missing-token]

If provider configuration fails with a missing token error, confirm `PRISMA_SERVICE_TOKEN` is set in the same shell session running Terraform.

### Region issues [#region-issues]

If create fails for a region value, use `prisma-postgres_regions` to list currently available regions for your workspace.

### Authorization failures [#authorization-failures]

If you receive authorization errors, verify your service token belongs to the expected workspace and has permission to create projects and databases.

## References [#references]

* [Prisma Postgres provider on Terraform Registry](https://registry.terraform.io/providers/prisma/prisma-postgres/latest)
* [Provider configuration](https://registry.terraform.io/providers/prisma/prisma-postgres/latest/docs)
* [Project resource](https://registry.terraform.io/providers/prisma/prisma-postgres/latest/docs/resources/project)
* [Database resource](https://registry.terraform.io/providers/prisma/prisma-postgres/latest/docs/resources/database)
* [Connection resource](https://registry.terraform.io/providers/prisma/prisma-postgres/latest/docs/resources/connection)
* [Regions data source](https://registry.terraform.io/providers/prisma/prisma-postgres/latest/docs/data-sources/regions)

## Related pages

- [`Alchemy`](https://www.prisma.io/docs/postgres/iac/alchemy): Provision and manage Prisma Postgres projects, databases, and connections with Alchemy.
- [`Pulumi`](https://www.prisma.io/docs/postgres/iac/pulumi): Provision and manage Prisma Postgres with Pulumi using the Prisma Terraform provider bridge.

# Raycast (/docs/postgres/integrations/raycast)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create and manage Prisma Postgres databases directly from Raycast

Location: Postgres > Tools & Integrations > Raycast

## Overview [#overview]

[Raycast](https://www.raycast.com/) is a fast and extendable launcher for macOS that lets you control your tools with a few keystrokes. The [Prisma Postgres Raycast extension](https://www.raycast.com/amanvarshney01/prisma-postgres) brings database creation and management directly into your workflow.

With the extension, you can create Prisma Postgres databases without leaving Raycast, which suits rapid prototyping and development.

![Prisma Postgres Raycast Extension](https://www.prisma.io/img/postgres/raycast-extension.png)

## Installation [#installation]

Install the extension directly from the Raycast Store:

1. Open Raycast (⌘ + Space)
2. Search for "Store" or type `store`
3. Search for "Prisma Postgres"
4. Click **Install Extension**

Alternatively, visit the [extension page](https://www.raycast.com/amanvarshney01/prisma-postgres) and click **Install Extension**.

## Features [#features]

The extension provides two main commands:

### Create Database [#create-database]

Create a new Prisma Postgres database with no configuration:

1. Open Raycast and search for "Create Database"
2. Select your preferred region (defaults to US East)
3. Press Enter to create

You'll receive:

* A connection string for immediate use
* A direct URL for connecting to your database
* A claim URL to make your database permanent

> [!NOTE]
> Databases created through Raycast expire after 24 hours. Use the claim URL provided after creation to keep your database permanently.

### List Databases [#list-databases]

View and manage all your previously created databases:

1. Open Raycast and search for "List Databases"
2. Browse your databases with their:
   * Connection strings
   * Expiry status
   * Claim URLs

Use it to retrieve connection details or check which databases still need to be claimed.

## Configuration [#configuration]

### Default Region [#default-region]

You can set your preferred default region for database creation:

1. Open Raycast Settings (⌘ + ,)
2. Navigate to **Extensions** → **Prisma Postgres**
3. Select your preferred region from the dropdown

See the [list of available regions](https://www.prisma.io/docs/postgres/faq#what-regions-is-prisma-postgres-available-in) for all supported locations.

## Learn More [#learn-more]

* [Raycast Extension Page](https://www.raycast.com/amanvarshney01/prisma-postgres)
* [Prisma Postgres Documentation](https://www.prisma.io/docs/postgres)
* [Getting Started with Prisma Postgres](https://www.prisma.io/docs/postgres)

# Embed Studio (/docs/studio/integrations/embedding)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to embed Prisma Studio in your own applications so your users can view and edit data.

Location: Studio > Integrations > Embed Studio

## Embed Prisma Studio in your own application [#embed-prisma-studio-in-your-own-application]

Prisma Studio can be embedded in your own application via the [`@prisma/studio-core`](https://www.npmjs.com/package/@prisma/studio-core) package.

It provides `Studio`, a React component which renders Prisma Studio for your database. The `Studio` component accepts an executor that calls a `/studio` endpoint in your backend. The backend uses your `DATABASE_URL` (connection string) to connect to the correct database instance (PostgreSQL, SQLite, or MySQL) and execute the SQL query.

> [!NOTE]
> If you want to see what embedded Studio looks like, **[check out the demo](https://github.com/prisma/studio-core-demo) on GitHub**!

## Use cases [#use-cases]

You can embed Prisma Studio in your own app in various scenarios:

* Create an admin dashboard for editing data
* Multi-tenant application where every user has their own DB
* Let your users view and edit their own data

## Prerequisites [#prerequisites]

* Frontend: A React application
* Backend:
  * A server-side application to expose the `/studio` endpoint (e.g. with Express or Hono)
  * A database instance (PostgreSQL, SQLite, or MySQL)

## Database support [#database-support]

Embedded Prisma Studio supports the following databases:

* **PostgreSQL**
* **SQLite**
* **MySQL**

> [!NOTE]
> The implementation pattern is the same across all databases; use the executor and adapter for your database type.

## Installation [#installation]

Install the npm package:

  

#### bun

```bash
bun add @prisma/studio-core
```

#### pnpm

```bash
pnpm add @prisma/studio-core
```

#### yarn

```bash
yarn add @prisma/studio-core
```

#### npm

```bash
npm install @prisma/studio-core
```

### Additional dependencies [#additional-dependencies]

Depending on your database type, you may need additional packages:

  

#### bun

```bash
# For SQLite support
bun add better-sqlite3

# For MySQL support
bun add mysql2
```

#### pnpm

```bash
# For SQLite support
pnpm add better-sqlite3

# For MySQL support
pnpm add mysql2
```

#### yarn

```bash
# For SQLite support
yarn add better-sqlite3

# For MySQL support
yarn add mysql2
```

#### npm

```bash
# For SQLite support
npm install better-sqlite3

# For MySQL support
npm install mysql2
```

PostgreSQL support is included with `@prisma/studio-core` and requires no additional dependencies.

## Frontend setup [#frontend-setup]

In your React app, you can use the `Studio` component to render the tables in your database via Prisma Studio. It receives an *executor* which is responsible for packaging the current SQL query in an HTTP request (also allowing for custom headers/payloads) and sending it to the `/studio` endpoint in your backend.

The implementation varies slightly depending on your database type. Choose the appropriate section below:

> Check out the [demo](https://github.com/prisma/studio-core-demo/blob/main/frontend/index.tsx) on GitHub for a full reference implementation.

### PostgreSQL implementation [#postgresql-implementation]

Here's what a minimal implementation looks like for PostgreSQL:

```tsx
import { Studio } from "@prisma/studio-core/ui";
import { createPostgresAdapter } from "@prisma/studio-core/data/postgres-core";
import { createStudioBFFClient } from "@prisma/studio-core/data/bff";
import "@prisma/studio-core/ui/index.css";

function App() {
  const adapter = useMemo(() => {
    // 1. Create a client that points to your backend endpoint
    const executor = createStudioBFFClient({
      url: "http://localhost:4242/studio",
    });

    // 2. Create a Postgres adapter with the executor
    const adapter = createPostgresAdapter({ executor });
    return adapter;
  }, []);

  return (
    <Layout>
      <Studio adapter={adapter} />
    </Layout>
  );
}
```

### SQLite implementation [#sqlite-implementation]

Here's what a minimal implementation looks like for SQLite:

```tsx
import { Studio } from "@prisma/studio-core/ui";
import { createSQLiteAdapter } from "@prisma/studio-core/data/sqlite-core";
import { createStudioBFFClient } from "@prisma/studio-core/data/bff";
import "@prisma/studio-core/ui/index.css";

function App() {
  const adapter = useMemo(() => {
    // 1. Create a client that points to your backend endpoint
    const executor = createStudioBFFClient({
      url: "http://localhost:4242/studio",
    });

    // 2. Create a SQLite adapter with the executor
    const adapter = createSQLiteAdapter({ executor });
    return adapter;
  }, []);

  return (
    <Layout>
      <Studio adapter={adapter} />
    </Layout>
  );
}
```

### MySQL implementation [#mysql-implementation]

Here's what a minimal implementation looks like for MySQL:

```tsx
import { Studio } from "@prisma/studio-core/ui";
import { createMySQLAdapter } from "@prisma/studio-core/data/mysql-core";
import { createStudioBFFClient } from "@prisma/studio-core/data/bff";
import "@prisma/studio-core/ui/index.css";

function App() {
  const adapter = useMemo(() => {
    // 1. Create a client that points to your backend endpoint
    const executor = createStudioBFFClient({
      url: "http://localhost:4242/studio",
    });

    // 2. Create a MySQL adapter with the executor
    const adapter = createMySQLAdapter({ executor });
    return adapter;
  }, []);

  return (
    <Layout>
      <Studio adapter={adapter} />
    </Layout>
  );
}
```

### Custom headers/payload implementation [#custom-headerspayload-implementation]

Here's what an implementation with custom headers/payload looks like (works for all database types):

```tsx
import { Studio } from "@prisma/studio-core/ui";
import { createPostgresAdapter } from "@prisma/studio-core/data/postgres-core";
import { createStudioBFFClient } from "@prisma/studio-core/data/bff";
import "@prisma/studio-core/ui/index.css";

function App() {
  const adapter = useMemo(() => {
    // 1. Create a client that points to your backend endpoint
    const executor = createStudioBFFClient({
      url: "http://localhost:4242/studio",
      customHeaders: {
        "X-Custom-Header": "example-value", // Pass any custom headers
      },
      customPayload: {
        customValue: "example-value", // Pass any custom data
      },
    });

    // 2. Create a database adapter with the executor
    const adapter = createPostgresAdapter({ executor }); // PostgreSQL
    // const adapter = createSQLiteAdapter({ executor }); // SQLite
    // const adapter = createMySQLAdapter({ executor }); // MySQL
    return adapter;
  }, []);

  return (
    <Layout>
      <Studio adapter={adapter} />
    </Layout>
  );
}
```

### Custom styling [#custom-styling]

You can customize the look and feel of Prisma Studio so that it matches your application's design. This is done by passing a custom theme to the `Studio` component. A theme is a set of CSS variables that define colors, spacing, and other style properties for both light and dark modes.

Here's an example of applying a custom theme:

```tsx
import { Studio } from "@prisma/studio-core/ui";
import { createPostgresAdapter } from "@prisma/studio-core/data/postgres-core";
import { createStudioBFFClient } from "@prisma/studio-core/data/bff";
import "@prisma/studio-core/ui/index.css";

const customTheme = `
@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 20 14.3% 4.1%;
    --primary: 47.9 95.8% 53.1%;
    --primary-foreground: 26 83.3% 14.1%;
    --border: 20 5.9% 90%;
    --input: 20 5.9% 90%;
    --ring: 20 14.3% 4.1%;
    --radius: 0rem;
  }

  .dark {
    --background: 20 14.3% 4.1%;
    --foreground: 60 9.1% 97.8%;
    --primary: 47.9 95.8% 53.1%;
    --primary-foreground: 26 83.3% 14.1%;
    --border: 12 6.5% 15.1%;
    --input: 12 6.5% 15.1%;
    --ring: 35.5 91.7% 32.9%;
  }
}
`;

function App() {
  const adapter = useMemo(() => {
    const executor = createStudioBFFClient({
      url: "http://localhost:4242/studio",
    });
    return createPostgresAdapter({ executor });
  }, []);

  return (
    <Layout>
      <Studio theme={customTheme} adapter={adapter} />
    </Layout>
  );
}
```

With this setup, Studio inherits your custom colors, borders, and typography rules. You can define as many or as few variables as you need.

### Concepts [#concepts]

The key concepts in your frontend:

* **Executor**: The bridge between Studio and your backend, it's created using the `createStudioBFFClient` function
* **Adapter**: Handles database-specific query formatting (PostgreSQL, SQLite, or MySQL)
* **Custom headers**: Pass authentication tokens, user info, etc.
* **Custom payload**: Send additional context/data with each request

## Backend setup [#backend-setup]

Your backend needs to expose a `/studio` endpoint where the frontend sends its requests. The implementation varies depending on your database type. Choose the appropriate section below:

### PostgreSQL backend implementation [#postgresql-backend-implementation]

The PostgreSQL implementation uses `createPrismaPostgresHttpClient` from `@prisma/studio-core`. This works with Prisma Postgres or any PostgreSQL instance.

> Check out the [demo](https://github.com/prisma/studio-core-demo/blob/main/server/index.ts) on GitHub for a full reference implementation.

### Minimal implementation [#minimal-implementation]

Here's what a minimal implementation for the `/studio` endpoint looks like with [Hono](https://hono.dev/). This assumes that your connection URL is available via the `DATABASE_URL` env var:

```ts
import { Hono } from "hono";
import { createPrismaPostgresHttpClient } from "@prisma/studio-core/data/ppg";
import { serializeError } from "@prisma/studio-core/data/bff";

const app = new Hono().use("*", cors());

app.post("/studio", async (c) => {
  // 1. Extract the query and custom data from the request
  const { query } = await c.req.json();

  // 2. Read DB URL from env vars
  const url = process.env.DATABASE_URL;

  // 3. Execute the query against Prisma Postgres
  const [error, results] = await createPrismaPostgresHttpClient({ url }).execute(query);

  // 6. Return results or errors
  if (error) {
    return c.json([serializeError(error)]);
  }

  return c.json([null, results]);
});
```

### SQLite backend implementation [#sqlite-backend-implementation]

The SQLite implementation uses `createNodeSQLiteExecutor` from `@prisma/studio-core` and requires the `better-sqlite3` package. This works with local SQLite database files.

```ts
import { Hono } from "hono";
import { createNodeSQLiteExecutor } from "@prisma/studio-core/data/node-sqlite";
import { serializeError } from "@prisma/studio-core/data/bff";
import DatabaseSync from "better-sqlite3";

const app = new Hono().use("*", cors());

app.post("/studio", async (c) => {
  try {
    // 1. Extract the query from the request
    const { query } = await c.req.json();

    // 2. Read DB URL from env vars (should be a file path)
    const url = process.env.DATABASE_URL;

    if (!url) {
      return c.json([serializeError(new Error("DATABASE_URL is missing"))], 500);
    }

    // 3. Extract file path from URL and create database connection
    const dbPath = url.replace("file:", "");
    const database = new DatabaseSync(dbPath);

    // 4. Execute the query against SQLite
    const [error, results] = await createNodeSQLiteExecutor(database).execute(query);

    // 5. Return results or errors
    if (error) {
      return c.json([serializeError(error)]);
    }

    return c.json([null, results]);
  } catch (err) {
    return c.json([serializeError(err)], 400);
  }
});
```

### MySQL backend implementation [#mysql-backend-implementation]

The MySQL implementation uses `createMySQL2Executor` from `@prisma/studio-core` and requires the `mysql2` package. This works with MySQL instances.

```ts
import { Hono } from "hono";
import { createMySQL2Executor } from "@prisma/studio-core/data/mysql2";
import { serializeError } from "@prisma/studio-core/data/bff";
import mysql from "mysql2/promise";

const app = new Hono().use("*", cors());

app.post("/studio", async (c) => {
  try {
    // 1. Extract the query from the request
    const { query } = await c.req.json();

    // 2. Read DB URL from env vars
    const url = process.env.DATABASE_URL;

    if (!url) {
      return c.json([serializeError(new Error("DATABASE_URL is missing"))], 500);
    }

    // 3. Create MySQL connection pool
    const pool = mysql.createPool(url);

    // 4. Execute the query against MySQL
    const [error, results] = await createMySQL2Executor(pool).execute(query);

    // 5. Return results or errors
    if (error) {
      return c.json([serializeError(error)]);
    }

    return c.json([null, results]);
  } catch (err) {
    return c.json([serializeError(err)], 400);
  }
});
```

### Custom headers/payload implementation [#custom-headerspayload-implementation-1]

Here's what a slightly more advanced implementation for the `/studio` endpoint looks like with [Hono](https://hono.dev/). In this case, a multi-tenant scenario is assumed where the frontend sends over a user ID and authentication token which is used on the backend to determine the database instance that belongs to that user via a hypothetical `determineUrlFromContext` function:

```ts
// server/index.ts
import { Hono } from "hono";
import { createPrismaPostgresHttpClient } from "@prisma/studio-core/data/ppg";
import { serializeError } from "@prisma/studio-core/data/bff";

const app = new Hono().use("*", cors());

app.post("/studio", async (c) => {
  // 1. Extract the query and custom data from the request
  const { query, customPayload } = await c.req.json();

  // 2. Access custom headers (great for auth!)
  const customHeader = c.req.header("X-Custom-Header");
  console.log("Received headers:", { customHeader });

  // 3. Use custom payload data
  console.log("Received value:", customPayload.customValue);

  // 4. Determine the URL (this is where you'd implement your auth logic)
  const url = determineUrlFromContext(customHeader, customPayload);

  // 5. Execute the query using the appropriate database client
  // PostgreSQL:
  const [error, results] = await createPrismaPostgresHttpClient({ url }).execute(query);
  // SQLite: (requires additional setup with better-sqlite3)
  // MySQL: (requires additional setup with mysql2)

  // 6. Return results or errors
  if (error) {
    return c.json([serializeError(error)]);
  }

  return c.json([null, results]);
});
```

### Concepts [#concepts-1]

* Query object: Contains the SQL query and parameters from Studio
* Custom payload: Additional data sent with each request
* Database client: Executes queries against your database (PostgreSQL, SQLite, or MySQL)
* Error handling: Properly serialize errors for Studio to display

## Execution flow [#execution-flow]

The execution flow in your embedded Prisma Studio version:

![Diagram showing the execution flow of embedded Prisma Studio: user, Studio UI, React app, backend API, and database.](https://www.prisma.io/img/studio/embedded-flow.png)

## Adding user authentication [#adding-user-authentication]

When you want to authenticate the users of your app against Prisma Studio, you can do that by adding custom logic around your embedded Prisma Studio version.

On the frontend, you can ensure to pass the `Authorization` header and other data (e.g. a user ID) when creating the executor:

```tsx
const executor = createStudioBFFClient({
  url: "http://localhost:4242/studio",
  customHeaders: {
    "X-User-ID": currentUser.id,
    Authorization: `Bearer ${userToken}`,
  },
});
```

In your server-side implementation, you can then retrieve these values from the incoming request and extract the Prisma Postgres API key that's needed for this user's query:

```typescript
const userId = c.req.header("X-User-ID");
const token = c.req.header("Authorization");

const userApiKey = await getUserApiKey(userId, token);
```

## Licensing [#licensing]

Embeddable Prisma Studio (Free) is licensed under Apache 2.0.

✔️ Free for production use\
⚠️ Prisma branding must remain visible and unaltered\
🔐 To remove our branding or to inquire about upcoming partner-only features, ping us here: [partnerships@prisma.io](mailto\:partnerships@prisma.io)

## Telemetry [#telemetry]

This package includes anonymized telemetry to help us improve Prisma Studio.\
Use implies consent. Learn more in our [Privacy Policy](https://www.prisma.io/privacy).

## Related pages

- [`Studio in VS Code`](https://www.prisma.io/docs/studio/integrations/vscode-integration): Learn how to use Prisma Studio directly in VS Code

# Studio in VS Code (/docs/studio/integrations/vscode-integration)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma Studio directly in VS Code

Location: Studio > Integrations > Studio in VS Code

## Overview [#overview]

You can use Prisma Studio directly in VS Code via the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma).

> [!NOTE]
> Supported databases
> 
> Prisma Studio currently supports PostgreSQL, MySQL, and SQLite. Support for CockroachDB and MongoDB is not available yet but may be added in future releases.
> 
> For detailed database support information, including SQLite requirements, see [Databases supported by Prisma Studio](https://www.prisma.io/docs/studio#getting-started).

## Usage [#usage]

1. Install the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma)
2. Find the **Prisma logo** in the VS Code Activity Bar
3. Sign in to [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=studio)
4. Once authenticated, select the database you want to explore in Prisma Studio

## Related pages

- [`Embed Studio`](https://www.prisma.io/docs/studio/integrations/embedding): Learn how to embed Prisma Studio in your own applications so your users can view and edit data.

# MongoDB (/docs/prisma-orm/add-to-existing-project/mongodb)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to an existing MongoDB project.

Location: Prisma ORM > Add to Existing Project > MongoDB

To add Prisma ORM to a project that already uses MongoDB, you will run `orm init`, describe the collections you want to work with, emit the generated artifacts, and run a couple of queries.

Use this path when you already have an application and database. Make sure the app can already reach its MongoDB deployment and runs on Node.js 22.18 or newer (on the 24 line, 24.11 or newer; Node.js 24 is recommended). If you want Prisma ORM to create a new app for you, use the [MongoDB quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/mongodb).

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release, as a release candidate. Prisma ORM 7 remains fully supported; its docs live at [/orm/v7](https://www.prisma.io/docs/orm/v7) and its setup paths at [/v7/getting-started](https://www.prisma.io/docs/v7/getting-started).
> 
> For what release candidate means, when the final release is expected, and how to stay on version 7, see [Release status](https://www.prisma.io/docs/orm/release-status).

A standalone `mongod` is enough for the steps below. A replica set is only needed for transactions and change streams; MongoDB Atlas already gives you one.

## 1. Make sure you can run the example script [#1-make-sure-you-can-run-the-example-script]

If your project already runs TypeScript scripts, you can skip this step.

Otherwise, install the script tooling:

  

#### bun

```bash
bun add --dev tsx typescript
```

#### pnpm

```bash
pnpm add --save-dev tsx typescript
```

#### yarn

```bash
yarn add --dev tsx typescript
```

#### npm

```bash
npm install --save-dev tsx typescript
```

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

From the root of your existing project, run:

  

#### bun

```bash
bunx prisma@latest orm init --target mongodb
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --target mongodb
```

#### yarn

```bash
yarn dlx prisma@latest orm init --target mongodb
```

#### npm

```bash
npx prisma@latest orm init --target mongodb
```

This command is for a project that already exists: it preselects MongoDB, adds Prisma ORM files and package scripts to the app you already have, and does not scaffold a new framework project.

`orm init` also changes the `module` settings in `tsconfig.json`, and adds `"type": "module"` to `package.json` when the file has no `"type"` field. If your app is CommonJS, follow [In a CommonJS project](https://www.prisma.io/docs/cli/orm-init#in-a-commonjs-project) before you run the app again.

It also adds `prisma-8.md`, a short project-level reference your coding agent can read. It does not install agent skills; the Prisma ORM skill ships inside the `@prisma/orm-mongo` package your project installs. If you later run `prisma init` or `prisma skills sync`, Prisma writes skill files for coding agents into your repo. To stop that, pass `--skills=none` to [`init`](https://www.prisma.io/docs/cli/init) or set the [`skills.agents`](https://www.prisma.io/docs/cli/configuration#agent-skills) config field to `[]`; the next [`skills sync`](https://www.prisma.io/docs/cli/skills) removes any copies already written.

When Prisma ORM asks the remaining setup questions:

* choose `PSL`
* keep the default schema path, `src/prisma/contract.prisma`. Pass `--schema-path` if you want the contract somewhere else; the rest of this page assumes the default.
* answer the last question, `Also write a .env file from .env.example? (gitignored)`, with Yes. It defaults to No, and `--write-env` skips the prompt and writes the file.

## 3. Set your database connection string [#3-set-your-database-connection-string]

`orm init` always writes `.env.example`, and writes `.env` only if you asked it to. Put the connection string for the MongoDB deployment your app already uses into `.env`:

```text title=".env"
DATABASE_URL="mongodb://127.0.0.1:27017/app?replicaSet=rs0"
```

`orm init` also writes `src/prisma/db.ts`, the file your application imports. It builds the Prisma ORM client from the emitted contract and reads the connection string from the environment:

```typescript title="src/prisma/db.ts"
import "dotenv/config";
import mongo from "@prisma/orm-mongo/runtime";
import type { Contract } from "./contract.d";
import contractJson from "./contract.json" with { type: "json" };

export const db = mongo<Contract>({
  contractJson,
  url: process.env["DATABASE_URL"]!,
});
```

The first line is `import "dotenv/config"`, so any script that imports `db` loads `.env` for itself. You do not need to pass the URL again at the call site.

## 4. Describe the collections you want Prisma ORM to know about [#4-describe-the-collections-you-want-prisma-orm-to-know-about]

This is the key adoption step for MongoDB, because you decide which part of the existing database Prisma ORM should model first.

PostgreSQL has `contract infer`, but MongoDB does not, so this step is manual.

Open `src/prisma/contract.prisma` and make it match the collections you want Prisma ORM to query first. If your existing database already has `users` and `posts` collections with `email`, `name`, `title`, and `authorId`, the starter contract is already a useful first draft:

```prisma title="src/prisma/contract.prisma"
// use prisma-8

model User {
  id    ObjectId @id @map("_id")
  email String   @unique
  name  String?
  posts Post[]
  @@map("users")
}

model Post {
  id       ObjectId @id @map("_id")
  title    String
  content  String?
  author   User     @relation(fields: [authorId], references: [id])
  authorId ObjectId
  @@map("posts")
}
```

You do not need to model every collection on day one. Start with the part of the database you want to read and write first.

## 5. Emit the generated artifacts [#5-emit-the-generated-artifacts]

Once the contract looks right, this step turns it into the generated files the runtime and query APIs use.

Run:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

This refreshes `src/prisma/contract.json` and `src/prisma/contract.d.ts` so the runtime and query APIs match the contract you just reviewed.

## 6. Run a simple high-level query [#6-run-a-simple-high-level-query]

With the emitted artifacts in place, you can test the higher-level API first and confirm Prisma ORM can read the existing collections.

Create a `script.ts` file:

```typescript title="script.ts"
import { db } from "./src/prisma/db";

async function main() {
  const user = await db.orm.users.where({ email: "existing@example.com" }).first();
  console.log(user);

  await db.close();
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
```

Run it:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 7. Run a simple low-level query [#7-run-a-simple-low-level-query]

After the ORM example, this step shows the lower-level MongoDB pipeline builder against the same existing collections.

Pipeline plans run through the runtime. On MongoDB `db.runtime()` returns a promise, so it has to be awaited; on PostgreSQL the same call is synchronous.

Replace `script.ts` with this version:

```typescript title="script.ts"
import { db } from "./src/prisma/db";

async function main() {
  const runtime = await db.runtime();
  const plan = db.query
    .from("users")
    .match((fields) => fields.email.eq("existing@example.com"))
    .project("email", "name")
    .build();

  const rows = await runtime.query(plan);
  console.log(rows);

  await db.close();
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
```

Run it again:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 8. Next steps [#8-next-steps]

When you change `src/prisma/contract.prisma`, emit the contract again:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

You do not need a migration just to read collections that already exist. Use [migration plan](https://www.prisma.io/docs/cli/migration-plan) when you want Prisma ORM to own a schema change.

## Related pages

- [`PostgreSQL`](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql): Add Prisma ORM to an existing PostgreSQL project.

# PostgreSQL (/docs/prisma-orm/add-to-existing-project/postgresql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to an existing PostgreSQL project.

Location: Prisma ORM > Add to Existing Project > PostgreSQL

To add Prisma ORM to a project that already uses PostgreSQL, you will run `orm init`, infer a contract from the live schema, sign the database, and run a couple of queries.

Use this path when you already have an application and database. Make sure the app can already reach its PostgreSQL database and runs on Node.js 22.18 or newer (on the 24 line, 24.11 or newer; Node.js 24 is recommended). If you want Prisma ORM to create a new app for you, use the [PostgreSQL quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql).

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release, as a release candidate. Prisma ORM 7 remains fully supported; its docs live at [/orm/v7](https://www.prisma.io/docs/orm/v7) and its setup paths at [/v7/getting-started](https://www.prisma.io/docs/v7/getting-started).
> 
> For what release candidate means, when the final release is expected, and how to stay on version 7, see [Release status](https://www.prisma.io/docs/orm/release-status). For the Prisma ORM 8 name of every Prisma ORM 7 API, see [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7).

## 1. Make sure you can run the example script [#1-make-sure-you-can-run-the-example-script]

If your project already runs TypeScript scripts, you can skip this step.

Otherwise, install the script tooling:

  

#### bun

```bash
bun add --dev tsx typescript
```

#### pnpm

```bash
pnpm add --save-dev tsx typescript
```

#### yarn

```bash
yarn add --dev tsx typescript
```

#### npm

```bash
npm install --save-dev tsx typescript
```

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

From the root of your existing project, run:

  

#### bun

```bash
bunx prisma@latest orm init --target postgres
```

#### pnpm

```bash
pnpm dlx prisma@latest orm init --target postgres
```

#### yarn

```bash
yarn dlx prisma@latest orm init --target postgres
```

#### npm

```bash
npx prisma@latest orm init --target postgres
```

This command is for a project that already exists: it preselects PostgreSQL, adds Prisma ORM files and package scripts to the app you already have, and does not scaffold a new framework project.

`orm init` also changes the `module` settings in `tsconfig.json`, and adds `"type": "module"` to `package.json` when the file has no `"type"` field. If your app is CommonJS, follow [In a CommonJS project](https://www.prisma.io/docs/cli/orm-init#in-a-commonjs-project) before you run the app again. The scripts in this guide run through `tsx`, which works in both kinds of project.

It also adds `prisma-8.md`, a short project-level reference your coding agent can read. It does not install agent skills; the Prisma ORM skill ships inside the `@prisma/orm-postgres` package your project installs. If you later run `prisma init` or `prisma skills sync`, Prisma writes skill files for coding agents into your repo. To stop that, pass `--skills=none` to [`init`](https://www.prisma.io/docs/cli/init) or set the [`skills.agents`](https://www.prisma.io/docs/cli/configuration#agent-skills) config field to `[]`; the next [`skills sync`](https://www.prisma.io/docs/cli/skills) removes any copies already written.

When Prisma ORM asks the remaining setup questions:

* choose `PSL`
* keep the default schema path, `src/prisma/contract.prisma`. Pass `--schema-path` if you want the contract somewhere else; the rest of this page assumes the default.
* answer the last question, `Also write a .env file from .env.example? (gitignored)`, with Yes. It defaults to No, and `--write-env` skips the prompt and writes the file.

## 3. Set your database connection string [#3-set-your-database-connection-string]

`orm init` always writes `.env.example`, and writes `.env` only if you asked it to. Put the connection string for the database your app already uses into `.env`:

```text title=".env"
DATABASE_URL="postgres://username:password@host:5432/database?sslmode=require"
```

`orm init` also writes `src/prisma/db.ts`, the file your application imports. It builds the Prisma ORM client from the emitted contract and reads the connection string from the environment:

```typescript title="src/prisma/db.ts"
import "dotenv/config";
import postgres from "@prisma/orm-postgres/runtime";
import type { Contract } from "./contract.d";
import contractJson from "./contract.json" with { type: "json" };

export const db = postgres<Contract>({
  contractJson,
  url: process.env["DATABASE_URL"]!,
});
```

The first line is `import "dotenv/config"`, so any script that imports `db` loads `.env` for itself. You do not need to pass the URL again at the call site.

## 4. Infer a starter contract from the live database [#4-infer-a-starter-contract-from-the-live-database]

This step gives you a starting contract by reading the schema that already exists in PostgreSQL.

Run:

  

#### bun

```bash
bunx prisma contract infer --output ./src/prisma/contract.prisma
```

#### pnpm

```bash
pnpm prisma contract infer --output ./src/prisma/contract.prisma
```

#### yarn

```bash
yarn prisma contract infer --output ./src/prisma/contract.prisma
```

#### npm

```bash
npx prisma contract infer --output ./src/prisma/contract.prisma
```

The command writes a first draft of `src/prisma/contract.prisma`.

Open that file and review it before you go on. This is the moment to clean up model names, keep only the tables you want Prisma ORM to know about first, and make the file easier to read. A model's table is the model name exactly as written, so a table such as `User` gets a model with no `@@map`, and a table such as `user` or `user_profile` gets `@@map` with its name. Keep those `@@map` lines when you rename a model, so the table stays the same.

> [!NOTE]
> Temporal types on inferred date and time columns
> 
> `contract infer` maps `timestamp` columns to `Timestamp` and `timestamptz` columns to `Timestamptz`. Both read and write their values through the global `Temporal` API. Node.js 26 ships it enabled by default (check with `node -p "typeof Temporal"`, which prints `object` when it is there); on Node.js 24 and earlier, reading such a column fails with `RUNTIME.TEMPORAL_UNAVAILABLE` unless you install [`temporal-polyfill`](https://www.npmjs.com/package/temporal-polyfill) and add `import "temporal-polyfill/full/global";` before the first query. If you would rather not add the polyfill, change the field's type in the contract to `TimestamptzString` and read and write PostgreSQL's own text instead.

## 5. Emit the generated artifacts [#5-emit-the-generated-artifacts]

Once the contract looks right, this step turns it into the generated files the runtime and CLI use.

After you are happy with the contract, run:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

This refreshes `src/prisma/contract.json` and `src/prisma/contract.d.ts` so the runtime and query APIs match the contract you just reviewed.

## 6. Sign the database [#6-sign-the-database]

Record that the live database matches the emitted contract:

  

#### bun

```bash
bunx prisma db sign
```

#### pnpm

```bash
pnpm prisma db sign
```

#### yarn

```bash
yarn prisma db sign
```

#### npm

```bash
npx prisma db sign
```

**Expected result:** `Database signed`. The command also stores the contract snapshot under `migrations/snapshots/` and points the `db` ref at it, so a later [migration plan](https://www.prisma.io/docs/cli/migration-plan) starts from the schema you just adopted instead of from an empty database.

This step matters in two common cases:

* the database has never been signed by Prisma ORM before
* the database was signed earlier, but under an older contract hash

## 7. Run a simple high-level query [#7-run-a-simple-high-level-query]

With the database signed, you can test the higher-level API first and confirm Prisma ORM is reading the existing schema correctly.

Create a `script.ts` file:

```typescript title="script.ts"
import { db } from "./src/prisma/db";

async function main() {
  const users = await db.orm.public.User
    .select("id", "email", "name")
    .limit(2)
    .all();

  console.log(users);

  await db.close();
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
```

Run it:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 8. Run a simple low-level query [#8-run-a-simple-low-level-query]

After the ORM example, this step shows the lower-level SQL builder against the same existing schema.

The SQL builder names the table, where the ORM API names the model. This example reads a table named `User`. If your model has `@@map("user")`, write `db.sql.public.user`.

Replace `script.ts` with this version:

```typescript title="script.ts"
import { db } from "./src/prisma/db";

async function main() {
  const plan = db.sql.public.User
    .select("id", "email", "name")
    .limit(2)
    .build();

  const rows = await db.runtime().query(plan);
  console.log(rows);

  await db.close();
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
```

Run it again:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 9. Next steps [#9-next-steps]

When you change `src/prisma/contract.prisma`, emit the contract again:

  

#### bun

```bash
bunx prisma contract emit
```

#### pnpm

```bash
pnpm prisma contract emit
```

#### yarn

```bash
yarn prisma contract emit
```

#### npm

```bash
npx prisma contract emit
```

Use [db update](https://www.prisma.io/docs/cli/db-update) for a direct development update, or [migration plan](https://www.prisma.io/docs/cli/migration-plan) when you want a checked-in migration.

Put together, adopting the database and making a first schema change is this sequence:

  

#### bun

```bash
bunx prisma contract infer --output ./src/prisma/contract.prisma
bunx prisma contract emit
bunx prisma db sign
# edit src/prisma/contract.prisma
bunx prisma contract emit
bunx prisma migration plan --name <slug>
```

#### pnpm

```bash
pnpm prisma contract infer --output ./src/prisma/contract.prisma
pnpm prisma contract emit
pnpm prisma db sign
# edit src/prisma/contract.prisma
pnpm prisma contract emit
pnpm prisma migration plan --name <slug>
```

#### yarn

```bash
yarn prisma contract infer --output ./src/prisma/contract.prisma
yarn prisma contract emit
yarn prisma db sign
# edit src/prisma/contract.prisma
yarn prisma contract emit
yarn prisma migration plan --name <slug>
```

#### npm

```bash
npx prisma contract infer --output ./src/prisma/contract.prisma
npx prisma contract emit
npx prisma db sign
# edit src/prisma/contract.prisma
npx prisma contract emit
npx prisma migration plan --name <slug>
```

The plan starts from the contract `db sign` recorded, so it contains only your change. Because `migrations/app/` is still empty, that first plan also writes a baseline package recording the schema you adopted; see [the automatic baseline](https://www.prisma.io/docs/cli/migration-plan#the-automatic-baseline).

## Related pages

- [`MongoDB`](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/mongodb): Add Prisma ORM to an existing MongoDB project.

# MongoDB (/docs/prisma-orm/quickstart/mongodb)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new Prisma ORM project with MongoDB using create-prisma@latest.

Location: Prisma ORM > Quickstart > MongoDB

Create a Prisma ORM app with MongoDB, apply the first migration, and run your first query against seeded data.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release, as a release candidate. Prisma ORM 7 remains fully supported; its docs live at [/orm/v7](https://www.prisma.io/docs/orm/v7) and its setup paths at [/v7/getting-started](https://www.prisma.io/docs/v7/getting-started).
> 
> For what release candidate means, when the final release is expected, and how to stay on version 7, see [Release status](https://www.prisma.io/docs/orm/release-status).

## Quick start [#quick-start]

  

#### bun

```bash
bun create prisma@latest --provider mongodb --no-deploy
```

#### pnpm

```bash
pnpm create prisma@latest --provider mongodb --no-deploy
```

#### yarn

```bash
yarn create prisma@latest --provider mongodb --no-deploy
```

#### npm

```bash
npm create prisma@latest -- --provider mongodb --no-deploy
```

Run this from a Node.js 22.18 or newer (on the 24 line, 24.11 or newer) environment; Node.js 24 is recommended. The command preselects MongoDB and prompts you for the project name, the template, the contract authoring style (PSL or TypeScript), your package manager, and whether to install agent skills.

Setup gives you the app template, a starter contract, `prisma-8.md`, project-level Prisma ORM skills for your coding agent, and package scripts for the database steps below. Answer no at the skills prompt, or pass `--skills none`, to skip the agent skill files; to remove them later, see [`skills sync`](https://www.prisma.io/docs/cli/skills) and the [`skills` config section](https://www.prisma.io/docs/cli/configuration#agent-skills). Sample users are seeded automatically the first time the app queries the database, so there is no separate seed step.

A standalone `mongod` is enough to work through this quickstart. A replica set is only needed for transactions and change streams, and MongoDB Atlas already gives you one. The connection string the scaffold writes assumes a single-node replica set named `rs0` on port 27017, so either run one locally or edit the string to point at your standalone server. If you use a standalone `mongod`, remove `replicaSet=rs0` from the connection strings below (keep `directConnection=true`); a URL that names a replica set only connects to a server that belongs to one.

## 1. Set the database connection [#1-set-the-database-connection]

The scaffold writes a `.env` with a local replica-set connection string:

```text title=".env"
DATABASE_URL="mongodb://localhost:27017/mydb?replicaSet=rs0&directConnection=true"
```

The generated scripts read environment variables directly rather than `.env`, and the CLI and the app use different variable names: the CLI commands read `MONGODB_URL`, and the app reads `DATABASE_URL`. Export both in the shell you work in:

```bash
export MONGODB_URL="mongodb://localhost:27017/mydb?replicaSet=rs0&directConnection=true"
export DATABASE_URL="$MONGODB_URL"
```

If you use MongoDB Atlas, use the connection string from your Atlas cluster instead.

## 2. Create the migration plan [#2-create-the-migration-plan]

Create the first migration plan from the starter contract.

  

#### bun

```bash
bun run migration:plan --name init
```

#### pnpm

```bash
pnpm run migration:plan --name init
```

#### yarn

```bash
yarn migration:plan --name init
```

#### npm

```bash
npm run migration:plan -- --name init
```

The output reports the planned operations: creating the `users` and `posts` collections and a unique index on `users.email`.

## 3. Apply the migration [#3-apply-the-migration]

Apply the planned migration to MongoDB.

  

#### bun

```bash
bun run migrate
```

#### pnpm

```bash
pnpm run migrate
```

#### yarn

```bash
yarn migrate
```

#### npm

```bash
npm run migrate
```

The output ends with a summary like `Applied 3 operation(s) across 1 contract space`. If it fails with a connection error, confirm `MONGODB_URL` is exported in this shell and points at a running MongoDB deployment; if the string still names `replicaSet=rs0`, that replica set has to exist.

## 4. Run the app [#4-run-the-app]

Start the app and confirm the sample query runs successfully.

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Use the URL or terminal output shown by your template. You should see the seeded users returned from MongoDB.

## Next steps [#next-steps]

* Open `src/prisma/contract.prisma` or `src/prisma/contract.ts` and change the starter model.
* Use the [MongoDB existing-project guide](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/mongodb) if you already have an app and database.
* Read the [Prisma ORM overview](https://www.prisma.io/docs/orm) when you want the concepts behind contracts, query APIs, and migrations.

## Related pages

- [`PostgreSQL`](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql): Create a new Prisma ORM project with PostgreSQL using create-prisma@latest.

# PostgreSQL (/docs/prisma-orm/quickstart/postgresql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new Prisma ORM project with PostgreSQL using create-prisma@latest.

Location: Prisma ORM > Quickstart > PostgreSQL

Create a Prisma ORM app with PostgreSQL and run your first query against seeded data.

> [!NOTE]
> Using Prisma ORM 7?
> 
> Prisma ORM 8 is the current release, as a release candidate. Prisma ORM 7 remains fully supported; its docs live at [/orm/v7](https://www.prisma.io/docs/orm/v7) and its setup paths at [/v7/getting-started](https://www.prisma.io/docs/v7/getting-started).
> 
> For what release candidate means, when the final release is expected, and how to stay on version 7, see [Release status](https://www.prisma.io/docs/orm/release-status). For the Prisma ORM 8 name of every Prisma ORM 7 API, see [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7).

## Quick start [#quick-start]

  

#### bun

```bash
bun create prisma@latest --provider postgres --no-deploy
```

#### pnpm

```bash
pnpm create prisma@latest --provider postgres --no-deploy
```

#### yarn

```bash
yarn create prisma@latest --provider postgres --no-deploy
```

#### npm

```bash
npm create prisma@latest -- --provider postgres --no-deploy
```

Run this from a Node.js 22.18 or newer (on the 24 line, 24.11 or newer) environment; Node.js 24 is recommended. The command preselects PostgreSQL and prompts you for the project name, the template, the contract authoring style (PSL or TypeScript), your package manager, and whether to install agent skills. If you would rather add Prisma ORM to a project by hand, without the generated template, follow [Set up Prisma ORM from scratch](https://www.prisma.io/docs/prisma-orm/from-scratch).

Setup gives you the app template, a starter contract, `prisma-8.md`, project-level Prisma ORM skills for your coding agent, and package scripts for the database steps below. Answer no at the skills prompt, or pass `--skills none`, to skip the agent skill files; to remove them later, see [`skills sync`](https://www.prisma.io/docs/cli/skills) and the [`skills` config section](https://www.prisma.io/docs/cli/configuration#agent-skills). Sample users are seeded automatically the first time the app queries the database, so there is no separate seed step.

From here you have two paths: let [Prisma Composer](https://www.prisma.io/docs/composer) run a local Prisma Postgres database for you, or connect a PostgreSQL database you provide.

## Path A: Run with a local database [#path-a-run-with-a-local-database]

Composer builds the app, starts a local Prisma Postgres database, and applies the starter contract for you, so you do not need a connection string.

  

#### bun

```bash
bun run dev:composer
```

#### pnpm

```bash
pnpm run dev:composer
```

#### yarn

```bash
yarn dev:composer
```

#### npm

```bash
npm run dev:composer
```

Open the URL the command prints. You should see the seeded users returned from PostgreSQL.

## Path B: Connect your own database [#path-b-connect-your-own-database]

### 1. Set the database connection [#1-set-the-database-connection]

Export `DATABASE_URL` in the shell you run the commands from. The generated scripts read the variable from the environment, not from `.env`.

```bash
export DATABASE_URL="postgresql://username:password@host:5432/database?sslmode=require"
```

If you don't have a PostgreSQL database yet, `npx create-db@latest` creates a temporary Prisma Postgres database and prints its connection string, plus a claim URL if you want to keep it.

### 2. Initialize the database [#2-initialize-the-database]

From the generated project directory, run `db:init` to apply the starter contract to PostgreSQL and sign the database.

  

#### bun

```bash
bun run db:init
```

#### pnpm

```bash
pnpm run db:init
```

#### yarn

```bash
yarn db:init
```

#### npm

```bash
npm run db:init
```

The output ends with a summary like `Applied 5 operation(s) across 1 space(s), database signed`.

### 3. Run the app [#3-run-the-app]

Start the app and confirm the sample query runs successfully.

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Use the URL or terminal output shown by your template. You should see the seeded users returned from PostgreSQL. If the response is `Could not query users yet`, `DATABASE_URL` is not set in the environment the app runs in; export it in the same shell and restart.

## Next steps [#next-steps]

* Open `src/prisma/contract.prisma` or `src/prisma/contract.ts` and change the starter model.
* Use the [PostgreSQL existing-project guide](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql) if you already have an app and database.
* Read the [Prisma ORM overview](https://www.prisma.io/docs/orm) when you want the concepts behind contracts, query APIs, and migrations.

## Related pages

- [`MongoDB`](https://www.prisma.io/docs/prisma-orm/quickstart/mongodb): Create a new Prisma ORM project with MongoDB using create-prisma@latest.

# Drizzle ORM (/docs/prisma-postgres/quickstart/drizzle-orm)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Get started with Drizzle ORM and Prisma Postgres

Location: Prisma Postgres > Quickstart > Drizzle ORM

[Drizzle ORM](https://orm.drizzle.team) is a TypeScript ORM. In this guide, you'll learn how to connect Drizzle ORM to [Prisma Postgres](https://www.prisma.io/docs/postgres).

## Prerequisites [#prerequisites]

* Node.js version 16 or higher
* TypeScript version 5.0 or higher

## 1. Create a new project [#1-create-a-new-project]

Create a new directory for your project and initialize it with npm:

  

#### bun

```bash
mkdir drizzle-quickstart
cd drizzle-quickstart
bun init
```

#### pnpm

```bash
mkdir drizzle-quickstart
cd drizzle-quickstart
pnpm init
```

#### yarn

```bash
mkdir drizzle-quickstart
cd drizzle-quickstart
yarn init
```

#### npm

```bash
mkdir drizzle-quickstart
cd drizzle-quickstart
npm init
```

Install TypeScript and initialize it:

  

#### bun

```bash
bun add --dev typescript
```

#### pnpm

```bash
pnpm add --save-dev typescript
```

#### yarn

```bash
yarn add --dev typescript
```

#### npm

```bash
npm install --save-dev typescript
```

  

#### bun

```bash
bunx tsc --init
```

#### pnpm

```bash
pnpm tsc --init
```

#### yarn

```bash
yarn tsc --init
```

#### npm

```bash
npx tsc --init
```

In your `package.json`, set the `type` to `module`:

```json title="package.json"
{
  // ...
  "type": "module" // [!code ++]
  // ...
}
```

## 2. Create a Prisma Postgres database [#2-create-a-prisma-postgres-database]

Create a Prisma Postgres database with the `create-db` CLI tool:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

Then the CLI tool should output:

```bash
┌  🚀 Creating a Prisma Postgres database
│
│  Provisioning a temporary database in us-east-1...
│
│  It will be automatically deleted in 24 hours, but you can claim it.
│
◇  Database created successfully!
│
│
●  Database Connection
│
│
│    Connection String:
│
│    postgresql://hostname:password@db.prisma.io:5432/postgres?sslmode=require
│
│
◆  Claim Your Database
│
│    Keep your database for free:
│
│    https://create-db.prisma.io/claim?CLAIM_CODE
│
│    Database will be deleted on 11/18/2025, 1:55:39 AM if not claimed.
│
└
```

Create a `.env` file and add the connection string from the output:

```text title=".env"
DATABASE_URL="postgresql://hostname:password@db.prisma.io:5432/postgres?sslmode=require"
```

> [!WARNING]
> **Never commit `.env` files to version control.** Add `.env` to your `.gitignore` file to keep credentials secure.

The database created is temporary and will be deleted in 24 hours unless claimed. Claiming moves the database into your [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29) account. Visit the claim URL from the output to keep your database.

> [!NOTE]
> To learn more about the `create-db` CLI tool, see the [create-db documentation](https://www.prisma.io/docs/postgres/npx-create-db).

## 3. Install dependencies [#3-install-dependencies]

Install Drizzle ORM and the PostgreSQL driver:

  

#### bun

```bash
bun add drizzle-orm pg dotenv
```

#### pnpm

```bash
pnpm add drizzle-orm pg dotenv
```

#### yarn

```bash
yarn add drizzle-orm pg dotenv
```

#### npm

```bash
npm install drizzle-orm pg dotenv
```

  

#### bun

```bash
bun add --dev drizzle-kit @types/pg tsx
```

#### pnpm

```bash
pnpm add --save-dev drizzle-kit @types/pg tsx
```

#### yarn

```bash
yarn add --dev drizzle-kit @types/pg tsx
```

#### npm

```bash
npm install --save-dev drizzle-kit @types/pg tsx
```

**Package breakdown:**

* `drizzle-orm`: The lightweight TypeScript ORM
* `pg`: PostgreSQL driver for Node.js
* `dotenv`: Loads environment variables from `.env` file
* `drizzle-kit`: CLI tool for migrations and schema management
* `@types/pg`: TypeScript type definitions for the pg driver
* `tsx`: TypeScript execution engine for running `.ts` files directly

## 4. Run a query [#4-run-a-query]

Create a `src/script.ts` file:

```typescript title="src/script.ts"
import "dotenv/config";
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

const db = drizzle({ client: pool });

async function main() {
  const result = await db.execute("select 1");
  console.log("Query result:", result);
}

main()
  .then(async () => {
    await pool.end();
    console.log("Connection closed");
  })
  .catch(async (error) => {
    console.error("Error:", error);
    await pool.end();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx src/script.ts
```

#### pnpm

```bash
pnpm dlx tsx src/script.ts
```

#### yarn

```bash
yarn dlx tsx src/script.ts
```

#### npm

```bash
npx tsx src/script.ts
```

You should receive output similar to:

```bash
Query result: Result {
  command: 'SELECT',
  rowCount: 1,
  oid: null,
  rows: [ { '?column?': 1 } ],
  fields: [
    Field {
      name: '?column?',
      tableID: 0,
      columnID: 0,
      dataTypeID: 23,
      dataTypeSize: 4,
      dataTypeModifier: -1,
      format: 'text'
    }
  ],
  _parsers: [ [Function: parseInteger] ],
  _types: { getTypeParser: [Function: getTypeParser] },
  RowCtor: null,
  rowAsArray: false,
  _prebuiltEmptyResultObject: { '?column?': null }
}
Connection closed
```

## Next steps [#next-steps]

Drizzle ORM is now connected to Prisma Postgres. For schemas, migrations, and queries, see the [Drizzle ORM documentation](https://orm.drizzle.team/docs/get-started).

> [!NOTE]
> Deploy to Compute
> 
> To run this app in the cloud, deploy it to [Prisma Compute](https://www.prisma.io/docs/compute), which runs your app next to your Prisma Postgres database. Follow [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy).

## Related pages

- [`Kysely`](https://www.prisma.io/docs/prisma-postgres/quickstart/kysely): Get started with Kysely and Prisma Postgres by creating a type-safe SQL query builder for your database
- [`Prisma ORM`](https://www.prisma.io/docs/prisma-postgres/quickstart/prisma-orm): Create a Prisma ORM app with Prisma Postgres.
- [`TypeORM`](https://www.prisma.io/docs/prisma-postgres/quickstart/typeorm): Get started with TypeORM and Prisma Postgres by connecting your TypeScript ORM to a managed PostgreSQL database

# Kysely (/docs/prisma-postgres/quickstart/kysely)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Get started with Kysely and Prisma Postgres by creating a type-safe SQL query builder for your database

Location: Prisma Postgres > Quickstart > Kysely

[Kysely](https://kysely.dev) is a type-safe TypeScript SQL query builder that provides TypeScript support and a fluent API for building SQL queries. In this guide, you'll learn how to connect Kysely to [Prisma Postgres](https://www.prisma.io/docs/postgres) and start querying your database with full type safety.

## Prerequisites [#prerequisites]

* Node.js version 14 or higher
* TypeScript version 4.6 or higher (5.4+ recommended for improved type inference, 5.9+ for better compilation performance)
* Strict mode enabled in your `tsconfig.json` for Kysely's type safety

## 1. Create a new project [#1-create-a-new-project]

Create a new directory for your project and initialize it with npm:

  

#### bun

```bash
mkdir kysely-quickstart
cd kysely-quickstart
bun init
```

#### pnpm

```bash
mkdir kysely-quickstart
cd kysely-quickstart
pnpm init
```

#### yarn

```bash
mkdir kysely-quickstart
cd kysely-quickstart
yarn init
```

#### npm

```bash
mkdir kysely-quickstart
cd kysely-quickstart
npm init
```

Install TypeScript and initialize it:

  

#### bun

```bash
bun add --dev typescript
```

#### pnpm

```bash
pnpm add --save-dev typescript
```

#### yarn

```bash
yarn add --dev typescript
```

#### npm

```bash
npm install --save-dev typescript
```

  

#### bun

```bash
bunx tsc --init
```

#### pnpm

```bash
pnpm tsc --init
```

#### yarn

```bash
yarn tsc --init
```

#### npm

```bash
npx tsc --init
```

## 2. Configure TypeScript [#2-configure-typescript]

Kysely requires TypeScript's strict mode for proper type safety. Update your `tsconfig.json` file:

```json title="tsconfig.json"
{
  // ...
  "compilerOptions": {
    // ...
    "strict": true, // [!code ++]
    "allowImportingTsExtensions": true, // [!code ++]
    "noEmit": true // [!code ++]
    // ...
  }
  // ...
}
```

> [!NOTE]
> The `strict: true` setting is **required** for Kysely's type safety to work correctly.

In your `package.json`, set the `type` to `module`:

```json
{
  // ...
  "type": "module" // [!code ++]
  // ...
}
```

## 3. Create a Prisma Postgres database [#3-create-a-prisma-postgres-database]

Create a Prisma Postgres database with the `create-db` CLI tool:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

Then the CLI tool should output:

```bash
┌  🚀 Creating a Prisma Postgres database
│
│  Provisioning a temporary database in us-east-1...
│
│  It will be automatically deleted in 24 hours, but you can claim it.
│
◇  Database created successfully!
│
│
●  Database Connection
│
│
│    Connection String:
│
│    postgresql://hostname:password@db.prisma.io:5432/postgres?sslmode=require
│
│
◆  Claim Your Database
│
│    Keep your database for free:
│
│    https://create-db.prisma.io/claim?CLAIM_CODE
│
│    Database will be deleted on 11/18/2025, 1:55:39 AM if not claimed.
│
└
```

Create a `.env` file and add the connection string from the output:

```text title=".env"
DATABASE_URL="postgresql://hostname:password@db.prisma.io:5432/postgres?sslmode=require"
```

> [!WARNING]
> **Never commit `.env` files to version control.** Add `.env` to your `.gitignore` file to keep credentials secure.

The database created is temporary and will be deleted in 24 hours unless claimed. Claiming moves the database into your [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29) account. Visit the claim URL from the output to keep your database.

> [!NOTE]
> To learn more about the `create-db` CLI tool, see the [create-db documentation](https://www.prisma.io/docs/postgres/npx-create-db).

## 4. Install dependencies [#4-install-dependencies]

Install Kysely and the PostgreSQL driver:

  

#### bun

```bash
bun add kysely pg dotenv
```

#### pnpm

```bash
pnpm add kysely pg dotenv
```

#### yarn

```bash
yarn add kysely pg dotenv
```

#### npm

```bash
npm install kysely pg dotenv
```

  

#### bun

```bash
bun add --dev @types/pg tsx
```

#### pnpm

```bash
pnpm add --save-dev @types/pg tsx
```

#### yarn

```bash
yarn add --dev @types/pg tsx
```

#### npm

```bash
npm install --save-dev @types/pg tsx
```

**Package breakdown:**

* `kysely`: The type-safe SQL query builder
* `pg`: PostgreSQL driver for Node.js (required by Kysely's PostgresDialect)
* `dotenv`: Loads environment variables from `.env` file
* `@types/pg`: TypeScript type definitions for the pg driver
* `tsx`: TypeScript execution engine for running `.ts` files directly

## 5. Define database types [#5-define-database-types]

Create a `src/types.ts` file to define your database schema types:

```typescript title="src/types.ts"
import type { Generated } from "kysely";

export interface Database {
  users: UsersTable;
}

export interface UsersTable {
  id: Generated<number>;
  email: string;
  name: string | null;
}
```

## 6. Configure database connection [#6-configure-database-connection]

Create a `src/database.ts` file to instantiate Kysely with your Prisma Postgres connection:

```typescript title="src/database.ts"
import "dotenv/config";
import type { Database } from "./types.ts";
import { Pool } from "pg";
import { Kysely, PostgresDialect } from "kysely";

// Parse DATABASE_URL into connection parameters
function parseConnectionString(url: string) {
  const parsed = new URL(url);
  return {
    host: parsed.hostname,
    port: parseInt(parsed.port),
    user: parsed.username,
    password: parsed.password,
    database: parsed.pathname.slice(1), // Remove leading '/'
  };
}

const connectionParams = parseConnectionString(process.env.DATABASE_URL!);

const dialect = new PostgresDialect({
  pool: new Pool({
    ...connectionParams,
    ssl: true,
    max: 10,
  }),
});

// Database interface is passed to Kysely's constructor, and from now on, Kysely
// knows your database structure.
// Dialect is passed to Kysely's constructor, and from now on, Kysely knows how
// to communicate with your database.
export const db = new Kysely<Database>({
  dialect,
});
```

## 7. Run queries [#7-run-queries]

Create a `src/script.ts` file:

```typescript title="src/script.ts"
import { db } from "./database.ts";

async function main() {
  // Create the users table
  await db.schema
    .createTable("users")
    .ifNotExists()
    .addColumn("id", "serial", (col) => col.primaryKey())
    .addColumn("email", "varchar(255)", (col) => col.notNull().unique())
    .addColumn("name", "varchar(255)")
    .execute();

  // Insert a user
  const user = await db
    .insertInto("users")
    .values({
      email: "alice@prisma.io",
      name: "Alice",
    })
    .returningAll()
    .executeTakeFirstOrThrow();

  console.log("Created user:", user);

  // Query all users
  const users = await db.selectFrom("users").selectAll().execute();

  console.log("All users:", users);
}

main()
  .then(async () => {
    await db.destroy();
  })
  .catch(async (error) => {
    console.error("Error:", error);
    await db.destroy();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx src/script.ts
```

#### pnpm

```bash
pnpm dlx tsx src/script.ts
```

#### yarn

```bash
yarn dlx tsx src/script.ts
```

#### npm

```bash
npx tsx src/script.ts
```

You should receive the following output:

```bash
Created user: { id: 1, email: 'alice@prisma.io', name: 'Alice' }
All users: [ { id: 1, email: 'alice@prisma.io', name: 'Alice' } ]
```

## Next steps [#next-steps]

Kysely is now connected to Prisma Postgres. For schemas, migrations, and more complex queries, see the [Kysely documentation](https://kysely.dev/docs/intro).

> [!NOTE]
> Deploy to Compute
> 
> To run this app in the cloud, deploy it to [Prisma Compute](https://www.prisma.io/docs/compute), which runs your app next to your Prisma Postgres database. Follow [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy).

## Related pages

- [`Drizzle ORM`](https://www.prisma.io/docs/prisma-postgres/quickstart/drizzle-orm): Get started with Drizzle ORM and Prisma Postgres
- [`Prisma ORM`](https://www.prisma.io/docs/prisma-postgres/quickstart/prisma-orm): Create a Prisma ORM app with Prisma Postgres.
- [`TypeORM`](https://www.prisma.io/docs/prisma-postgres/quickstart/typeorm): Get started with TypeORM and Prisma Postgres by connecting your TypeScript ORM to a managed PostgreSQL database

# Prisma ORM (/docs/prisma-postgres/quickstart/prisma-orm)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a Prisma ORM app with Prisma Postgres.

Location: Prisma Postgres > Quickstart > Prisma ORM

Create a Prisma ORM app backed by Prisma Postgres.

## Quick start [#quick-start]

  

#### bun

```bash
bun create prisma@latest
```

#### pnpm

```bash
pnpm create prisma@latest
```

#### yarn

```bash
yarn create prisma@latest
```

#### npm

```bash
npm create prisma@latest
```

Run this from a Node.js 22.18 or newer (on the 24 line, 24.11 or newer) environment; Node.js 24 is recommended. When prompted, choose PostgreSQL, and answer No to `Deploy to Prisma now?`.

Setup adds a starter contract, creates `prisma-8.md`, installs project-level Prisma ORM skills for your coding agent, and adds package scripts for the database steps below. Choose the minimal template if you want the fastest first run, or a framework template when you want the first query wired into an app route or page.

## 1. Create the database [#1-create-the-database]

Create a Prisma Postgres database from the terminal and export its connection string. The generated scripts read the environment variable, not `.env`:

  

#### bun

```bash
bunx create-db@latest
```

#### pnpm

```bash
pnpm dlx create-db@latest
```

#### yarn

```bash
yarn dlx create-db@latest
```

#### npm

```bash
npx create-db@latest
```

```bash
export DATABASE_URL="<the connection string create-db printed>"
```

The command also prints a claim URL; open it within 24 hours to keep the database in your account.

## 2. Initialize the database [#2-initialize-the-database]

From the generated project directory, run `db:init` to apply the starter schema to Prisma Postgres and sign the database.

  

#### bun

```bash
bun run db:init
```

#### pnpm

```bash
pnpm run db:init
```

#### yarn

```bash
yarn db:init
```

#### npm

```bash
npm run db:init
```

Sample users are seeded automatically the first time the app queries the database, so there is no separate seed step.

## 3. Run the app [#3-run-the-app]

Start the app and confirm the sample query runs successfully.

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Use the URL or terminal output shown by your template to confirm the sample query runs successfully.

## Next steps [#next-steps]

* Open the generated contract and change the starter model.
* Use [Import from PostgreSQL](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-postgresql) or [Import from MySQL](https://www.prisma.io/docs/prisma-postgres/import-from-existing-database-mysql) when you want to move an existing database to Prisma Postgres.
* Use the [PostgreSQL existing-project guide](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql) when your app already has a Prisma Postgres database.

## Related pages

- [`Drizzle ORM`](https://www.prisma.io/docs/prisma-postgres/quickstart/drizzle-orm): Get started with Drizzle ORM and Prisma Postgres
- [`Kysely`](https://www.prisma.io/docs/prisma-postgres/quickstart/kysely): Get started with Kysely and Prisma Postgres by creating a type-safe SQL query builder for your database
- [`TypeORM`](https://www.prisma.io/docs/prisma-postgres/quickstart/typeorm): Get started with TypeORM and Prisma Postgres by connecting your TypeScript ORM to a managed PostgreSQL database

# TypeORM (/docs/prisma-postgres/quickstart/typeorm)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Get started with TypeORM and Prisma Postgres by connecting your TypeScript ORM to a managed PostgreSQL database

Location: Prisma Postgres > Quickstart > TypeORM

[TypeORM](https://typeorm.io) is a TypeScript ORM. In this guide, you'll learn how to connect TypeORM to [Prisma Postgres](https://www.prisma.io/docs/postgres).

## Prerequisites [#prerequisites]

* Node.js version 16 or higher
* TypeScript version 4.5 or higher

## 1. Generate a TypeORM project [#1-generate-a-typeorm-project]

Use the TypeORM CLI to generate a starter project:

  

#### bun

```bash
bunx typeorm init --name typeorm-quickstart --database postgres
```

#### pnpm

```bash
pnpm dlx typeorm init --name typeorm-quickstart --database postgres
```

#### yarn

```bash
yarn dlx typeorm init --name typeorm-quickstart --database postgres
```

#### npm

```bash
npx typeorm init --name typeorm-quickstart --database postgres
```

This command will generate a new project with the following structure:

```
typeorm-quickstart
├── src
│   ├── entity
│   │   └── User.ts       # Sample entity
│   ├── migration         # Migrations folder
│   ├── data-source.ts    # Data source configuration
│   └── index.ts          # Application entry point
├── .gitignore
├── package.json
├── README.md
└── tsconfig.json
```

## 2. Install dependencies [#2-install-dependencies]

Navigate to the project directory and install dependencies:

  

#### bun

```bash
cd typeorm-quickstart
bun install
```

#### pnpm

```bash
cd typeorm-quickstart
pnpm install
```

#### yarn

```bash
cd typeorm-quickstart
yarn install
```

#### npm

```bash
cd typeorm-quickstart
npm install
```

Install dotenv to load environment variables:

  

#### bun

```bash
bun add dotenv
```

#### pnpm

```bash
pnpm add dotenv
```

#### yarn

```bash
yarn add dotenv
```

#### npm

```bash
npm install dotenv
```

## 3. Create a Prisma Postgres database [#3-create-a-prisma-postgres-database]

Create a Prisma Postgres database with the `create-db` CLI tool:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

Then the CLI tool should output:

```bash
┌  🚀 Creating a Prisma Postgres database
│
│  Provisioning a temporary database in us-east-1...
│
│  It will be automatically deleted in 24 hours, but you can claim it.
│
◇  Database created successfully!
│
│
●  Database Connection
│
│
│    Connection String:
│
│    postgresql://hostname:password@db.prisma.io:5432/postgres?sslmode=require
│
│
◆  Claim Your Database
│
│    Keep your database for free:
│
│    https://create-db.prisma.io/claim?CLAIM_CODE
│
│    Database will be deleted on 11/18/2025, 1:55:39 AM if not claimed.
│
└
```

Create a `.env` file and add the connection string from the output:

```text title=".env"
DATABASE_URL="postgresql://hostname:password@db.prisma.io:5432/postgres?sslmode=require"
```

> [!WARNING]
> **Never commit `.env` files to version control.** Add `.env` to your `.gitignore` file to keep credentials secure.

The database created is temporary and will be deleted in 24 hours unless claimed. Claiming moves the database into your [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29) account. Visit the claim URL from the output to keep your database.

> [!NOTE]
> To learn more about the `create-db` CLI tool, see the [create-db documentation](https://www.prisma.io/docs/postgres/npx-create-db).

## 4. Configure database connection [#4-configure-database-connection]

Update the `src/data-source.ts` file to use your Prisma Postgres connection:

```typescript title="src/data-source.ts"
import "reflect-metadata";
import "dotenv/config"; // [!code ++]
import { DataSource } from "typeorm";
import { User } from "./entity/User";

// Parse DATABASE_URL into connection parameters // [!code ++]
function parseConnectionString(url: string) {
  // [!code ++]
  const parsed = new URL(url); // [!code ++]
  return {
    // [!code ++]
    host: parsed.hostname, // [!code ++]
    port: parseInt(parsed.port), // [!code ++]
    username: parsed.username, // [!code ++]
    password: parsed.password, // [!code ++]
    database: parsed.pathname.slice(1), // Remove leading '/' // [!code ++]
  }; // [!code ++]
} // [!code ++]

const connectionParams = parseConnectionString(process.env.DATABASE_URL!); // [!code ++]

export const AppDataSource = new DataSource({
  type: "postgres",
  host: "localhost", // [!code --]
  port: 5432, // [!code --]
  username: "test", // [!code --]
  password: "test", // [!code --]
  database: "test", // [!code --]
  ...connectionParams, // [!code ++]
  ssl: true, // [!code ++]
  synchronize: true,
  logging: false,
  entities: [User],
  migrations: [],
  subscribers: [],
});
```

## 5. Run the application [#5-run-the-application]

Start the application:

  

#### bun

```bash
bun start
```

#### pnpm

```bash
pnpm start
```

#### yarn

```bash
yarn start
```

#### npm

```bash
npm start
```

You should see output indicating the connection was successful and a new user was inserted into the database:

```bash
Inserting a new user into the database...
Saved a new user with id: 1
Loading users from the database...
Loaded users:  [ User { id: 1, firstName: 'Timber', lastName: 'Saw', age: 25 } ]
```

## Next steps [#next-steps]

TypeORM is now connected to Prisma Postgres. For entities, migrations, and queries, see the [TypeORM documentation](https://typeorm.io/docs/getting-started).

> [!NOTE]
> Deploy to Compute
> 
> To run this app in the cloud, deploy it to [Prisma Compute](https://www.prisma.io/docs/compute), which runs your app next to your Prisma Postgres database. Follow [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy).

## Related pages

- [`Drizzle ORM`](https://www.prisma.io/docs/prisma-postgres/quickstart/drizzle-orm): Get started with Drizzle ORM and Prisma Postgres
- [`Kysely`](https://www.prisma.io/docs/prisma-postgres/quickstart/kysely): Get started with Kysely and Prisma Postgres by creating a type-safe SQL query builder for your database
- [`Prisma ORM`](https://www.prisma.io/docs/prisma-postgres/quickstart/prisma-orm): Create a Prisma ORM app with Prisma Postgres.

# From the CLI (Prisma ORM v7) (/docs/v7/prisma-postgres/from-the-cli)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Start building a Prisma application with a Prisma Postgres database from the CLI

Location: v7 > Prisma Postgres > From the CLI

This page provides a step-by-step guide for Prisma Postgres after setting it up with `prisma init` and `npx create-db`:

1. Set up a TypeScript app with Prisma ORM
2. Migrate the schema of your database
3. Query your database from TypeScript

## Prerequisites [#prerequisites]

This guide assumes you initialized Prisma with `prisma init` and created a Prisma Postgres database with `npx create-db`:

  

#### bun

```bash
bunx --bun prisma@prev init
bunx create-db
```

#### pnpm

```bash
pnpm dlx prisma@prev init
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx prisma@prev init
yarn dlx create-db
```

#### npm

```bash
npx prisma@prev init
npx create-db
```

Once these commands have terminated:

* The `prisma/` folder was created with an empty `schema.prisma` file.
* The `DATABASE_URL` env var was set in a `.env` file.
* The `prisma7.config.ts` file was created with the default configuration.
* You have a Prisma Postgres connection string to paste into `.env`.

## 1. Organize your project directory [#1-organize-your-project-directory]

> [!NOTE]
> If you ran the `prisma init` command inside a folder where you want your project to live, you can skip this step and [proceed to the next section](https://www.prisma.io/docs/v7/prisma-postgres/from-the-cli#2-set-up-your-project).

If you ran the command outside your intended project directory (e.g., in your home folder or another location), you need to move the generated `prisma` folder and the `.env` file into a dedicated project directory.

Create a new folder (e.g. `hello-prisma`) where you want your project to live and move the necessary files into it:

```bash
mkdir hello-prisma
mv .env ./hello-prisma/
mv prisma ./hello-prisma/
```

Navigate into your project folder:

```bash
cd ./hello-prisma
```

Now that your project is in the correct location, continue with the setup.

## 2. Set up your project [#2-set-up-your-project]

### 2.1. Set up TypeScript [#21-set-up-typescript]

Initialize a TypeScript project and add the Prisma CLI as a development dependency:

  

#### bun

```bash
bun init
```

#### pnpm

```bash
pnpm init
```

#### yarn

```bash
yarn init
```

#### npm

```bash
npm init
```

  

#### bun

```bash
bun add typescript tsx @types/node @types/pg --dev
```

#### pnpm

```bash
pnpm add typescript tsx @types/node @types/pg -D
```

#### yarn

```bash
yarn add typescript tsx @types/node @types/pg --dev
```

#### npm

```bash
npm install typescript tsx @types/node @types/pg -D
```

This creates a `package.json` file with an initial setup for your TypeScript app.

Next, initialize TypeScript with a `tsconfig.json` file in the project:

  

#### bun

```bash
bunx tsc --init
```

#### pnpm

```bash
pnpm tsc --init
```

#### yarn

```bash
yarn tsc --init
```

#### npm

```bash
npx tsc --init
```

### 2.2. Configure ESM support [#22-configure-esm-support]

Update `tsconfig.json` for ESM compatibility:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "ignoreDeprecations": "6.0"
  }
}
```

Update `package.json` to enable ESM:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

### 2.3. Set up Prisma ORM [#23-set-up-prisma-orm]

Install the required dependencies to use Prisma Postgres:

  

#### bun

```bash
bun add prisma@prev --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### yarn

```bash
yarn add prisma@prev --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### npm

```bash
npm install prisma@prev --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma migrate` and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-pg`** - The [`node-postgres` driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters) that connects Prisma Client to your database
* **`pg`** - The node-postgres database driver
* **`@types/pg`** - TypeScript type definitions for node-postgres
* **`dotenv`** - Loads environment variables from your `.env` file

### 2.4. Review the generated prisma7.config.ts [#24-review-the-generated-prisma7configts]

The `prisma init` command automatically created a `prisma7.config.ts` file that looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

### 2.5. Create a script to query the database [#25-create-a-script-to-query-the-database]

Create an `index.ts` file in the root directory, this will be used to query your application with Prisma ORM:

```bash
touch index.ts
```

## 3. Migrate the database schema [#3-migrate-the-database-schema]

Update your `prisma/schema.prisma` file to include the `User` and `Post` models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User    @relation(fields: [authorId], references: [id])
  authorId  Int
}
```

After adding the models, migrate your database using [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate):

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This command creates the database tables based on your schema.

Now run the following command to generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 4. Send queries with Prisma ORM [#4-send-queries-with-prisma-orm]

### 4.1. Instantiate Prisma Client [#41-instantiate-prisma-client]

Create a `lib/prisma.ts` file to instantiate Prisma Client with the driver adapter:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

> [!NOTE]
> If you need to query your database via HTTP from an edge runtime (Cloudflare Workers, Vercel Edge Functions, etc.), use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver#use-with-prisma-orm).

### 4.2. Write your first query [#42-write-your-first-query]

Paste the following boilerplate into `index.ts`:

```ts title="index.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // ... you will write your Prisma ORM queries here
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

This code contains a `main` function that's invoked at the end of the script. It also instantiates `PrismaClient` which you'll use to send queries to your database.

### 4.3. Create a new `User` record [#43-create-a-new-user-record]

Start with a small query that creates a new `User` record in the database and logs the resulting object to the console. Add the following code to your `index.ts` file:

```ts title="index.ts"
import { prisma } from "./lib/prisma";

async function main() {
  const user = await prisma.user.create({
    // [!code ++]
    data: {
      // [!code ++]
      name: "Alice", // [!code ++]
      email: "alice@prisma.io", // [!code ++]
    }, // [!code ++]
  }); // [!code ++]
  console.log(user); // [!code ++]
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Next, execute the script with the following command:

  

#### bun

```bash
bunx tsx index.ts
```

#### pnpm

```bash
pnpm dlx tsx index.ts
```

#### yarn

```bash
yarn dlx tsx index.ts
```

#### npm

```bash
npx tsx index.ts
```

```text no-copy
{ id: 1, email: 'alice@prisma.io', name: 'Alice' }
```

You have created your first database record with Prisma Postgres.

### 4.4. Retrieve all `User` records [#44-retrieve-all-user-records]

Prisma ORM offers several queries to read data from your database. Next, use the `findMany` query, which returns *all* the records in the database for a given model.

Delete the previous Prisma ORM query and add the new `findMany` query instead:

```ts title="index.ts"
import { prisma } from "./lib/prisma";

async function main() {
  const users = await prisma.user.findMany(); // [!code ++]
  console.log(users); // [!code ++]
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Execute the script again:

  

#### bun

```bash
bunx tsx index.ts
```

#### pnpm

```bash
pnpm dlx tsx index.ts
```

#### yarn

```bash
yarn dlx tsx index.ts
```

#### npm

```bash
npx tsx index.ts
```

```text no-copy
[{ id: 1, email: 'alice@prisma.io', name: 'Alice' }]
```

Notice how the single `User` object is now enclosed with square brackets in the console. That's because the `findMany` returned an array with a single object inside.

### 4.5. Explore relation queries [#45-explore-relation-queries]

Prisma ORM reads and writes [relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations) through the same query API. Next, create a `User` and a `Post` record in one nested write query, then retrieve the relation from the database with the `include` option.

First, adjust your script to include the nested query:

```ts title="index.ts"
import { prisma } from "./lib/prisma";

async function main() {
  const user = await prisma.user.create({
    // [!code ++]
    data: {
      // [!code ++]
      name: "Bob", // [!code ++]
      email: "bob@prisma.io", // [!code ++]
      posts: {
        // [!code ++]
        create: [
          // [!code ++]
          {
            // [!code ++]
            title: "Hello World", // [!code ++]
            published: true, // [!code ++]
          }, // [!code ++]
          {
            // [!code ++]
            title: "My second post", // [!code ++]
            content: "This is still a draft", // [!code ++]
          }, // [!code ++]
        ], // [!code ++]
      }, // [!code ++]
    }, // [!code ++]
  }); // [!code ++]
  console.log(user); // [!code ++]
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the query by executing the script again:

  

#### bun

```bash
bunx tsx index.ts
```

#### pnpm

```bash
pnpm dlx tsx index.ts
```

#### yarn

```bash
yarn dlx tsx index.ts
```

#### npm

```bash
npx tsx index.ts
```

```text no-copy
{ id: 2, email: 'bob@prisma.io', name: 'Bob' }
```

In order to also retrieve the `Post` records that belong to a `User`, you can use the `include` option via the `posts` relation field:

```ts title="index.ts"
import { prisma } from "./lib/prisma";

async function main() {
  const usersWithPosts = await prisma.user.findMany({
    // [!code ++]
    include: {
      // [!code ++]
      posts: true, // [!code ++]
    }, // [!code ++]
  }); // [!code ++]
  console.dir(usersWithPosts, { depth: null }); // [!code ++]
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script again to see the results of the nested read query:

  

#### bun

```bash
bunx tsx index.ts
```

#### pnpm

```bash
pnpm dlx tsx index.ts
```

#### yarn

```bash
yarn dlx tsx index.ts
```

#### npm

```bash
npx tsx index.ts
```

```text no-copy
[
  { id: 1, email: 'alice@prisma.io', name: 'Alice', posts: [] },
  {
    id: 2,
    email: 'bob@prisma.io',
    name: 'Bob',
    posts: [
      {
        id: 1,
        title: 'Hello World',
        content: null,
        published: true,
        authorId: 2
      },
      {
        id: 2,
        title: 'My second post',
        content: 'This is still a draft',
        published: false,
        authorId: 2
      }
    ]
  }
]
```

This time, you're seeing two `User` objects being printed. Both of them have a `posts` field (which is empty for `"Alice"` and populated with two `Post` objects for `"Bob"`) that represents the `Post` records associated with them.

## Next steps [#next-steps]

This page covered a basic Prisma Postgres setup. The [Quickstart](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres) covers the full setup.

### View and edit data in Prisma Studio [#view-and-edit-data-in-prisma-studio]

Prisma ORM comes with a built-in GUI to view and edit the data in your database. You can open it using the following command:

  

#### bun

```bash
bunx prisma studio --config ./prisma7.config.ts
```

#### pnpm

```bash
pnpm prisma studio --config ./prisma7.config.ts
```

#### yarn

```bash
yarn prisma studio --config ./prisma7.config.ts
```

#### npm

```bash
npx prisma studio --config ./prisma7.config.ts
```

With Prisma Postgres, you can also directly use Prisma Studio inside the [Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29) by selecting the **Studio** tab in your project.

### Build a fullstack app with Next.js [#build-a-fullstack-app-with-nextjs]

Learn how to use Prisma Postgres in a fullstack app:

* [Build a fullstack app with Next.js 15](https://www.prisma.io/docs/guides/v7/frameworks/nextjs)
* [Next.js 15 example app](https://github.com/prisma/nextjs-prisma-postgres-demo) (including authentication)

### Explore ready-to-run examples [#explore-ready-to-run-examples]

Check out the [`prisma-examples`](https://github.com/prisma/prisma-examples/) repository on GitHub to see how Prisma ORM can be used with the library you work with. The repo contains examples with Express, NestJS, GraphQL as well as fullstack examples with Next.js and Vue.js, and a lot more.

These examples use SQLite by default; the project README explains how to switch them to Prisma Postgres.

## Related pages

- [`Import from MySQL`](https://www.prisma.io/docs/v7/prisma-postgres/import-from-existing-database-mysql): Learn how to import data from an existing MySQL database into Prisma Postgres
- [`Import from PostgreSQL`](https://www.prisma.io/docs/v7/prisma-postgres/import-from-existing-database-postgresql): Learn how to import data from an existing PostgreSQL database into Prisma Postgres

# Import from MySQL (Prisma ORM v7) (/docs/v7/prisma-postgres/import-from-existing-database-mysql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to import data from an existing MySQL database into Prisma Postgres

Location: v7 > Prisma Postgres > Import from MySQL

This guide provides step-by-step instructions for importing data from an existing MySQL database into Prisma Postgres.

You can accomplish this migration in four steps:

1. Create a new Prisma Postgres database.
2. Connect directly to a Prisma Postgres instance using a [direct connection](https://www.prisma.io/docs/postgres/database/connecting-to-your-database).
3. Migrate your MySQL data to Prisma Postgres using [pgloader](https://pgloader.io/).
4. Configure your Prisma project for Prisma Postgres.

## Prerequisites [#prerequisites]

* The connection URL to your existing MySQL database.
* A [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29) account.
* Node.js 18+ installed.
* [pgloader](https://pgloader.io/) installed.

> [!NOTE]
> Make sure your PostgreSQL tools match the Prisma Postgres version
> 
> Prisma Postgres runs PostgreSQL 17. Your `pgloader` and any other PostgreSQL tools you use need to be compatible with PostgreSQL 17.

We recommend attempting this migration in a separate git development branch.

## 1. Create a new Prisma Postgres database [#1-create-a-new-prisma-postgres-database]

Follow these steps to create a new Prisma Postgres database:

1. Log in to [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29) and open the Console.
2. In a [workspace](https://www.prisma.io/docs/console/concepts#workspace) of your choice, click the **New project** button.
3. Type a name for your project in the **Name** field, e.g. **hello-ppg**.
4. In the **Prisma Postgres** section, click the **Get started** button.
5. In the **Region** dropdown, select the region that's closest to your current location, e.g. &#x2A;*US East (N. Virginia)**.
6. Click the **Create project** button.

Once your database is provisioned, find your direct Prisma Postgres connection string:

1. Navigate to your active Prisma Postgres instance.
2. Click the **Connection Strings** tab in the project's sidenav.
3. Click the **Create connection string** button.
4. In the popup, provide a **Name** for the connection string and click **Create**.
5. Copy the connection string starting with `postgres://`, this is your direct connection string.

Save the connection string, as you'll need it in step 3.

## 2. Prepare your direct connection string [#2-prepare-your-direct-connection-string]

In this step, you'll use the [direct connection string](https://www.prisma.io/docs/postgres/database/connecting-to-your-database) you obtained in step 1 to connect to your Prisma Postgres instance.

Your direct connection string should look like this:

```text
postgres://USER:PASSWORD@db.prisma.io:5432/?sslmode=require
```

You'll use this connection string in the next step when configuring pgloader.

## 3. Migrate your MySQL data to Prisma Postgres using pgloader [#3-migrate-your-mysql-data-to-prisma-postgres-using-pgloader]

Now that you have an active connection to your Prisma Postgres instance, you'll use [pgloader](https://pgloader.io/) to export data from your MySQL database to Prisma Postgres.

Open a separate terminal window and create a `config.load` file:

```bash
touch config.load
```

Open the `config.load` file in your preferred text editor and copy-paste the following configuration:

```text title="config.load"
LOAD DATABASE
    FROM mysql://username:password@host:PORT/database_name
    INTO postgres://__USER__:__PASSWORD__@db.prisma.io:5432/?sslmode=require

WITH quote identifiers,    -- preserve table/column name case by quoting them
     include drop,
     create tables,
     create indexes,
     reset sequences

ALTER SCHEMA 'database_name' RENAME TO 'public';
```

Make sure to update the following details in the `config.load` file:

* `FROM` url (MySQL database URL):
  * Replace `username`, `password`, `host`, `PORT`, and `database_name` with the actual connection details for your MySQL database.
  * Ensure that your connection string includes `useSSL=true` if SSL is required, for example: `mysql://username:password@host:PORT/database_name?useSSL=true`. Note that when using PlanetScale, appending `sslaccept=strict` will not work.
* `INTO` url (Postgres database URL):
  * Update this with your direct connection string from above, replacing the `__USER__` and `__PASSWORD__` placeholders.
* Update the `database_name` in `ALTER SCHEMA 'database_name' RENAME TO 'public';` to exactly match the `database_name` in your MySQL connection string.

After saving the configuration file with your updated credentials, in the same terminal window, execute the following command:

```bash
pgloader config.load
```

You should see a log similar to this, which confirms the successful migration of your data:

```bash
LOG report summary reset
               table name     errors       rows      bytes      total time
-------------------------  ---------  ---------  ---------  --------------
          fetch meta data          0          9                     2.546s
           Create Schemas          0          0                     0.325s
         Create SQL Types          0          0                     0.635s
            Create tables          0          6                     5.695s
           Set Table OIDs          0          3                     0.328s
-------------------------  ---------  ---------  ---------  --------------
              public.post          0          8     0.5 kB          4.255s
            public."user"          0          4     0.1 kB          2.775s
public._prisma_migrations          0          1     0.2 kB          4.278s
-------------------------  ---------  ---------  ---------  --------------
  COPY Threads Completion          0          4                     5.095s
   Index Build Completion          0          5                     9.601s
           Create Indexes          0          5                     4.116s
          Reset Sequences          0          2                     4.540s
             Primary Keys          0          3                     2.917s
      Create Foreign Keys          0          1                     1.121s
          Create Triggers          0          0                     0.651s
         Install Comments          0          0                     0.000s
-------------------------  ---------  ---------  ---------  --------------
        Total import time          ✓         13     0.8 kB         28.042s
```

If you see output like this, it means your data has been successfully exported to your Prisma Postgres instance.

You can also use [Prisma Studio](https://www.prisma.io/docs/guides/postgres/viewing-data#viewing-and-editing-data-in-prisma-studio) to verify whether the migration was successful:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

## 4. Configure your Prisma project for Prisma Postgres [#4-configure-your-prisma-project-for-prisma-postgres]

After migrating your data, you need to set up your Prisma project to work with Prisma Postgres. The steps differ depending on whether you were already using Prisma ORM.

### If you **were not** previously using Prisma ORM [#if-you-were-not-previously-using-prisma-orm]

Initialize Prisma in your project by running `npx prisma init` in your project directory. This creates a `prisma` folder with a `schema.prisma` file and `.env` file (if not already present).

In the generated `.env` file, update `DATABASE_URL` to match your Prisma Postgres direct connection string that you received in [step 1](https://www.prisma.io/docs/v7/prisma-postgres/import-from-existing-database-mysql#1-create-a-new-prisma-postgres-database):

```text title=".env" no-copy
DATABASE_URL="postgres://USER:PASSWORD@db.prisma.io:5432/?sslmode=require"
```

[Introspect](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) your newly migrated database by running:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This command updates your `schema.prisma` file with models representing your migrated tables, so you can start using [Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) to query your data or [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started) to manage future changes.

Your MySQL database is now migrated to Prisma Postgres and your Prisma project is configured.

> [!NOTE]
> For a comprehensive guide on getting started with Prisma and Prisma Postgres, see [start from scratch with Prisma and Prisma Postgres](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres).

### If you **were** already using Prisma ORM [#if-you-were-already-using-prisma-orm]

In your `schema.prisma` file, change the `provider` in the `datasource` block from `mysql` to `postgresql`:

```prisma title="schema.prisma"
datasource db {
  provider = "mysql" // [!code --]
  provider = "postgres" // [!code ++]
}
```

In the generated `.env` file, update `DATABASE_URL` to match your Prisma Postgres direct connection string that you received in [step 1](https://www.prisma.io/docs/v7/prisma-postgres/import-from-existing-database-mysql#1-create-a-new-prisma-postgres-database):

```text title=".env" no-copy
DATABASE_URL="postgres://USER:PASSWORD@db.prisma.io:5432/?sslmode=require"
```

Introspect your newly migrated Prisma Postgres database and generate Prisma Client:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This command refreshes your Prisma models based on the new database schema.

If you were using [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started) before:

* Delete your existing `migrations` folder in the `prisma` directory.
* [Baseline your database](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining#baselining-a-database) to begin creating new migrations.

Your MySQL database is now migrated to Prisma Postgres and your Prisma project is configured.

If you run into issues during the migration, ask on [Discord](https://pris.ly/discord?utm_source=docs\&utm_medium=conclusion) or via [X](https://pris.ly/x?utm_source=docs\&utm_medium=conclusion).

## Related pages

- [`From the CLI`](https://www.prisma.io/docs/v7/prisma-postgres/from-the-cli): Start building a Prisma application with a Prisma Postgres database from the CLI
- [`Import from PostgreSQL`](https://www.prisma.io/docs/v7/prisma-postgres/import-from-existing-database-postgresql): Learn how to import data from an existing PostgreSQL database into Prisma Postgres

# Import from PostgreSQL (Prisma ORM v7) (/docs/v7/prisma-postgres/import-from-existing-database-postgresql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to import data from an existing PostgreSQL database into Prisma Postgres

Location: v7 > Prisma Postgres > Import from PostgreSQL

This guide provides step-by-step instructions for importing data from an existing PostgreSQL database into Prisma Postgres.

You can accomplish this migration in three steps:

1. Create a new Prisma Postgres database.
2. Export your existing data via `pg_dump`.
3. Import the previously exported data into Prisma Postgres via `pg_restore`.

In the third step, you will be using a [direct connection](https://www.prisma.io/docs/postgres/database/connecting-to-your-database) to securely connect to your Prisma Postgres database to run `pg_restore`.

## Prerequisites [#prerequisites]

* The connection URL to your existing PostgreSQL database
* A [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29) account
* Node.js 18+ installed
* PostgreSQL CLI Tools (`pg_dump`, `pg_restore`) for creating and restoring backups

> [!NOTE]
> Make sure your PostgreSQL tools match the Prisma Postgres version
> 
> Prisma Postgres runs PostgreSQL 17. Your `pg_dump` and `pg_restore` tools need to be version 17 to ensure compatibility. You can check your version by running `pg_dump --version` or `pg_restore --version`.

## 1. Create a new Prisma Postgres database [#1-create-a-new-prisma-postgres-database]

Follow these steps to create a new Prisma Postgres database:

1. Log in to [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29) and open the Console.
2. In a [workspace](https://www.prisma.io/docs/console/concepts#workspace) of your choice, click the **New project** button.
3. Type a name for your project in the **Name** field, e.g. **hello-ppg**.
4. In the **Prisma Postgres** section, click the **Get started** button.
5. In the **Region** dropdown, select the region that's closest to your current location, e.g. &#x2A;*US East (N. Virginia)**.
6. Click the **Create project** button.

Once your database is provisioned, obtain your direct connection string:

1. Navigate to your active Prisma Postgres instance.
2. Click the **Connection Strings** tab in the project's sidenav.
3. Click the **Create connection string** button.
4. In the popup, provide a **Name** for the connection string and click **Create**.
5. Copy the connection string starting with `postgres://`, this is your direct connection string.

Save the connection string, as you'll need it in step 3.

## 2. Export data from your existing database [#2-export-data-from-your-existing-database]

In this step, you're going to export the data from your existing database and store it in a `.bak` file on your local machine.

Make sure to have the connection URL for your existing database ready, it should be [structured](https://www.prisma.io/docs/orm/v7/reference/connection-urls) like this:

```text
postgresql://USER:PASSWORD@HOST:PORT/DATABASE
```

Expand below for provider-specific instructions that help you determine the right connection string:

### Neon

* Make sure to select non-pooled connection string by switching off the **Connection pooling** toggle.
* The `sslmode` has to be set to `require` and appended to your Neon database URL for the command to work.
* The connection URL should look similar to this:

```text
postgresql://USER:PASSWORD@YOUR-NEON-HOST/DATABASE?sslmode=require
```

### Supabase

* Use a database connection URL that uses [Supavisor session mode](https://supabase.com/docs/guides/database/connecting-to-postgres#supavisor-session-mode).
* The connection URL should look similar to this:

```text
postgres://postgres.apbkobhfnmcqqzqeeqss:[YOUR-PASSWORD]@aws-0-ca-central-1.pooler.supabase.com:5432/postgres
```

Next, run the following command to export the data of your PostgreSQL database (replace the `__DATABASE_URL__` placeholder with your actual database connection URL):

```bash
pg_dump \
  -Fc \
  -v \
  -d __DATABASE_URL__ \
  -n public \
  -f db_dump.bak
```

Here's a quick overview of the CLI options that were used for this command:

* `-Fc`: Uses the custom format for backups, recommended for `pg_restore`
* `-v`: Runs `pg_dump` in verbose mode
* `-d`: Specifies the database connection string
* `-n`: Specifies the target PostgreSQL schema
* `-f`: Specifies the output name for the backup file

Running this command will create a backup file named `db_dump.bak` which you will use to restore the data into your Prisma Postgres database in the next step.

## 3. Import data into Prisma Postgres [#3-import-data-into-prisma-postgres]

Use your [direct connection string](https://www.prisma.io/docs/postgres/database/connecting-to-your-database) to connect to your Prisma Postgres instance and import data via `pg_restore`.

Your direct connection string from step 1 should look like this:

```text
postgres://USER:PASSWORD@db.prisma.io:5432/?sslmode=require
```

Use the backup file from **Step 2** to restore data into your Prisma Postgres database with `pg_restore` by running this command (replace `__USER__`, `__PASSWORD__` with the values from your direct connection string):

```bash
pg_restore \
  -h db.prisma.io \
  -p 5432 \
  -U __USER__ \
  -d postgres \
  -v \
  ./db_dump.bak \
&& echo "-complete-"
```

When prompted, enter the `__PASSWORD__` from your direct connection string.

You can also use the full connection string format:

```bash
pg_restore \
  -d "postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require" \
  -v \
  ./db_dump.bak \
&& echo "-complete-"
```

When the command completes, the data from your existing PostgreSQL database is in Prisma Postgres.

To validate that the import worked, you can use [Prisma Studio](https://www.prisma.io/docs/guides/postgres/viewing-data#viewing-and-editing-data-in-prisma-studio). Either open it in the [Platform Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=%28index%29) by clicking the **Studio** tab in the left-hand sidenav in your project or run this command to launch Prisma Studio locally:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

## 4. Update your application code to query Prisma Postgres [#4-update-your-application-code-to-query-prisma-postgres]

### Scenario A: You are already using Prisma ORM [#scenario-a-you-are-already-using-prisma-orm]

If you're already using Prisma ORM, you need to update your database connection URL to point to your new Prisma Postgres instance.

Update the `DATABASE_URL` in your `.env` file to match your Prisma Postgres direct connection string from step 1:

```text title=".env"
DATABASE_URL="postgres://USER:PASSWORD@db.prisma.io:5432/?sslmode=require"
```

Then, re-generate Prisma Client so that the updated environment variable takes effect:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

Once this is done, you can run your application and it should work as before.

> [!NOTE]
> For a complete guide on setting up Prisma ORM with Prisma Postgres from scratch, including driver adapter configuration and best practices, see the [Prisma ORM with Prisma Postgres quickstart](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres).

### Scenario B: You are not yet using Prisma ORM [#scenario-b-you-are-not-yet-using-prisma-orm]

If you are not yet using Prisma ORM, you'll need to go through the following steps to use Prisma Postgres from your application:

1. Install the Prisma CLI and other required dependencies in your project
2. Introspect the database to generate a Prisma schema
3. Generate Prisma Client
4. Update the queries in your application to use Prisma ORM

You can find the detailed step-by-step instructions for this process in this guide: [Add Prisma ORM to an existing project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/prisma-postgres).

## Related pages

- [`From the CLI`](https://www.prisma.io/docs/v7/prisma-postgres/from-the-cli): Start building a Prisma application with a Prisma Postgres database from the CLI
- [`Import from MySQL`](https://www.prisma.io/docs/v7/prisma-postgres/import-from-existing-database-mysql): Learn how to import data from an existing MySQL database into Prisma Postgres

# platform (Prisma CLI v7) (/docs/cli/v7/console)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma Data Platform commands

Location: CLI > v7 > platform

The `prisma platform` command group provides tools for interacting with the Prisma Data Platform.

## Usage [#usage]

```bash
prisma platform [command] [options]
```

## Options [#options]

| Option         | Description          |
| -------------- | -------------------- |
| `-h`, `--help` | Display help message |

## Subcommands [#subcommands]

| Command                                            | Description                              |
| -------------------------------------------------- | ---------------------------------------- |
| [`prisma platform status`](https://www.prisma.io/docs/cli/v7/console/status) | Show Prisma Data Platform service status |

## Examples [#examples]

```bash
# Check service status
prisma platform status

# Output status as JSON
prisma platform status --json
```

## See also [#see-also]

* [Console overview](https://www.prisma.io/docs/console)
* [Getting started with Console](https://www.prisma.io/docs/console/getting-started)

## Related pages

- [`db`](https://www.prisma.io/docs/cli/v7/db): Manage your database schema and lifecycle during development
- [`debug`](https://www.prisma.io/docs/cli/v7/debug): Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting
- [`dev`](https://www.prisma.io/docs/cli/v7/dev): Start a local Prisma Postgres server for development
- [`format`](https://www.prisma.io/docs/cli/v7/format): Format and validate your Prisma schema file with consistent structure
- [`generate`](https://www.prisma.io/docs/cli/v7/generate): Generate artifacts like Prisma Client based on your Prisma schema

# status (Prisma CLI v7) (/docs/cli/v7/console/status)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Show Prisma Data Platform service status

Location: CLI > v7 > Console > status

The `prisma platform status` command shows the current status of Prisma Data Platform services.

## Usage [#usage]

```bash
prisma platform status [options]
```

## Options [#options]

| Option         | Description                         |
| -------------- | ----------------------------------- |
| `-h`, `--help` | Display help message                |
| `--json`       | Output raw JSON from the status API |

## Examples [#examples]

### Check service status [#check-service-status]

  

#### bun

```bash
bunx prisma platform status
```

#### pnpm

```bash
pnpm prisma platform status
```

#### yarn

```bash
yarn prisma platform status
```

#### npm

```bash
npx prisma platform status
```

### Output status as JSON [#output-status-as-json]

  

#### bun

```bash
bunx prisma platform status --json
```

#### pnpm

```bash
pnpm prisma platform status --json
```

#### yarn

```bash
yarn prisma platform status --json
```

#### npm

```bash
npx prisma platform status --json
```

# execute (Prisma CLI v7) (/docs/cli/v7/db/execute)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Execute native commands to your database

Location: CLI > v7 > db > execute

The `prisma db execute` command applies a SQL script to the database without interacting with the Prisma migrations table.

> [!WARNING]
> This command is currently not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

## Usage [#usage]

```bash
prisma db execute [options]
```

The datasource URL configuration is read from the Prisma config file (e.g., `prisma.config.ts`).

The script input must be provided using either `--file` or `--stdin`. The whole script is sent as a single command to the database.

The output is connector-specific and reports success or failure only. It is not meant for returning data.

## Prerequisites [#prerequisites]

Configure your database connection in `prisma.config.ts`:

```prisma file=schema.prisma
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

```typescript file=prisma.config.ts
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

## Options [#options]

| Option         | Description                                     |
| -------------- | ----------------------------------------------- |
| `-h`, `--help` | Display help message                            |
| `--config`     | Custom path to your Prisma config file          |
| `--file`       | Path to a file containing the script to execute |

## Flags [#flags]

| Flag      | Description                                          |
| --------- | ---------------------------------------------------- |
| `--stdin` | Use terminal standard input as the script to execute |

Either `--file` or `--stdin` is required.

> [!NOTE]
> **Prisma v7 breaking change**: The `--schema` and `--url` options have been removed. Configure your database connection in `prisma.config.ts` instead.

## Examples [#examples]

### Execute a SQL file [#execute-a-sql-file]

  

#### bun

```bash
bunx prisma db execute --file ./script.sql
```

#### pnpm

```bash
pnpm prisma db execute --file ./script.sql
```

#### yarn

```bash
yarn prisma db execute --file ./script.sql
```

#### npm

```bash
npx prisma db execute --file ./script.sql
```

### Execute SQL from stdin [#execute-sql-from-stdin]

```bash
echo 'TRUNCATE TABLE dev;' | prisma db execute --stdin
```

## See also [#see-also]

* [Migration troubleshooting in production](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing#fixing-failed-migrations-with-migrate-diff-and-db-execute)

## Related pages

- [`pull`](https://www.prisma.io/docs/cli/v7/db/pull): Pull the state from the database to the Prisma schema using introspection
- [`push`](https://www.prisma.io/docs/cli/v7/db/push): Push the state from your Prisma schema to your database
- [`seed`](https://www.prisma.io/docs/cli/v7/db/seed): Seed your database with test or initial data using custom scripts

# db (Prisma CLI v7) (/docs/cli/v7/db)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Manage your database schema and lifecycle during development

Location: CLI > v7 > db

The `prisma db` command group provides tools to manage your database schema and lifecycle during development.

## Usage [#usage]

```bash
prisma db [command] [options]
```

## Global options [#global-options]

| Option         | Description                            |
| -------------- | -------------------------------------- |
| `-h`, `--help` | Display help message                   |
| `--config`     | Custom path to your Prisma config file |
| `--schema`     | Custom path to your Prisma schema      |

## Subcommands [#subcommands]

| Command                                   | Description                                                               |
| ----------------------------------------- | ------------------------------------------------------------------------- |
| [`prisma db pull`](https://www.prisma.io/docs/cli/v7/db/pull)       | Pull the state from the database to the Prisma schema using introspection |
| [`prisma db push`](https://www.prisma.io/docs/cli/v7/db/push)       | Push the state from Prisma schema to the database during prototyping      |
| [`prisma db seed`](https://www.prisma.io/docs/cli/v7/db/seed)       | Seed your database                                                        |
| [`prisma db execute`](https://www.prisma.io/docs/cli/v7/db/execute) | Execute native commands to your database                                  |

## Examples [#examples]

```bash
# Pull schema from database
prisma db pull

# Push schema to database
prisma db push

# Seed the database
prisma db seed

# Execute a SQL script
prisma db execute --file ./script.sql
```

## Related pages

- [`debug`](https://www.prisma.io/docs/cli/v7/debug): Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting
- [`dev`](https://www.prisma.io/docs/cli/v7/dev): Start a local Prisma Postgres server for development
- [`format`](https://www.prisma.io/docs/cli/v7/format): Format and validate your Prisma schema file with consistent structure
- [`generate`](https://www.prisma.io/docs/cli/v7/generate): Generate artifacts like Prisma Client based on your Prisma schema
- [`init`](https://www.prisma.io/docs/cli/v7/init): Set up a new Prisma project in the current directory

# pull (Prisma CLI v7) (/docs/cli/v7/db/pull)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Pull the state from the database to the Prisma schema using introspection

Location: CLI > v7 > db > pull

The `prisma db pull` command connects to your database and adds Prisma models to your Prisma schema that reflect the current database schema.

## Usage [#usage]

```bash
prisma db pull [options]
```

The datasource URL configuration is read from the Prisma config file (e.g., `prisma.config.ts`).

> [!WARNING]
> This command will overwrite the current `schema.prisma` file with the new schema. Back up your current schema or commit to version control before running `db pull` if it contains important modifications.

> [!NOTE]
> Introspection with `db pull` on the [MongoDB connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb) samples the data instead of reading a schema.

## Prerequisites [#prerequisites]

Configure your database connection in `prisma.config.ts`:

```prisma file=schema.prisma
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

```typescript file=prisma.config.ts
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

## Flags [#flags]

| Flag           | Description                                    |
| -------------- | ---------------------------------------------- |
| `-h`, `--help` | Display help message                           |
| `--force`      | Ignore current Prisma schema file              |
| `--print`      | Print the introspected Prisma schema to stdout |

## Options [#options]

| Option                   | Description                                                                                                                 |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| `--config`               | Custom path to your Prisma config file                                                                                      |
| `--schema`               | Custom path to your Prisma schema                                                                                           |
| `--url`                  | Override the datasource URL from the Prisma config file                                                                     |
| `--composite-type-depth` | Depth for introspecting composite types (e.g., MongoDB Embedded Documents). Default `-1` for infinite depth, `0` to disable |
| `--schemas`              | Specify database schemas to introspect (overrides datasource block)                                                         |
| `--local-d1`             | Generate a Prisma schema from a local Cloudflare D1 database                                                                |

## Examples [#examples]

### Introspect the database [#introspect-the-database]

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

Output:

```text
Introspecting based on datasource defined in schema.prisma …

✔ Introspected 2 models and wrote them into schema.prisma in 38ms

Run prisma generate to generate Prisma Client.
```

### Specify a schema path [#specify-a-schema-path]

  

#### bun

```bash
bunx prisma db pull --schema=./alternative/schema.prisma
```

#### pnpm

```bash
pnpm prisma db pull --schema=./alternative/schema.prisma
```

#### yarn

```bash
yarn prisma db pull --schema=./alternative/schema.prisma
```

#### npm

```bash
npx prisma db pull --schema=./alternative/schema.prisma
```

### Print to stdout instead of writing to file [#print-to-stdout-instead-of-writing-to-file]

  

#### bun

```bash
bunx prisma db pull --print
```

#### pnpm

```bash
pnpm prisma db pull --print
```

#### yarn

```bash
yarn prisma db pull --print
```

#### npm

```bash
npx prisma db pull --print
```

### Force overwrite existing schema [#force-overwrite-existing-schema]

Ignore any customizations in the current schema:

  

#### bun

```bash
bunx prisma db pull --force
```

#### pnpm

```bash
pnpm prisma db pull --force
```

#### yarn

```bash
yarn prisma db pull --force
```

#### npm

```bash
npx prisma db pull --force
```

### Set composite type depth for MongoDB [#set-composite-type-depth-for-mongodb]

  

#### bun

```bash
bunx prisma db pull --composite-type-depth=2
```

#### pnpm

```bash
pnpm prisma db pull --composite-type-depth=2
```

#### yarn

```bash
yarn prisma db pull --composite-type-depth=2
```

#### npm

```bash
npx prisma db pull --composite-type-depth=2
```

## Related pages

- [`execute`](https://www.prisma.io/docs/cli/v7/db/execute): Execute native commands to your database
- [`push`](https://www.prisma.io/docs/cli/v7/db/push): Push the state from your Prisma schema to your database
- [`seed`](https://www.prisma.io/docs/cli/v7/db/seed): Seed your database with test or initial data using custom scripts

# push (Prisma CLI v7) (/docs/cli/v7/db/push)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Push the state from your Prisma schema to your database

Location: CLI > v7 > db > push

The `prisma db push` command pushes the state of your Prisma schema to the database without using migrations. It creates the database if it does not exist.

This command is a good choice when you don't need to version schema changes, such as during prototyping and local development.

## Usage [#usage]

```bash
prisma db push [options]
```

The datasource URL configuration is read from the Prisma config file (e.g., `prisma.config.ts`).

## Prerequisites [#prerequisites]

Configure your database connection in `prisma.config.ts`:

```prisma file=schema.prisma
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

```typescript file=prisma.config.ts
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

## Options [#options]

| Option               | Description                                             |
| -------------------- | ------------------------------------------------------- |
| `-h`, `--help`       | Display help message                                    |
| `--config`           | Custom path to your Prisma config file                  |
| `--schema`           | Custom path to your Prisma schema                       |
| `--url`              | Override the datasource URL from the Prisma config file |
| `--accept-data-loss` | Ignore data loss warnings                               |
| `--force-reset`      | Force a reset of the database before push               |

> [!WARNING]
> In Prisma v7, `db push` no longer runs `prisma generate` automatically. Run it explicitly if needed.

## Examples [#examples]

### Push the schema to the database [#push-the-schema-to-the-database]

  

#### bun

```bash
bunx prisma db push
```

#### pnpm

```bash
pnpm prisma db push
```

#### yarn

```bash
yarn prisma db push
```

#### npm

```bash
npx prisma db push
```

### Accept data loss [#accept-data-loss]

Proceed even if the changes might result in data loss:

  

#### bun

```bash
bunx prisma db push --accept-data-loss
```

#### pnpm

```bash
pnpm prisma db push --accept-data-loss
```

#### yarn

```bash
yarn prisma db push --accept-data-loss
```

#### npm

```bash
npx prisma db push --accept-data-loss
```

### Specify a schema path [#specify-a-schema-path]

  

#### bun

```bash
bunx prisma db push --schema=/tmp/schema.prisma
```

#### pnpm

```bash
pnpm prisma db push --schema=/tmp/schema.prisma
```

#### yarn

```bash
yarn prisma db push --schema=/tmp/schema.prisma
```

#### npm

```bash
npx prisma db push --schema=/tmp/schema.prisma
```

### Force reset before push [#force-reset-before-push]

Reset the database before applying changes:

  

#### bun

```bash
bunx prisma db push --force-reset
```

#### pnpm

```bash
pnpm prisma db push --force-reset
```

#### yarn

```bash
yarn prisma db push --force-reset
```

#### npm

```bash
npx prisma db push --force-reset
```

## See also [#see-also]

* [Conceptual overview of `db push` and when to use it over Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema)
* [Schema prototyping with `db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema)

## Related pages

- [`execute`](https://www.prisma.io/docs/cli/v7/db/execute): Execute native commands to your database
- [`pull`](https://www.prisma.io/docs/cli/v7/db/pull): Pull the state from the database to the Prisma schema using introspection
- [`seed`](https://www.prisma.io/docs/cli/v7/db/seed): Seed your database with test or initial data using custom scripts

# seed (Prisma CLI v7) (/docs/cli/v7/db/seed)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Seed your database with test or initial data using custom scripts

Location: CLI > v7 > db > seed

The `prisma db seed` command seeds your database with initial data.

## Usage [#usage]

```bash
prisma db seed [options]
```

## Options [#options]

| Option         | Description                            |
| -------------- | -------------------------------------- |
| `-h`, `--help` | Display help message                   |
| `--config`     | Custom path to your Prisma config file |
| `--`           | Pass custom arguments to the seed file |

The `--` delimiter allows you to pass custom arguments to your seed script (available in version 4.15.0+).

## Examples [#examples]

### Run the seed script [#run-the-seed-script]

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

### Pass custom arguments [#pass-custom-arguments]

  

#### bun

```bash
bunx prisma db seed -- --arg1 value1 --arg2 value2
```

#### pnpm

```bash
pnpm prisma db seed -- --arg1 value1 --arg2 value2
```

#### yarn

```bash
yarn prisma db seed -- --arg1 value1 --arg2 value2
```

#### npm

```bash
npx prisma db seed -- --arg1 value1 --arg2 value2
```

## See also [#see-also]

* [Seeding your database](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/seeding)

## Related pages

- [`execute`](https://www.prisma.io/docs/cli/v7/db/execute): Execute native commands to your database
- [`pull`](https://www.prisma.io/docs/cli/v7/db/pull): Pull the state from the database to the Prisma schema using introspection
- [`push`](https://www.prisma.io/docs/cli/v7/db/push): Push the state from your Prisma schema to your database

# dev (Prisma CLI v7) (/docs/cli/v7/dev)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Start a local Prisma Postgres server for development

Location: CLI > v7 > dev

The `prisma dev` command starts a [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) database that you can run Prisma ORM commands against. Use it for development and testing, then point the same project at [Prisma Postgres](https://www.prisma.io/docs/postgres) for production.

## Usage [#usage]

```bash
prisma dev [options]
```

## Options [#options]

| Option             | Description                                               | Default   |
| ------------------ | --------------------------------------------------------- | --------- |
| `-n`, `--name`     | Name of the server (helps isolate state between projects) | `default` |
| `-p`, `--port`     | Main port number the Prisma Dev server will listen on     | `51213`   |
| `-P`, `--db-port`  | Port number the database server will listen on            | `51214`   |
| `--shadow-db-port` | Port number the shadow database server will listen on     | `51215`   |
| `-d`, `--detach`   | Run the server in the background                          | `false`   |
| `--debug`          | Enable debug logging                                      | `false`   |

## Subcommands [#subcommands]

| Command                                 | Description                       |
| --------------------------------------- | --------------------------------- |
| [`prisma dev ls`](https://www.prisma.io/docs/cli/v7/dev/ls)       | List available servers            |
| [`prisma dev rm`](https://www.prisma.io/docs/cli/v7/dev/rm)       | Remove servers                    |
| [`prisma dev start`](https://www.prisma.io/docs/cli/v7/dev/start) | Start one or more stopped servers |
| [`prisma dev stop`](https://www.prisma.io/docs/cli/v7/dev/stop)   | Stop servers                      |

## Examples [#examples]

### Start a local Prisma Postgres server [#start-a-local-prisma-postgres-server]

  

#### bun

```bash
bunx prisma dev
```

#### pnpm

```bash
pnpm prisma dev
```

#### yarn

```bash
yarn prisma dev
```

#### npm

```bash
npx prisma dev
```

Output:

```text
✔  Great Success!

   Your  prisma dev  server default is ready and listening on ports 63567-63569.

╭──────────────────────────────────╮
│[q]uit  [h]ttp url  [t]cp urls    │
╰──────────────────────────────────╯
```

### Start with a specific name [#start-with-a-specific-name]

Create a named instance for project isolation:

  

#### bun

```bash
bunx prisma dev --name="mydbname"
```

#### pnpm

```bash
pnpm prisma dev --name="mydbname"
```

#### yarn

```bash
yarn prisma dev --name="mydbname"
```

#### npm

```bash
npx prisma dev --name="mydbname"
```

### Run in detached mode [#run-in-detached-mode]

Run the server in the background:

  

#### bun

```bash
bunx prisma dev --detach
```

#### pnpm

```bash
pnpm prisma dev --detach
```

#### yarn

```bash
yarn prisma dev --detach
```

#### npm

```bash
npx prisma dev --detach
```

This frees up your terminal. Use `prisma dev ls` to see running servers and `prisma dev stop` to stop them.

### Specify custom ports [#specify-custom-ports]

  

#### bun

```bash
bunx prisma dev --port 5000 --db-port 5001 --shadow-db-port 5002
```

#### pnpm

```bash
pnpm prisma dev --port 5000 --db-port 5001 --shadow-db-port 5002
```

#### yarn

```bash
yarn prisma dev --port 5000 --db-port 5001 --shadow-db-port 5002
```

#### npm

```bash
npx prisma dev --port 5000 --db-port 5001 --shadow-db-port 5002
```

## Related pages

- [`db`](https://www.prisma.io/docs/cli/v7/db): Manage your database schema and lifecycle during development
- [`debug`](https://www.prisma.io/docs/cli/v7/debug): Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting
- [`format`](https://www.prisma.io/docs/cli/v7/format): Format and validate your Prisma schema file with consistent structure
- [`generate`](https://www.prisma.io/docs/cli/v7/generate): Generate artifacts like Prisma Client based on your Prisma schema
- [`init`](https://www.prisma.io/docs/cli/v7/init): Set up a new Prisma project in the current directory

# ls (Prisma CLI v7) (/docs/cli/v7/dev/ls)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

List available local Prisma Postgres servers

Location: CLI > v7 > dev > ls

The `prisma dev ls` command lists all available [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) instances on your system.

## Usage [#usage]

```bash
prisma dev ls [options]
```

## Options [#options]

| Option    | Description          | Default |
| --------- | -------------------- | ------- |
| `--debug` | Enable debug logging | `false` |

## Examples [#examples]

### List all servers [#list-all-servers]

  

#### bun

```bash
bunx prisma dev ls
```

#### pnpm

```bash
pnpm prisma dev ls
```

#### yarn

```bash
yarn prisma dev ls
```

#### npm

```bash
npx prisma dev ls
```

This shows all instances on your system with their current status and configuration.

## Related pages

- [`rm`](https://www.prisma.io/docs/cli/v7/dev/rm): Remove local Prisma Postgres servers
- [`start`](https://www.prisma.io/docs/cli/v7/dev/start): Start one or more stopped local Prisma Postgres servers
- [`stop`](https://www.prisma.io/docs/cli/v7/dev/stop): Stop local Prisma Postgres servers

# rm (Prisma CLI v7) (/docs/cli/v7/dev/rm)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Remove local Prisma Postgres servers

Location: CLI > v7 > dev > rm

The `prisma dev rm` command removes the data of one or more [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) databases from your file system.

## Usage [#usage]

```bash
prisma dev rm [options] <name>
```

## Arguments [#arguments]

| Argument | Description                                           |
| -------- | ----------------------------------------------------- |
| `<name>` | Name(s) or glob pattern(s) of the server(s) to remove |

## Options [#options]

| Option    | Description                                   | Default |
| --------- | --------------------------------------------- | ------- |
| `--debug` | Enable debug logging                          | `false` |
| `--force` | Stop any running servers before removing them | `false` |

Without `--force`, the command fails if any server is running.

## Examples [#examples]

### Remove a specific database [#remove-a-specific-database]

  

#### bun

```bash
bunx prisma dev rm mydb
```

#### pnpm

```bash
pnpm prisma dev rm mydb
```

#### yarn

```bash
yarn prisma dev rm mydb
```

#### npm

```bash
npx prisma dev rm mydb
```

### Remove multiple databases with a pattern [#remove-multiple-databases-with-a-pattern]

Remove all databases starting with `mydb`:

  

#### bun

```bash
bunx prisma dev rm mydb*
```

#### pnpm

```bash
pnpm prisma dev rm mydb*
```

#### yarn

```bash
yarn prisma dev rm mydb*
```

#### npm

```bash
npx prisma dev rm mydb*
```

### Force remove a running database [#force-remove-a-running-database]

Stop and remove a database in one command:

  

#### bun

```bash
bunx prisma dev rm --force mydb
```

#### pnpm

```bash
pnpm prisma dev rm --force mydb
```

#### yarn

```bash
yarn prisma dev rm --force mydb
```

#### npm

```bash
npx prisma dev rm --force mydb
```

> [!NOTE]
> The `rm` command is interactive and includes safety prompts to prevent accidental data loss.

## Related pages

- [`ls`](https://www.prisma.io/docs/cli/v7/dev/ls): List available local Prisma Postgres servers
- [`start`](https://www.prisma.io/docs/cli/v7/dev/start): Start one or more stopped local Prisma Postgres servers
- [`stop`](https://www.prisma.io/docs/cli/v7/dev/stop): Stop local Prisma Postgres servers

# start (Prisma CLI v7) (/docs/cli/v7/dev/start)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Start one or more stopped local Prisma Postgres servers

Location: CLI > v7 > dev > start

The `prisma dev start` command starts existing [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) instances in the background.

## Usage [#usage]

```bash
prisma dev start [options] <name>
```

## Arguments [#arguments]

| Argument | Description                                          |
| -------- | ---------------------------------------------------- |
| `<name>` | Name(s) or glob pattern(s) of the server(s) to start |

## Options [#options]

| Option    | Description          | Default |
| --------- | -------------------- | ------- |
| `--debug` | Enable debug logging | `false` |

> [!NOTE]
> This command only works with instances that already exist. Use `prisma dev` to create a new instance.

## Examples [#examples]

### Start a specific database [#start-a-specific-database]

  

#### bun

```bash
bunx prisma dev start mydb
```

#### pnpm

```bash
pnpm prisma dev start mydb
```

#### yarn

```bash
yarn prisma dev start mydb
```

#### npm

```bash
npx prisma dev start mydb
```

### Start multiple databases with a pattern [#start-multiple-databases-with-a-pattern]

Start all databases starting with `mydb`:

  

#### bun

```bash
bunx prisma dev start mydb*
```

#### pnpm

```bash
pnpm prisma dev start mydb*
```

#### yarn

```bash
yarn prisma dev start mydb*
```

#### npm

```bash
npx prisma dev start mydb*
```

## Related pages

- [`ls`](https://www.prisma.io/docs/cli/v7/dev/ls): List available local Prisma Postgres servers
- [`rm`](https://www.prisma.io/docs/cli/v7/dev/rm): Remove local Prisma Postgres servers
- [`stop`](https://www.prisma.io/docs/cli/v7/dev/stop): Stop local Prisma Postgres servers

# stop (Prisma CLI v7) (/docs/cli/v7/dev/stop)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Stop local Prisma Postgres servers

Location: CLI > v7 > dev > stop

The `prisma dev stop` command stops one or more [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) databases.

## Usage [#usage]

```bash
prisma dev stop [options] <name>
```

## Arguments [#arguments]

| Argument | Description                                         |
| -------- | --------------------------------------------------- |
| `<name>` | Name(s) or glob pattern(s) of the server(s) to stop |

## Options [#options]

| Option    | Description          | Default |
| --------- | -------------------- | ------- |
| `--debug` | Enable debug logging | `false` |

## Examples [#examples]

### Stop a specific database [#stop-a-specific-database]

  

#### bun

```bash
bunx prisma dev stop mydb
```

#### pnpm

```bash
pnpm prisma dev stop mydb
```

#### yarn

```bash
yarn prisma dev stop mydb
```

#### npm

```bash
npx prisma dev stop mydb
```

### Stop multiple databases with a pattern [#stop-multiple-databases-with-a-pattern]

Stop all databases starting with `mydb`:

  

#### bun

```bash
bunx prisma dev stop mydb*
```

#### pnpm

```bash
pnpm prisma dev stop mydb*
```

#### yarn

```bash
yarn prisma dev stop mydb*
```

#### npm

```bash
npx prisma dev stop mydb*
```

> [!NOTE]
> The `stop` command is interactive and includes safety prompts to prevent accidental operations.

## Related pages

- [`ls`](https://www.prisma.io/docs/cli/v7/dev/ls): List available local Prisma Postgres servers
- [`rm`](https://www.prisma.io/docs/cli/v7/dev/rm): Remove local Prisma Postgres servers
- [`start`](https://www.prisma.io/docs/cli/v7/dev/start): Start one or more stopped local Prisma Postgres servers

# deploy (Prisma CLI v7) (/docs/cli/v7/migrate/deploy)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Apply pending migrations to update the database schema in production/staging

Location: CLI > v7 > migrate > deploy

The `prisma migrate deploy` command applies all pending migrations and creates the database if it doesn't exist. Primarily used in non-development environments.

> [!WARNING]
> This command is not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). Use [`db push`](https://www.prisma.io/docs/cli/v7/db/push) instead.

## Usage [#usage]

```bash
prisma migrate deploy [options]
```

The datasource URL configuration is read from the Prisma config file (e.g., `prisma.config.ts`).

## Characteristics [#characteristics]

* Does **not** look for drift in the database or changes in the Prisma schema
* Does **not** reset the database or generate artifacts
* Does **not** rely on a shadow database

## Options [#options]

| Option         | Description                            |
| -------------- | -------------------------------------- |
| `-h`, `--help` | Display help message                   |
| `--config`     | Custom path to your Prisma config file |
| `--schema`     | Custom path to your Prisma schema      |

## Examples [#examples]

### Deploy pending migrations [#deploy-pending-migrations]

  

#### bun

```bash
bunx prisma migrate deploy
```

#### pnpm

```bash
pnpm prisma migrate deploy
```

#### yarn

```bash
yarn prisma migrate deploy
```

#### npm

```bash
npx prisma migrate deploy
```

### Specify a schema path [#specify-a-schema-path]

  

#### bun

```bash
bunx prisma migrate deploy --schema=./alternative/schema.prisma
```

#### pnpm

```bash
pnpm prisma migrate deploy --schema=./alternative/schema.prisma
```

#### yarn

```bash
yarn prisma migrate deploy --schema=./alternative/schema.prisma
```

#### npm

```bash
npx prisma migrate deploy --schema=./alternative/schema.prisma
```

## Related pages

- [`dev`](https://www.prisma.io/docs/cli/v7/migrate/dev): Create a migration from changes in Prisma schema, apply it to the database, and trigger generators
- [`diff`](https://www.prisma.io/docs/cli/v7/migrate/diff): Compare the database schema from two arbitrary sources
- [`reset`](https://www.prisma.io/docs/cli/v7/migrate/reset): Reset your database and apply all migrations. All data will be lost
- [`resolve`](https://www.prisma.io/docs/cli/v7/migrate/resolve): Resolve issues with database migrations in deployment databases
- [`status`](https://www.prisma.io/docs/cli/v7/migrate/status): Check the status of your database migrations

# dev (Prisma CLI v7) (/docs/cli/v7/migrate/dev)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a migration from changes in Prisma schema, apply it to the database, and trigger generators

Location: CLI > v7 > migrate > dev

The `prisma migrate dev` command creates and applies migrations during development. It requires a [shadow database](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database).

**For use in development environments only.**

> [!WARNING]
> This command is not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). Use [`db push`](https://www.prisma.io/docs/cli/v7/db/push) instead.

## Usage [#usage]

```bash
prisma migrate dev [options]
```

The datasource URL configuration is read from the Prisma config file (e.g., `prisma.config.ts`).

## How it works [#how-it-works]

1. Reruns the existing migration history in the shadow database to detect schema drift
2. Applies pending migrations to the shadow database
3. Generates a new migration from any changes you made to the Prisma schema
4. Applies all unapplied migrations to the development database and updates the `_prisma_migrations` table

> [!NOTE]
> **Prisma v7**: `migrate dev` no longer automatically triggers `prisma generate` or seed scripts. Run them explicitly if needed.

## Options [#options]

| Option          | Description                                             |
| --------------- | ------------------------------------------------------- |
| `-h`, `--help`  | Display help message                                    |
| `--config`      | Custom path to your Prisma config file                  |
| `--schema`      | Custom path to your Prisma schema                       |
| `--url`         | Override the datasource URL from the Prisma config file |
| `-n`, `--name`  | Name the migration                                      |
| `--create-only` | Create a new migration but do not apply it              |

> [!NOTE]
> If a [schema drift](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database#detecting-schema-drift) is detected while running with `--create-only`, you will be prompted to reset your database.

## Examples [#examples]

### Create and apply migrations [#create-and-apply-migrations]

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

### Name the migration [#name-the-migration]

  

#### bun

```bash
bunx prisma migrate dev --name added_job_title
```

#### pnpm

```bash
pnpm prisma migrate dev --name added_job_title
```

#### yarn

```bash
yarn prisma migrate dev --name added_job_title
```

#### npm

```bash
npx prisma migrate dev --name added_job_title
```

### Create migration without applying [#create-migration-without-applying]

  

#### bun

```bash
bunx prisma migrate dev --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --create-only
```

#### yarn

```bash
yarn prisma migrate dev --create-only
```

#### npm

```bash
npx prisma migrate dev --create-only
```

This creates the migration file but doesn't apply it. Run `prisma migrate dev` again to apply.

### Specify a schema path [#specify-a-schema-path]

  

#### bun

```bash
bunx prisma migrate dev --schema=./alternative/schema.prisma
```

#### pnpm

```bash
pnpm prisma migrate dev --schema=./alternative/schema.prisma
```

#### yarn

```bash
yarn prisma migrate dev --schema=./alternative/schema.prisma
```

#### npm

```bash
npx prisma migrate dev --schema=./alternative/schema.prisma
```

## See also [#see-also]

* [Conceptual overview of Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)
* [Developing with Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)

## Related pages

- [`deploy`](https://www.prisma.io/docs/cli/v7/migrate/deploy): Apply pending migrations to update the database schema in production/staging
- [`diff`](https://www.prisma.io/docs/cli/v7/migrate/diff): Compare the database schema from two arbitrary sources
- [`reset`](https://www.prisma.io/docs/cli/v7/migrate/reset): Reset your database and apply all migrations. All data will be lost
- [`resolve`](https://www.prisma.io/docs/cli/v7/migrate/resolve): Resolve issues with database migrations in deployment databases
- [`status`](https://www.prisma.io/docs/cli/v7/migrate/status): Check the status of your database migrations

# diff (Prisma CLI v7) (/docs/cli/v7/migrate/diff)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Compare the database schema from two arbitrary sources

Location: CLI > v7 > migrate > diff

The `prisma migrate diff` command compares two database schema sources and outputs a description of the migration needed to transform the first into the second.

> [!NOTE]
> This command is only partially supported for [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). See options below for details.

## Usage [#usage]

```bash
prisma migrate diff --from-... <source1> --to-... <source2>
```

The output can be a human-readable summary (default) or an executable script.

> [!WARNING]
> The `migrate diff` command can only compare database features [supported by Prisma](https://www.prisma.io/docs/orm/v7/reference/database-features). Differences in unsupported features (views, triggers, etc.) won't be shown.

## Prerequisites [#prerequisites]

If using `--from-config-datasource` or `--to-config-datasource`, configure your database connection in `prisma.config.ts`:

```prisma file=schema.prisma
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

```typescript file=prisma.config.ts
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

## Source types [#source-types]

Both sources must use the same database provider.

### From options (one required) [#from-options-one-required]

| Option                     | Description                              | Notes                    |
| -------------------------- | ---------------------------------------- | ------------------------ |
| `--from-empty`             | Assume the source is an empty data model |                          |
| `--from-schema`            | Path to a Prisma schema file             |                          |
| `--from-migrations`        | Path to Prisma migrations directory      | Not supported in MongoDB |
| `--from-config-datasource` | Use datasource from Prisma config file   | Prisma v7+               |

### To options (one required) [#to-options-one-required]

| Option                   | Description                                   | Notes                    |
| ------------------------ | --------------------------------------------- | ------------------------ |
| `--to-empty`             | Assume the destination is an empty data model |                          |
| `--to-schema`            | Path to a Prisma schema file                  |                          |
| `--to-migrations`        | Path to Prisma migrations directory           | Not supported in MongoDB |
| `--to-config-datasource` | Use datasource from Prisma config file        | Prisma v7+               |

### Other options [#other-options]

| Option           | Description                                              | Notes                       |
| ---------------- | -------------------------------------------------------- | --------------------------- |
| `--config`       | Custom path to your Prisma config file                   |                             |
| `--script`       | Output a SQL script instead of human-readable summary    | Not supported in MongoDB    |
| `-o`, `--output` | Write to a file instead of stdout                        | Available since 5.12.1      |
| `--exit-code`    | Change exit code behavior: Empty=0, Error=1, Not empty=2 | Default: Success=0, Error=1 |
| `--help`         | Display help message                                     |                             |

> [!NOTE]
> **Prisma v7 breaking change**: The `--from-url`, `--to-url`, `--from-schema-datasource`, `--to-schema-datasource`, and `--shadow-database-url` options have been removed. Use `--from-config-datasource` and `--to-config-datasource` instead.

## Examples [#examples]

### Compare database to schema [#compare-database-to-schema]

Roll forward after a migration failed:

  

#### bun

```bash
bunx prisma migrate diff \
  --from-config-datasource \
  --to-schema=next_datamodel.prisma \
  --script
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --from-config-datasource \
  --to-schema=next_datamodel.prisma \
  --script
```

#### yarn

```bash
yarn prisma migrate diff \
  --from-config-datasource \
  --to-schema=next_datamodel.prisma \
  --script
```

#### npm

```bash
npx prisma migrate diff \
  --from-config-datasource \
  --to-schema=next_datamodel.prisma \
  --script
```

### Compare schema to database [#compare-schema-to-database]

  

#### bun

```bash
bunx prisma migrate diff \
  --from-schema=schema.prisma \
  --to-config-datasource \
  --script
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --from-schema=schema.prisma \
  --to-config-datasource \
  --script
```

#### yarn

```bash
yarn prisma migrate diff \
  --from-schema=schema.prisma \
  --to-config-datasource \
  --script
```

#### npm

```bash
npx prisma migrate diff \
  --from-schema=schema.prisma \
  --to-config-datasource \
  --script
```

### Compare migrations to database [#compare-migrations-to-database]

Generate a migration for a hotfix already applied on production:

  

#### bun

```bash
bunx prisma migrate diff \
  --from-migrations ./migrations \
  --to-config-datasource \
  --script
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --from-migrations ./migrations \
  --to-config-datasource \
  --script
```

#### yarn

```bash
yarn prisma migrate diff \
  --from-migrations ./migrations \
  --to-config-datasource \
  --script
```

#### npm

```bash
npx prisma migrate diff \
  --from-migrations ./migrations \
  --to-config-datasource \
  --script
```

### Pipe output to db execute [#pipe-output-to-db-execute]

  

#### bun

```bash
bunx prisma migrate diff \
  --from-config-datasource \
  --to-schema=schema.prisma \
  --script | prisma db execute --stdin
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --from-config-datasource \
  --to-schema=schema.prisma \
  --script | prisma db execute --stdin
```

#### yarn

```bash
yarn prisma migrate diff \
  --from-config-datasource \
  --to-schema=schema.prisma \
  --script | prisma db execute --stdin
```

#### npm

```bash
npx prisma migrate diff \
  --from-config-datasource \
  --to-schema=schema.prisma \
  --script | prisma db execute --stdin
```

### Check if sources are in sync [#check-if-sources-are-in-sync]

Exits with code 2 if changes are detected:

  

#### bun

```bash
bunx prisma migrate diff \
  --exit-code \
  --from-config-datasource \
  --to-schema=schema.prisma
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --exit-code \
  --from-config-datasource \
  --to-schema=schema.prisma
```

#### yarn

```bash
yarn prisma migrate diff \
  --exit-code \
  --from-config-datasource \
  --to-schema=schema.prisma
```

#### npm

```bash
npx prisma migrate diff \
  --exit-code \
  --from-config-datasource \
  --to-schema=schema.prisma
```

## See also [#see-also]

* [Migration troubleshooting in production](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing#fixing-failed-migrations-with-migrate-diff-and-db-execute)

## Related pages

- [`deploy`](https://www.prisma.io/docs/cli/v7/migrate/deploy): Apply pending migrations to update the database schema in production/staging
- [`dev`](https://www.prisma.io/docs/cli/v7/migrate/dev): Create a migration from changes in Prisma schema, apply it to the database, and trigger generators
- [`reset`](https://www.prisma.io/docs/cli/v7/migrate/reset): Reset your database and apply all migrations. All data will be lost
- [`resolve`](https://www.prisma.io/docs/cli/v7/migrate/resolve): Resolve issues with database migrations in deployment databases
- [`status`](https://www.prisma.io/docs/cli/v7/migrate/status): Check the status of your database migrations

# migrate (Prisma CLI v7) (/docs/cli/v7/migrate)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Update your database schema with migrations

Location: CLI > v7 > migrate

The `prisma migrate` command group provides tools to create and apply database migrations.

> [!NOTE]
> Prisma Migrate does not apply to MongoDB. Use [`db push`](https://www.prisma.io/docs/cli/v7/db/push) instead.

## Usage [#usage]

```bash
prisma migrate [command] [options]
```

## Global options [#global-options]

| Option         | Description                            |
| -------------- | -------------------------------------- |
| `-h`, `--help` | Display help message                   |
| `--config`     | Custom path to your Prisma config file |
| `--schema`     | Custom path to your Prisma schema      |

## Development commands [#development-commands]

| Command                                         | Description                                                              |
| ----------------------------------------------- | ------------------------------------------------------------------------ |
| [`prisma migrate dev`](https://www.prisma.io/docs/cli/v7/migrate/dev)     | Create a migration from schema changes, apply it, and trigger generators |
| [`prisma migrate reset`](https://www.prisma.io/docs/cli/v7/migrate/reset) | Reset your database and apply all migrations (all data will be lost)     |

## Production/staging commands [#productionstaging-commands]

| Command                                             | Description                                                                  |
| --------------------------------------------------- | ---------------------------------------------------------------------------- |
| [`prisma migrate deploy`](https://www.prisma.io/docs/cli/v7/migrate/deploy)   | Apply pending migrations to the database                                     |
| [`prisma migrate status`](https://www.prisma.io/docs/cli/v7/migrate/status)   | Check the status of your database migrations                                 |
| [`prisma migrate resolve`](https://www.prisma.io/docs/cli/v7/migrate/resolve) | Resolve issues with database migrations (baseline, failed migration, hotfix) |

## Commands for any stage [#commands-for-any-stage]

| Command                                       | Description                                            |
| --------------------------------------------- | ------------------------------------------------------ |
| [`prisma migrate diff`](https://www.prisma.io/docs/cli/v7/migrate/diff) | Compare the database schema from two arbitrary sources |

## Examples [#examples]

```bash
# Create and apply a migration in development
prisma migrate dev

# Reset the database (development only)
prisma migrate reset

# Apply pending migrations in production
prisma migrate deploy

# Check migration status
prisma migrate status

# Compare database schemas
prisma migrate diff \
  --from-config-datasource \
  --to-schema=./prisma/schema.prisma \
  --script
```

## See also [#see-also]

* [Conceptual overview of Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)
* [Developing with Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)

## Related pages

- [`db`](https://www.prisma.io/docs/cli/v7/db): Manage your database schema and lifecycle during development
- [`debug`](https://www.prisma.io/docs/cli/v7/debug): Display Prisma debug information including schema paths, engine binaries, environment variables, and cache directories for troubleshooting
- [`dev`](https://www.prisma.io/docs/cli/v7/dev): Start a local Prisma Postgres server for development
- [`format`](https://www.prisma.io/docs/cli/v7/format): Format and validate your Prisma schema file with consistent structure
- [`generate`](https://www.prisma.io/docs/cli/v7/generate): Generate artifacts like Prisma Client based on your Prisma schema

# reset (Prisma CLI v7) (/docs/cli/v7/migrate/reset)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Reset your database and apply all migrations. All data will be lost

Location: CLI > v7 > migrate > reset

The `prisma migrate reset` command resets your database and re-applies all migrations.

**For use in development environments only.**

> [!WARNING]
> This command is not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). Use [`db push`](https://www.prisma.io/docs/cli/v7/db/push) instead.

## Usage [#usage]

```bash
prisma migrate reset [options]
```

The datasource URL configuration is read from the Prisma config file (e.g., `prisma.config.ts`).

## How it works [#how-it-works]

1. Drops the database/schema if possible, or performs a soft reset if the environment doesn't allow it
2. Creates a new database/schema with the same name
3. Applies all migrations

> [!NOTE]
> **Prisma v7**: `migrate reset` no longer automatically runs seed scripts. Run `npx prisma db seed` explicitly if needed.

## Options [#options]

| Option          | Description                            |
| --------------- | -------------------------------------- |
| `-h`, `--help`  | Display help message                   |
| `--config`      | Custom path to your Prisma config file |
| `--schema`      | Custom path to your Prisma schema      |
| `-f`, `--force` | Skip the confirmation prompt           |

## Examples [#examples]

### Reset the database [#reset-the-database]

  

#### bun

```bash
bunx prisma migrate reset
```

#### pnpm

```bash
pnpm prisma migrate reset
```

#### yarn

```bash
yarn prisma migrate reset
```

#### npm

```bash
npx prisma migrate reset
```

### Skip confirmation prompt [#skip-confirmation-prompt]

  

#### bun

```bash
bunx prisma migrate reset --force
```

#### pnpm

```bash
pnpm prisma migrate reset --force
```

#### yarn

```bash
yarn prisma migrate reset --force
```

#### npm

```bash
npx prisma migrate reset --force
```

### Specify a schema path [#specify-a-schema-path]

  

#### bun

```bash
bunx prisma migrate reset --schema=./alternative/schema.prisma
```

#### pnpm

```bash
pnpm prisma migrate reset --schema=./alternative/schema.prisma
```

#### yarn

```bash
yarn prisma migrate reset --schema=./alternative/schema.prisma
```

#### npm

```bash
npx prisma migrate reset --schema=./alternative/schema.prisma
```

## AI safety guardrails [#ai-safety-guardrails]

Prisma ORM includes built-in safety checks to prevent accidental destructive commands when run through AI coding assistants.

When AI agents like Claude Code, Cursor, Gemini CLI, or others attempt `prisma migrate reset --force`, Prisma blocks execution and shows a protective error message.

To proceed, you must provide explicit consent. The AI agent will:

1. Explain what action it's attempting
2. Warn that this action irreversibly destroys all data
3. Confirm whether this is a development or production database
4. Ask for your explicit consent before proceeding

After consent, the AI sets the `PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION` environment variable and reruns the command.

## Related pages

- [`deploy`](https://www.prisma.io/docs/cli/v7/migrate/deploy): Apply pending migrations to update the database schema in production/staging
- [`dev`](https://www.prisma.io/docs/cli/v7/migrate/dev): Create a migration from changes in Prisma schema, apply it to the database, and trigger generators
- [`diff`](https://www.prisma.io/docs/cli/v7/migrate/diff): Compare the database schema from two arbitrary sources
- [`resolve`](https://www.prisma.io/docs/cli/v7/migrate/resolve): Resolve issues with database migrations in deployment databases
- [`status`](https://www.prisma.io/docs/cli/v7/migrate/status): Check the status of your database migrations

# resolve (Prisma CLI v7) (/docs/cli/v7/migrate/resolve)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Resolve issues with database migrations in deployment databases

Location: CLI > v7 > migrate > resolve

The `prisma migrate resolve` command allows you to solve migration history issues in production by marking a failed migration as already applied (supports baselining) or rolled back.

> [!WARNING]
> This command is not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). Use [`db push`](https://www.prisma.io/docs/cli/v7/db/push) instead.

## Usage [#usage]

```bash
prisma migrate resolve [options]
```

The datasource URL configuration is read from the Prisma config file (e.g., `prisma.config.ts`).

> [!NOTE]
> This command can only be used with a failed migration. Using it with a successful migration results in an error.

## Use cases [#use-cases]

* Recover from failed migrations
* Baseline databases when starting to use Prisma Migrate on existing databases
* Reconcile hotfixes done manually on databases with your migration history

Run `prisma migrate status` to identify if you need to use `resolve`.

## Options [#options]

| Option          | Description                                |
| --------------- | ------------------------------------------ |
| `-h`, `--help`  | Display help message                       |
| `--config`      | Custom path to your Prisma config file     |
| `--schema`      | Custom path to your Prisma schema          |
| `--applied`     | Record a specific migration as applied     |
| `--rolled-back` | Record a specific migration as rolled back |

You must specify either `--applied` or `--rolled-back`.

## Examples [#examples]

### Mark a migration as applied [#mark-a-migration-as-applied]

  

#### bun

```bash
bunx prisma migrate resolve --applied 20201231000000_add_users_table
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied 20201231000000_add_users_table
```

#### yarn

```bash
yarn prisma migrate resolve --applied 20201231000000_add_users_table
```

#### npm

```bash
npx prisma migrate resolve --applied 20201231000000_add_users_table
```

### Mark a migration as rolled back [#mark-a-migration-as-rolled-back]

  

#### bun

```bash
bunx prisma migrate resolve --rolled-back 20201231000000_add_users_table
```

#### pnpm

```bash
pnpm prisma migrate resolve --rolled-back 20201231000000_add_users_table
```

#### yarn

```bash
yarn prisma migrate resolve --rolled-back 20201231000000_add_users_table
```

#### npm

```bash
npx prisma migrate resolve --rolled-back 20201231000000_add_users_table
```

### Specify a schema path [#specify-a-schema-path]

  

#### bun

```bash
bunx prisma migrate resolve --rolled-back 20201231000000_add_users_table --schema=./schema.prisma
```

#### pnpm

```bash
pnpm prisma migrate resolve --rolled-back 20201231000000_add_users_table --schema=./schema.prisma
```

#### yarn

```bash
yarn prisma migrate resolve --rolled-back 20201231000000_add_users_table --schema=./schema.prisma
```

#### npm

```bash
npx prisma migrate resolve --rolled-back 20201231000000_add_users_table --schema=./schema.prisma
```

## See also [#see-also]

* [Resolving migration history issues](https://pris.ly/d/migrate-resolve)

## Related pages

- [`deploy`](https://www.prisma.io/docs/cli/v7/migrate/deploy): Apply pending migrations to update the database schema in production/staging
- [`dev`](https://www.prisma.io/docs/cli/v7/migrate/dev): Create a migration from changes in Prisma schema, apply it to the database, and trigger generators
- [`diff`](https://www.prisma.io/docs/cli/v7/migrate/diff): Compare the database schema from two arbitrary sources
- [`reset`](https://www.prisma.io/docs/cli/v7/migrate/reset): Reset your database and apply all migrations. All data will be lost
- [`status`](https://www.prisma.io/docs/cli/v7/migrate/status): Check the status of your database migrations

# status (Prisma CLI v7) (/docs/cli/v7/migrate/status)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Check the status of your database migrations

Location: CLI > v7 > migrate > status

The `prisma migrate status` command checks the migrations in `./prisma/migrations/*` and the entries in the `_prisma_migrations` table to report the state of your migrations.

> [!WARNING]
> This command is not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). Use [`db push`](https://www.prisma.io/docs/cli/v7/db/push) instead.

## Usage [#usage]

```bash
prisma migrate status [options]
```

The datasource URL configuration is read from the Prisma config file (e.g., `prisma.config.ts`).

## Options [#options]

| Option         | Description                            |
| -------------- | -------------------------------------- |
| `-h`, `--help` | Display help message                   |
| `--config`     | Custom path to your Prisma config file |
| `--schema`     | Custom path to your Prisma schema      |

## Exit codes [#exit-codes]

In versions 4.3.0 and later, `prisma migrate status` exits with code 1 when:

* A database connection error occurs
* Migration files haven't been applied to the database
* Migration history has diverged from the database state
* No migration table is found
* Failed migrations are found

## Example output [#example-output]

```text
Status
3 migrations found in prisma/migrations

Your local migration history and the migrations table from your database are different:

The last common migration is: 20201127134938_new_migration

The migration have not yet been applied:
20201208100950_test_migration

The migrations from the database are not found locally in prisma/migrations:
20201208100950_new_migration
```

## Examples [#examples]

### Check migration status [#check-migration-status]

  

#### bun

```bash
bunx prisma migrate status
```

#### pnpm

```bash
pnpm prisma migrate status
```

#### yarn

```bash
yarn prisma migrate status
```

#### npm

```bash
npx prisma migrate status
```

### Specify a schema path [#specify-a-schema-path]

  

#### bun

```bash
bunx prisma migrate status --schema=./alternative/schema.prisma
```

#### pnpm

```bash
pnpm prisma migrate status --schema=./alternative/schema.prisma
```

#### yarn

```bash
yarn prisma migrate status --schema=./alternative/schema.prisma
```

#### npm

```bash
npx prisma migrate status --schema=./alternative/schema.prisma
```

## Related pages

- [`deploy`](https://www.prisma.io/docs/cli/v7/migrate/deploy): Apply pending migrations to update the database schema in production/staging
- [`dev`](https://www.prisma.io/docs/cli/v7/migrate/dev): Create a migration from changes in Prisma schema, apply it to the database, and trigger generators
- [`diff`](https://www.prisma.io/docs/cli/v7/migrate/diff): Compare the database schema from two arbitrary sources
- [`reset`](https://www.prisma.io/docs/cli/v7/migrate/reset): Reset your database and apply all migrations. All data will be lost
- [`resolve`](https://www.prisma.io/docs/cli/v7/migrate/resolve): Resolve issues with database migrations in deployment databases

# Auth.js (with Next.js) (/docs/guides/authentication/authjs/nextjs)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a Next.js app with Auth.js

Location: Guides > Authentication > Authjs > Auth.js (with Next.js)

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is not available yet: `@auth/prisma-adapter` requires Prisma Client, which Prisma ORM 8 replaces with the `@prisma/orm-postgres` runtime.

## Introduction [#introduction]

[Auth.js](https://authjs.dev/) is a flexible, open-source authentication library designed to simplify adding authentication to your Next.js applications.

In this guide, you'll wire Auth.js into a brand-new [Next.js](https://nextjs.org/) app and persist users in a [Prisma Postgres](https://prisma.io/postgres) database. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/authjs-nextjs).

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* Basic familiarity with Next.js App Router and Prisma

## 1. Set up your project [#1-set-up-your-project]

Create a new Next.js application:

  

#### bun

```bash
bunx create-next-app@latest authjs-prisma
```

#### pnpm

```bash
pnpm dlx create-next-app@latest authjs-prisma
```

#### yarn

```bash
yarn dlx create-next-app@latest authjs-prisma
```

#### npm

```bash
npx create-next-app@latest authjs-prisma
```

It will prompt you to customize your setup. Choose the defaults:

> [!NOTE]
> * *Would you like to use TypeScript?* `Yes`
> * *Would you like to use ESLint?* `Yes`
> * *Would you like to use Tailwind CSS?* `Yes`
> * *Would you like your code inside a `src/` directory?* `No`
> * *Would you like to use App Router?* (recommended) `Yes`
> * *Would you like to use Turbopack for `next dev`?* `Yes`
> * _Would you like to customize the import alias (`@/_`by default)?\*`No`

Navigate to the project directory:

```bash
cd authjs-prisma
```

## 2. Install and configure Prisma [#2-install-and-configure-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../app/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../app/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../app/generated/prisma
```

#### npm

```bash
npx prisma init --output ../app/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma` directory with a `schema.prisma` file.
* A `prisma.config.ts` file for configuring Prisma
* A `.env` file containing a local `DATABASE_URL` at the project root.
* A schema configuration that specifies where the Prisma Client will be generated (`../app/generated/prisma`).

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define your Prisma Schema [#22-define-your-prisma-schema]

In the `prisma/schema.prisma` file, swap the provider to `prisma-client` and add the runtime `vercel-edge` to the generator:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
  runtime  = "vercel-edge" // [!code ++]
}

datasource db {
  provider = "postgresql"
}
```

Add the following models to the `schema.prisma` file, these models are provided by Auth.js:

```prisma title="prisma/schema.prisma"
model Account { // [!code ++]
  id                String  @id @default(cuid()) // [!code ++]
  userId            String  @map("user_id") // [!code ++]
  type              String // [!code ++]
  provider          String // [!code ++]
  providerAccountId String  @map("provider_account_id") // [!code ++]
  refresh_token     String? @db.Text // [!code ++]
  access_token      String? @db.Text // [!code ++]
  expires_at        Int? // [!code ++]
  token_type        String? // [!code ++]
  scope             String? // [!code ++]
  id_token          String? @db.Text // [!code ++]
  session_state     String? // [!code ++]
 // [!code ++]
  user User @relation(fields: [userId], references: [id], onDelete: Cascade) // [!code ++]
 // [!code ++]
  @@unique([provider, providerAccountId]) // [!code ++]
  @@map("accounts") // [!code ++]
} // [!code ++]
 // [!code ++]
model Session { // [!code ++]
  id           String   @id @default(cuid()) // [!code ++]
  sessionToken String   @unique @map("session_token") // [!code ++]
  userId       String   @map("user_id") // [!code ++]
  expires      DateTime // [!code ++]
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade) // [!code ++]
 // [!code ++]
  @@map("sessions") // [!code ++]
} // [!code ++]
 // [!code ++]
model User { // [!code ++]
  id            String    @id @default(cuid()) // [!code ++]
  name          String? // [!code ++]
  email         String?   @unique // [!code ++]
  emailVerified DateTime? @map("email_verified") // [!code ++]
  image         String? // [!code ++]
  accounts      Account[] // [!code ++]
  sessions      Session[] // [!code ++]
 // [!code ++]
  @@map("users") // [!code ++]
} // [!code ++]
 // [!code ++]
model VerificationToken { // [!code ++]
  identifier String // [!code ++]
  token      String // [!code ++]
  expires    DateTime // [!code ++]
 // [!code ++]
  @@unique([identifier, token]) // [!code ++]
  @@map("verification_tokens") // [!code ++]
} // [!code ++]
```

This creates the following models:

* **`Account`**: Stores OAuth provider information (access tokens, refresh tokens, provider account IDs) and enables users to sign in with multiple providers while maintaining a single user record.

* **`Session`**: Tracks authenticated user sessions with a unique session token, user ID, and expiration time to maintain authentication state across requests.

* **`User`**: The core model storing user information (name, email, profile image). Users can have multiple accounts from different providers and multiple active sessions.

* **`VerificationToken`**: Stores temporary tokens for email verification, password reset, and other security operations with expiration times.

### 2.3 Add `dotenv` to `prisma.config.ts` [#23-add-dotenv-to-prismaconfigts]

To get access to the variables in the `.env` file, they can either be loaded by your runtime, or by using `dotenv`.
Include an import for `dotenv` at the top of the `prisma.config.ts`

```ts
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.4. Configure the Prisma Client generator [#24-configure-the-prisma-client-generator]

Now, run the following command to create the database tables and generate the Prisma Client:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 2.5 Create a Prisma Client [#25-create-a-prisma-client]

Create a new folder in the root called `lib` and create a new file called `prisma.ts` in it. This file will contain the Prisma Client:

```typescript title="lib/prisma.ts" showLineNumbers
import { PrismaClient } from "../app/generated/prisma/client"; // [!code ++]
import { PrismaPg } from "@prisma/adapter-pg"; // [!code ++]
// [!code ++]
const adapter = new PrismaPg({
  // [!code ++]
  connectionString: process.env.DATABASE_URL!, // [!code ++]
}); // [!code ++]
// [!code ++]
const globalForPrisma = global as unknown as {
  // [!code ++]
  prisma: PrismaClient; // [!code ++]
}; // [!code ++]
// [!code ++]
const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    // [!code ++]
    adapter, // [!code ++]
  }); // [!code ++]
// [!code ++]
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma; // [!code ++]
// [!code ++]
export default prisma; // [!code ++]
```

## 3. Set up Auth.js credentials [#3-set-up-authjs-credentials]

### 3.1. Install dependencies [#31-install-dependencies]

Install the Auth.js dependencies:

  

#### bun

```bash
bun add @auth/prisma-adapter next-auth@beta
```

#### pnpm

```bash
pnpm add @auth/prisma-adapter next-auth@beta
```

#### yarn

```bash
yarn add @auth/prisma-adapter next-auth@beta
```

#### npm

```bash
npm install @auth/prisma-adapter next-auth@beta
```

### 3.2 Credentials [#32-credentials]

For this guide, you'll be setting up OAuth with Github. For this, you'll need 3 environment variables:

* `AUTH_SECRET` - Provided by Auth.js
* `CLIENT_ID` - Provided by Github
* `CLIENT_SECRET` - Provided by Github

To get the `AUTH_SECRET`, you can run the following command:

  

#### bun

```bash
bunx auth secret --copy
```

#### pnpm

```bash
pnpm dlx auth secret --copy
```

#### yarn

```bash
yarn dlx auth secret --copy
```

#### npm

```bash
npx auth secret --copy
```

* `--copy&#x60; will copy the secret to your clipboard. &#x2A;(Normally, running `npx auth secret` adds the secret to your `.env.local` file. To keep it tidy, you can use `--copy` and add it to the `.env` file that Prisma created earlier.)*

Add the following to the `.env` file:

```bash title=".env"
DATABASE_URL=<YOUR_DATABASE_URL>
AUTH_SECRET=<YOUR_AUTH_SECRET> # [!code ++]
```

To get the `CLIENT_ID` and `CLIENT_SECRET`, you can create a new OAuth application on Github.

1. Navigate to [Github Developer Settings](https://github.com/settings/developers)
2. Click on `New OAuth App`
3. Enter a name for your app, a home page URL, and a callback URL

* Name: `Auth.js + Prisma` (Or anything you want)
* Homepage URL: `http://localhost:3000`
* Callback URL: `http://localhost:3000/api/auth/callback/github`

4. Click `Register application`
5. Click `Generate new client secret` and copy the `Client ID` and `Client Secret`.
6. Add the `Client ID` and `Client Secret` to the `.env` file:

```bash title=".env"
DATABASE_URL=<YOUR_DATABASE_URL>
AUTH_SECRET=<YOUR_AUTH_SECRET>
AUTH_GITHUB_ID=<YOUR_GITHUB_CLIENT_ID> # [!code ++]
AUTH_GITHUB_SECRET=<YOUR_GITHUB_CLIENT_SECRET> # [!code ++]
```

### 3.3. Configure Auth.js [#33-configure-authjs]

In the `/lib` folder, create a new file called `auth.ts` and add the following code:

```typescript title="lib/auth.ts"
import NextAuth from "next-auth";

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [],
});
```

Next, you'll need to add the Github provider to the `auth.ts` file:

```typescript title="lib/auth.ts"
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github"; // [!code ++]

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [GitHub], // [!code highlight]
});
```

Users will now be able to sign in with Github. To add them to your database, you'll need to use the [Prisma Adapter](https://authjs.dev/getting-started/adapters/prisma):

```typescript title="lib/auth.ts"
import NextAuth from "next-auth";
import { PrismaAdapter } from "@auth/prisma-adapter"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
import GitHub from "next-auth/providers/github";

export const { handlers, auth, signIn, signOut } = NextAuth({
  adapter: PrismaAdapter(prisma), // [!code highlight]
  providers: [GitHub],
});
```

In the root, create a new file called `middleware.ts`. This will protect your routes and ensure that only authenticated users can access them:

```tsx title="middleware.ts"
export { auth as middleware } from "@/lib/auth";
```

### 3.4. Configure the Route [#34-configure-the-route]

The route handler is required to handle authentication requests from Auth.js. It exports the `GET` and `POST` handlers that Auth.js uses for sign-in, sign-out, and callback operations.

Create a new file at `app/api/auth/[...nextauth]/route.ts`:

```bash
mkdir -p app/api/auth/[...nextauth]
touch app/api/auth/[...nextauth]/route.ts
```

Add the following code to the file:

```tsx title="app/api/auth/[...nextauth]/route.ts"
import { handlers } from "@/lib/auth";

export const { GET, POST } = handlers;
```

Your routes are now protected by Auth.js. To see more configuration options, check out the [Auth.js Middleware documentation](https://next-auth.js.org/configuration/nextjs#middleware).

## 4. Auth components [#4-auth-components]

You will be creating a Sign In and Sign Out button. Create a `/components` folder in the root and add a new file called `auth-components.tsx` in it.

Start by importing the `signIn` and `signOut` functions from the `auth` file:

```tsx title="components/auth-components.tsx"
import { signIn, signOut } from "@/lib/auth"; // [!code ++]
```

Next, create the `SignIn` and `SignOut` components:

```tsx title="components/auth-components.tsx"
import { signIn, signOut } from "@/lib/auth";

export function SignIn({ provider }: { provider?: string }) {
  // [!code ++]
  return (
    // [!code ++]
    <form>
      {" "}
      // [!code ++]
      <button className="bg-neutral-700 text-white p-2 rounded-md">
        {" "}
        // [!code ++] Sign In with {provider} // [!code ++]
      </button>{" "}
      // [!code ++]
    </form> // [!code ++]
  ); // [!code ++]
} // [!code ++]
// [!code ++]
export function SignOut() {
  // [!code ++]
  return (
    // [!code ++]
    <form>
      {" "}
      // [!code ++]
      <button className="bg-neutral-700 text-white p-2 rounded-md">
        {" "}
        // [!code ++] Sign Out // [!code ++]
      </button>{" "}
      // [!code ++]
    </form> // [!code ++]
  ); // [!code ++]
} // [!code ++]
```

To add functionality to both of the buttons, add an action to the form that calls the `signIn` and `signOut` functions respectively:

```tsx title="components/auth-components.tsx"
import { signIn, signOut } from "@/lib/auth";

export function SignIn({ provider }: { provider?: string }) {
  return (
    <form
      action={async () => {
        // [!code ++]
        "use server"; // [!code ++]
        await signIn(provider); // [!code ++]
      }} // [!code ++]
    >
      <button className="bg-neutral-700 text-white p-2 rounded-md">Sign In with {provider}</button>
    </form>
  );
}

export function SignOut() {
  return (
    <form
      action={async () => {
        // [!code ++]
        "use server"; // [!code ++]
        await signOut(); // [!code ++]
      }} // [!code ++]
      className="w-full"
    >
      <button className="bg-neutral-700 text-white p-2 rounded-md">Sign Out</button>
    </form>
  );
}
```

## 5. Add the components to your app [#5-add-the-components-to-your-app]

### 5.1. Set up the basic page structure [#51-set-up-the-basic-page-structure]

In the `/app` folder, replace the `page.tsx` file with the following code:

```tsx title="app/page.tsx"
const Page = async () => {
  // [!code ++]
  return (
    // [!code ++]
    <div className="min-h-screen bg-black flex items-center justify-center p-4">
      {" "}
      // [!code ++]
      <div className="bg-neutral-800 rounded-lg p-6 max-w-xl w-full">
        {" "}
        // [!code ++]
        <h1 className="text-white text-xl mb-4 text-center">Auth.js + Prisma</h1> // [!code ++]
      </div>{" "}
      // [!code ++]
    </div> // [!code ++]
  ); // [!code ++]
}; // [!code ++]
// [!code ++]
export default Page; // [!code ++]
```

### 5.2. Add imports and authentication check [#52-add-imports-and-authentication-check]

Import the required components and add session checking:

```tsx title="app/page.tsx"
import { SignIn, SignOut } from "@/components/auth-components"; // [!code ++]
import { auth } from "@/lib/auth"; // [!code ++]

const Page = async () => {
  const session = await auth(); // [!code ++]

  return (
    <div className="min-h-screen bg-black flex items-center justify-center p-4">
      <div className="bg-neutral-800 rounded-lg p-6 max-w-xl w-full">
        <h1 className="text-white text-xl mb-4 text-center">Auth.js + Prisma</h1>
      </div>
    </div>
  );
};

export default Page;
```

### 5.3. Show content based on auth state [#53-show-content-based-on-auth-state]

Add the logic to show different content based on whether the user is signed in:

```tsx title="app/page.tsx"
import { SignIn, SignOut } from "@/components/auth-components";
import { auth } from "@/lib/auth";

const Page = async () => {
  const session = await auth();

  return (
    <div className="min-h-screen bg-black flex items-center justify-center p-4">
      <div className="bg-neutral-800 rounded-lg p-6 max-w-xl w-full">
        <h1 className="text-white text-xl mb-4 text-center">Auth.js + Prisma</h1>

        {!session ? (
          <div className="text-center">
            <SignIn provider="github" />
          </div>
        ) : (
          <div className="space-y-4">
            <div className="text-center">
              <p className="text-gray-300">Signed in as:</p>
              <p className="text-white">{session.user?.email}</p>
            </div>

            <div className="text-center">
              <p className="text-gray-300">Data fetched from DB with Prisma:</p>
            </div>

            <div className="text-center">
              <SignOut />
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

export default Page;
```

### 5.4. Add the user data to the page [#54-add-the-user-data-to-the-page]

If the user is signed in, you can fetch the user data from the database and display it on the page.

```tsx title="app/page.tsx"
import { SignIn, SignOut } from "@/components/auth-components";
import { auth } from "@/lib/auth";
import prisma from "@/lib/prisma"; // [!code ++]

const Page = async () => {
  const session = await auth();
  let user = null; // [!code ++]
  // [!code ++]
  if (session) {
    // [!code ++]
    user = await prisma.user.findUnique({
      // [!code ++]
      where: {
        // [!code ++]
        id: session.user?.id, // [!code ++]
      }, // [!code ++]
    }); // [!code ++]
  } // [!code ++]

  return (
    <div className="min-h-screen bg-black flex items-center justify-center p-4">
      <div className="bg-neutral-800 rounded-lg p-6 max-w-xl w-full">
        <h1 className="text-white text-xl mb-4 text-center">Auth.js + Prisma</h1>

        {!session ? (
          <div className="text-center">
            <SignIn provider="github" />
          </div>
        ) : (
          <div className="space-y-4">
            <div className="text-center">
              <p className="text-gray-300">Signed in as:</p>
              <p className="text-white">{session.user?.email}</p>
            </div>
            <div className="text-center">
              <p className="text-gray-300">Data fetched from DB with Prisma:</p>
            </div>
            <div className="bg-neutral-900 rounded p-3">
              {" "}
              // [!code ++]
              <pre className="text-xs text-gray-300">
                {" "}
                // [!code ++]
                {JSON.stringify(user, null, 2)} // [!code ++]
              </pre>{" "}
              // [!code ++]
            </div>{" "}
            // [!code ++]
            <div className="text-center">
              <SignOut />
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

export default Page;
```

## 6. Test it out [#6-test-it-out]

> [!WARNING]
> Before starting the development server, note that if you are using Next.js v15.2.0 or v15.2.1, do not use Turbopack as there is a known [issue](https://github.com/vercel/next.js/issues/76497). Remove Turbopack from your dev script by updating your `package.json`
> 
> ```json title="package.json"
> "script":{
>     "dev": "next dev --turbopack", // [!code --]
>     "dev": "next dev", // [!code ++]
> }
> ```
>
> This change is not needed on any versions before or after.

Your application is now fully configured.

1. Start the development server to test it:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

2. Navigate to `http://localhost:3000` in your browser. You should see the home page with a "Sign In with github" button.

3. Click on **Sign In with github**, authorize the app, and you should be redirected to the dashboard. You can then sign out and sign back in.

4. To view the user data directly in your database, you can use Prisma Studio:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

5. This will open a new tab in your browser where you can see the `User`, `Session`, and `Account` tables and their contents.

> [!TIP]
> You now have a working authentication system built with Auth.js, Prisma, and Next.js.

# Better Auth (with Astro) (/docs/guides/authentication/better-auth/astro)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in an Astro app with Better Auth

Location: Guides > Authentication > Better Auth > Better Auth (with Astro)

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is not available yet: Better Auth's `prismaAdapter` requires Prisma Client, which Prisma ORM 8 replaces with the `@prisma/orm-postgres` runtime.

## Introduction [#introduction]

[Better Auth](https://better-auth.com/) is an open-source authentication library for web apps. It's written in TypeScript, can be extended with plugins, and supports multiple database adapters, including Prisma.

In this guide, you'll wire Better Auth into a brand-new [Astro](https://astro.build/) app and persist users in a [Prisma Postgres](https://prisma.io/postgres) database. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/betterauth-astro).

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* Basic familiarity with Astro and Prisma

## 1. Set up your project [#1-set-up-your-project]

Create a new Astro project:

  

#### bun

```bash
bunx create-astro betterauth-astro-prisma
```

#### pnpm

```bash
pnpm create astro betterauth-astro-prisma
```

#### yarn

```bash
yarn create astro betterauth-astro-prisma
```

#### npm

```bash
npm create astro@latest betterauth-astro-prisma
```

> [!NOTE]
> * *How would you like to start your new project?* `Use minimal (empty) template `
> * *Install dependencies? (recommended)* `Yes`
> * *Initialize a new git repository? (optional)* `Yes`

Navigate to the project directory:

```bash
cd betterauth-astro-prisma
```

These selections will create a minimal Astro project with TypeScript for type safety.

## 2. Set up Prisma [#2-set-up-prisma]

Next, you'll add Prisma to your project to manage your database.

### 2.1. Install Prisma and dependencies [#21-install-prisma-and-dependencies]

Install the necessary Prisma packages:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../prisma/generated
```

#### pnpm

```bash
pnpm prisma init --output ../prisma/generated
```

#### yarn

```bash
yarn prisma init --output ../prisma/generated
```

#### npm

```bash
npx prisma init --output ../prisma/generated
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma` directory with a `schema.prisma` file
* A `.env` file containing a local `DATABASE_URL` at the project root
* A `prisma.config.ts` file for configuring Prisma
* An `output` directory for the generated Prisma Client as `prisma/generated`

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Configure Prisma to load environment variables [#22-configure-prisma-to-load-environment-variables]

To get access to the variables in the `.env` file, update your `prisma.config.ts` to import `dotenv`:

```ts title="prisma.config.ts" showLineNumbers
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  engine: "classic",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.3. Generate the Prisma Client [#23-generate-the-prisma-client]

Run the following command to generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 2.4. Set up a global Prisma client [#24-set-up-a-global-prisma-client]

In the `src` directory, create a `lib` folder and a `prisma.ts` file inside it. This file will be used to create and export your Prisma Client instance.

```bash
mkdir -p src/lib
touch src/lib/prisma.ts
```

Set up the Prisma client like this:

```ts title="src/lib/prisma.ts"
import { PrismaClient } from "../../prisma/generated/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: import.meta.env.DATABASE_URL,
});

const prisma = new PrismaClient({
  adapter,
});

export default prisma;
```

> [!WARNING]
> We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently.
> 
> If you choose not to use one, **avoid** instantiating `PrismaClient` globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections.

## 3. Set up Better Auth [#3-set-up-better-auth]

Next, add Better Auth to handle sign-up, sign-in, and sessions.

### 3.1. Install and configure Better Auth [#31-install-and-configure-better-auth]

First, install the Better Auth core package:

  

#### bun

```bash
bun add better-auth
```

#### pnpm

```bash
pnpm add better-auth
```

#### yarn

```bash
yarn add better-auth
```

#### npm

```bash
npm install better-auth
```

Next, generate a secure secret that Better Auth will use to sign authentication tokens. This ensures your tokens cannot be tampered with.

  

#### bun

```bash
bunx @better-auth/cli@latest secret
```

#### pnpm

```bash
pnpm dlx @better-auth/cli@latest secret
```

#### yarn

```bash
yarn dlx @better-auth/cli@latest secret
```

#### npm

```bash
npx @better-auth/cli@latest secret
```

Copy the generated secret and add it, along with your application's URL, to your `.env` file:

```bash title=".env"
# Better Auth
BETTER_AUTH_SECRET=your-generated-secret # [!code ++]
BETTER_AUTH_URL=http://localhost:4321 # [!code ++]

# Prisma
DATABASE_URL="your-database-url"
```

> [!NOTE]
> Astro's default development server runs on port `4321`. If your application runs on a different port, update the `BETTER_AUTH_URL` accordingly.

Now, create a configuration file for Better Auth. In the `src/lib` directory, create an `auth.ts` file:

```bash
touch src/lib/auth.ts
```

In this file, you'll configure Better Auth to use the Prisma adapter, which allows it to persist user and session data in your database. You will also enable email and password authentication.

```ts title="src/lib/auth.ts"
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import prisma from "./prisma";

export const auth = betterAuth({
  database: prismaAdapter(prisma, {
    provider: "postgresql",
  }),
  emailAndPassword: {
    enabled: true,
  },
});
```

Better Auth also supports other sign-in methods like social logins (Google, GitHub, etc.), which you can explore in their [email and password documentation](https://www.better-auth.com/docs/authentication/email-password).

### 3.2. Add Better Auth models to your schema [#32-add-better-auth-models-to-your-schema]

Better Auth provides a CLI command to automatically add the necessary authentication models (`User`, `Session`, `Account`, and `Verification`) to your `schema.prisma` file.

Run the following command:

  

#### bun

```bash
bunx @better-auth/cli generate
```

#### pnpm

```bash
pnpm dlx @better-auth/cli generate
```

#### yarn

```bash
yarn dlx @better-auth/cli generate
```

#### npm

```bash
npx @better-auth/cli generate
```

> [!NOTE]
> It will ask for confirmation to overwrite your existing Prisma schema. Select `y`.

This will add the following models:

```prisma
model User {
  id            String    @id
  name          String
  email         String
  emailVerified Boolean
  image         String?
  createdAt     DateTime
  updatedAt     DateTime
  sessions      Session[]
  accounts      Account[]

  @@unique([email])
  @@map("user")
}

model Session {
  id        String   @id
  expiresAt DateTime
  token     String
  createdAt DateTime
  updatedAt DateTime
  ipAddress String?
  userAgent String?
  userId    String
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([token])
  @@map("session")
}

model Account {
  id                    String    @id
  accountId             String
  providerId            String
  userId                String
  user                  User      @relation(fields: [userId], references: [id], onDelete: Cascade)
  accessToken           String?
  refreshToken          String?
  idToken               String?
  accessTokenExpiresAt  DateTime?
  refreshTokenExpiresAt DateTime?
  scope                 String?
  password              String?
  createdAt             DateTime
  updatedAt             DateTime

  @@map("account")
}

model Verification {
  id         String    @id
  identifier String
  value      String
  expiresAt  DateTime
  createdAt  DateTime?
  updatedAt  DateTime?

  @@map("verification")
}
```

### 3.3. Migrate the database [#33-migrate-the-database]

With the new models in your schema, you need to update your database. Run a migration to create the corresponding tables:

  

#### bun

```bash
bunx prisma migrate dev --name add-auth-models
```

#### pnpm

```bash
pnpm prisma migrate dev --name add-auth-models
```

#### yarn

```bash
yarn prisma migrate dev --name add-auth-models
```

#### npm

```bash
npx prisma migrate dev --name add-auth-models
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

<br />

## 4. Set up the API routes [#4-set-up-the-api-routes]

Better Auth needs an API endpoint to handle authentication requests like sign-in, sign-up, and sign-out. You'll create a catch-all API route in Astro to handle all requests sent to `/api/auth/[...all]`.

In the `src/pages` directory, create an `api/auth` folder structure and a `[...all].ts` file inside it:

```bash
mkdir -p src/pages/api/auth
touch 'src/pages/api/auth/[...all].ts'
```

Add the following code to the newly created `[...all].ts` file. This code uses the Better Auth handler to process authentication requests.

```ts title="src/pages/api/auth/[...all].ts"
import { auth } from "../../../lib/auth";
import type { APIRoute } from "astro";

export const prerender = false; // Not needed in 'server' mode

export const ALL: APIRoute = async (ctx) => {
  return auth.handler(ctx.request);
};
```

Next, you'll need a client-side utility to interact with these endpoints from your Astro pages. In the `src/lib` directory, create an `auth-client.ts` file:

```bash
touch src/lib/auth-client.ts
```

Add the following code, which creates the client functions you'll use in your UI:

```ts title="src/lib/auth-client.ts"
import { createAuthClient } from "better-auth/client";

export const authClient = createAuthClient();

export const { signIn, signUp, signOut, useSession } = authClient;
```

## 5. Configure TypeScript definitions [#5-configure-typescript-definitions]

In the `src` directory, create an `env.d.ts` file to provide TypeScript definitions for environment variables and Astro locals:

```bash
touch src/env.d.ts
```

Add the following type definitions:

```ts title="src/env.d.ts"
/// <reference path="../.astro/types.d.ts" />

declare namespace App {
  interface Locals {
    user: import("better-auth").User | null;
    session: import("better-auth").Session | null;
  }
}

interface ImportMetaEnv {
  readonly DATABASE_URL: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}
```

## 6. Set up authentication middleware [#6-set-up-authentication-middleware]

In the `src` directory, create a `middleware.ts` file to check authentication status on every request. This will make the user and session data available to all your pages.

```bash
touch src/middleware.ts
```

Add the following code:

```ts title="src/middleware.ts"
import { auth } from "./lib/auth";
import { defineMiddleware } from "astro:middleware";

export const onRequest = defineMiddleware(async (context, next) => {
  context.locals.user = null;
  context.locals.session = null;
  const isAuthed = await auth.api.getSession({
    headers: context.request.headers,
  });
  if (isAuthed) {
    context.locals.user = isAuthed.user;
    context.locals.session = isAuthed.session;
  }
  return next();
});
```

## 7. Set up your pages [#7-set-up-your-pages]

Next, build the user interface for authentication. In the `src/pages` directory, create the following folder structure:

* `sign-up/index.astro`
* `sign-in/index.astro`
* `dashboard/index.astro`

```bash
mkdir -p src/pages/{sign-up,sign-in,dashboard}
touch src/pages/{sign-up,sign-in,dashboard}/index.astro
```

### 7.1. Sign up page [#71-sign-up-page]

This page allows new users to create an account. Start with the basic HTML structure in `src/pages/sign-up/index.astro`.

```html title="src/pages/sign-up/index.astro"
---
export const prerender = false;
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Sign Up</title>
  </head>
  <body>
    <main>
      <h1>Sign Up</h1>
    </main>
  </body>
</html>
```

Add a form with input fields for name, email, and password. This form will collect the user's registration information.

```html title="src/pages/sign-up/index.astro"
---
export const prerender = false;
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Sign Up</title>
  </head>
  <body>
    <main>
      <h1>Sign Up</h1>
      <form id="signup-form"> // [!code ++]
        <input type="text" name="name" placeholder="Name" required /> // [!code ++]
        <input type="email" name="email" placeholder="Email" required /> // [!code ++]
        <input // [!code ++]
          required // [!code ++]
          type="password" // [!code ++]
          name="password" // [!code ++]
          placeholder="Password" // [!code ++]
        /> // [!code ++]
        <button type="submit">Sign up</button> // [!code ++]
      </form> // [!code ++]
      <p>Already have an account? <a href="/sign-in">Sign in here</a>.</p> // [!code ++]
    </main>
  </body>
</html>
```

Now add a script to handle form submission. Import the `authClient` and add an event listener to the form that prevents the default submission behavior, extracts the form data, and calls the Better Auth sign-up method.

```html title="src/pages/sign-up/index.astro"
---
export const prerender = false;
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Sign Up</title>
  </head>
  <body>
    <main>
      <h1>Sign Up</h1>
      <form id="signup-form">
        <input type="text" name="name" placeholder="Name" required />
        <input type="email" name="email" placeholder="Email" required />
        <input required type="password" name="password" placeholder="Password" />
        <button type="submit">Sign up</button>
      </form>
      <p>Already have an account? <a href="/sign-in">Sign in here</a>.</p>
    </main>
    <script>
      // [!code ++]
           import { authClient } from "../../lib/auth-client"; // [!code ++]
           document // [!code ++]
             .getElementById("signup-form") // [!code ++]
             ?.addEventListener("submit", async (event) => { // [!code ++]
               event.preventDefault(); // [!code ++]
               const formData = new FormData(event.target as HTMLFormElement); // [!code ++]
               const name = formData.get("name") as string; // [!code ++]
               const email = formData.get("email") as string; // [!code ++]
               const password = formData.get("password") as string; // [!code ++]
               const tmp = await authClient.signUp.email({ // [!code ++]
                 name, // [!code ++]
                 email, // [!code ++]
                 password, // [!code ++]
               }); // [!code ++]
               console.log(tmp); // [!code ++]
               if (Boolean(tmp.error) === false) window.location.href = "/dashboard"; // [!code ++]
             }); // [!code ++]
    </script>
    // [!code ++]
  </body>
</html>
```

Finally, add a server-side check to redirect authenticated users away from this page. If a user is already signed in, they should be redirected to the dashboard instead.

```html title="src/pages/sign-up/index.astro"
---
export const prerender = false;

if (Astro.locals.user?.id) return Astro.redirect("/dashboard"); // [!code ++]
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Sign Up</title>
  </head>
  <body>
    <main>
      <h1>Sign Up</h1>
      <form id="signup-form">
        <input type="text" name="name" placeholder="Name" required />
        <input type="email" name="email" placeholder="Email" required />
        <input required type="password" name="password" placeholder="Password" />
        <button type="submit">Sign up</button>
      </form>
      <p>Already have an account? <a href="/sign-in">Sign in here</a>.</p>
    </main>
    <script>
      import { authClient } from "../../lib/auth-client";
      document
        .getElementById("signup-form")
        ?.addEventListener("submit", async (event) => {
          event.preventDefault();
          const formData = new FormData(event.target as HTMLFormElement);
          const name = formData.get("name") as string;
          const email = formData.get("email") as string;
          const password = formData.get("password") as string;
          const tmp = await authClient.signUp.email({
            name,
            email,
            password,
          });
          console.log(tmp);
          if (Boolean(tmp.error) === false) window.location.href = "/dashboard";
        });
    </script>
  </body>
</html>
```

### 7.2. Sign in page [#72-sign-in-page]

This page allows existing users to authenticate. Start with the basic HTML structure in `src/pages/sign-in/index.astro`.

```html title="src/pages/sign-in/index.astro"
---
export const prerender = false;
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Sign In</title>
  </head>
  <body>
    <main>
      <h1>Sign In</h1>
    </main>
  </body>
</html>
```

Add a form with input fields for email and password. This form will collect the user's credentials.

```html title="src/pages/sign-in/index.astro"
---
export const prerender = false;
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Sign In</title>
  </head>
  <body>
    <main>
      <h1>Sign In</h1>
      <form id="signin-form"> // [!code ++]
        <input type="email" name="email" placeholder="Email" required /> // [!code ++]
        <input // [!code ++]
          required // [!code ++]
          type="password" // [!code ++]
          name="password" // [!code ++]
          placeholder="Password" // [!code ++]
        /> // [!code ++]
        <button type="submit">Sign In</button> // [!code ++]
      </form> // [!code ++]
      <p>Don't have an account? <a href="/sign-up">Sign up here</a>.</p> // [!code ++]
    </main>
  </body>
</html>
```

Now add a script to handle form submission. Import the `authClient` and add an event listener that prevents default submission, extracts the form data, and calls the Better Auth sign-in method.

```html title="src/pages/sign-in/index.astro"
---
export const prerender = false;
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Sign In</title>
  </head>
  <body>
    <main>
      <h1>Sign In</h1>
      <form id="signin-form">
        <input type="email" name="email" placeholder="Email" required />
        <input required type="password" name="password" placeholder="Password" />
        <button type="submit">Sign In</button>
      </form>
      <p>Don't have an account? <a href="/sign-up">Sign up here</a>.</p>
    </main>
    <script>
      // [!code ++]
           import { authClient } from "../../lib/auth-client"; // [!code ++]
           document // [!code ++]
             .getElementById("signin-form") // [!code ++]
             ?.addEventListener("submit", async (event) => { // [!code ++]
               event.preventDefault(); // [!code ++]
               const formData = new FormData(event.target as HTMLFormElement); // [!code ++]
               const email = formData.get("email") as string; // [!code ++]
               const password = formData.get("password") as string; // [!code ++]
               const tmp = await authClient.signIn.email({ // [!code ++]
                 email, // [!code ++]
                 password, // [!code ++]
               }); // [!code ++]
               if (Boolean(tmp.error) === false) window.location.href = "/dashboard"; // [!code ++]
             }); // [!code ++]
    </script>
    // [!code ++]
  </body>
</html>
```

Finally, add a server-side check to redirect authenticated users away from this page. If a user is already signed in, they should be redirected to the dashboard instead.

```html title="src/pages/sign-in/index.astro"
---
export const prerender = false;

if (Astro.locals.user?.id) return Astro.redirect("/dashboard"); // [!code ++]
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Sign In</title>
  </head>
  <body>
    <main>
      <h1>Sign In</h1>
      <form id="signin-form">
        <input type="email" name="email" placeholder="Email" required />
        <input required type="password" name="password" placeholder="Password" />
        <button type="submit">Sign In</button>
      </form>
      <p>Don't have an account? <a href="/sign-up">Sign up here</a>.</p>
    </main>
    <script>
      import { authClient } from "../../lib/auth-client";
      document
        .getElementById("signin-form")
        ?.addEventListener("submit", async (event) => {
          event.preventDefault();
          const formData = new FormData(event.target as HTMLFormElement);
          const email = formData.get("email") as string;
          const password = formData.get("password") as string;
          const tmp = await authClient.signIn.email({
            email,
            password,
          });
          if (Boolean(tmp.error) === false) window.location.href = "/dashboard";
        });
    </script>
  </body>
</html>
```

### 7.3. Dashboard page [#73-dashboard-page]

This is the protected page for authenticated users. Start with the basic HTML structure in `src/pages/dashboard/index.astro`.

```html title="src/pages/dashboard/index.astro"
---
export const prerender = false;
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Dashboard</title>
  </head>
  <body>
    <main>
      <h1>Dashboard</h1>
    </main>
  </body>
</html>
```

Add a server-side check to protect this route. If the user is not authenticated, redirect them to the sign-in page.

```html title="src/pages/dashboard/index.astro"
---
export const prerender = false;

if (!Astro.locals.user?.id) return Astro.redirect("/sign-in"); // [!code ++]
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Dashboard</title>
  </head>
  <body>
    <main>
      <h1>Dashboard</h1>
    </main>
  </body>
</html>
```

Now display the authenticated user's information. The `Astro.locals.user` object contains the user data that was set by the middleware.

```html title="src/pages/dashboard/index.astro"
---
export const prerender = false;

if (!Astro.locals.user?.id) return Astro.redirect("/sign-in");
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Dashboard</title>
  </head>
  <body>
    <main>
      <h1>Dashboard</h1>
      <pre>{JSON.stringify(Astro.locals.user, null, 2)}</pre>
      // [!code ++]
    </main>
  </body>
</html>
```

Finally, add a sign-out button. Import the `authClient` and add a button that calls the sign-out method, allowing the user to log out and be redirected to the sign-in page.

```html title="src/pages/dashboard/index.astro"
---
export const prerender = false;

if (!Astro.locals.user?.id) return Astro.redirect("/sign-in");
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Dashboard</title>
  </head>
  <body>
    <main>
      <h1>Dashboard</h1>
      <pre>{JSON.stringify(Astro.locals.user, null, 2)}</pre>
      <button id="signOutButton">Sign Out</button> // [!code ++]
    </main>
    <script>
      // [!code ++]
      import { authClient } from "../../lib/auth-client"; // [!code ++]
      document // [!code ++]
        .getElementById("signOutButton") // [!code ++]
        ?.addEventListener("click", async () => {
          // [!code ++]
          await authClient.signOut(); // [!code ++]
          window.location.href = "/sign-in"; // [!code ++]
        }); // [!code ++]
    </script>
    // [!code ++]
  </body>
</html>
```

### 7.4. Home page [#74-home-page]

Finally, update the home page to link to the sign-up, sign-in, and dashboard pages. Replace the contents of `src/pages/index.astro` with the following:

```html title="src/pages/index.astro"
---
export const prerender = false;
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Better Auth + Astro + Prisma</title>
  </head>
  <body>
    <main>
      <h1>Better Auth + Astro + Prisma</h1>
      { Astro.locals.user ? (
      <div>
        <p>Welcome back, {Astro.locals.user.name}!</p>
        <a href="/dashboard">Go to Dashboard</a>
      </div>
      ) : (
      <div>
        <a href="/sign-up">Sign Up</a>
        <a href="/sign-in">Sign In</a>
      </div>
      ) }
    </main>
  </body>
</html>
```

## 8. Test it out [#8-test-it-out]

Your application is now fully configured.

1. Start the development server to test it:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

2. Navigate to `http://localhost:4321` in your browser. You should see the home page with "Sign Up" and "Sign In" links.

3. Click on **Sign Up**, create a new account, and you should be redirected to the dashboard. You can then sign out and sign back in.

4. To view the user data directly in your database, you can use Prisma Studio.

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

5. This will open a new tab in your browser where you can see the `User`, `Session`, and `Account` tables and their contents.

> [!TIP]
> You now have a working authentication system built with Better Auth, Prisma, and Astro.

## Next steps [#next-steps]

* Add support for social login or magic links
* Implement password reset and email verification
* Add user profile and account management pages
* Deploy to Vercel or Netlify and secure your environment variables
* Extend your Prisma schema with custom application models

## Further reading [#further-reading]

* [Better Auth documentation](https://www.better-auth.com/docs)
* [Prisma documentation](https://www.prisma.io/docs/orm/v7)
* [Astro documentation](https://astro.build/docs)

## Related pages

- [`Better Auth (with Next.js)`](https://www.prisma.io/docs/guides/authentication/better-auth/nextjs): Learn how to use Prisma ORM in a Next.js app with Better Auth

# Better Auth (with Next.js) (/docs/guides/authentication/better-auth/nextjs)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a Next.js app with Better Auth

Location: Guides > Authentication > Better Auth > Better Auth (with Next.js)

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is not available yet: Better Auth's `prismaAdapter` requires Prisma Client, which Prisma ORM 8 replaces with the `@prisma/orm-postgres` runtime.

## Introduction [#introduction]

[Better Auth](https://better-auth.com/) is an open-source authentication library for web applications. It's written in TypeScript, can be extended with plugins, and supports multiple database adapters, including Prisma.

In this guide, you'll wire Better Auth into a brand-new [Next.js](https://nextjs.org/) app and persist users in a [Prisma Postgres](https://prisma.io/postgres) database. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/betterauth-nextjs).

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* Basic familiarity with Next.js App Router and Prisma

## 1. Set up your project [#1-set-up-your-project]

Create a new Next.js application:

  

#### bun

```bash
bunx create-next-app@latest betterauth-nextjs-prisma
```

#### pnpm

```bash
pnpm dlx create-next-app@latest betterauth-nextjs-prisma
```

#### yarn

```bash
yarn dlx create-next-app@latest betterauth-nextjs-prisma
```

#### npm

```bash
npx create-next-app@latest betterauth-nextjs-prisma
```

It will prompt you to customize your setup. Choose the defaults:

> [!NOTE]
> * *Would you like to use TypeScript?* `Yes`
> * *Would you like to use ESLint?* `Yes`
> * *Would you like to use Tailwind CSS?* `Yes`
> * *Would you like your code inside a `src/` directory?* `Yes`
> * *Would you like to use App Router?* `Yes`
> * *Would you like to use Turbopack?* `Yes`
> * _Would you like to customize the import alias (`@/_`by default)?\*`No`

Navigate to the project directory:

```bash
cd betterauth-nextjs-prisma
```

These selections create a Next.js project with TypeScript for type safety, ESLint for code quality, and Tailwind CSS for styling. Using the `src/` directory and the App Router are common conventions for new Next.js applications.

## 2. Set up Prisma [#2-set-up-prisma]

Next, you'll add Prisma to your project to manage your database.

### 2.1. Install Prisma and dependencies [#21-install-prisma-and-dependencies]

Install the necessary Prisma packages. The dependencies differ slightly depending on whether you use Prisma Postgres with Accelerate or another database.

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../src/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../src/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../src/generated/prisma
```

#### npm

```bash
npx prisma init --output ../src/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma` directory with a `schema.prisma` file
* A `.env` file containing a local `DATABASE_URL` at the project root
* An `output` directory for the generated Prisma Client as `better-auth/generated/prisma`

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Configure Prisma [#22-configure-prisma]

Create a `prisma.config.ts` file in the root of your project with the following content:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

> [!NOTE]
> The `dotenv` package should already be installed as it's a Next.js dependency. If not, install it using:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 

### 2.3. Generate the Prisma client [#23-generate-the-prisma-client]

Run the following command to create the database tables and generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 2.4. Set up a global Prisma client [#24-set-up-a-global-prisma-client]

In the `src` directory, create a `lib` folder and a `prisma.ts` file inside it. This file will be used to create and export your Prisma Client instance.

```bash
mkdir -p src/lib
touch src/lib/prisma.ts
```

Set up the Prisma client like this:

```tsx title="src/lib/prisma.ts"
import { PrismaClient } from "@/generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const globalForPrisma = global as unknown as {
  prisma: PrismaClient;
};

const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    adapter,
  });

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

export default prisma;
```

> [!WARNING]
> We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently.
> 
> If you choose not to use one, **avoid** instantiating `PrismaClient` globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections.

## 3. Set up Better Auth [#3-set-up-better-auth]

Next, add Better Auth to handle sign-up, sign-in, and sessions.

### 3.1. Install and configure Better Auth [#31-install-and-configure-better-auth]

First, install the Better Auth core package:

  

#### bun

```bash
bun add better-auth
```

#### pnpm

```bash
pnpm add better-auth
```

#### yarn

```bash
yarn add better-auth
```

#### npm

```bash
npm install better-auth
```

Next, generate a secure secret that Better Auth will use to sign authentication tokens. This ensures your tokens cannot be messed with.

  

#### bun

```bash
bunx auth@latest secret
```

#### pnpm

```bash
pnpm dlx auth@latest secret
```

#### yarn

```bash
yarn dlx auth@latest secret
```

#### npm

```bash
npx auth@latest secret
```

Copy the generated secret and add it, along with your application's URL, to your `.env` file:

```bash title=".env"
# Better Auth
BETTER_AUTH_SECRET=your-generated-secret # [!code ++]
BETTER_AUTH_URL=http://localhost:3000 # [!code ++]

# Prisma
DATABASE_URL="your-database-url"
```

Now, create a configuration file for Better Auth. In the `src/lib` directory, create an `auth.ts` file:

```bash
touch src/lib/auth.ts
```

In this file, you'll configure Better Auth to use the Prisma adapter, which allows it to persist user and session data in your database. You will also enable email and password authentication.

```ts title="src/lib/auth.ts"
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import prisma from "@/lib/prisma";

export const auth = betterAuth({
  database: prismaAdapter(prisma, {
    provider: "postgresql",
  }),
});
```

Better Auth also supports other sign-in methods like social logins (Google, GitHub, etc.), which you can explore in their [email and password documentation](https://www.better-auth.com/docs/authentication/email-password).

```ts title="src/lib/auth.ts"
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import prisma from "@/lib/prisma";

export const auth = betterAuth({
  database: prismaAdapter(prisma, {
    provider: "postgresql",
  }),
  emailAndPassword: {
    // [!code ++]
    enabled: true, // [!code ++]
  }, // [!code ++]
});
```

> [!NOTE]
> If your application runs on a port other than `3000`, you must add it to the `trustedOrigins` in your `auth.ts` configuration to avoid CORS errors during authentication requests.
> 
> ```ts title="src/lib/auth.ts"
> import { betterAuth } from "better-auth";
> import { prismaAdapter } from "better-auth/adapters/prisma";
> import prisma from "@/lib/prisma";
>
> export const auth = betterAuth({
>   database: prismaAdapter(prisma, {
>     provider: "postgresql",
>   }),
>   emailAndPassword: {
>     enabled: true,
>   },
>   trustedOrigins: ["http://localhost:3001"], // [!code ++]
> });
> ```

### 3.2. Add Better Auth models to your schema [#32-add-better-auth-models-to-your-schema]

Better Auth provides a CLI command to automatically add the necessary authentication models (`User`, `Session`, `Account`, and `Verification`) to your `schema.prisma` file.

Run the following command:

  

#### bun

```bash
bunx auth generate
```

#### pnpm

```bash
pnpm dlx auth generate
```

#### yarn

```bash
yarn dlx auth generate
```

#### npm

```bash
npx auth generate
```

> [!NOTE]
> It will ask for confirmation to overwrite your existing Prisma schema. Select `y`.

This will add the following models:

```prisma
model User {
  id            String    @id
  name          String
  email         String
  emailVerified Boolean
  image         String?
  createdAt     DateTime
  updatedAt     DateTime
  sessions      Session[]
  accounts      Account[]

  @@unique([email])
  @@map("user")
}

model Session {
  id        String   @id
  expiresAt DateTime
  token     String
  createdAt DateTime
  updatedAt DateTime
  ipAddress String?
  userAgent String?
  userId    String
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([token])
  @@map("session")
}

model Account {
  id                    String    @id
  accountId             String
  providerId            String
  userId                String
  user                  User      @relation(fields: [userId], references: [id], onDelete: Cascade)
  accessToken           String?
  refreshToken          String?
  idToken               String?
  accessTokenExpiresAt  DateTime?
  refreshTokenExpiresAt DateTime?
  scope                 String?
  password              String?
  createdAt             DateTime
  updatedAt             DateTime

  @@map("account")
}

model Verification {
  id         String    @id
  identifier String
  value      String
  expiresAt  DateTime
  createdAt  DateTime?
  updatedAt  DateTime?

  @@map("verification")
}
```

### 3.3. Migrate the database [#33-migrate-the-database]

With the new models in your schema, you need to update your database. Run a migration to create the corresponding tables:

  

#### bun

```bash
bunx prisma migrate dev --name add-auth-models
```

#### pnpm

```bash
pnpm prisma migrate dev --name add-auth-models
```

#### yarn

```bash
yarn prisma migrate dev --name add-auth-models
```

#### npm

```bash
npx prisma migrate dev --name add-auth-models
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 4. Set up the API routes [#4-set-up-the-api-routes]

Better Auth needs an API endpoint to handle authentication requests like sign-in, sign-up, and sign-out. You'll create a catch-all API route in Next.js to handle all requests sent to `/api/auth/[...all]`.

In the `src/app/api` directory, create an `auth/[...all]` folder structure and a `route.ts` file inside it:

```bash
mkdir -p "src/app/api/auth/[...all]"
touch "src/app/api/auth/[...all]/route.ts"
```

Add the following code to the newly created `route.ts` file. This code uses a helper from Better Auth to create Next.js-compatible `GET` and `POST` request handlers.

```ts
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";

export const { POST, GET } = toNextJsHandler(auth);
```

Next, you'll need a client-side utility to interact with these endpoints from your React components. In the `src/lib` directory, create an `auth-client.ts` file:

```bash
touch src/lib/auth-client.ts
```

Add the following code, which creates the React hooks and functions you'll use in your UI:

```ts
import { createAuthClient } from "better-auth/react";

export const { signIn, signUp, signOut, useSession } = createAuthClient();
```

## 5. Set up your pages [#5-set-up-your-pages]

Next, build the user interface for authentication. In the `src/app` directory, create the following folder structure:

* `sign-up/page.tsx`
* `sign-in/page.tsx`
* `dashboard/page.tsx`

```bash
mkdir -p src/app/{sign-up,sign-in,dashboard}
touch src/app/{sign-up,sign-in,dashboard}/page.tsx
```

### 5.1. Sign up page [#51-sign-up-page]

First, create the basic `SignUpPage` component in `src/app/sign-up/page.tsx`. This sets up the main container and a title for your page.

```tsx title="src/app/sign-up/page.tsx"
"use client";

export default function SignUpPage() {
  return (
    <main className="max-w-md mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Sign Up</h1>
    </main>
  );
}
```

Next, import the necessary hooks from React and Next.js to manage state and navigation. Initialize the router and a state variable to hold any potential error messages.

```tsx title="src/app/sign-up/page.tsx"
"use client";

import { useState } from "react"; // [!code ++]
import { useRouter } from "next/navigation"; // [!code ++]

export default function SignUpPage() {
  const router = useRouter(); // [!code ++]
  const [error, setError] = useState<string | null>(null); // [!code ++]

  return (
    <main className="max-w-md mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Sign Up</h1>
    </main>
  );
}
```

Now, import the `signUp` function from your Better Auth client and add the `handleSubmit` function. This function is triggered on form submission and calls the `signUp.email` method provided by Better Auth, passing the user's name, email, and password.

```tsx title="src/app/sign-up/page.tsx"
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
//add-next-lin
import { signUp } from "@/lib/auth-client";

export default function SignUpPage() {
  const router = useRouter();
  const [error, setError] = useState<string | null>(null);

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    // [!code ++]
    e.preventDefault(); // [!code ++]
    setError(null); // [!code ++]
    // [!code ++]
    const formData = new FormData(e.currentTarget); // [!code ++]
    // [!code ++]
    const res = await signUp.email({
      // [!code ++]
      name: formData.get("name") as string, // [!code ++]
      email: formData.get("email") as string, // [!code ++]
      password: formData.get("password") as string, // [!code ++]
    }); // [!code ++]
    // [!code ++]
    if (res.error) {
      // [!code ++]
      setError(res.error.message || "Something went wrong."); // [!code ++]
    } else {
      // [!code ++]
      router.push("/dashboard"); // [!code ++]
    } // [!code ++]
  } // [!code ++]

  return (
    <main className="max-w-md mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Sign Up</h1>
    </main>
  );
}
```

To inform the user of any issues, add an element that conditionally renders when the `error` state is not null.

```tsx title="src/app/sign-up/page.tsx"
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { signUp } from "@/lib/auth-client";

export default function SignUpPage() {
  const router = useRouter();
  const [error, setError] = useState<string | null>(null);

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setError(null);

    const formData = new FormData(e.currentTarget);

    const res = await signUp.email({
      name: formData.get("name") as string,
      email: formData.get("email") as string,
      password: formData.get("password") as string,
    });

    if (res.error) {
      setError(res.error.message || "Something went wrong.");
    } else {
      router.push("/dashboard");
    }
  }

  return (
    <main className="max-w-md mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Sign Up</h1>
      {error && <p className="text-red-500">{error}</p>} // [!code ++]
    </main>
  );
}
```

Finally, add the HTML form with input fields for the user's name, email, and password, and a submit button.

```tsx title="src/app/sign-up/page.tsx"
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { signUp } from "@/lib/auth-client";

export default function SignUpPage() {
  const router = useRouter();
  const [error, setError] = useState<string | null>(null);

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setError(null);

    const formData = new FormData(e.currentTarget);

    const res = await signUp.email({
      name: formData.get("name") as string,
      email: formData.get("email") as string,
      password: formData.get("password") as string,
    });

    if (res.error) {
      setError(res.error.message || "Something went wrong.");
    } else {
      router.push("/dashboard");
    }
  }

  return (
    <main className="max-w-md mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Sign Up</h1>
      {error && <p className="text-red-500">{error}</p>}
      <form onSubmit={handleSubmit} className="space-y-4">
        {" "}
        // [!code ++]
        <input // [!code ++]
          name="name" // [!code ++]
          placeholder="Full Name" // [!code ++]
          required // [!code ++]
          className="w-full rounded-md bg-neutral-900 border border-neutral-700 px-3 py-2" // [!code ++]
        />{" "}
        // [!code ++]
        <input // [!code ++]
          name="email" // [!code ++]
          type="email" // [!code ++]
          placeholder="Email" // [!code ++]
          required // [!code ++]
          className="w-full rounded-md bg-neutral-900 border border-neutral-700 px-3 py-2" // [!code ++]
        />{" "}
        // [!code ++]
        <input // [!code ++]
          name="password" // [!code ++]
          type="password" // [!code ++]
          placeholder="Password" // [!code ++]
          required // [!code ++]
          minLength={8} // [!code ++]
          className="w-full rounded-md bg-neutral-900 border border-neutral-700 px-3 py-2" // [!code ++]
        />{" "}
        // [!code ++]
        <button // [!code ++]
          type="submit" // [!code ++]
          className="w-full bg-white text-black font-medium rounded-md px-4 py-2 hover:bg-gray-200" // [!code ++]
        >
          {" "}
          // [!code ++] Create Account // [!code ++]
        </button>{" "}
        // [!code ++]
      </form>{" "}
      // [!code ++]
    </main>
  );
}
```

### 5.2. Sign in page [#52-sign-in-page]

For the sign-in page, start with the basic structure in `src/app/sign-in/page.tsx`.

```tsx title="src/app/sign-in/page.tsx"
"use client";

export default function SignInPage() {
  return (
    <main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Sign In</h1>
    </main>
  );
}
```

Now, add the state and router hooks, similar to the sign-up page.

```tsx title="src/app/sign-in/page.tsx"
"use client";

import { useState } from "react"; // [!code ++]
import { useRouter } from "next/navigation"; // [!code ++]

export default function SignInPage() {
  const router = useRouter(); // [!code ++]
  const [error, setError] = useState<string | null>(null); // [!code ++]

  return (
    <main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Sign In</h1>
    </main>
  );
}
```

Add the `handleSubmit` function, this time importing and using the `signIn.email` method from Better Auth.

```tsx title="src/app/sign-in/page.tsx"
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { signIn } from "@/lib/auth-client"; // [!code ++]

export default function SignInPage() {
  const router = useRouter();
  const [error, setError] = useState<string | null>(null);

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    // [!code ++]
    e.preventDefault(); // [!code ++]
    setError(null); // [!code ++]
    // [!code ++]
    const formData = new FormData(e.currentTarget); // [!code ++]
    // [!code ++]
    const res = await signIn.email({
      // [!code ++]
      email: formData.get("email") as string, // [!code ++]
      password: formData.get("password") as string, // [!code ++]
    }); // [!code ++]
    // [!code ++]
    if (res.error) {
      // [!code ++]
      setError(res.error.message || "Something went wrong."); // [!code ++]
    } else {
      // [!code ++]
      router.push("/dashboard"); // [!code ++]
    } // [!code ++]
  } // [!code ++]

  return (
    <main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Sign In</h1>
    </main>
  );
}
```

Add the conditional error message display.

```tsx title="src/app/sign-in/page.tsx"
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { signIn } from "@/lib/auth-client";

export default function SignInPage() {
  const router = useRouter();
  const [error, setError] = useState<string | null>(null);

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setError(null);

    const formData = new FormData(e.currentTarget);

    const res = await signIn.email({
      email: formData.get("email") as string,
      password: formData.get("password") as string,
    });

    if (res.error) {
      setError(res.error.message || "Something went wrong.");
    } else {
      router.push("/dashboard");
    }
  }

  return (
    <main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Sign In</h1>
      {error && <p className="text-red-500">{error}</p>} // [!code ++]
    </main>
  );
}
```

Finally, add the form fields for email and password and a sign-in button.

```tsx title="src/app/sign-in/page.tsx"
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { signIn } from "@/lib/auth-client";

export default function SignInPage() {
  const router = useRouter();
  const [error, setError] = useState<string | null>(null);

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setError(null);

    const formData = new FormData(e.currentTarget);

    const res = await signIn.email({
      email: formData.get("email") as string,
      password: formData.get("password") as string,
    });

    if (res.error) {
      setError(res.error.message || "Something went wrong.");
    } else {
      router.push("/dashboard");
    }
  }

  return (
    <main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Sign In</h1>
      {error && <p className="text-red-500">{error}</p>}
      <form onSubmit={handleSubmit} className="space-y-4">
        {" "}
        // [!code ++]
        <input // [!code ++]
          name="email" // [!code ++]
          type="email" // [!code ++]
          placeholder="Email" // [!code ++]
          required // [!code ++]
          className="w-full rounded-md bg-neutral-900 border border-neutral-700 px-3 py-2" // [!code ++]
        />{" "}
        // [!code ++]
        <input // [!code ++]
          name="password" // [!code ++]
          type="password" // [!code ++]
          placeholder="Password" // [!code ++]
          required // [!code ++]
          className="w-full rounded-md bg-neutral-900 border border-neutral-700 px-3 py-2" // [!code ++]
        />{" "}
        // [!code ++]
        <button // [!code ++]
          type="submit" // [!code ++]
          className="w-full bg-white text-black font-medium rounded-md px-4 py-2 hover:bg-gray-200" // [!code ++]
        >
          {" "}
          // [!code ++] Sign In // [!code ++]
        </button>{" "}
        // [!code ++]
      </form>{" "}
      // [!code ++]
    </main>
  );
}
```

### 5.3. Dashboard page [#53-dashboard-page]

This is the protected page for authenticated users. Start with the basic component in `src/app/dashboard/page.tsx`.

```tsx title="src/app/dashboard/page.tsx"
"use client";

export default function DashboardPage() {
  return (
    <main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Dashboard</h1>
    </main>
  );
}
```

Import the `useSession` hook from your Better Auth client. This hook is the key to managing authentication state on the client side. It provides the session data and a pending status.

```tsx title="src/app/dashboard/page.tsx"
"use client";

import { useRouter } from "next/navigation"; // [!code ++]
import { useSession } from "@/lib/auth-client"; // [!code ++]

export default function DashboardPage() {
  const router = useRouter(); // [!code ++]
  const { data: session, isPending } = useSession(); // [!code ++]

  return (
    <main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Dashboard</h1>
    </main>
  );
}
```

To protect this route, use a `useEffect` hook. This effect checks if the session has loaded (`!isPending`) and if there is no authenticated user (`!session?.user`). If both are true, it redirects the user to the sign-in page.

```tsx title="src/app/dashboard/page.tsx"
"use client";

import { useRouter } from "next/navigation";
import { useSession } from "@/lib/auth-client";
import { useEffect } from "react"; // [!code ++]

export default function DashboardPage() {
  const router = useRouter();
  const { data: session, isPending } = useSession();

  useEffect(() => {
    // [!code ++]
    if (!isPending && !session?.user) {
      // [!code ++]
      router.push("/sign-in"); // [!code ++]
    } // [!code ++]
  }, [isPending, session, router]); // [!code ++]

  return (
    <main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Dashboard</h1>
    </main>
  );
}
```

Add loading and redirecting states so the page does not flash an empty dashboard while the session is being verified.

```tsx title="src/app/dashboard/page.tsx"
"use client";

import { useRouter } from "next/navigation";
import { useSession } from "@/lib/auth-client";
import { useEffect } from "react";

export default function DashboardPage() {
  const router = useRouter();
  const { data: session, isPending } = useSession();

  useEffect(() => {
    if (!isPending && !session?.user) {
      router.push("/sign-in");
    }
  }, [isPending, session, router]);

  if (isPending)
    // [!code ++]
    return <p className="text-center mt-8 text-white">Loading...</p>; // [!code ++]
  if (!session?.user)
    // [!code ++]
    return <p className="text-center mt-8 text-white">Redirecting...</p>; // [!code ++]

  return (
    <main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Dashboard</h1>
    </main>
  );
}
```

Finally, if the user is authenticated, display their name and email from the `session` object. Also, import the `signOut` function and add a button that calls it, allowing the user to log out.

```tsx title="src/app/dashboard/page.tsx"
"use client";

import { useRouter } from "next/navigation";
import { useSession, signOut } from "@/lib/auth-client";
import { useEffect } from "react";

export default function DashboardPage() {
  const router = useRouter();
  const { data: session, isPending } = useSession();

  useEffect(() => {
    if (!isPending && !session?.user) {
      router.push("/sign-in");
    }
  }, [isPending, session, router]);

  if (isPending) return <p className="text-center mt-8 text-white">Loading...</p>;
  if (!session?.user) return <p className="text-center mt-8 text-white">Redirecting...</p>;

  const { user } = session; // [!code ++]

  return (
    <main className="max-w-md h-screen flex items-center justify-center flex-col mx-auto p-6 space-y-4 text-white">
      <h1 className="text-2xl font-bold">Dashboard</h1>
      <p>Welcome, {user.name || "User"}!</p>
      <p>Email: {user.email}</p>
      <button {/* [!code ++] */}
        onClick={() => signOut()} {/* [!code ++] */}
        className="w-full bg-white text-black font-medium rounded-md px-4 py-2 hover:bg-gray-200" {/* [!code ++] */}
      > {/* [!code ++] */}
        Sign Out {/* [!code ++] */}
      </button> {/* [!code ++] */}
    </main>
  );
}
```

### 5.4. Home page [#54-home-page]

Finally, update the home page to link to the sign-in and sign-up pages. Replace the contents of `src/app/page.tsx` with the following:

```tsx title="src/app/page.tsx"
"use client";

import { useRouter } from "next/navigation";

export default function Home() {
  const router = useRouter();

  return (
    <main className="flex items-center justify-center h-screen bg-neutral-950 text-white">
      <div className="flex gap-4">
        <button
          onClick={() => router.push("/sign-up")}
          className="bg-white text-black font-medium px-6 py-2 rounded-md hover:bg-gray-200"
        >
          Sign Up
        </button>
        <button
          onClick={() => router.push("/sign-in")}
          className="border border-white text-white font-medium px-6 py-2 rounded-md hover:bg-neutral-800"
        >
          Sign In
        </button>
      </div>
    </main>
  );
}
```

## 6. Test it out [#6-test-it-out]

Your application is now fully configured.

1. Start the development server to test it:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

2. Navigate to `http://localhost:3000` in your browser. You should see the home page with "Sign Up" and "Sign In" buttons.

3. Click on **Sign Up**, create a new account, and you should be redirected to the dashboard. You can then sign out and sign back in.

4. To view the user data directly in your database, you can use Prisma Studio.

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

5. This will open a new tab in your browser where you can see the `User`, `Session`, and `Account` tables and their contents.

> [!TIP]
> You now have a working authentication system built with Better Auth, Prisma, and Next.js.

## Next steps [#next-steps]

* Add support for social login or magic links
* Implement password reset and email verification
* Add user profile and account management pages
* Deploy to Vercel and secure your environment variables
* Extend your Prisma schema with custom application models

## Further reading [#further-reading]

* [Better Auth documentation](https://www.better-auth.com/docs)
* [Prisma documentation](https://www.prisma.io/docs/orm/v7)
* [Next.js App Router](https://nextjs.org/docs/app)

## Related pages

- [`Better Auth (with Astro)`](https://www.prisma.io/docs/guides/authentication/better-auth/astro): Learn how to use Prisma ORM in an Astro app with Better Auth

# Clerk (with Astro) (/docs/guides/authentication/clerk/astro)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in an Astro app with Clerk Auth

Location: Guides > Authentication > Clerk > Clerk (with Astro)

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is planned.

## Introduction [#introduction]

[Clerk](https://clerk.com/) is a drop-in auth provider that handles sign-up, sign-in, user management, and webhooks so you don't have to.

In this guide you'll wire Clerk into a brand-new [Astro](https://astro.build/) app and persist users in a [Prisma Postgres](https://prisma.io/postgres) database. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/clerk-astro).

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* [Clerk account](https://clerk.com)
* [ngrok account](https://ngrok.com)

## 1. Set up your project [#1-set-up-your-project]

Create a new Astro project:

  

#### bun

```bash
bun create astro@latest
```

#### pnpm

```bash
pnpm create astro@latest
```

#### yarn

```bash
yarn create astro@latest
```

#### npm

```bash
npm create astro@latest
```

It will prompt you to customize your setup. Choose the defaults:

> [!NOTE]
> * *How would you like to start your new project?* `Empty`
> * *Install dependencies?* `Yes`
> * *Initialize a new git repository?* `Yes`

Navigate into the newly created project directory:

```bash
cd <your-project-name>
```

## 2. Set up Clerk [#2-set-up-clerk]

### 2.1. Create a new Clerk application [#21-create-a-new-clerk-application]

[Sign in](https://dashboard.clerk.com/sign-in) to Clerk and navigate to the home page. From there, press the `Create Application` button to create a new application. Enter a title, select your sign-in options, and click `Create Application`.

> [!NOTE]
> For this guide, the Google, Github, and Email sign in options will be used.

Install the Clerk Astro SDK and Node adapter:

  

#### bun

```bash
bun add @clerk/astro @astrojs/node
```

#### pnpm

```bash
pnpm add @clerk/astro @astrojs/node
```

#### yarn

```bash
yarn add @clerk/astro @astrojs/node
```

#### npm

```bash
npm install @clerk/astro @astrojs/node
```

In the Clerk Dashboard, navigate to the **API keys** page. In the **Quick Copy** section, copy your Clerk Publishable and Secret Keys. Paste your keys into `.env` in the root of your project:

```bash title=".env"
PUBLIC_CLERK_PUBLISHABLE_KEY=<your-publishable-key>
CLERK_SECRET_KEY=<your-secret-key>
```

### 2.2. Configure Astro with Clerk [#22-configure-astro-with-clerk]

Astro needs to be configured for server-side rendering (SSR) with the Node adapter to work with Clerk. Update your `astro.config.mjs` file to include the Clerk integration and enable SSR:

```javascript title="astro.config.mjs"
import { defineConfig } from "astro/config";
import node from "@astrojs/node"; // [!code ++]
import clerk from "@clerk/astro"; // [!code ++]

export default defineConfig({
  integrations: [clerk()], // [!code ++]
  adapter: node({ mode: "standalone" }), // [!code ++]
  output: "server", // [!code ++]
});
```

### 2.3. Set up Clerk middleware [#23-set-up-clerk-middleware]

The `clerkMiddleware` helper enables authentication across your entire application. Create a `middleware.ts` file in the `src` directory:

```typescript title="src/middleware.ts"
import { clerkMiddleware } from "@clerk/astro/server";

export const onRequest = clerkMiddleware();
```

### 2.4. Add Clerk UI to your page [#24-add-clerk-ui-to-your-page]

Update your `src/pages/index.astro` file to import the Clerk authentication components:

```html title="src/pages/index.astro"
---
import { // [!code ++]
SignedIn, // [!code ++]
SignedOut, // [!code ++]
UserButton, // [!code ++]
SignInButton, // [!code ++]
} from "@clerk/astro/components"; // [!code ++]
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <meta name="generator" content="{Astro.generator}" />
    <title>Astro</title>
  </head>
  <body></body>
</html>
```

Now add a header with conditional rendering to show sign-in buttons for unauthenticated users and a user button for authenticated users:

```html title="src/pages/index.astro"
---
import {
SignedIn,
SignedOut,
UserButton,
SignInButton,
} from "@clerk/astro/components";
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <meta name="generator" content="{Astro.generator}" />
    <title>Astro</title>
  </head>
  <body>
    <header>
      // [!code ++]
      <SignedOut> // [!code ++] <SignInButton mode="modal" /> // [!code ++] </SignedOut> // [!code
      ++] <SignedIn> // [!code ++] <UserButton /> // [!code ++] </SignedIn> // [!code ++]
    </header>
    // [!code ++]
  </body>
</html>
```

## 3. Install and configure Prisma [#3-install-and-configure-prisma]

### 3.1. Install dependencies [#31-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma/` directory with a `schema.prisma` file
* A `prisma.config.ts` file with your Prisma configuration
* A `.env` file with a local `DATABASE_URL` already set

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 3.2. Define your Prisma Schema [#32-define-your-prisma-schema]

Add a `User` model that will store authenticated user information from Clerk. The `clerkId` field uniquely links each database user to their Clerk account:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id      Int     @id @default(autoincrement()) // [!code ++]
  clerkId String  @unique // [!code ++]
  email   String  @unique // [!code ++]
  name    String? // [!code ++]
} // [!code ++]
```

Run the following command to create the database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

After the migration is complete, generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This generates the Prisma Client in the `src/generated/prisma` directory.

### 3.3. Create TypeScript environment definitions [#33-create-typescript-environment-definitions]

Create an `env.d.ts` file in your `src` directory to provide TypeScript definitions for your environment variables:

```bash
touch src/env.d.ts
```

Add type definitions for all the environment variables your application uses:

```typescript title="src/env.d.ts"
interface ImportMetaEnv {
  readonly DATABASE_URL: string;
  readonly CLERK_WEBHOOK_SIGNING_SECRET: string;
  readonly CLERK_SECRET_KEY: string;
  readonly PUBLIC_CLERK_PUBLISHABLE_KEY: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}
```

### 3.4. Create a reusable Prisma Client [#34-create-a-reusable-prisma-client]

In the `src` directory, create a `lib` directory and a `prisma.ts` file inside it:

```bash
mkdir src/lib
touch src/lib/prisma.ts
```

Initialize the Prisma Client with the PostgreSQL adapter:

```typescript title="src/lib/prisma.ts"
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: import.meta.env.DATABASE_URL,
});

const prisma = new PrismaClient({
  adapter,
});

export default prisma;
```

## 4. Wire Clerk to the database [#4-wire-clerk-to-the-database]

### 4.1. Create a Clerk webhook endpoint [#41-create-a-clerk-webhook-endpoint]

Webhooks allow Clerk to notify your application when events occur, such as when a user signs up. You'll create an API route to handle these webhooks and sync user data to your database.

Create the directory structure and file for the webhook endpoint:

```bash
mkdir -p src/pages/api/webhooks
touch src/pages/api/webhooks/clerk.ts
```

Import the necessary dependencies:

```typescript title="src/pages/api/webhooks/clerk.ts"
import { verifyWebhook } from "@clerk/astro/webhooks";
import type { APIRoute } from "astro";
import prisma from "../../../lib/prisma";
```

Create the `POST` handler that Clerk will call. The `verifyWebhook` function validates that the request actually comes from Clerk using the signing secret:

```typescript title="src/pages/api/webhooks/clerk.ts"
import { verifyWebhook } from "@clerk/astro/webhooks";
import type { APIRoute } from "astro";
import prisma from "../../../lib/prisma";

export const POST: APIRoute = async ({ request }) => {
  // [!code ++]
  try {
    // [!code ++]
    const evt = await verifyWebhook(request, {
      // [!code ++]
      signingSecret: import.meta.env.CLERK_WEBHOOK_SIGNING_SECRET, // [!code ++]
    }); // [!code ++]
    const { id } = evt.data; // [!code ++]
    const eventType = evt.type; // [!code ++]
    console.log(
      // [!code ++]
      `Received webhook with ID ${id} and event type of ${eventType}`, // [!code ++]
    ); // [!code ++]
  } catch (err) {
    // [!code ++]
    console.error("Error verifying webhook:", err); // [!code ++]
    return new Response("Error verifying webhook", { status: 400 }); // [!code ++]
  } // [!code ++]
}; // [!code ++]
```

When a new user is created, they need to be stored in the database.

You'll do that by checking if the event type is `user.created` and then using Prisma's `upsert` method to create a new user if they don't exist:

```typescript title="src/pages/api/webhooks/clerk.ts"
import { verifyWebhook } from "@clerk/astro/webhooks";
import type { APIRoute } from "astro";
import prisma from "../../../lib/prisma";

export const POST: APIRoute = async ({ request }) => {
  try {
    const evt = await verifyWebhook(request, {
      signingSecret: import.meta.env.CLERK_WEBHOOK_SIGNING_SECRET,
    });
    const { id } = evt.data;
    const eventType = evt.type;
    console.log(`Received webhook with ID ${id} and event type of ${eventType}`);

    if (eventType === "user.created") {
      // [!code ++]
      const { id, email_addresses, first_name, last_name } = evt.data; // [!code ++]
      await prisma.user.upsert({
        // [!code ++]
        where: { clerkId: id }, // [!code ++]
        update: {}, // [!code ++]
        create: {
          // [!code ++]
          clerkId: id, // [!code ++]
          email: email_addresses[0].email_address, // [!code ++]
          name: `${first_name} ${last_name}`, // [!code ++]
        }, // [!code ++]
      }); // [!code ++]
    } // [!code ++]
  } catch (err) {
    console.error("Error verifying webhook:", err);
    return new Response("Error verifying webhook", { status: 400 });
  }
};
```

Finally, return a response to Clerk to confirm the webhook was received:

```typescript title="src/pages/api/webhooks/clerk.ts"
import { verifyWebhook } from "@clerk/astro/webhooks";
import type { APIRoute } from "astro";
import prisma from "../../../lib/prisma";

export const POST: APIRoute = async ({ request }) => {
  try {
    const evt = await verifyWebhook(request, {
      signingSecret: import.meta.env.CLERK_WEBHOOK_SIGNING_SECRET,
    });
    const { id } = evt.data;
    const eventType = evt.type;
    console.log(`Received webhook with ID ${id} and event type of ${eventType}`);

    if (eventType === "user.created") {
      const { id, email_addresses, first_name, last_name } = evt.data;
      await prisma.user.upsert({
        where: { clerkId: id },
        update: {},
        create: {
          clerkId: id,
          email: email_addresses[0].email_address,
          name: `${first_name} ${last_name}`,
        },
      });
    }

    return new Response("Webhook received", { status: 200 }); // [!code ++]
  } catch (err) {
    console.error("Error verifying webhook:", err);
    return new Response("Error verifying webhook", { status: 400 });
  }
};
```

### 4.2. Expose your local app for webhooks [#42-expose-your-local-app-for-webhooks]

You'll need to expose your local app for webhooks with [ngrok](https://ngrok.com/). This will allow Clerk to reach your `/api/webhooks/clerk` route to push events like `user.created`.

Start your development server:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

In a separate terminal window, install ngrok globally and expose your local app:

  

#### bun

```bash
bun add --global ngrok
ngrok http 4321
```

#### pnpm

```bash
pnpm add --global ngrok
ngrok http 4321
```

#### yarn

```bash
yarn global add ngrok
ngrok http 4321
```

#### npm

```bash
npm install --global ngrok
ngrok http 4321
```

Copy the ngrok `Forwarding URL` (e.g., `https://a65a60261342.ngrok-free.app`). This will be used to configure the webhook URL in Clerk.

### 4.3. Configure Astro to allow ngrok connections [#43-configure-astro-to-allow-ngrok-connections]

Astro needs to be configured to accept connections from the ngrok domain. Update your `astro.config.mjs` to include the ngrok host in the allowed hosts list:

```javascript title="astro.config.mjs"
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
import clerk from "@clerk/astro";

export default defineConfig({
  integrations: [clerk()],
  adapter: node({ mode: "standalone" }),
  output: "server",
  server: {
    // [!code ++]
    allowedHosts: ["localhost", "<your-ngrok-subdomain>.ngrok-free.app"], // [!code ++]
  }, // [!code ++]
});
```

> [!NOTE]
> Replace `<your-ngrok-subdomain>` with the subdomain from your ngrok URL. For example, if your ngrok URL is `https://a65a60261342.ngrok-free.app`, use `a65a60261342.ngrok-free.app`.

### 4.4. Register the webhook in Clerk [#44-register-the-webhook-in-clerk]

Navigate to the &#x2A;**Webhooks**&#x2A; section of your Clerk application located near the bottom of the &#x2A;**Configure**&#x2A; tab under &#x2A;**Developers***.

Click &#x2A;**Add Endpoint**&#x2A; and paste the ngrok URL into the &#x2A;**Endpoint URL*** field and add `/api/webhooks/clerk` to the end. It should look similar to this:

```text
https://a65a60261342.ngrok-free.app/api/webhooks/clerk
```

Subscribe to the **user.created*&#x2A; event by checking the box next to it under &#x2A;**Message Filtering***.

Click &#x2A;**Create*** to save the webhook endpoint.

Copy the &#x2A;**Signing Secret*** and add it to your `.env` file:

```bash title=".env"
# Prisma
DATABASE_URL=<your-database-url>

# Clerk
PUBLIC_CLERK_PUBLISHABLE_KEY=<your-publishable-key>
CLERK_SECRET_KEY=<your-secret-key>
CLERK_WEBHOOK_SIGNING_SECRET=<your-signing-secret> # [!code ++]
```

Restart your dev server to pick up the new environment variable:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

### 4.5. Test the integration [#45-test-the-integration]

Navigate to `http://localhost:4321` in your browser and sign in using any of the sign-up options you configured in Clerk.

Open Prisma Studio to verify that the user was created in your database:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

You should see a new user record with the Clerk ID, email, and name from your sign-up.

> [!NOTE]
> If you don't see a user record, there are a few things to check:
> 
> * Delete your user from the Users tab in Clerk and try signing up again.
> * Check your ngrok URL and ensure it's correct &#x2A;(it will change every time you restart ngrok)*.
> * Verify your Clerk webhook is pointing to the correct ngrok URL.
> * Make sure you've added `/api/webhooks/clerk` to the end of the webhook URL.
> * Ensure you've subscribed to the **user.created** event in Clerk.
> * Confirm you've added the ngrok host to `allowedHosts` in `astro.config.mjs` and removed `https://`.
> * Check the terminal running `npm run dev` for any error messages.

You now have an Astro application where Clerk handles authentication and every new sign-up is synced to your Prisma Postgres database through the webhook.

## Next steps [#next-steps]

Now that you have a working Astro app with Clerk authentication and Prisma connected to a Prisma Postgres database, you can:

* Add user profile management and update functionality
* Build protected API routes that require authentication
* Extend your schema with additional models related to users
* Deploy to your preferred hosting platform and set your production webhook URL in Clerk

### More info [#more-info]

* [Prisma Documentation](https://www.prisma.io/docs/orm/v7)
* [Astro Documentation](https://docs.astro.build)
* [Clerk Documentation](https://clerk.com/docs)

## Related pages

- [`Clerk (with Next.js)`](https://www.prisma.io/docs/guides/authentication/clerk/nextjs): Learn how to use Prisma ORM in a Next.js app with Clerk Auth

# Clerk (with Next.js) (/docs/guides/authentication/clerk/nextjs)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a Next.js app with Clerk Auth

Location: Guides > Authentication > Clerk > Clerk (with Next.js)

> [!NOTE]
> This guide uses Prisma ORM 7
> 
> The commands and code on this page target Prisma ORM 7, which remains fully supported. To start a new Prisma ORM 8 project, see the [Prisma ORM 8 quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql); to add Prisma ORM 8 to an existing app, see [Add to an existing project](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql). A Prisma ORM 8 version of this guide is planned.

## Introduction [#introduction]

[Clerk](https://clerk.com/) is a drop-in auth provider that handles sign-up, sign-in, user management, and webhooks so you don't have to.

In this guide you'll wire Clerk into a brand-new [Next.js](https://nextjs.org/) app, persist users in a [Prisma Postgres](https://prisma.io/postgres) database, and expose a tiny posts API. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/clerk-nextjs).

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* [Clerk account](https://clerk.com)
* [ngrok account](https://ngrok.com)

## 1. Set up your project [#1-set-up-your-project]

Create the app:

  

#### bun

```bash
bunx create-next-app@latest clerk-nextjs-prisma
```

#### pnpm

```bash
pnpm dlx create-next-app@latest clerk-nextjs-prisma
```

#### yarn

```bash
yarn dlx create-next-app@latest clerk-nextjs-prisma
```

#### npm

```bash
npx create-next-app@latest clerk-nextjs-prisma
```

It will prompt you to customize your setup. Choose the defaults:

> [!NOTE]
> * *Would you like to use TypeScript?* `Yes`
> * *Would you like to use ESLint?* `Yes`
> * *Would you like to use Tailwind CSS?* `Yes`
> * *Would you like your code inside a `src/` directory?* `No`
> * *Would you like to use App Router?* (recommended) `Yes`
> * *Would you like to use Turbopack for `next dev`?* `Yes`
> * _Would you like to customize the import alias (`@/_`by default)?\*`No`

Navigate to the project directory:

```bash
cd clerk-nextjs-prisma
```

## 2. Set up Clerk [#2-set-up-clerk]

### 2.1. Create a new Clerk application [#21-create-a-new-clerk-application]

[Sign in](https://dashboard.clerk.com/sign-in) to Clerk and navigate to the home page. From there, press the `Create Application` button to create a new application. Enter a title, select your sign-in options, and click `Create Application`.

> [!NOTE]
> For this guide, the Google, Github, and Email sign in options will be used.

Install the Clerk Next.js SDK:

  

#### bun

```bash
bun add @clerk/nextjs
```

#### pnpm

```bash
pnpm add @clerk/nextjs
```

#### yarn

```bash
yarn add @clerk/nextjs
```

#### npm

```bash
npm install @clerk/nextjs
```

Copy your Clerk keys and paste them into **.env** in the root of your project:

```bash title=".env"
# Clerk # [!code ++]
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=<your-publishable-key> # [!code ++]
CLERK_SECRET_KEY=<your-secret-key> # [!code ++]
```

### 2.2. Protect routes with Clerk middleware [#22-protect-routes-with-clerk-middleware]

The `clerkMiddleware` helper enables authentication and is where you'll configure your protected routes.

Create a `middleware.ts` file in the root directory of your project:

```tsx title="middleware.ts" showLineNumbers
import { clerkMiddleware } from "@clerk/nextjs/server"; // [!code ++]
// [!code ++]
export default clerkMiddleware(); // [!code ++]
// [!code ++]
export const config = {
  // [!code ++]
  matcher: [
    // [!code ++]
    "/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)", // [!code ++]
    "/(api|trpc)(.*)", // [!code ++]
  ], // [!code ++]
}; // [!code ++]
```

### 2.3. Add Clerk UI to your layout [#23-add-clerk-ui-to-your-layout]

Next, you'll need to wrap your app in the `ClerkProvider` component to make authentication globally available.

In your `layout.tsx` file, add the `ClerkProvider` component:

```tsx title="app/layout.tsx" showLineNumbers
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { ClerkProvider } from "@clerk/nextjs"; // [!code ++]

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <ClerkProvider>
      {" "}
      // [!code ++]
      <html lang="en">
        <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
          {children}
        </body>
      </html>
    </ClerkProvider> // [!code ++]
  );
}
```

Create a `Navbar` component which will be used to display the Sign In and Sign Up buttons as well as the User Button once a user is signed in:

```tsx title="app/layout.tsx" showLineNumbers
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import {
  ClerkProvider,
  UserButton, // [!code ++]
  SignInButton, // [!code ++]
  SignUpButton, // [!code ++]
  SignedOut, // [!code ++]
  SignedIn, // [!code ++]
} from "@clerk/nextjs";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
          <Navbar /> // [!code ++]
          {children}
        </body>
      </html>
    </ClerkProvider>
  );
}

const Navbar = () => {
  // [!code ++]
  return (
    // [!code ++]
    <header className="flex justify-end items-center p-4 gap-4 h-16">
      {" "}
      // [!code ++]
      <SignedOut>
        {" "}
        // [!code ++]
        <SignInButton /> // [!code ++]
        <SignUpButton /> // [!code ++]
      </SignedOut>{" "}
      // [!code ++]
      <SignedIn>
        {" "}
        // [!code ++]
        <UserButton /> // [!code ++]
      </SignedIn>{" "}
      // [!code ++]
    </header> // [!code ++]
  ); // [!code ++]
}; // [!code ++]
```

## 3. Install and configure Prisma [#3-install-and-configure-prisma]

### 3.1. Install dependencies [#31-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../app/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../app/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../app/generated/prisma
```

#### npm

```bash
npx prisma init --output ../app/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma/` directory with a `schema.prisma` file
* A local `DATABASE_URL` in `.env`

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 3.2. Define your Prisma Schema [#32-define-your-prisma-schema]

In the `prisma/schema.prisma` file, add the following models:

```prisma title="prisma/schema.prisma" showLineNumbers
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id      Int     @id @default(autoincrement()) // [!code ++]
  clerkId String  @unique // [!code ++]
  email   String  @unique // [!code ++]
  name    String? // [!code ++]
  posts   Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
  createdAt DateTime @default(now()) // [!code ++]
} // [!code ++]
```

This will create two models: `User` and `Post`, with a one-to-many relationship between them.

Create a `prisma.config.ts` file to configure Prisma:

```typescript title="prisma.config.ts" showLineNumbers
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config"; // [!code ++]
// [!code ++]
export default defineConfig({
  // [!code ++]
  schema: "prisma/schema.prisma", // [!code ++]
  migrations: {
    // [!code ++]
    path: "prisma/migrations", // [!code ++]
  }, // [!code ++]
  datasource: {
    // [!code ++]
    url: env("DATABASE_URL"), // [!code ++]
  }, // [!code ++]
}); // [!code ++]
```

> [!NOTE]
> You'll need to install the `dotenv` package:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 

Now, run the following command to create the database tables and generate the Prisma Client:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

> [!WARNING]
> It is recommended that you add `/app/generated/prisma` to your `.gitignore` file.

### 3.3. Create a reusable Prisma Client [#33-create-a-reusable-prisma-client]

In the root directory, create a `lib` directory and a `prisma.ts` file inside it:

```tsx title="lib/prisma.ts" showLineNumbers
import { PrismaClient } from "../app/generated/prisma/client"; // [!code ++]
import { PrismaPg } from "@prisma/adapter-pg"; // [!code ++]
// [!code ++]
const adapter = new PrismaPg({
  // [!code ++]
  connectionString: process.env.DATABASE_URL!, // [!code ++]
}); // [!code ++]
// [!code ++]
const globalForPrisma = global as unknown as {
  // [!code ++]
  prisma: PrismaClient; // [!code ++]
}; // [!code ++]
// [!code ++]
const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    // [!code ++]
    adapter, // [!code ++]
  }); // [!code ++]
// [!code ++]
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma; // [!code ++]
// [!code ++]
export default prisma; // [!code ++]
```

## 4. Wire Clerk to the database [#4-wire-clerk-to-the-database]

### 4.1. Create a Clerk webhook endpoint [#41-create-a-clerk-webhook-endpoint]

Create a new API route at `app/api/webhooks/clerk/route.ts`:

Import the necessary dependencies:

```tsx title="app/api/webhooks/clerk/route.ts" showLineNumbers
import { verifyWebhook } from "@clerk/nextjs/webhooks"; // [!code ++]
import { NextRequest } from "next/server"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
```

Create the `POST` method that Clerk will call and verify the webhook:

```tsx title="app/api/webhooks/clerk/route.ts" showLineNumbers
import { verifyWebhook } from "@clerk/nextjs/webhooks";
import { NextRequest } from "next/server";
import prisma from "@/lib/prisma";

export async function POST(req: NextRequest) {
  // [!code ++]
  try {
    // [!code ++]
    const evt = await verifyWebhook(req); // [!code ++]
    const { id } = evt.data; // [!code ++]
    const eventType = evt.type; // [!code ++]
    console.log(
      // [!code ++]
      `Received webhook with ID ${id} and event type of ${eventType}`, // [!code ++]
    ); // [!code ++]
  } catch (err) {
    // [!code ++]
    console.error("Error verifying webhook:", err); // [!code ++]
    return new Response("Error verifying webhook", { status: 400 }); // [!code ++]
  } // [!code ++]
} // [!code ++]
```

When a new user is created, they need to be stored in the database.

You'll do that by checking if the event type is `user.created` and then using Prisma's `upsert` method to create a new user if they don't exist:

```tsx title="app/api/webhooks/clerk/route.ts" showLineNumbers
import { verifyWebhook } from "@clerk/nextjs/webhooks";
import { NextRequest } from "next/server";
import prisma from "@/lib/prisma";

export async function POST(req: NextRequest) {
  try {
    const evt = await verifyWebhook(req);
    const { id } = evt.data;
    const eventType = evt.type;
    console.log(`Received webhook with ID ${id} and event type of ${eventType}`);

    if (eventType === "user.created") {
      // [!code ++]
      const { id, email_addresses, first_name, last_name } = evt.data; // [!code ++]
      await prisma.user.upsert({
        // [!code ++]
        where: { clerkId: id }, // [!code ++]
        update: {}, // [!code ++]
        create: {
          // [!code ++]
          clerkId: id, // [!code ++]
          email: email_addresses[0].email_address, // [!code ++]
          name: `${first_name} ${last_name}`, // [!code ++]
        }, // [!code ++]
      }); // [!code ++]
    } // [!code ++]
  } catch (err) {
    console.error("Error verifying webhook:", err);
    return new Response("Error verifying webhook", { status: 400 });
  }
}
```

Finally, return a response to Clerk to confirm the webhook was received:

```tsx title="app/api/webhooks/clerk/route.ts" showLineNumbers
import { verifyWebhook } from "@clerk/nextjs/webhooks";
import { NextRequest } from "next/server";
import prisma from "@/lib/prisma";

export async function POST(req: NextRequest) {
  try {
    const evt = await verifyWebhook(req);
    const { id } = evt.data;
    const eventType = evt.type;
    console.log(`Received webhook with ID ${id} and event type of ${eventType}`);

    if (eventType === "user.created") {
      const { id, email_addresses, first_name, last_name } = evt.data;
      await prisma.user.upsert({
        where: { clerkId: id },
        update: {},
        create: {
          clerkId: id,
          email: email_addresses[0].email_address,
          name: `${first_name} ${last_name}`,
        },
      });
    }

    return new Response("Webhook received", { status: 200 }); // [!code ++]
  } catch (err) {
    console.error("Error verifying webhook:", err);
    return new Response("Error verifying webhook", { status: 400 });
  }
}
```

### 4.2. Expose your local app for webhooks [#42-expose-your-local-app-for-webhooks]

You'll need to expose your local app for webhooks with [ngrok](https://ngrok.com/). This will allow Clerk to reach your `/api/webhooks/clerk` route to push events like `user.created`.

Install ngrok and expose your local app:

  

#### bun

```bash
bun add --global ngrok
ngrok http 3000
```

#### pnpm

```bash
pnpm add --global ngrok
ngrok http 3000
```

#### yarn

```bash
yarn global add ngrok
ngrok http 3000
```

#### npm

```bash
npm install --global ngrok
ngrok http 3000
```

Copy the ngrok `Forwarding URL`. This will be used to set the webhook URL in Clerk.

Navigate to the &#x2A;**Webhooks**&#x2A; section of your Clerk application located near the bottom of the &#x2A;**Configure**&#x2A; tab under &#x2A;**Developers***.

Click &#x2A;**Add Endpoint**&#x2A; and paste the ngrok URL into the &#x2A;**Endpoint URL*** field and add `/api/webhooks/clerk` to the end of the URL. It should look similar to this:

```text
https://a60b-99-42-62-240.ngrok-free.app/api/webhooks/clerk
```

Copy the &#x2A;**Signing Secret*** and add it to your `.env` file:

```bash title=".env"
# Prisma
DATABASE_URL=<your-database-url>

# Clerk
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=<your-publishable-key>
CLERK_SECRET_KEY=<your-secret-key>
CLERK_WEBHOOK_SIGNING_SECRET=<your-signing-secret> # [!code ++]
```

On the home page, press Sign Up and create an account using any of the sign-up options

Open Prisma Studio and you should see a user record.

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

> [!NOTE]
> If you don't see a user record, there are a few things to check:
> 
> * Delete your user from the Users tab in Clerk and try again.
> * Check your ngrok URL and ensure it's correct &#x2A;(it will change everytime you restart ngrok)*.
> * Check your Clerk webhook is pointing to the correct ngrok URL.
> * Make sure you've added `/api/webhooks/clerk` to the end of the URL.

## 5. Build a posts API [#5-build-a-posts-api]

To create posts under a user, you'll need to create a new API route at `app/api/posts/route.ts`:

Start by importing the necessary dependencies:

```tsx title="app/api/posts/route.ts" showLineNumbers
import { auth } from "@clerk/nextjs/server"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
```

Get the `clerkId` of the authenticated user. If there's no user, return a `401` Unauthorized response:

```tsx title="app/api/posts/route.ts" showLineNumbers
import { auth } from "@clerk/nextjs/server";
import prisma from "@/lib/prisma";

export async function POST(req: Request) {
  // [!code ++]
  const { userId: clerkId } = await auth(); // [!code ++]
  if (!clerkId) return new Response("Unauthorized", { status: 401 }); // [!code ++]
} // [!code ++]
```

Match the Clerk user to a user in the database. If none is found, return a `404` Not Found response:

```tsx title="app/api/posts/route.ts" showLineNumbers
import { auth } from "@clerk/nextjs/server";
import prisma from "@/lib/prisma";

export async function POST(req: Request) {
  const { userId: clerkId } = await auth();
  if (!clerkId) return new Response("Unauthorized", { status: 401 });

  const user = await prisma.user.findUnique({
    // [!code ++]
    where: { clerkId }, // [!code ++]
  }); // [!code ++]
  // [!code ++]
  if (!user) return new Response("User not found", { status: 404 }); // [!code ++]
}
```

Destructure the title and content from the incoming request and create a post. Once done, return a `201` Created response:

```tsx title="app/api/posts/route.ts" showLineNumbers
import { auth } from "@clerk/nextjs/server";
import prisma from "@/lib/prisma";

export async function POST(req: Request) {
  const { userId: clerkId } = await auth();
  if (!clerkId) return new Response("Unauthorized", { status: 401 });

  const { title, content } = await req.json(); // [!code ++]

  const user = await prisma.user.findUnique({
    where: { clerkId },
  });

  if (!user) return new Response("User not found", { status: 404 });

  const post = await prisma.post.create({
    // [!code ++]
    data: {
      // [!code ++]
      title, // [!code ++]
      content, // [!code ++]
      authorId: user.id, // [!code ++]
    }, // [!code ++]
  }); // [!code ++]

  return new Response(JSON.stringify(post), { status: 201 }); // [!code ++]
}
```

## 6. Add a Post creation UI [#6-add-a-post-creation-ui]

In `/app`, create a `/components` directory and a `PostInputs.tsx` file inside it:

```tsx title="app/components/PostInputs.tsx" showLineNumbers
"use client"; // [!code ++]

import { useState } from "react"; // [!code ++]

export default function PostInputs() {
  // [!code ++]
  const [title, setTitle] = useState(""); // [!code ++]
  const [content, setContent] = useState(""); // [!code ++]
} // [!code ++]
```

This component uses `"use client"` to ensure the component is rendered on the client. The title and content are stored in their own `useState` hooks.

Create a function that will be called when a form is submitted:

```tsx title="app/components/PostInputs.tsx" showLineNumbers
"use client";

import { useState } from "react";

export default function PostInputs() {
  const [title, setTitle] = useState("");
  const [content, setContent] = useState("");

  async function createPost(e: React.FormEvent) {
    // [!code ++]
    e.preventDefault(); // [!code ++]
    if (!title || !content) return; // [!code ++]
    // [!code ++]
    await fetch("/api/posts", {
      // [!code ++]
      method: "POST", // [!code ++]
      headers: { "Content-Type": "application/json" }, // [!code ++]
      body: JSON.stringify({ title, content }), // [!code ++]
    }); // [!code ++]
    // [!code ++]
    setTitle(""); // [!code ++]
    setContent(""); // [!code ++]
    location.reload(); // [!code ++]
  } // [!code ++]
}
```

You'll be using a form to create a post and call the `POST` route you created earlier:

```tsx title="app/components/PostInputs.tsx" showLineNumbers
"use client";

import { useState } from "react";

export default function PostInputs() {
  const [title, setTitle] = useState("");
  const [content, setContent] = useState("");

  async function createPost(e: React.FormEvent) {
    e.preventDefault();
    if (!title || !content) return;

    await fetch("/api/posts", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ title, content }),
    });

    setTitle("");
    setContent("");
    location.reload();
  }

  return (
    // [!code ++]
    <form onSubmit={createPost} className="space-y-2">
      {" "}
      // [!code ++]
      <input // [!code ++]
        type="text" // [!code ++]
        placeholder="Title" // [!code ++]
        value={title} // [!code ++]
        onChange={(e) => setTitle(e.target.value)} // [!code ++]
        className="w-full p-2 border border-zinc-800 rounded" // [!code ++]
      />{" "}
      // [!code ++]
      <textarea // [!code ++]
        placeholder="Content" // [!code ++]
        value={content} // [!code ++]
        onChange={(e) => setContent(e.target.value)} // [!code ++]
        className="w-full p-2 border border-zinc-800 rounded" // [!code ++]
      />{" "}
      // [!code ++]
      <button className="w-full p-2 border border-zinc-800 rounded">
        {" "}
        // [!code ++] Post // [!code ++]
      </button>{" "}
      // [!code ++]
    </form> // [!code ++]
  ); // [!code ++]
}
```

On submit:

* It sends a `POST` request to the `/api/posts` route
* Clears the input fields
* Reloads the page to show the new post

## 7. Set up `page.tsx` [#7-set-up-pagetsx]

Now, update the `page.tsx` file to fetch posts, show the form, and render the list.

Delete everything within `page.tsx`, leaving only the following:

```tsx title="app/page.tsx" showLineNumbers
export default function Home() {
  return ()
}
```

Import the necessary dependencies:

```tsx title="app/page.tsx" showLineNumbers
import { currentUser } from "@clerk/nextjs/server"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
import PostInputs from "@/app/components/PostInputs"; // [!code ++]

export default function Home() {
  return ()
}
```

To ensure only signed-in users can access the post functionality, update the `Home` component to check for a user:

```tsx title="app/page.tsx" showLineNumbers
import { currentUser } from "@clerk/nextjs/server"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
import PostInputs from "@/app/components/PostInputs"; // [!code ++]

export default async function Home() {
  const user = await currentUser(); // [!code ++]
  if (!user) return <div className="flex justify-center">Sign in to post</div>; // [!code ++]

  return ()
}
```

Once a user is found, fetch that user's posts from the database:

```tsx title="app/page.tsx" showLineNumbers
import { currentUser } from "@clerk/nextjs/server"; // [!code ++]
import prisma from "@/lib/prisma"; // [!code ++]
import PostInputs from "@/app/components/PostInputs"; // [!code ++]

export default async function Home() {
  const user = await currentUser();
  if (!user) return <div className="flex justify-center">Sign in to post</div>;

  const posts = await prisma.post.findMany({ // [!code ++]
    where: { author: { clerkId: user.id } }, // [!code ++]
    orderBy: { createdAt: "desc" }, // [!code ++]
  }); // [!code ++]

  return ()
}
```

Finally, render the form and post list:

```tsx title="app/page.tsx" showLineNumbers
import { currentUser } from "@clerk/nextjs/server";
import prisma from "@/lib/prisma";
import PostInputs from "@/app/components/PostInputs";

export default async function Home() {
  const user = await currentUser();
  if (!user) return <div className="flex justify-center">Sign in to post</div>;

  const posts = await prisma.post.findMany({
    where: { author: { clerkId: user.id } },
    orderBy: { createdAt: "desc" },
  });

  return (
    <main className="max-w-2xl mx-auto p-4">
      {" "}
      // [!code ++]
      <PostInputs /> // [!code ++]
      <div className="mt-8">
        {" "}
        // [!code ++]
        {posts.map(
          (
            post, // [!code ++]
          ) => (
            <div // [!code ++]
              key={post.id} // [!code ++]
              className="p-4 border border-zinc-800 rounded mt-4"
            >
              {" "}
              // [!code ++]
              <h2 className="font-bold">{post.title}</h2> // [!code ++]
              <p className="mt-2">{post.content}</p> // [!code ++]
            </div> // [!code ++]
          ),
        )}{" "}
        // [!code ++]
      </div>{" "}
      // [!code ++]
    </main> // [!code ++]
  );
}
```

You now have a Next.js application where Clerk handles authentication, new sign-ups are synced to your Prisma Postgres database through the webhook, and signed-in users can create and list their own posts.

## Next Steps [#next-steps]

* Add delete functionality to posts and users.
* Add a search bar to filter posts.
* Deploy to Vercel and set your production webhook URL in Clerk.

### More Info [#more-info]

* [Prisma Docs](https://www.prisma.io/docs/orm/v7)
* [Next.js Docs](https://nextjs.org/docs)
* [Clerk Docs](https://clerk.com/docs)

## Related pages

- [`Clerk (with Astro)`](https://www.prisma.io/docs/guides/authentication/clerk/astro): Learn how to use Prisma ORM in an Astro app with Clerk Auth

# Expand-and-contract migrations (Prisma ORM v7) (/docs/guides/v7/database/data-migration)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to perform data migrations using the expand and contract pattern with Prisma ORM

Location: Guides > v7 > Database > Expand-and-contract migrations

## Introduction [#introduction]

When you change your database schema in production, you need to keep the data consistent and avoid downtime. This guide shows you how to use the expand and contract pattern to safely migrate data between columns. The example replaces a boolean field with an enum field while preserving existing data.

## Prerequisites [#prerequisites]

Before starting this guide, make sure you have:

* Node.js installed (version 20 or higher)
* A Prisma ORM project with an existing schema
* A supported database (PostgreSQL, MySQL, SQLite, SQL Server, etc.)
* Access to both development and production databases
* Basic understanding of Git branching
* Basic familiarity with TypeScript

## 1. Set up your environment [#1-set-up-your-environment]

### 1.1. Review initial schema [#11-review-initial-schema]

Start with a basic schema containing a Post model:

```prisma
generator client {
  provider = "prisma-client"
  output   = "./generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
}
```

### 1.2. Configure Prisma [#12-configure-prisma]

Create a `prisma.config.ts` file in the root of your project with the following content:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

> [!NOTE]
> You'll need to install the required packages. If you haven't already, install them using your package manager:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add prisma@prev tsx @types/pg --dev
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add prisma@prev tsx @types/pg --save-dev
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add prisma@prev tsx @types/pg --dev
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install prisma@prev tsx @types/pg --save-dev
>     ```
>
> 
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
>     ```
>
> 
> 
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

### 1.3. Create a development branch [#13-create-a-development-branch]

Create a new branch for your changes:

```bash
git checkout -b create-status-field
```

## 2. Expand the schema [#2-expand-the-schema]

### 2.1. Add new column [#21-add-new-column]

Update your schema to add the new Status enum and field:

```prisma
model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean? @default(false)
  status    Status   @default(Unknown)
}

enum Status {
  Unknown
  Draft
  InProgress
  InReview
  Published
}
```

### 2.2. Create migration [#22-create-migration]

Generate the migration:

  

#### bun

```bash
bunx prisma migrate dev --name add-status-column
```

#### pnpm

```bash
pnpm prisma migrate dev --name add-status-column
```

#### yarn

```bash
yarn prisma migrate dev --name add-status-column
```

#### npm

```bash
npx prisma migrate dev --name add-status-column
```

Then generate Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 3. Migrate the data [#3-migrate-the-data]

### 3.1. Create migration script [#31-create-migration-script]

Create a new TypeScript file for the data migration:

```typescript
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
import "dotenv/config";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
});

const prisma = new PrismaClient({
  adapter,
});

async function main() {
  await prisma.$transaction(async (tx) => {
    const posts = await tx.post.findMany();
    for (const post of posts) {
      await tx.post.update({
        where: { id: post.id },
        data: {
          status: post.published ? "Published" : "Unknown",
        },
      });
    }
  });
}

main()
  .catch(async (e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => await prisma.$disconnect());
```

### 3.2. Set up migration script [#32-set-up-migration-script]

Add the migration script to your package.json:

```json
{
  "scripts": {
    "data-migration:add-status-column": "tsx ./prisma/migrations/<migration-timestamp>/data-migration.ts"
  }
}
```

### 3.3. Execute migration [#33-execute-migration]

1. Update your DATABASE_URL to point to the production database
2. Run the migration script:

  

#### bun

```bash
bun run data-migration:add-status-column
```

#### pnpm

```bash
pnpm run data-migration:add-status-column
```

#### yarn

```bash
yarn data-migration:add-status-column
```

#### npm

```bash
npm run data-migration:add-status-column
```

## 4. Contract the schema [#4-contract-the-schema]

### 4.1. Create cleanup branch [#41-create-cleanup-branch]

Create a new branch for removing the old column:

```bash
git checkout -b drop-published-column
```

### 4.2. Remove old column [#42-remove-old-column]

Update your schema to remove the published field:

```prisma
model Post {
  id      Int      @id @default(autoincrement())
  title   String
  content String?
  status  Status   @default(Draft)
}

enum Status {
  Draft
  InProgress
  InReview
  Published
}
```

### 4.3. Generate cleanup migration [#43-generate-cleanup-migration]

Create and run the final migration:

  

#### bun

```bash
bunx prisma migrate dev --name drop-published-column
```

#### pnpm

```bash
pnpm prisma migrate dev --name drop-published-column
```

#### yarn

```bash
yarn prisma migrate dev --name drop-published-column
```

#### npm

```bash
npx prisma migrate dev --name drop-published-column
```

Then generate Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 5. Deploy to production [#5-deploy-to-production]

### 5.1. Set up deployment [#51-set-up-deployment]

Add the following command to your CI/CD pipeline:

  

#### bun

```bash
bunx prisma migrate deploy
```

#### pnpm

```bash
pnpm prisma migrate deploy
```

#### yarn

```bash
yarn prisma migrate deploy
```

#### npm

```bash
npx prisma migrate deploy
```

### 5.2. Monitor deployment [#52-monitor-deployment]

Watch for any errors in your logs and monitor your application's behavior after deployment.

## Troubleshooting [#troubleshooting]

### Common issues and solutions [#common-issues-and-solutions]

1. **Migration fails due to missing default**
   * Ensure you've added a proper default value
   * Check that all existing records can be migrated

2. **Data loss prevention**
   * Always backup your database before running migrations
   * Test migrations on a copy of production data first

3. **Transaction rollback**
   * If the data migration fails, the transaction will automatically rollback
   * Fix any errors and retry the migration

## Next steps [#next-steps]

Now that you've completed your first expand and contract migration, you can:

* Learn more about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)
* Explore [schema prototyping](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema)
* Understand [customizing migrations](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations)

For more information:

* [Expand and Contract Pattern Documentation](https://www.prisma.io/dataguide/types/relational/expand-and-contract-pattern)
* [Prisma Migrate Workflows](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production)

## Related pages

- [`Multiple databases`](https://www.prisma.io/docs/guides/v7/database/multiple-databases): Learn how to use multiple Prisma Clients in a single app to connect to multiple databases, handle migrations, and deploy your application to Vercel
- [`Schema management in teams`](https://www.prisma.io/docs/guides/v7/database/schema-changes): Learn how to use Prisma Migrate effectively when collaborating on a project as a team

# Multiple databases (Prisma ORM v7) (/docs/guides/v7/database/multiple-databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use multiple Prisma Clients in a single app to connect to multiple databases, handle migrations, and deploy your application to Vercel

Location: Guides > v7 > Database > Multiple databases

## Introduction [#introduction]

This guide shows you how to use multiple databases using Prisma ORM in a single [Next.js app](https://nextjs.org/). You will learn how to connect to two different Prisma Postgres databases, manage migrations, and deploy your application to Vercel. This approach is useful for multi-tenant applications or when you need to separate concerns when managing connections to multiple databases.

## Prerequisites [#prerequisites]

Before you begin, make sure that you have the following:

* Node.js 20+ installed.
* A [Prisma Data Platform account](https://pris.ly/pdp?utm_campaign=multi-client\&utm_source=docs).
* A Vercel account (if you plan to deploy your application).

## 1. Set up a Next.js project [#1-set-up-a-nextjs-project]

Create a new Next.js app using `create-next-app` from your desired directory:

  

#### bun

```bash
bunx create-next-app@latest my-multi-client-app
```

#### pnpm

```bash
pnpm dlx create-next-app@latest my-multi-client-app
```

#### yarn

```bash
yarn dlx create-next-app@latest my-multi-client-app
```

#### npm

```bash
npx create-next-app@latest my-multi-client-app
```

You will be prompted to answer a few questions about your project. Select all of the defaults.

> [!NOTE]
> For completeness, those are:
> 
> * TypeScript
> * ESLint
> * Tailwind CSS
> * No `src` directory
> * App Router
> * Turbopack
> * Default custom import alias: `@/*`

Then, navigate to the project directory:

```bash
cd my-multi-client-app
```

## 2. Set up your databases and Prisma Clients [#2-set-up-your-databases-and-prisma-clients]

In this section, you will create two separate Prisma Postgres instances, one for user data and one for post data. You will also configure the Prisma schema and environment variables for each.

First, install Prisma and the required dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

You have installed the required dependencies for the project.

### 2.1. Create a Prisma Postgres instance to contain user data [#21-create-a-prisma-postgres-instance-to-contain-user-data]

Initialize Prisma with a [Prisma Postgres](https://www.prisma.io/docs/postgres) instance by running:

  

#### bun

```bash
bunx --bun prisma@prev init --db
```

#### pnpm

```bash
pnpm dlx prisma@prev init --db
```

#### yarn

```bash
yarn dlx prisma@prev init --db
```

#### npm

```bash
npx prisma@prev init --db
```

> [!NOTE]
> If you are not using a Prisma Postgres database, do not use the `--db` flag. Instead, create two PostgreSQL database instances and add their connection URLs to the `.env` file as `PPG_USER_DATABASE_URL` and `PPG_POST_DATABASE_URL`.

Follow the prompts to name your project and choose a database region.

The `prisma@prev init --db` command:

* Connects your CLI to your [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides) account. If you are not logged in or do not have an account, your browser will open to guide you through creating a new account or signing into your existing one.
* Creates a `prisma` directory containing a `schema.prisma` file for your database models.
* Creates a `.env` file with your `DATABASE_URL` (e.g., `DATABASE_URL="postgresql://user:password@host:5432/database?sslmode=require"`).

Rename the `prisma` folder to `prisma-user-database`:

```bash
mv prisma prisma-user-database
```

Edit your `.env` file to rename `DATABASE_URL` to `PPG_USER_DATABASE_URL`:

```bash title=".env"
DATABASE_URL="postgresql://user:password@host:5432/database?sslmode=require" # [!code --]
PPG_USER_DATABASE_URL="postgresql://user:password@host:5432/database?sslmode=require" # [!code ++]
```

Open `prisma-user-database/schema.prisma` file and update it to define a `User` model. Also, set the environment variable and specify a [custom `output` directory](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider) for the generated Prisma Client:

```prisma title="prisma-user-database/schema.prisma"
generator client {
  provider = "prisma-client"
  output = "../prisma-user-database/user-database-client-types" // [!code ++]
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
} // [!code ++]
```

Create a `prisma.config.ts` file for the user database:

```typescript title="prisma-user-database/prisma.config.ts"
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config"; // [!code ++]
// [!code ++]
export default defineConfig({
  // [!code ++]
  schema: "prisma-user-database/schema.prisma", // [!code ++]
  migrations: {
    // [!code ++]
    path: "prisma-user-database/migrations", // [!code ++]
  }, // [!code ++]
  datasource: {
    // [!code ++]
    url: env("PPG_USER_DATABASE_URL"), // [!code ++]
  }, // [!code ++]
}); // [!code ++]
```

> [!NOTE]
> You'll need to install the `dotenv` package if you haven't already:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 

Your user database schema is now ready.

### 2.2. Create a Prisma Postgres instance for post data [#22-create-a-prisma-postgres-instance-for-post-data]

Repeat the initialization for the post database:

  

#### bun

```bash
bunx --bun prisma init
bunx create-db
```

#### pnpm

```bash
pnpm prisma init
pnpm dlx create-db
```

#### yarn

```bash
yarn prisma init
yarn dlx create-db
```

#### npm

```bash
npx prisma init
npx create-db
```

Replace the generated `DATABASE_URL` in your `.env` file with the value from `npx create-db`, then rename the new `prisma` folder to `prisma-post-database`:

```bash
mv prisma prisma-post-database
```

Rename the `DATABASE_URL` variable in `.env` to `PPG_POST_DATABASE_URL`:

```bash title=".env"
DATABASE_URL="postgresql://user:password@host:5432/database?sslmode=require" # [!code --]
PPG_POST_DATABASE_URL="postgresql://user:password@host:5432/database?sslmode=require" # [!code ++]
```

Edit the `prisma-post-database/schema.prisma` file to define a `Post` model. Also, update the datasource URL and set a [custom `output` directory](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider):

```prisma title="prisma-post-database/schema.prisma"
generator client {
  provider = "prisma-client"
  output = "../prisma-post-database/post-database-client-types" // [!code ++]
}

datasource db {
  provider = "postgresql"
}

model Post { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  title String // [!code ++]
  content  String? // [!code ++]
} // [!code ++]
```

Create a `prisma.config.ts` file for the post database:

```typescript title="prisma-post-database/prisma.config.ts"
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config"; // [!code ++]
// [!code ++]
export default defineConfig({
  // [!code ++]
  schema: "prisma-post-database/schema.prisma", // [!code ++]
  migrations: {
    // [!code ++]
    path: "prisma-post-database/migrations", // [!code ++]
  }, // [!code ++]
  datasource: {
    // [!code ++]
    url: env("PPG_POST_DATABASE_URL"), // [!code ++]
  }, // [!code ++]
}); // [!code ++]
```

Your post database schema is now set.

### 2.3. Add helper scripts and migrate the schemas [#23-add-helper-scripts-and-migrate-the-schemas]

So you don't have to pass `--schema` for each database on every command, add helper scripts to your `package.json` file that run Prisma commands for both databases:

```json title="package.json"
"scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "postinstall": "npx prisma generate --config ./prisma-user-database/prisma.config.ts && npx prisma generate --config ./prisma-post-database/prisma.config.ts", // [!code ++]
    "generate": "npx prisma generate --config ./prisma-user-database/prisma.config.ts && npx prisma generate --config ./prisma-post-database/prisma.config.ts", // [!code ++]
    "migrate": "npx prisma migrate dev --config ./prisma-user-database/prisma.config.ts && npx prisma migrate dev --config ./prisma-post-database/prisma.config.ts", // [!code ++]
    "deploy": "npx prisma migrate deploy --config ./prisma-user-database/prisma.config.ts && npx prisma migrate deploy --config ./prisma-post-database/prisma.config.ts", // [!code ++]
    "studio": "npx prisma studio --config ./prisma-user-database/prisma.config.ts --port 5555 & npx prisma studio --config ./prisma-post-database/prisma.config.ts --port 5556" // [!code ++]
}
```

Here is an explanation of the custom scripts:

* `postinstall`: Runs immediately after installing dependencies to generate Prisma Clients for both the user and post databases using their respective schema files.
* `generate`: Manually triggers the generation of Prisma Clients for both schemas, ensuring your client code reflects the latest models.
* `migrate`: Applies pending migrations in development mode for both databases using [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate), updating their schemas based on changes in your Prisma files.
* `deploy`: Executes migrations in a production environment, synchronizing your live databases with your Prisma schemas.
* `studio`: Opens Prisma Studio for both databases simultaneously on different ports (`5555` for the user database and `5556` for the post database) for visual data management.

Run the migrations:

  

#### bun

```bash
bun run migrate
```

#### pnpm

```bash
pnpm run migrate
```

#### yarn

```bash
yarn migrate
```

#### npm

```bash
npm run migrate
```

When prompted, name the migration for each database accordingly.

## 3. Prepare the application to use multiple Prisma Clients [#3-prepare-the-application-to-use-multiple-prisma-clients]

Next, create a `lib` folder to store helper files for instantiating and exporting your Prisma Clients:

```bash
mkdir -p lib && touch lib/user-prisma-client.ts lib/post-prisma-client.ts
```

### 3.1. Instantiate and export the Prisma Client for the user database [#31-instantiate-and-export-the-prisma-client-for-the-user-database]

In `lib/user-prisma-client.ts`, add the following code:

```ts title="lib/user-prisma-client.ts"
import { PrismaClient } from "../prisma-user-database/user-database-client-types/client"; // [!code ++]
import { PrismaPg } from "@prisma/adapter-pg"; // [!code ++]
// [!code ++]
const adapter = new PrismaPg({
  // [!code ++]
  connectionString: process.env.PPG_USER_DATABASE_URL, // [!code ++]
}); // [!code ++]
// [!code ++]
const getPrisma = () =>
  new PrismaClient({
    // [!code ++]
    adapter, // [!code ++]
  }); // [!code ++]
// [!code ++]
const globalForUserDBPrismaClient = global as unknown as {
  // [!code ++]
  userDBPrismaClient: ReturnType<typeof getPrisma>; // [!code ++]
}; // [!code ++]
// [!code ++]
export const userDBPrismaClient = globalForUserDBPrismaClient.userDBPrismaClient || getPrisma(); // [!code ++] // [!code ++]
// [!code ++]
if (process.env.NODE_ENV !== "production")
  // [!code ++]
  globalForUserDBPrismaClient.userDBPrismaClient = userDBPrismaClient; // [!code ++]
```

### 3.2. Instantiate and export the Prisma Client for the post database [#32-instantiate-and-export-the-prisma-client-for-the-post-database]

In `lib/post-prisma-client.ts`, add this code:

```ts title="lib/post-prisma-client.ts"
import { PrismaClient } from "../prisma-post-database/post-database-client-types/client"; // [!code ++]
import { PrismaPg } from "@prisma/adapter-pg"; // [!code ++]
// [!code ++]
const adapter = new PrismaPg({
  // [!code ++]
  connectionString: process.env.PPG_POST_DATABASE_URL, // [!code ++]
}); // [!code ++]
// [!code ++]
const getPrisma = () =>
  new PrismaClient({
    // [!code ++]
    adapter, // [!code ++]
  }); // [!code ++]
// [!code ++]
const globalForPostDBPrismaClient = global as unknown as {
  // [!code ++]
  postDBPrismaClient: ReturnType<typeof getPrisma>; // [!code ++]
}; // [!code ++]
// [!code ++]
export const postDBPrismaClient = globalForPostDBPrismaClient.postDBPrismaClient || getPrisma(); // [!code ++] // [!code ++]
// [!code ++]
if (process.env.NODE_ENV !== "production")
  // [!code ++]
  globalForPostDBPrismaClient.postDBPrismaClient = postDBPrismaClient; // [!code ++]
```

## 4. Integrate multiple Prisma Clients in your Next.js app [#4-integrate-multiple-prisma-clients-in-your-nextjs-app]

Modify your application code to fetch data from both databases. Update the `app/page.tsx` file as follows:

```ts title="app/page.tsx"
import { postDBPrismaClient } from "@/lib/post-prisma-client"; // [!code ++]
import { userDBPrismaClient } from "@/lib/user-prisma-client"; // [!code ++]
 // [!code ++]
export default async function Home() { // [!code ++]
  const user = await userDBPrismaClient.user.findFirst(); // [!code ++]
  const post = await postDBPrismaClient.post.findFirst(); // [!code ++]
 // [!code ++]
  return ( // [!code ++]
    <main className="min-h-screen bg-gray-50 py-12"> // [!code ++]
      <div className="max-w-4xl mx-auto px-4"> // [!code ++]
        <header className="mb-12 text-center"> // [!code ++]
          <h1 className="text-5xl font-extrabold text-gray-900">Multi-DB Showcase</h1> // [!code ++]
          <p className="mt-4 text-xl text-gray-600"> // [!code ++]
            Data fetched from two distinct databases. // [!code ++]
          </p> // [!code ++]
        </header> // [!code ++]
 // [!code ++]
        <section className="mb-8 bg-white shadow-md rounded-lg p-6"> // [!code ++]
          <h2 className="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4"> // [!code ++]
            User Data // [!code ++]
          </h2> // [!code ++]
          <pre className="whitespace-pre-wrap text-sm text-gray-700"> // [!code ++]
            {user ? JSON.stringify(user, null, 2) : "No user data available."} // [!code ++]
          </pre> // [!code ++]
        </section> // [!code ++]
 // [!code ++]
        <section className="bg-white shadow-md rounded-lg p-6"> // [!code ++]
          <h2 className="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4"> // [!code ++]
            Post Data // [!code ++]
          </h2> // [!code ++]
          <pre className="whitespace-pre-wrap text-sm text-gray-700"> // [!code ++]
            {post ? JSON.stringify(post, null, 2) : "No post data available."} // [!code ++]
          </pre> // [!code ++]
        </section> // [!code ++]
      </div> // [!code ++]
    </main> // [!code ++]
  ); // [!code ++]
} // [!code ++]
```

### 4.1. Populate your databases with data [#41-populate-your-databases-with-data]

In a separate terminal window, open two instances of [Prisma Studio](https://www.prisma.io/docs/studio) to add data to your databases by running the script:

  

#### bun

```bash
bun run studio
```

#### pnpm

```bash
pnpm run studio
```

#### yarn

```bash
yarn studio
```

#### npm

```bash
npm run studio
```

This will open up two browser windows, one in `http://localhost:5555` and one in `http://localhost:5556`. Navigate to those windows and add sample data to both databases.

### 4.2. Run the development server [#42-run-the-development-server]

Before starting the development server, note that if you are using Next.js `v15.2.0`, do not use Turbopack as there is a known [issue](https://github.com/vercel/next.js/issues/76497). Remove Turbopack from your dev script by updating your `package.json`:

```json title="package.json"
"scripts": {
    "dev": "next dev --turbopack", // [!code --]
    "dev": "next dev", // [!code ++]
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "postinstall": "npx prisma generate --config ./prisma-user-database/prisma.config.ts && npx prisma generate --config ./prisma-post-database/prisma.config.ts",
    "generate": "npx prisma generate --config ./prisma-user-database/prisma.config.ts && npx prisma generate --config ./prisma-post-database/prisma.config.ts",
    "migrate": "npx prisma migrate dev --config ./prisma-user-database/prisma.config.ts && npx prisma migrate dev --config ./prisma-post-database/prisma.config.ts",
    "deploy": "npx prisma migrate deploy --config ./prisma-user-database/prisma.config.ts && npx prisma migrate deploy --config ./prisma-post-database/prisma.config.ts",
    "studio": "npx prisma studio --config ./prisma-user-database/prisma.config.ts --port 5555 & npx prisma studio --config ./prisma-post-database/prisma.config.ts --port 5556"
}
```

In a separate terminal window, start the development server by running:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Navigate to `http://localhost:3000` to see your Next.js app display data from both databases:

![App displaying data by querying two separate database instances](https://www.prisma.io/img/guides/multi-client-app-demo.png)

Congratulations, you have a Next.js app running with two Prisma Client instances querying different databases.

## 5. Deploy your Next.js app using multiple databases to Vercel [#5-deploy-your-nextjs-app-using-multiple-databases-to-vercel]

Deploy your app by following these steps:

1. Ensure your project is version-controlled and pushed to a GitHub repository. If you do not have a repository yet, [create one on GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository). Once the repository is ready, run the following commands:
   ```bash
   git add .
   git commit -m "Initial commit with Prisma Postgres integration"
   git branch -M main
   git remote add origin https://github.com/<your-username>/<repository-name>.git
   git push -u origin main
   ```
   > [!NOTE]
> Replace `<your-username>` and `<repository-name>` with your GitHub username and the name of your repository.
2. Log in to [Vercel](https://vercel.com/) and navigate to your [Dashboard](https://vercel.com/docs/deployments).
3. Create a new project. Follow Vercel's [Import an existing project](https://vercel.com/docs/getting-started-with-vercel/import) guide, but stop at [step 3](https://vercel.com/docs/getting-started-with-vercel/import#optionally-configure-any-settings) where you will configure environment variables *before* clicking **Deploy**.
4. Configure the `DATABASE_URL` environment variable:
   1. Expand the **Environment variables** section.
   2. Add the `PPG_USER_DATABASE_URL` environment variable:
      * **Key**: `PPG_USER_DATABASE_URL`
      * **Value**: Paste your user database connection URL, e.g. by copying it from the `.env` file in your project.
   3. Add the `PPG_POST_DATABASE_URL` environment variable:
      * **Key**: `PPG_POST_DATABASE_URL`
      * **Value**: Paste your post database connection URL, e.g. by copying it from the `.env` file in your project.
        > [!WARNING]
> Do not deploy without setting the environment variables. Your deployment will fail if the application cannot connect to the databases.
5. Click the **Deploy** button. Vercel will build your project and deploy it to a live URL.

Open the live URL provided by Vercel and verify that your application is working.

Your application now runs on Vercel and uses two Prisma Clients to query two different databases.

## Next steps [#next-steps]

In this guide, you learned how to use multiple databases using Prisma ORM in a single Next.js app by:

* Setting up separate Prisma schemas for user and post databases.
* Configuring custom output directories and environment variables.
* Creating helper scripts to generate and migrate each schema.
* Instantiating and integrating multiple Prisma Clients into your application.
* Deploying your multi-database application to Vercel.

This approach allows you to maintain a clear separation of data models and simplifies multi-tenant or multi-database scenarios.

For further improvements in managing your project, consider using a monorepo setup. Check out our related guides:

* [How to use Prisma ORM in a pnpm workspaces monorepo](https://www.prisma.io/docs/guides/v7/deployment/pnpm-workspaces)
* [How to use Prisma ORM with Turborepo](https://www.prisma.io/docs/guides/v7/deployment/turborepo)

## Related pages

- [`Expand-and-contract migrations`](https://www.prisma.io/docs/guides/v7/database/data-migration): Learn how to perform data migrations using the expand and contract pattern with Prisma ORM
- [`Schema management in teams`](https://www.prisma.io/docs/guides/v7/database/schema-changes): Learn how to use Prisma Migrate effectively when collaborating on a project as a team

# Schema management in teams (Prisma ORM v7) (/docs/guides/v7/database/schema-changes)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma Migrate effectively when collaborating on a project as a team

Location: Guides > v7 > Database > Schema management in teams

## Introduction [#introduction]

When working in a team, managing database schema changes can be challenging. This guide shows you how to effectively collaborate on schema changes using Prisma Migrate, ensuring that all team members can safely contribute to and incorporate schema changes.

## Prerequisites [#prerequisites]

Before starting this guide, make sure you have:

* Node.js installed (version 20 or higher)
* A Prisma project set up with migrations
* A relational database (PostgreSQL, MySQL, SQLite, SQL Server, etc.)
* Basic understanding of Git
* Basic familiarity with Prisma Migrate

> [!WARNING]
> This guide **does not apply for MongoDB**.<br />
> Instead of `migrate dev`, [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) is used for [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

## 1. Understand migration basics [#1-understand-migration-basics]

### 1.1. Migration order [#11-migration-order]

Migrations are **applied in the same order as they were created**. The creation date is part of the migration subfolder name - for example, `20210316081837-updated-fields` was created on `2021-03-16-08:18:37`.

### 1.2. Source control requirements [#12-source-control-requirements]

You should commit the following files to source control:

* The contents of the `prisma/migrations` folder, including the `migration_lock.toml` file
* The Prisma Schema (`schema.prisma`)

Source-controlling the `schema.prisma` file is not enough - you must include your migration history because:

* Customized migrations contain information that cannot be represented in the Prisma schema
* The `prisma migrate deploy` command only runs migration files

### 1.3. Configure Prisma [#13-configure-prisma]

Create a `prisma.config.ts` file in the root of your project with the following content:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

> [!NOTE]
> You'll need to install the `dotenv` package to load environment variables. If you haven't already, install it using your package manager:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 

## 2. Incorporate team changes [#2-incorporate-team-changes]

### 2.1. Pull latest changes [#21-pull-latest-changes]

To incorporate changes from collaborators:

1. Pull the changed Prisma schema and `./prisma/migrations` folder
2. Run the migrate command:

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

### 2.2. Example scenario [#22-example-scenario]

Consider a sample scenario with three developers sharing schema changes:

  

#### Before

```prisma title="schema.prisma" 
model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields: [authorId], references: [id])
  authorId  Int?
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}
```

#### After

```prisma title="schema.prisma" 
model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields: [authorId], references: [id])
  authorId  Int?
}

model User {
  id              Int     @id @default(autoincrement())
  email           String  @unique
  name            String?
  favoriteColor   String? // Added by Ania // [!code ++]
  bestPacmanScore Int? // Added by you // [!code ++]
  posts           Post[]
}

// Added by Javier // [!code ++]
model Tag { // [!code ++]
  tagName     String   @id // [!code ++]
  tagCategory Category // [!code ++]
} // [!code ++]
```

## 3. Handle concurrent changes [#3-handle-concurrent-changes]

### 3.1. Developer A's changes [#31-developer-as-changes]

Ania adds a new field:

```prisma
model User {
  /* ... */
  favoriteColor String?
}
```

And generates a migration:

  

#### bun

```bash
bunx prisma migrate dev --name new-field
```

#### pnpm

```bash
pnpm prisma migrate dev --name new-field
```

#### yarn

```bash
yarn prisma migrate dev --name new-field
```

#### npm

```bash
npx prisma migrate dev --name new-field
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 3.2. Developer B's changes [#32-developer-bs-changes]

Javier adds a new model:

```prisma
model Tag {
  tagName     String   @id
  tagCategory Category
}
```

And generates a migration:

  

#### bun

```bash
bunx prisma migrate dev --name new-model
```

#### pnpm

```bash
pnpm prisma migrate dev --name new-model
```

#### yarn

```bash
yarn prisma migrate dev --name new-model
```

#### npm

```bash
npx prisma migrate dev --name new-model
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 3.3. Merge changes [#33-merge-changes]

The migration history now has two new migrations:

![A diagram showing changes by two separate developers converging in a single migration history.](https://www.prisma.io/img/guides/migrate-team-dev.png)

## 4. Integrate your changes [#4-integrate-your-changes]

### 4.1. Pull team changes [#41-pull-team-changes]

1. Pull the most recent changes:
   * Two new migrations
   * Updated schema file

2. Review the merged schema:

```prisma
model User {
  /* ... */
  favoriteColor   String?
  bestPacmanScore Int?
}

model Tag {
  tagName     String   @id
  tagCategory Category
  posts       Post[]
}
```

### 4.2. Generate your migration [#42-generate-your-migration]

Run the migrate command:

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This will:

1. Apply your team's migrations
2. Create a new migration for your changes
3. Apply your new migration

### 4.3. Commit changes [#43-commit-changes]

Commit:

* The merged `schema.prisma`
* Your new migration file

## Next steps [#next-steps]

Now that you understand team schema management, you can:

* Learn about [customizing migrations](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations)
* Explore [deployment workflows](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production)

For more information:

* [Prisma Migrate documentation](https://www.prisma.io/docs/orm/v7/prisma-migrate)
* [Team development workflows](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production)

## Related pages

- [`Expand-and-contract migrations`](https://www.prisma.io/docs/guides/v7/database/data-migration): Learn how to perform data migrations using the expand and contract pattern with Prisma ORM
- [`Multiple databases`](https://www.prisma.io/docs/guides/v7/database/multiple-databases): Learn how to use multiple Prisma Clients in a single app to connect to multiple databases, handle migrations, and deploy your application to Vercel

# Bun workspaces (Prisma ORM v7) (/docs/guides/v7/deployment/bun-workspaces)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn step-by-step how to integrate Prisma ORM in a Bun workspaces monorepo through a shared database package

Location: Guides > v7 > Deployment > Bun workspaces

## Introduction [#introduction]

This guide shows you how to use Prisma ORM in a [Bun Workspaces](https://bun.sh/docs/install/workspaces) monorepo. You'll set up a shared database package with Prisma ORM, then integrate it into a Next.js app in the same workspace.

## Prerequisites [#prerequisites]

* [Bun](https://bun.sh/docs/installation) installed
* A [Prisma Postgres](https://www.prisma.io/docs/postgres) database (or another [supported database](https://www.prisma.io/docs/orm/v7/reference/supported-databases))

## 1. Set up project [#1-set-up-project]

Before integrating Prisma ORM, you need to set up your project structure. Start by creating a new directory for your project (for example, `my-monorepo`) and initialize a Node.js project:

  

#### bun

```bash
mkdir my-monorepo
cd my-monorepo
bun init
```

#### pnpm

```bash
mkdir my-monorepo
cd my-monorepo
pnpm init
```

#### yarn

```bash
mkdir my-monorepo
cd my-monorepo
yarn init
```

#### npm

```bash
mkdir my-monorepo
cd my-monorepo
npm init
```

Next, add the `workspaces` array to your root `package.json` to define your workspace structure:

```json title="package.json"
{
  "name": "my-monorepo", // [!code ++]
  "workspaces": ["apps/*", "packages/*"] // [!code ++]
}
```

Finally, create directories for your applications and shared packages:

```bash
mkdir apps
mkdir -p packages/database
```

## 2. Set up database package [#2-set-up-database-package]

This section covers creating a standalone database package that uses Prisma ORM. The package will house all database models and the generated Prisma ORM client, making it reusable across your monorepo.

### 2.1. Install dependencies [#21-install-dependencies]

Navigate to the `packages/database` directory and initialize a new package:

  

#### bun

```bash
cd packages/database
bun init
```

#### pnpm

```bash
cd packages/database
pnpm init
```

#### yarn

```bash
cd packages/database
yarn init
```

#### npm

```bash
cd packages/database
npm init
```

Install the required Prisma ORM packages and other dependencies:

  

#### bun

```bash
bun add prisma@prev typescript tsx @types/node @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg
```

#### pnpm

```bash
pnpm add prisma@prev typescript tsx @types/node @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg
```

#### yarn

```bash
yarn add prisma@prev typescript tsx @types/node @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg
```

#### npm

```bash
npm install prisma@prev typescript tsx @types/node @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

### 2.2. Set up Prisma ORM and schema [#22-set-up-prisma-orm-and-schema]

Initialize Prisma ORM with an instance of [Prisma Postgres](https://www.prisma.io/docs/postgres) in the `database` package by running the following command:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This command:

* Creates a `prisma` directory containing a `schema.prisma` file for your database models.
* Creates a `prisma.config.ts` file for configuring Prisma.
* Creates a `.env` file with a local `DATABASE_URL`.

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

Edit the `schema.prisma` file to add a `User` model. The default generator already sets `output = "../generated/prisma"`:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
} // [!code ++]
```

If the generated `prisma.config.ts` comments mention installing `dotenv`, install it so environment variables load:

  

#### bun

```bash
bun add dotenv
```

#### pnpm

```bash
pnpm add dotenv
```

#### yarn

```bash
yarn add dotenv
```

#### npm

```bash
npm install dotenv
```

Add a `scripts` section to your database `package.json` (Bun init may not add one by default):

```json title="database/package.json"
{
  "scripts": { // [!code ++]
    "db:generate": "prisma generate", // [!code ++]
    "db:migrate": "prisma migrate dev", // [!code ++]
    "db:deploy": "prisma migrate deploy", // [!code ++]
    "db:seed": "prisma db seed", // [!code ++]
    "db:studio": "prisma studio" // [!code ++]
  } // [!code ++]
}
```

Use [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) to migrate your database changes:

  

#### bun

```bash
bun run db:migrate
```

#### pnpm

```bash
pnpm run db:migrate
```

#### yarn

```bash
yarn db:migrate
```

#### npm

```bash
npm run db:migrate
```

When prompted by the CLI, enter a descriptive name for your migration. After the migration completes, run generate so the Prisma ORM client is created:

  

#### bun

```bash
bun run db:generate
```

#### pnpm

```bash
pnpm run db:generate
```

#### yarn

```bash
yarn db:generate
```

#### npm

```bash
npm run db:generate
```

Create a `client.ts` file to initialize the Prisma ORM client with a driver adapter:

```ts title="database/client.ts"
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
});

// Use globalThis for broader environment compatibility
const globalForPrisma = globalThis as typeof globalThis & {
  prisma?: PrismaClient;
};

export const prisma: PrismaClient =
  globalForPrisma.prisma ??
  new PrismaClient({
    adapter,
  });

if (process.env.NODE_ENV !== "production") {
  globalForPrisma.prisma = prisma;
}
```

Then, create an `index.ts` file to re-export the instance of the Prisma ORM client and all generated types:

```ts title="database/index.ts"
export { prisma } from "./client";
export * from "./generated/prisma/client";
```

### 2.3. Seed the database [#23-seed-the-database]

Add a seed script to populate the database with sample users. Create `prisma/seed.ts` in the database package:

```ts title="database/prisma/seed.ts"
import "dotenv/config";
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({ adapter });

async function main() {
  await prisma.user.createMany({
    data: [
      { email: "alice@example.com", name: "Alice" },
      { email: "bob@example.com", name: "Bob" },
      { email: "charlie@example.com", name: "Charlie" },
    ],
    skipDuplicates: true,
  });
  console.log("Seed complete.");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

Add the `seed` option to the existing `migrations` config in your database package's `prisma.config.ts` (add the `seed` line inside `migrations`):

```ts title="database/prisma.config.ts"
  migrations: {
    path: "prisma/migrations",
    seed: "bun prisma/seed.ts", // [!code ++]
  },
```

At this point, your shared database package is fully configured and ready for use across your monorepo.

### 2.4. Add root scripts [#24-add-root-scripts]

Add the following scripts to the root `package.json` of your monorepo. They let you run database and app commands from the root:

```json title="package.json"
"scripts": { // [!code ++]
  "build": "bun run --filter database db:deploy && bun run --filter database db:generate && bun run --filter web build", // [!code ++]
  "start": "bun run --filter web start", // [!code ++]
  "dev": "bun run --filter database db:generate && bun run --filter web dev", // [!code ++]
  "seed": "bun run --filter database db:seed", // [!code ++]
  "studio": "bun run --filter database db:studio" // [!code ++]
} // [!code ++]
```

From the monorepo root, run `bun run seed` to add sample users. Run `bun run studio` to open [Prisma Studio](https://www.prisma.io/docs/studio) at [`http://localhost:5555`](http://localhost:5555) to view and edit your data.

## 3. Set up Next.js app [#3-set-up-nextjs-app]

Now that the database package is set up, create a frontend application (using Next.js) that uses the shared Prisma ORM client to interact with your database.

### 3.1. Create Next.js app [#31-create-nextjs-app]

Navigate to the `apps` directory:

```bash
cd ../../apps
```

Create a new Next.js app named `web`:

```bash
bun create next-app@latest web --yes
```

> [!NOTE]
> important
> 
> The `--yes` flag uses default configurations to bootstrap the Next.js app (which in this guide uses the app router without a `src/` directory). When prompted for a package manager, choose **Bun** so the app uses Bun within the workspace.
> 
> The flag may also initialize a Git repository in the `web` folder. If that happens, please remove the `.git` directory by running `rm -r .git`.

Then, navigate into the web directory:

```bash
cd web/
```

Copy the `.env` file from the database package to ensure the same environment variables are available:

```bash
cp ../../packages/database/.env .
```

Open the `package.json` file of your Next.js app and add the shared `database` package as a dependency:

```json title="web/package.json"
"dependencies": {
  "database": "workspace:*" // [!code ++]
}
```

Run the following command to install the `database` package:

  

#### bun

```bash
bun install
```

#### pnpm

```bash
pnpm install
```

#### yarn

```bash
yarn install
```

#### npm

```bash
npm install
```

### 3.2. Add database to app [#32-add-database-to-app]

Modify your Next.js application code to use the Prisma ORM client from the database package. Update `app/page.tsx` as follows:

```tsx title="app/page.tsx"
import { prisma } from "database";

export default async function Home() {
  const user = await prisma.user.findFirst({
    select: {
      name: true,
    },
  });

  return (
    <div>
      {user?.name && <p>Hello from {user.name}</p>}
      {!user?.name && <p>No user has been added to the database yet.</p>}
    </div>
  );
}
```

This code demonstrates importing and using the shared Prisma ORM client to query your `User` model.

### 3.3. Run the app [#33-run-the-app]

Then head back to the root of the monorepo:

```bash
cd ../../
```

Start your development server by executing:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open your browser at [`http://localhost:3000`](http://localhost:3000) to see your app in action. You can run `bun run studio` to open [Prisma Studio](https://www.prisma.io/docs/studio) at [`http://localhost:5555`](http://localhost:5555) to view and edit your data.

## Next steps [#next-steps]

You have now created a monorepo that uses Prisma ORM, with a shared database package integrated into a Next.js application.

To add task orchestration and caching on top of this setup, see the [How to use Prisma ORM with Turborepo](https://www.prisma.io/docs/guides/v7/deployment/turborepo) guide.

## Related pages

- [`Cloudflare D1`](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-d1): Learn how to use Prisma ORM with Cloudflare D1
- [`Cloudflare Workers`](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-workers): Learn how to use Prisma ORM and Prisma Postgres in a Cloudflare Workers project
- [`Docker`](https://www.prisma.io/docs/guides/v7/deployment/docker): Learn step-by-step configure a Prisma ORM app in Docker
- [`pnpm workspaces`](https://www.prisma.io/docs/guides/v7/deployment/pnpm-workspaces): Learn step-by-step how to integrate Prisma ORM in a pnpm workspaces monorepo through a shared database package
- [`Turborepo`](https://www.prisma.io/docs/guides/v7/deployment/turborepo): Learn step-by-step how to integrate Prisma ORM with Turborepo through a shared database package

# Cloudflare D1 (Prisma ORM v7) (/docs/guides/v7/deployment/cloudflare-d1)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM with Cloudflare D1

Location: Guides > v7 > Deployment > Cloudflare D1

## Introduction [#introduction]

This guide shows you how to use Prisma ORM with Cloudflare D1, a serverless SQL database that runs on Cloudflare's edge network. You'll learn how to set up Prisma ORM with D1, handle migrations, and deploy your application to Cloudflare Workers. You can find a [deployment-ready example on GitHub](https://github.com/prisma/prisma-examples/blob/latest/deployment-platforms/edge/cloudflare-workers/with-d1).

## Prerequisites [#prerequisites]

Before starting this guide, make sure you have:

* A Cloudflare account
* Node.js installed (version 20 or higher)
* Wrangler CLI installed (version 3.39.0 or higher)
* Basic familiarity with Cloudflare Workers and D1

## 1. Create a new Cloudflare Worker and initialize Prisma ORM [#1-create-a-new-cloudflare-worker-and-initialize-prisma-orm]

Run the following command to create a [new Cloudflare Worker project](https://developers.cloudflare.com/d1/get-started/#1-create-a-worker):

  

#### bun

```bash
bunx create-cloudflare d1-tutorial --type hello-world --ts=true --git=true --deploy=false
```

#### pnpm

```bash
pnpm create cloudflare d1-tutorial --type=hello-world --ts=true --git=true --deploy=false
```

#### yarn

```bash
yarn create cloudflare d1-tutorial --type=hello-world --ts=true --git=true --deploy=false
```

#### npm

```bash
npm create cloudflare@latest d1-tutorial -- --type=hello-world --ts=true --git=true --deploy=false
```

Then navigate into the newly created directory:

```bash
cd d1-tutorial
```

And initialize Prisma ORM in the project:

  

#### bun

```bash
bunx --bun prisma@prev init --datasource-provider sqlite
```

#### pnpm

```bash
pnpm dlx prisma@prev init --datasource-provider sqlite
```

#### yarn

```bash
yarn dlx prisma@prev init --datasource-provider sqlite
```

#### npm

```bash
npx prisma@prev init --datasource-provider sqlite
```

And install the Prisma ORM CLI as a development dependency:

  

#### bun

```bash
bun add --dev prisma@prev
```

#### pnpm

```bash
pnpm add --save-dev prisma@prev
```

#### yarn

```bash
yarn add --dev prisma@prev
```

#### npm

```bash
npm install --save-dev prisma@prev
```

## 2. Configure Prisma schema [#2-configure-prisma-schema]

In your Prisma schema, set the `provider` of the `datasource` to `sqlite`. If you just bootstrapped the Prisma schema with `prisma init`, also be sure to add the `runtime = "cloudflare"` to the generator block and the following `User` model:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
  runtime  = "cloudflare"
}

datasource db {
  provider = "sqlite"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
} // [!code ++]
```

## 3. Install dependencies [#3-install-dependencies]

Next, install the required packages:

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-d1 dotenv
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-d1 dotenv
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-d1 dotenv
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-d1 dotenv
```

Also, be sure to use a version of the Wrangler CLI that's above [`wrangler@^3.39.0`](https://github.com/cloudflare/workers-sdk/releases/tag/wrangler%403.39.0), otherwise the `--remote` flag that's used in the next sections won't be available.

## 4. Create a D1 database [#4-create-a-d1-database]

Run the following command to create a new D1 database:

  

#### bun

```bash
bunx wrangler@latest d1 create __YOUR_D1_DATABASE_NAME__
```

#### pnpm

```bash
pnpm dlx wrangler@latest d1 create __YOUR_D1_DATABASE_NAME__
```

#### yarn

```bash
yarn dlx wrangler@latest d1 create __YOUR_D1_DATABASE_NAME__
```

#### npm

```bash
npx wrangler@latest d1 create __YOUR_D1_DATABASE_NAME__
```

> [!NOTE]
> The `__YOUR_D1_DATABASE_NAME__` is a placeholder that should be replaced with the name you want to give your D1 database. For example, you can use `prisma-d1-example`.

This command will authenticate you with Cloudflare and ask you to select a Cloudflare account. After that, it will create a new D1 database and output the database ID and name:

```bash
✅ Successfully created DB '__YOUR_D1_DATABASE_NAME__' in region __REGION__
Created your new D1 database.

{
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "__YOUR_D1_DATABASE_NAME__",
      "database_id": "<unique-ID-for-your-database>"
    }
  ]
}
```

Copy the terminal output and add the content to your `wrangler.jsonc` file. This file is used to configure your Cloudflare Worker and its bindings.

To connect your Workers with the D1 instance, add the following binding to your `wrangler.jsonc`:

```json title="wrangler.jsonc"
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "d1-tutorial",
  "main": "src/index.ts",
  "compatibility_date": "2025-08-05",
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "__YOUR_D1_DATABASE_NAME__", // to be replaced
      "database_id": "__YOUR_D1_DATABASE_ID__" // to be replaced
    }
  ]
}
```

> [!NOTE]
> The `__YOUR_D1_DATABASE_NAME__` and `__YOUR_D1_DATABASE_ID__` in the snippet above are placeholders that should be replaced with the database name and ID of your own D1 instance.
> 
> If you weren't able to grab the database ID from the terminal output, you can also find it in the Cloudflare Dashboard or by running `npx wrangler d1 list` and `npx wrangler d1 info __YOUR_D1_DATABASE_NAME__` in your terminal.

## 5. Set up database migrations [#5-set-up-database-migrations]

For Cloudflare D1, you'll use Prisma's migration workflow combined with Wrangler CLI to manage your database schema. Since D1 is a serverless SQLite database, we'll use `prisma migrate diff` to generate migration SQL and then apply it using Wrangler.

### 5.1 Set up environment variables [#51-set-up-environment-variables]

Add a `.env` file in the root of your project with your local database URL:

```text title=".env"
DATABASE_URL="file:./prisma/db.sqlite"
```

Also create a `prisma.config.ts` file in the root of your project:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 5.2 Generate migration SQL [#52-generate-migration-sql]

First, create a migrations directory inside the `prisma` folder and create a file named `0001_init.sql`:

```bash
mkdir -p prisma/migrations
```

Now use `prisma migrate diff` to generate the SQL needed to create your database schema:

  

#### bun

```bash
bunx prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0001_init.sql
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0001_init.sql
```

#### yarn

```bash
yarn prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0001_init.sql
```

#### npm

```bash
npx prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0001_init.sql
```

This command generates a SQL file that contains the statements needed to create your database tables. You can inspect the generated SQL in `prisma/migrations/0001_init.sql`.

### 5.3 Apply migrations to D1 [#53-apply-migrations-to-d1]

Now apply the migration to both your local and remote D1 databases using Wrangler:

  

#### bun

```bash
# Apply to local database
bunx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --local --file="./prisma/migrations/0001_init.sql"

# Apply to remote database
bunx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --remote --file="./prisma/migrations/0001_init.sql"
```

#### pnpm

```bash
# Apply to local database
pnpm dlx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --local --file="./prisma/migrations/0001_init.sql"

# Apply to remote database
pnpm dlx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --remote --file="./prisma/migrations/0001_init.sql"
```

#### yarn

```bash
# Apply to local database
yarn dlx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --local --file="./prisma/migrations/0001_init.sql"

# Apply to remote database
yarn dlx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --remote --file="./prisma/migrations/0001_init.sql"
```

#### npm

```bash
# Apply to local database
npx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --local --file="./prisma/migrations/0001_init.sql"

# Apply to remote database
npx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --remote --file="./prisma/migrations/0001_init.sql"
```

> [!NOTE]
> Replace `__YOUR_D1_DATABASE_NAME__` with the actual name of your D1 database that you created in step 4.

### 5.4 Add sample data [#54-add-sample-data]

Insert a sample user into each database so the Worker has something to return:

  

#### bun

```bash
# For the local database
bunx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --command="INSERT INTO \"User\" (\"email\", \"name\") VALUES ('jane@prisma.io', 'Jane Doe (Local)');" --local

# For the remote database
bunx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --command="INSERT INTO \"User\" (\"email\", \"name\") VALUES ('jane@prisma.io', 'Jane Doe (Remote)');" --remote
```

#### pnpm

```bash
# For the local database
pnpm dlx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --command="INSERT INTO \"User\" (\"email\", \"name\") VALUES ('jane@prisma.io', 'Jane Doe (Local)');" --local

# For the remote database
pnpm dlx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --command="INSERT INTO \"User\" (\"email\", \"name\") VALUES ('jane@prisma.io', 'Jane Doe (Remote)');" --remote
```

#### yarn

```bash
# For the local database
yarn dlx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --command="INSERT INTO \"User\" (\"email\", \"name\") VALUES ('jane@prisma.io', 'Jane Doe (Local)');" --local

# For the remote database
yarn dlx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --command="INSERT INTO \"User\" (\"email\", \"name\") VALUES ('jane@prisma.io', 'Jane Doe (Remote)');" --remote
```

#### npm

```bash
# For the local database
npx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --command="INSERT INTO \"User\" (\"email\", \"name\") VALUES ('jane@prisma.io', 'Jane Doe (Local)');" --local

# For the remote database
npx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --command="INSERT INTO \"User\" (\"email\", \"name\") VALUES ('jane@prisma.io', 'Jane Doe (Remote)');" --remote
```

> [!NOTE]
> For future schema changes, you can generate new migration files using:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bunx prisma migrate diff \
>       --from-local-d1 \
>       --to-schema prisma/schema.prisma \
>       --script > migrations/0002_add_new_field.sql
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm prisma migrate diff \
>       --from-local-d1 \
>       --to-schema prisma/schema.prisma \
>       --script > migrations/0002_add_new_field.sql
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn prisma migrate diff \
>       --from-local-d1 \
>       --to-schema prisma/schema.prisma \
>       --script > migrations/0002_add_new_field.sql
>     ```
>
> 
>   #### npm

>     ```bash
>     npx prisma migrate diff \
>       --from-local-d1 \
>       --to-schema prisma/schema.prisma \
>       --script > migrations/0002_add_new_field.sql
>     ```
>
> 
> 
> Then apply them using the same `wrangler d1 execute` commands as shown above.

## 6. Implement the Worker [#6-implement-the-worker]

Before adding a Prisma Client query to your Worker, you need to generate Prisma Client with the following command:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

In order to query your database from the Worker using Prisma ORM, you need to:

1. Add the `DB` binding to the `Env` interface. This `DB` name matches the binding name you configured in `wrangler.jsonc`. (Alternatively, you can run [`npx wrangler types`](https://developers.cloudflare.com/workers/wrangler/commands/#types) to generate the `Env` type from the binding in a separate file called `worker-configuration.d.ts`.)
2. Instantiate `PrismaClient` using the `PrismaD1` driver adapter, passing `env.DB` which accesses your D1 database binding.
3. Send a query using Prisma Client and return the result.

Open `src/index.ts` and replace the entire content with the following:

```typescript title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client";
import { PrismaD1 } from "@prisma/adapter-d1";

export interface Env {
  DB: D1Database;
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const adapter = new PrismaD1(env.DB);
    const prisma = new PrismaClient({ adapter });

    const users = await prisma.user.findMany();
    const result = JSON.stringify(users);
    ctx.waitUntil(prisma.$disconnect()); // or just await prisma.$disconnect()
    return new Response(result);
  },
};
```

We explicitly call `prisma.$disconnect()` here to guarantee timely release of resources or else the
worker might run out of memory.

## 7. Run the Worker locally [#7-run-the-worker-locally]

With the database query in place and Prisma Client generated, you can run the Worker locally.

If your Worker needs any environment variables, create a `.dev.vars` file in the root of your project. For this example, we don't need any additional environment variables since the D1 binding is already configured in `wrangler.jsonc`.

Now run the Worker locally:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Now you can open your browser at [`http://localhost:8787`](http://localhost:8787/) to see the result of the database query:

```js no-copy
[{ id: 1, email: "jane@prisma.io", name: "Jane Doe (Local)" }];
```

## 8. Deploy the Worker [#8-deploy-the-worker]

To deploy the Worker, run the following command:

  

#### bun

```bash
bun run deploy
```

#### pnpm

```bash
pnpm run deploy
```

#### yarn

```bash
yarn deploy
```

#### npm

```bash
npm run deploy
```

Your deployed Worker is accessible via `https://d1-tutorial.USERNAME.workers.dev` (replace `USERNAME` with your Cloudflare account username). If you navigate your browser to that URL, you should see the following data that's queried from your remote D1 database:

```js no-copy
[{ id: 1, email: "jane@prisma.io", name: "Jane Doe (Remote)" }];
```

## Next steps [#next-steps]

Now that you've set up Prisma ORM with Cloudflare D1, you can:

* Add more complex queries, such as filters, relations, and aggregations
* Set up Prisma Studio for database management
* Implement database monitoring
* Add automated tests

For more information:

* [Prisma ORM documentation](https://www.prisma.io/docs/orm/v7)
* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction)
* [Cloudflare D1 documentation](https://developers.cloudflare.com/d1)

## Related pages

- [`Bun workspaces`](https://www.prisma.io/docs/guides/v7/deployment/bun-workspaces): Learn step-by-step how to integrate Prisma ORM in a Bun workspaces monorepo through a shared database package
- [`Cloudflare Workers`](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-workers): Learn how to use Prisma ORM and Prisma Postgres in a Cloudflare Workers project
- [`Docker`](https://www.prisma.io/docs/guides/v7/deployment/docker): Learn step-by-step configure a Prisma ORM app in Docker
- [`pnpm workspaces`](https://www.prisma.io/docs/guides/v7/deployment/pnpm-workspaces): Learn step-by-step how to integrate Prisma ORM in a pnpm workspaces monorepo through a shared database package
- [`Turborepo`](https://www.prisma.io/docs/guides/v7/deployment/turborepo): Learn step-by-step how to integrate Prisma ORM with Turborepo through a shared database package

# Cloudflare Workers (Prisma ORM v7) (/docs/guides/v7/deployment/cloudflare-workers)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM and Prisma Postgres in a Cloudflare Workers project

Location: Guides > v7 > Deployment > Cloudflare Workers

## Introduction [#introduction]

**Yes, Prisma Postgres works on Cloudflare Workers.**

Standard PostgreSQL clients (like `pg` or `postgres.js`) use TCP connections, and Cloudflare Workers doesn't support TCP by default. That's why most Postgres databases can't be accessed directly from Workers. There are two ways around it with Prisma Postgres:

1. **Node.js compatibility mode**: add the `nodejs_compat` flag to your `wrangler.jsonc` and Prisma ORM can use TCP via Cloudflare's Node.js TCP API. That's what this guide does.
2. **Serverless HTTP driver**: the [`@prisma/ppg` driver](https://www.prisma.io/docs/postgres/database/serverless-driver) connects over HTTP instead of TCP, so no compatibility flag is needed.

This guide uses the `nodejs_compat` approach. Prisma Postgres handles connection pooling, so you don't have to worry about Workers spinning up a new connection per request.

You can find a complete example on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/cloudflare-workers).

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* A [Cloudflare account](https://dash.cloudflare.com/sign-up/workers-and-pages)

## 1. Set up your project [#1-set-up-your-project]

Create a new Cloudflare Workers project:

  

#### bun

```bash
bunx create-cloudflare prisma-cloudflare-worker --type hello-world --ts=true --git=true --deploy=false
```

#### pnpm

```bash
pnpm create cloudflare prisma-cloudflare-worker --type=hello-world --ts=true --git=true --deploy=false
```

#### yarn

```bash
yarn create cloudflare prisma-cloudflare-worker --type=hello-world --ts=true --git=true --deploy=false
```

#### npm

```bash
npm create cloudflare@latest prisma-cloudflare-worker -- --type=hello-world --ts=true --git=true --deploy=false
```

Navigate into the newly created project directory:

```bash
cd prisma-cloudflare-worker
```

## 2. Install and configure Prisma [#2-install-and-configure-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev dotenv-cli @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev dotenv-cli @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev dotenv-cli @types/pg --dev
```

#### npm

```bash
npm install prisma@prev dotenv-cli @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma/` directory with a `schema.prisma` file
* A `prisma.config.ts` file with your Prisma configuration
* A `.env` file with a local `DATABASE_URL` already set

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Enable Node.js compatibility in Cloudflare Workers [#22-enable-nodejs-compatibility-in-cloudflare-workers]

Cloudflare Workers needs Node.js compatibility enabled to work with Prisma. Add the `nodejs_compat` compatibility flag to your `wrangler.jsonc`:

```json title="wrangler.jsonc"
{
  "name": "prisma-cloudflare-worker",
  "main": "src/index.ts",
  "compatibility_flags": ["nodejs_compat"], // [!code ++]
  "compatibility_date": "2024-01-01"
}
```

### 2.3. Define your Prisma Schema [#23-define-your-prisma-schema]

In the `prisma/schema.prisma` file, add the following `User` model and set the runtime to `cloudflare`:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  runtime  = "cloudflare" // [!code ++]
  output   = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int    @id @default(autoincrement()) // [!code ++]
  email String // [!code ++]
  name  String // [!code ++]
} // [!code ++]
```

> [!NOTE]
> Both the `cloudflare` and `workerd` runtimes are supported. Read more about runtimes in [Field reference](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#field-reference).

This creates a `User` model with an auto-incrementing ID, email, and name.

### 2.4. Configure Prisma scripts [#24-configure-prisma-scripts]

Add the following scripts to your `package.json` to work with Prisma in the Cloudflare Workers environment:

```json title="package.json"
{
  "scripts": {
    "migrate": "prisma migrate dev", // [!code ++]
    "generate": "prisma generate", // [!code ++]
    "studio": "prisma studio" // [!code ++]
    // ... existing scripts
  }
}
```

### 2.5. Run migrations and generate Prisma Client [#25-run-migrations-and-generate-prisma-client]

Now, run the following command to create the database tables:

  

#### bun

```bash
bun run migrate
```

#### pnpm

```bash
pnpm run migrate
```

#### yarn

```bash
yarn migrate
```

#### npm

```bash
npm run migrate
```

When prompted, name your migration (e.g., `init`).

Then generate the Prisma Client:

  

#### bun

```bash
bun run generate
```

#### pnpm

```bash
pnpm run generate
```

#### yarn

```bash
yarn generate
```

#### npm

```bash
npm run generate
```

This generates the Prisma Client in the `src/generated/prisma/client` directory.

## 3. Integrate Prisma into Cloudflare Workers [#3-integrate-prisma-into-cloudflare-workers]

### 3.1. Import Prisma Client and configure types [#31-import-prisma-client-and-configure-types]

At the top of `src/index.ts`, import the generated Prisma Client and the PostgreSQL adapter, and define the `Env` interface for type-safe environment variables:

```typescript title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client"; // [!code ++]
import { PrismaPg } from "@prisma/adapter-pg"; // [!code ++]
// [!code ++]
export interface Env {
  // [!code ++]
  DATABASE_URL: string; // [!code ++]
} // [!code ++]

export default {
  async fetch(request, env, ctx): Promise<Response> {
    return new Response("Hello World!");
  },
} satisfies ExportedHandler<Env>;
```

### 3.2. Handle favicon requests [#32-handle-favicon-requests]

Add a check to filter out favicon requests, which browsers automatically send and can clutter your logs:

```typescript title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

export interface Env {
  DATABASE_URL: string;
}

export default {
  async fetch(request, env, ctx): Promise<Response> {
    const path = new URL(request.url).pathname; // [!code ++]
    if (path === "/favicon.ico")
      // [!code ++]
      return new Response("Resource not found", {
        // [!code ++]
        status: 404, // [!code ++]
        headers: {
          // [!code ++]
          "Content-Type": "text/plain", // [!code ++]
        }, // [!code ++]
      }); // [!code ++]

    return new Response("Hello World!");
  },
} satisfies ExportedHandler<Env>;
```

### 3.3. Initialize the Prisma Client [#33-initialize-the-prisma-client]

Create a database adapter and initialize Prisma Client with it. This must be done for each request in edge environments:

```typescript title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

export interface Env {
  DATABASE_URL: string;
}

export default {
  async fetch(request, env, ctx): Promise<Response> {
    const path = new URL(request.url).pathname;
    if (path === "/favicon.ico")
      return new Response("Resource not found", {
        status: 404,
        headers: {
          "Content-Type": "text/plain",
        },
      });

    const adapter = new PrismaPg({
      // [!code ++]
      connectionString: env.DATABASE_URL, // [!code ++]
    }); // [!code ++]
    // [!code ++]
    const prisma = new PrismaClient({
      // [!code ++]
      adapter, // [!code ++]
    }); // [!code ++]

    return new Response("Hello World!");
  },
} satisfies ExportedHandler<Env>;
```

> [!WARNING]
> In edge environments like Cloudflare Workers, you create a new Prisma Client instance per request. This is different from long-running Node.js servers where you typically instantiate a single client and reuse it.

### 3.4. Create a user and query the database [#34-create-a-user-and-query-the-database]

Now use Prisma Client to create a new user and count the total number of users:

```typescript title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

export interface Env {
  DATABASE_URL: string;
}

export default {
  async fetch(request, env, ctx): Promise<Response> {
    const path = new URL(request.url).pathname;
    if (path === "/favicon.ico")
      return new Response("Resource not found", {
        status: 404,
        headers: {
          "Content-Type": "text/plain",
        },
      });

    const adapter = new PrismaPg({
      connectionString: env.DATABASE_URL,
    });

    const prisma = new PrismaClient({
      adapter,
    });

    const user = await prisma.user.create({
      // [!code ++]
      data: {
        // [!code ++]
        email: `Prisma-Postgres-User-${Math.ceil(Math.random() * 1000)}@gmail.com`, // [!code ++]
        name: "Jon Doe", // [!code ++]
      }, // [!code ++]
    }); // [!code ++]
    // [!code ++]
    const userCount = await prisma.user.count(); // [!code ++]

    return new Response("Hello World!");
  },
} satisfies ExportedHandler<Env>;
```

### 3.5. Return the results [#35-return-the-results]

Finally, update the response to display the newly created user and the total user count:

```typescript title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

export interface Env {
  DATABASE_URL: string;
}

export default {
  async fetch(request, env, ctx): Promise<Response> {
    const path = new URL(request.url).pathname;
    if (path === "/favicon.ico")
      return new Response("Resource not found", {
        status: 404,
        headers: {
          "Content-Type": "text/plain",
        },
      });

    const adapter = new PrismaPg({
      connectionString: env.DATABASE_URL,
    });

    const prisma = new PrismaClient({
      adapter,
    });

    const user = await prisma.user.create({
      data: {
        email: `Prisma-Postgres-User-${Math.ceil(Math.random() * 1000)}@gmail.com`,
        name: "Jon Doe",
      },
    });

    const userCount = await prisma.user.count();

    return new Response(`\ // [!code highlight]
      Created new user: ${user.name} (${user.email}). // [!code highlight]
      Number of users in the database: ${userCount}. // [!code highlight]
    `); // [!code highlight]
  },
} satisfies ExportedHandler<Env>;
```

### 3.6. Test your Worker locally [#36-test-your-worker-locally]

First, generate the TypeScript types for your Worker environment:

  

#### bun

```bash
bunx wrangler types --no-strict-vars
```

#### pnpm

```bash
pnpm dlx wrangler types --no-strict-vars
```

#### yarn

```bash
yarn dlx wrangler types --no-strict-vars
```

#### npm

```bash
npx wrangler types --no-strict-vars
```

Then start the development server:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open [`http://localhost:8787`](http://localhost:8787) in your browser. Each time you refresh the page, a new user will be created. You should see output similar to:

```
Created new user: Jon Doe (Prisma-Postgres-User-742@gmail.com).
Number of users in the database: 5.
```

### 3.7. Inspect your data with Prisma Studio [#37-inspect-your-data-with-prisma-studio]

To view your database contents, open Prisma Studio:

  

#### bun

```bash
bun run studio
```

#### pnpm

```bash
pnpm run studio
```

#### yarn

```bash
yarn studio
```

#### npm

```bash
npm run studio
```

This will open a browser window where you can view and edit your `User` table data.

## 4. Deploy to Cloudflare Workers [#4-deploy-to-cloudflare-workers]

### 4.1. Set your database URL as a secret [#41-set-your-database-url-as-a-secret]

Before deploying, you need to set your `DATABASE_URL` as a secret in Cloudflare Workers. This keeps your database connection string secure in production.

  

#### bun

```bash
bunx wrangler secret put DATABASE_URL
```

#### pnpm

```bash
pnpm dlx wrangler secret put DATABASE_URL
```

#### yarn

```bash
yarn dlx wrangler secret put DATABASE_URL
```

#### npm

```bash
npx wrangler secret put DATABASE_URL
```

When prompted, paste your database connection string from the `.env` file.

### 4.2. Deploy your Worker [#42-deploy-your-worker]

Deploy your Worker to Cloudflare:

  

#### bun

```bash
bun run deploy
```

#### pnpm

```bash
pnpm run deploy
```

#### yarn

```bash
yarn deploy
```

#### npm

```bash
npm run deploy
```

Once deployed, Cloudflare will provide you with a URL where your Worker is live (e.g., `https://prisma-postgres-worker.your-subdomain.workers.dev`).

Visit the URL in your browser, and you'll see your Worker creating users in production!

## Next steps [#next-steps]

Now that you have a working Cloudflare Workers app connected to a Prisma Postgres database, you can:

* Add routes to handle different HTTP methods (GET, POST, PUT, DELETE)
* Extend your Prisma schema with more models and relationships
* Implement authentication and authorization
* Use [Hono](https://hono.dev/) for routing and middleware on Cloudflare Workers (see our [Hono guide](https://www.prisma.io/docs/guides/v7/frameworks/hono))
* Use the [`@prisma/ppg` serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver) to connect over HTTP instead of TCP, which removes the need for the `nodejs_compat` flag
* Read [Deploy to Cloudflare](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare) for a deeper reference on edge deployment options
* [Cloudflare Workers documentation](https://developers.cloudflare.com/workers/)
* [Prisma ORM documentation](https://www.prisma.io/docs/orm/v7)

## Related pages

- [`Bun workspaces`](https://www.prisma.io/docs/guides/v7/deployment/bun-workspaces): Learn step-by-step how to integrate Prisma ORM in a Bun workspaces monorepo through a shared database package
- [`Cloudflare D1`](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-d1): Learn how to use Prisma ORM with Cloudflare D1
- [`Docker`](https://www.prisma.io/docs/guides/v7/deployment/docker): Learn step-by-step configure a Prisma ORM app in Docker
- [`pnpm workspaces`](https://www.prisma.io/docs/guides/v7/deployment/pnpm-workspaces): Learn step-by-step how to integrate Prisma ORM in a pnpm workspaces monorepo through a shared database package
- [`Turborepo`](https://www.prisma.io/docs/guides/v7/deployment/turborepo): Learn step-by-step how to integrate Prisma ORM with Turborepo through a shared database package

# Docker (Prisma ORM v7) (/docs/guides/v7/deployment/docker)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn step-by-step configure a Prisma ORM app in Docker

Location: Guides > v7 > Deployment > Docker

This guide walks you through setting up a Prisma ORM application within a Docker environment. You'll learn how to configure a Node.js project, integrate Prisma for database management, and orchestrate the application using Docker Compose. By the end, you'll have a fully functional Prisma application running in a Docker container.

## Prerequisites [#prerequisites]

* [Docker](https://docs.docker.com/) and [Docker Compose](https://docs.docker.com/compose/) installed
* Node.js version: A [compatible Node.js version](https://www.prisma.io/docs/orm/v7/reference/system-requirements), required for Prisma 7.

See our [system requirements](https://www.prisma.io/docs/orm/v7/reference/system-requirements) for all minimum version requirements.

Before starting, ensure that no PostgreSQL services are running locally, and that the following ports are free to avoid conflicts: `5432` (PostgreSQL), `3000` (application server) or `5555` (Prisma Studio server).

To stop existing PostgreSQL services, use:

```bash
sudo systemctl stop postgresql  # Linux
brew services stop postgresql   # macOS
net stop postgresql             # Windows (Run as Administrator)
```

To stop all running Docker containers and free up ports:

```bash
docker ps -q | xargs docker stop
```

## 1. Set up your Node.js and Prisma application [#1-set-up-your-nodejs-and-prisma-application]

Start by creating a small Node.js application with Prisma ORM and [Express.js](https://expressjs.com/).

### 1.1. Initialize your project [#11-initialize-your-project]

First, create a new project directory and initialize a Node.js project:

  

#### bun

```bash
mkdir docker-test
cd docker-test
bun init
```

#### pnpm

```bash
mkdir docker-test
cd docker-test
pnpm init
```

#### yarn

```bash
mkdir docker-test
cd docker-test
yarn init
```

#### npm

```bash
mkdir docker-test
cd docker-test
npm init
```

This will generate a `package.json` file:

```json title="package.json"
{
  "name": "docker-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {},
  "keywords": [],
  "author": "",
  "license": "ISC"
}
```

### 1.2. Install required dependencies [#12-install-required-dependencies]

Next, install the Prisma CLI as a development dependency and Express.js for the server:

  

#### bun

```bash
bun add prisma@prev @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev @types/pg --dev
```

#### npm

```bash
npm install prisma@prev @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv express
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv express
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv express
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv express
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

### 1.3. Set up Prisma ORM [#13-set-up-prisma-orm]

Now, initialize Prisma to generate the necessary files:

  

#### bun

```bash
bunx --bun prisma init --output ../generated/prisma_client
```

#### pnpm

```bash
pnpm prisma init --output ../generated/prisma_client
```

#### yarn

```bash
yarn prisma init --output ../generated/prisma_client
```

#### npm

```bash
npx prisma init --output ../generated/prisma_client
```

This creates:

* A `prisma` folder containing `schema.prisma`, where you will define your database schema.
* An `.env` file in the project root, which stores environment variables.

Add a `User` model to the `schema.prisma` file located in the `prisma/schema.prisma` folder:

```prisma title="prisma/schema.prisma"
datasource db {
  provider = "postgresql"
}

generator client {
  provider = "prisma-client"
  output = "../generated/prisma_client" // [!code ++]
}

model User { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  createdAt DateTime @default(now()) // [!code ++]
  email     String   @unique // [!code ++]
  name      String? // [!code ++]
} // [!code ++]
```

> [!NOTE]
> In the `schema.prisma` file, we specify a [custom `output` path](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider) where Prisma will generate its types. This ensures Prisma's types are resolved correctly across different package managers and can be accessed by application consistently inside the container without any permission issues. In this guide, the types will be generated in the `./generated/prisma_client` directory.

Now, create a `prisma.config.ts` file in the root of your project:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

> [!NOTE]
> You'll need to install the `dotenv` package to load environment variables:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 

### 1.4. Create an Express.js server [#14-create-an-expressjs-server]

With the Prisma schema in place, create an Express.js server to interact with the database. Start by creating an `index.js` file:

```bash
touch index.js
```

Add the following code to set up a basic Express server:

```js title="index.js"
const express = require("express"); // [!code ++]
const { PrismaClient } = require("./generated/prisma_client/client"); // [!code ++]
const { PrismaPg } = require("@prisma/adapter-pg"); // [!code ++]
// [!code ++]
const adapter = new PrismaPg({
  // [!code ++]
  connectionString: process.env.DATABASE_URL, // [!code ++]
}); // [!code ++]
// [!code ++]
const app = express(); // [!code ++]
const prisma = new PrismaClient({
  // [!code ++]
  adapter, // [!code ++]
}); // [!code ++]
app.use(express.json()); // [!code ++]
// [!code ++]
// Get all users // [!code ++]
app.get("/", async (req, res) => {
  // [!code ++]
  const userCount = await prisma.user.count(); // [!code ++]
  res.json(
    // [!code ++]
    userCount == 0 // [!code ++]
      ? "No users have been added yet." // [!code ++]
      : "Some users have been added to the database.", // [!code ++]
  ); // [!code ++]
}); // [!code ++]
// [!code ++]
const PORT = 3000; // [!code ++]
// [!code ++]
app.listen(PORT, () => {
  // [!code ++]
  console.log(`Server is running on http://localhost:${PORT}`); // [!code ++]
}); // [!code ++]
```

Update the `package.json` scripts to include commands for running the server and deploying migrations:

```json title="package.json"
"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1", // [!code --]
  "dev": "node index.js", // [!code ++]
  "db:deploy": "npx prisma migrate deploy && npx prisma generate" // [!code ++]
}
```

With the application set up, the next step is to configure a PostgreSQL database using Docker Compose.

## 2. Set up a PostgreSQL database with Docker Compose [#2-set-up-a-postgresql-database-with-docker-compose]

To perform database migrations, we'll create a standalone PostgreSQL database using Docker Compose.

### 2.1. Create a Docker Compose file for PostgreSQL [#21-create-a-docker-compose-file-for-postgresql]

Create a `docker-compose.postgres.yml` file in the root directory:

```yml title="docker-compose.postgres.yml"
version: '3.7' // [!code ++]
 // [!code ++]
services: // [!code ++]
  postgres: // [!code ++]
    image: postgres:15 // [!code ++]
    restart: always // [!code ++]
    environment: // [!code ++]
      - POSTGRES_DB=postgres // [!code ++]
      - POSTGRES_USER=postgres // [!code ++]
      - POSTGRES_PASSWORD=prisma // [!code ++]
    ports: // [!code ++]
      - "5432:5432" // [!code ++]
    networks: // [!code ++]
      - prisma-network // [!code ++]
    healthcheck: // [!code ++]
      test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"] // [!code ++]
      interval: 5s // [!code ++]
      timeout: 2s // [!code ++]
      retries: 20 // [!code ++]
    volumes: // [!code ++]
      - postgres_data:/var/lib/postgresql/data // [!code ++]
    command: postgres -c listen_addresses='*' // [!code ++]
    logging: // [!code ++]
      options: // [!code ++]
        max-size: "10m" // [!code ++]
        max-file: "3" // [!code ++]
 // [!code ++]
networks: // [!code ++]
  prisma-network: // [!code ++]
 // [!code ++]
volumes: // [!code ++]
  postgres_data: // [!code ++]
```

### 2.2. Start the PostgreSQL container [#22-start-the-postgresql-container]

Run the following command to start the database:

```bash
docker compose -f docker-compose.postgres.yml up -d
```

### 2.3. Perform database migrations [#23-perform-database-migrations]

With the database running, update the `.env` file with the following database connection url:

```bash title=".env"
DATABASE_URL="postgresql://postgres:prisma@localhost:5432/postgres?schema=public" # [!code highlight]
```

Run the migration to create the database schema:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

Then generate Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This should generate a `migrations` folder in the `prisma` folder and the Prisma Client in the `generated/prisma_client` directory.

### 2.4. Test the application [#24-test-the-application]

Start the server and verify it works:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Visit [`http://localhost:3000`](http://localhost:3000) to see the message:

```bash
No users have been added yet.
```

Stop the local server.

### 2.5. Clean up the standalone database [#25-clean-up-the-standalone-database]

Once testing is complete, remove the standalone PostgreSQL container:

```bash
docker compose -f docker-compose.postgres.yml down --remove-orphans
```

This command will:

* Stop running containers.
* Remove containers.
* Remove the default network created by Docker Compose.
* Remove associated volumes (if not named explicitly).

With the application tested locally, the next step is to containerize it with Docker.

## 3. Run the app and database together with Docker Compose [#3-run-the-app-and-database-together-with-docker-compose]

Containerizing the application means it runs the same way on any host that has Docker installed.

To do that create a `Dockerfile` in project root:

```bash
touch Dockerfile
```

For the next step, you'll need to choose between two options for the base image: `node:alpine` (lightweight) or `node:slim` (stable). Both options are fully supported by Prisma ORM, but may have to be configured differently.

### 3.1. Option 1: Use Linux Alpine (`node:alpine`) as a base image [#31-option-1-use-linux-alpine-nodealpine-as-a-base-image]

The `node:alpine` image is based on Alpine Linux, a lightweight Linux distribution that uses the `musl` C standard library. Choose it if you want a small container image. Prisma supports Alpine on `amd64` out of the box, and supports it on `arm64` since `prisma@4.10.0`.

Add the following content to the `Dockerfile`:

```shell title="Dockerfile"
FROM node:lts-alpine3.17

WORKDIR /usr/src/app

COPY package.json package-lock.json ./

RUN npm ci

COPY . .

CMD ["sh", "-c", "npm run db:deploy && npm run dev"]
```

> [!NOTE]
> When running on Linux Alpine, Prisma downloads engines that are compiled for the `musl` C standard library. Please don't install `glibc` on Alpine (e.g., via the `libc6-compat` package), as that would prevent Prisma from running successfully.

Related Docker images:

* `node:lts-alpine`
* `node:16-alpine`
* `node:14-alpine`

### 3.1. Option 2: Use Linux Debian (`node:slim`) as a base image [#31-option-2-use-linux-debian-nodeslim-as-a-base-image]

The `node:slim` image is based on Linux Debian, a stable and widely supported distribution that uses the `glibc` C standard library. It is mostly supported out of the box on `amd64` and `arm64`, making it a good choice if you're running into compatibility issues with Alpine or need a more production-ready environment. However, some older versions of this image may come without `libssl` installed, so it's sometimes necessary to install it manually.

Add the following content to the `Dockerfile`:

```shell title="Dockerfile"
FROM node:slim

RUN apt-get update -y \
&& apt-get install -y openssl

WORKDIR /usr/src/app

COPY package.json package-lock.json ./

RUN npm ci

COPY . .

CMD ["sh", "-c", "npm run db:deploy && npm run dev"]
```

Related Docker images:

* `node:lts-slim`
* `node:bullseye-slim`
* `node:buster-slim`
* `node:stretch-slim`

### 3.2. Create and configure a Docker Compose file [#32-create-and-configure-a-docker-compose-file]

With the `Dockerfile` ready, use Docker Compose to manage the app and the database together, so you can start and stop both with one command.

Create a `docker-compose.yml` file in your project folder:

```bash
touch docker-compose.yml
```

Add the following configuration to the file:

```yml title="docker-compose.yml"
version: '3.7' // [!code ++]
 // [!code ++]
services: // [!code ++]
  postgres_db: // [!code ++]
    image: postgres:15 // [!code ++]
    hostname: postgres_db // [!code ++]
    container_name: postgres_db // [!code ++]
    restart: always // [!code ++]
    environment: // [!code ++]
      POSTGRES_DB: postgres // [!code ++]
      POSTGRES_USER: postgres // [!code ++]
      POSTGRES_PASSWORD: prisma // [!code ++]
    ports: // [!code ++]
      - '5432:5432' // [!code ++]
    networks: // [!code ++]
      - prisma-network // [!code ++]
    healthcheck: // [!code ++]
      test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"] // [!code ++]
      interval: 5s // [!code ++]
      timeout: 2s // [!code ++]
      retries: 20 // [!code ++]
 // [!code ++]
  server: // [!code ++]
    build: // [!code ++]
      context: . // [!code ++]
      dockerfile: Dockerfile // [!code ++]
    ports: // [!code ++]
      - '3000:3000' // [!code ++]
    stdin_open: true // [!code ++]
    tty: true  # Keeps the container running for debugging // [!code ++]
    depends_on: // [!code ++]
      postgres_db: // [!code ++]
        condition: service_healthy // [!code ++]
    env_file: // [!code ++]
      - .env.prod // [!code ++]
    networks: // [!code ++]
      - prisma-network // [!code ++]
networks: // [!code ++]
  prisma-network: // [!code ++]
    name: prisma-network // [!code ++]
```

### 3.3. Configure environment variable for the container [#33-configure-environment-variable-for-the-container]

Before running the app, we need to configure the environment variables. Create a `.env.prod` file:

```
touch .env.prod
```

Add the following database connection url to the `.env.prod` file:

```bash title=".env.prod"
DATABASE_URL="postgresql://postgres:prisma@postgres_db:5432/postgres?schema=public" # [!code highlight]
```

### 3.4. Build and run the application [#34-build-and-run-the-application]

Build and run the app using Docker Compose:

```bash
docker compose -f docker-compose.yml up --build -d
```

Visit `http://localhost:3000` to see your app running with the message:

```bash
No users have been added yet.
```

### 3.5. Bonus: Add Prisma Studio for database management [#35-bonus-add-prisma-studio-for-database-management]

[Prisma Studio](https://www.prisma.io/docs/studio) offers a graphical user interface (GUI) that allows you to view and manage your database directly in the browser. It is useful for inspecting and editing data during development.

To add Prisma Studio to your Docker setup, update the `docker-compose.yml` file:

```yml title="docker.compose.yml"
version: '3.7'

services:
  postgres_db:
    image: postgres:15
    hostname: postgres_db
    container_name: postgres_db
    restart: always
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: prisma
    ports:
      - '5432:5432'
    networks:
      - prisma-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
      interval: 5s
      timeout: 2s
      retries: 20

  server:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - '3000:3000'
    stdin_open: true
    tty: true  # Keeps the container running for debugging
    depends_on:
      postgres_db:
        condition: service_healthy
    env_file:
      - .env.prod
    networks:
      - prisma-network
  prisma-studio: // [!code ++]
    image: node:lts-alpine3.17 // [!code ++]
    working_dir: /usr/src/app // [!code ++]
    volumes: // [!code ++]
      - .:/usr/src/app // [!code ++]
    command: npx prisma studio --port 5555 --browser none // [!code ++]
    ports: // [!code ++]
      - "5555:5555" // [!code ++]
    env_file: // [!code ++]
      - .env.prod // [!code ++]
    networks: // [!code ++]
      - prisma-network // [!code ++]
    depends_on: // [!code ++]
      postgres_db: // [!code ++]
        condition: service_healthy // [!code ++]
      server: // [!code ++]
        condition: service_started // [!code ++]
networks:
  prisma-network:
    name: prisma-network
```

This will start Prisma Studio at [`http://localhost:5555`](http://localhost:5555) alongside the main app at [`http://localhost:3000`](http://localhost:3000). You can use Prisma Studio to manage your database with a GUI.

Run the following command to start everything:

```bash
docker compose -f docker-compose.yml up --build -d
```

Your Prisma app and database now run together under Docker Compose.

## Related pages

- [`Bun workspaces`](https://www.prisma.io/docs/guides/v7/deployment/bun-workspaces): Learn step-by-step how to integrate Prisma ORM in a Bun workspaces monorepo through a shared database package
- [`Cloudflare D1`](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-d1): Learn how to use Prisma ORM with Cloudflare D1
- [`Cloudflare Workers`](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-workers): Learn how to use Prisma ORM and Prisma Postgres in a Cloudflare Workers project
- [`pnpm workspaces`](https://www.prisma.io/docs/guides/v7/deployment/pnpm-workspaces): Learn step-by-step how to integrate Prisma ORM in a pnpm workspaces monorepo through a shared database package
- [`Turborepo`](https://www.prisma.io/docs/guides/v7/deployment/turborepo): Learn step-by-step how to integrate Prisma ORM with Turborepo through a shared database package

# pnpm workspaces (Prisma ORM v7) (/docs/guides/v7/deployment/pnpm-workspaces)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn step-by-step how to integrate Prisma ORM in a pnpm workspaces monorepo through a shared database package

Location: Guides > v7 > Deployment > pnpm workspaces

This guide shows you how to set up Prisma ORM in its own package within a [pnpm Workspaces](https://pnpm.io/workspaces) monorepo, so that every app in the workspace shares one Prisma Client and one set of generated types.

### What you'll learn: [#what-youll-learn]

* How to initialize a monorepo using pnpm Workspaces.
* Steps to integrate Prisma as a standalone package.
* How to generate and share the Prisma Client across packages.
* Integrating the Prisma package into an application within your workspace.

## 1. Prepare your project and configure pnpm workspaces [#1-prepare-your-project-and-configure-pnpm-workspaces]

Before integrating Prisma, you need to set up your project structure. Start by creating a new directory for your project (for example, `my-monorepo`) and initialize a Node.js project:

```bash
mkdir my-monorepo
cd my-monorepo
pnpm init
```

Next, create a `pnpm-workspace.yaml` file to define your workspace structure and pin the Prisma version:

```bash
touch pnpm-workspace.yaml
```

Add the following configuration to `pnpm-workspace.yaml`:

```yaml title="pnpm-workspace.yaml"
packages:
  - "apps/*"
  - "packages/*"
catalogs:
  prisma:
    prisma: 7.10.0
```

> [!NOTE]
> The `catalogs` help you pin a certain version of prisma across your repositories. You can learn more about them in [the pnpm catalogs documentation](https://pnpm.io/catalogs). *Explicitly* pin [prisma](https://www.npmjs.com/package/prisma) to `7.10.0` in the `pnpm-workspace.yaml` file.

Finally, create directories for your applications and shared packages:

```bash
mkdir apps
mkdir -p packages/database
```

## 2. Setup the shared database package [#2-setup-the-shared-database-package]

This section covers creating a standalone database package that uses Prisma. The package will house all database models and the generated Prisma Client, making it reusable across your monorepo.

### 2.1. Initialize the package and install dependencies [#21-initialize-the-package-and-install-dependencies]

Navigate to the `packages/database` directory and initialize a new package:

```bash
cd packages/database
pnpm init
```

Add Prisma as a development dependency in your `package.json` using the pinned `catalog`:

```json title="database/package.json"
"devDependencies": { // [!code ++]
  "prisma": "catalog:prisma" // [!code ++]
} // [!code ++]
```

Then install Prisma:

```bash
pnpm install
```

Then, add additional dependencies:

```bash
pnpm add typescript tsx @types/node @types/pg -D
pnpm add @prisma/adapter-pg pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Initialize a `tsconfig.json` file for your `database` package:

```bash
pnpm tsc --init
```

### 2.2. Setup Prisma ORM in your database package [#22-setup-prisma-orm-in-your-database-package]

Initialize Prisma ORM with an instance of [Prisma Postgres](https://www.prisma.io/docs/postgres) in the `database` package by running the following command:

```bash
pnpm prisma init
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This command:

* Creates a `prisma` directory containing a `schema.prisma` file for your database models.
* Creates a `.env` file with a local `DATABASE_URL`.

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

```bash
npx create-db
```

Edit the `schema.prisma` file to define a `User` model in your database and specify a [custom `output` directory](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider) to generate the Prisma Client. This ensures that generated types are resolved correctly:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output = "../generated/client" // [!code ++]
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
} // [!code ++]
```

Now, create a `prisma.config.ts` file in the `database` package to configure Prisma:

```typescript title="database/prisma.config.ts"
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config"; // [!code ++]
// [!code ++]
export default defineConfig({
  // [!code ++]
  schema: "prisma/schema.prisma", // [!code ++]
  migrations: {
    // [!code ++]
    path: "prisma/migrations", // [!code ++]
  }, // [!code ++]
  datasource: {
    // [!code ++]
    url: env("DATABASE_URL"), // [!code ++]
  }, // [!code ++]
}); // [!code ++]
```

> [!NOTE]
> You'll need to install the `dotenv` package to load environment variables from the `.env` file:
> 
> ```bash
> pnpm add dotenv
> ```

Next, add helper scripts to your `package.json` to simplify Prisma commands:

```json title="database/package.json"
{
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1", // [!code --]
    "db:generate": "prisma generate", // [!code ++]
    "db:migrate": "prisma migrate dev", // [!code ++]
    "db:deploy": "prisma migrate deploy", // [!code ++]
    "db:studio": "prisma studio" // [!code ++]
  }
}
```

Use [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) to migrate your database changes:

```bash
pnpm run db:migrate
```

When prompted by the CLI, enter a descriptive name for your migration.

Once the migration is successful, create a `client.ts` file to initialize Prisma Client with a driver adapter:

```ts title="database/client.ts"
import { PrismaClient } from "./generated/client/client"; // [!code ++]
import { PrismaPg } from "@prisma/adapter-pg"; // [!code ++]
// [!code ++]
const adapter = new PrismaPg({
  // [!code ++]
  connectionString: process.env.DATABASE_URL, // [!code ++]
}); // [!code ++]
// [!code ++]
// Use globalThis for broader environment compatibility // [!code ++]
const globalForPrisma = globalThis as typeof globalThis & {
  // [!code ++]
  prisma?: PrismaClient; // [!code ++]
}; // [!code ++]
// [!code ++]
// Named export with global memoization // [!code ++]
export const prisma: PrismaClient = // [!code ++]
  globalForPrisma.prisma ??
  new PrismaClient({
    // [!code ++]
    adapter, // [!code ++]
  }); // [!code ++]
// [!code ++]
if (process.env.NODE_ENV !== "production") {
  // [!code ++]
  globalForPrisma.prisma = prisma; // [!code ++]
} // [!code ++]
```

Then, create an `index.ts` file to re-export the instance of Prisma Client and all generated types:

```ts title="database/index.ts"
export { prisma } from "./client"; // [!code ++]
export * from "./generated/client/client"; // [!code ++]
```

At this point, your shared database package is fully configured and ready for use across your monorepo.

## 3. Set up and integrate your frontend application [#3-set-up-and-integrate-your-frontend-application]

Now that the database package is set up, create a frontend application (using Next.js) that uses the shared Prisma Client to interact with your database.

### 3.1. Bootstrap a Next.js application [#31-bootstrap-a-nextjs-application]

Navigate to the `apps` directory:

```bash
cd ../../apps
```

Create a new Next.js app named `web`:

```bash
pnpm create next-app@latest web --yes
```

> [!NOTE]
> important
> 
> The `--yes` flag uses default configurations to bootstrap the Next.js app (which in this guide uses the app router without a `src/` directory and `pnpm` as the installer).
> 
> The flag may also initialize a Git repository in the `web` folder. If that happens, please remove the `.git` directory by running `rm -r .git`.

Then, navigate into the web directory:

```bash
cd web/
```

Copy the `.env` file from the database package to ensure the same environment variables are available:

```bash
cp ../../packages/database/.env .
```

Open the `package.json` file of your Next.js app and add the shared `database` package as a dependency:

```json title="web/package.json"
"dependencies": {
  "database": "workspace:*", // [!code ++]
  // additional dependencies
  // ...
}
```

Run the following command to install the `database` package:

```bash
pnpm install
```

### 3.2. Integrate the shared `database` package in your app code [#32-integrate-the-shared-database-package-in-your-app-code]

Modify your Next.js application code to use Prisma Client from the database package. Update `app/page.tsx` as follows:

```tsx title="app/page.tsx"
import { prisma } from "database";

export default async function Home() {
  const user = await prisma.user.findFirst({
    select: {
      name: true,
    },
  });

  return (
    <div>
      {user?.name && <p>Hello from {user.name}</p>}
      {!user?.name && <p>No user has been added to the database yet.</p>}
    </div>
  );
}
```

This code demonstrates importing and using the shared Prisma Client to query your `User` model.

### 3.3. Add helper scripts and run your application [#33-add-helper-scripts-and-run-your-application]

Add the following scripts to the root `package.json` of your monorepo. They ensure that database migrations, type generation, and app builds run in the proper order:

```json
"scripts": {
  "build": "pnpm --filter database db:deploy && pnpm --filter database db:generate  && pnpm --filter web build", // [!code ++]
  "start": "pnpm --filter web start", // [!code ++]
  "dev": "pnpm --filter database db:generate && pnpm --filter web dev", // [!code ++]
  "studio": "pnpm --filter database db:studio" // [!code ++]
}
```

### 3.4. Run your application [#34-run-your-application]

Then head back to the root of the monorepo:

```bash
cd ../../
```

Start your development server by executing:

```bash
pnpm run dev
```

Open your browser at [`http://localhost:3000`](http://localhost:3000) to see your app in action.

### 3.5. (Optional) Add data to your database using Prisma Studio [#35-optional-add-data-to-your-database-using-prisma-studio]

There shouldn't be data in your database yet. You can execute `pnpm run studio` in your CLI to start a [Prisma Studio](https://www.prisma.io/docs/studio) in [`http://localhost:5555`](http://localhost:5555) to interact with your database and add data to it.

## Next Steps [#next-steps]

You have now created a monorepo that uses Prisma ORM, with a shared database package integrated into a Next.js application.

To add task orchestration and caching on top of this setup, see the [How to use Prisma ORM with Turborepo](https://www.prisma.io/docs/guides/v7/deployment/turborepo) guide.

## Related pages

- [`Bun workspaces`](https://www.prisma.io/docs/guides/v7/deployment/bun-workspaces): Learn step-by-step how to integrate Prisma ORM in a Bun workspaces monorepo through a shared database package
- [`Cloudflare D1`](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-d1): Learn how to use Prisma ORM with Cloudflare D1
- [`Cloudflare Workers`](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-workers): Learn how to use Prisma ORM and Prisma Postgres in a Cloudflare Workers project
- [`Docker`](https://www.prisma.io/docs/guides/v7/deployment/docker): Learn step-by-step configure a Prisma ORM app in Docker
- [`Turborepo`](https://www.prisma.io/docs/guides/v7/deployment/turborepo): Learn step-by-step how to integrate Prisma ORM with Turborepo through a shared database package

# Turborepo (Prisma ORM v7) (/docs/guides/v7/deployment/turborepo)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn step-by-step how to integrate Prisma ORM with Turborepo through a shared database package

Location: Guides > v7 > Deployment > Turborepo

This guide shows you how to set up Prisma ORM as a standalone package in a [Turborepo](https://turborepo.dev/docs) monorepo, so that multiple apps share one Prisma Client, one set of generated types, and one migration workflow.

#### What you'll learn: [#what-youll-learn]

* How to set up Prisma in a Turborepo monorepo.
* Steps to generate and reuse PrismaClient across packages.
* Integrating the Prisma package into other applications in the monorepo.

### Prerequisites [#prerequisites]

* [Node.js 20.19.0+](https://nodejs.org/)
* [TypeScript 5.4.0+](https://www.typescriptlang.org/)

## 1. Set up your project [#1-set-up-your-project]

To set up a Turborepo monorepo named `turborepo-prisma`, run the following command:

  

#### bun

```bash
bunx create-turbo@latest turborepo-prisma
```

#### pnpm

```bash
pnpm dlx create-turbo@latest turborepo-prisma
```

#### yarn

```bash
yarn dlx create-turbo@latest turborepo-prisma
```

#### npm

```bash
npx create-turbo@latest turborepo-prisma
```

You'll be prompted to select your package manager, this guide will use `npm`:

> [!NOTE]
> * *Which package manager do you want to use?* `npm`

After the setup, navigate to the project root directory:

```bash
cd turborepo-prisma
```

## 2. Add a new `database` package to the monorepo [#2-add-a-new-database-package-to-the-monorepo]

### 2.1 Create the package and install Prisma [#21-create-the-package-and-install-prisma]

Create a `database` directory inside `packages` and navigate into it:

```bash
mkdir -p packages/database
cd packages/database
```

Then initialize it with a `package.json`:

```json title="packages/database/package.json"
{
  "name": "@repo/db",
  "version": "0.0.0"
}
```

Then install the required Prisma ORM dependencies:

  

#### bun

```bash
bun add prisma@prev --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### yarn

```bash
yarn add prisma@prev --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### npm

```bash
npm install prisma@prev --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

### 2.2. Initialize Prisma and define models [#22-initialize-prisma-and-define-models]

Inside the `database` directory, initialize Prisma by running:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

This will create several files inside `packages/database`:

* A `prisma` directory with a `schema.prisma` file.
* A `prisma.config.ts` file for configuring Prisma.
* A `.env` file containing a local `DATABASE_URL` in the `packages/database` directory.

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

```bash
npx create-db
```

In the `packages/database/prisma/schema.prisma` file, add the following models:

```prisma title="packages/database/prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]
```

The `prisma.config.ts` file created in the `packages/database` directory should look like this:

```typescript title="packages/database/prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

> [!WARNING]
> It is recommended to add `packages/database/generated` to your root `.gitignore` because generated Prisma Client code is a build artifact that can be recreated with `db:generate`.

#### The importance of generating Prisma types in a custom directory [#the-importance-of-generating-prisma-types-in-a-custom-directory]

In the `schema.prisma` file, we specify a custom [`output`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider) path where Prisma will generate its types. This ensures Prisma's types are resolved correctly across different package managers.

> [!NOTE]
> In this guide, the types will be generated in the `database/generated/prisma` directory.

### 2.3. Add scripts and run migrations [#23-add-scripts-and-run-migrations]

Add the following scripts to the `package.json` inside `packages/database`:

```json title="packages/database/package.json"
{
  "name": "@repo/db",
  "version": "0.0.0",
  "type": "module", // [!code ++]
  "scripts": {
    // [!code ++]
    "db:generate": "prisma generate", // [!code ++]
    "db:migrate": "prisma migrate dev", // [!code ++]
    "db:deploy": "prisma migrate deploy" // [!code ++]
  }, // [!code ++]
  "devDependencies": {
    "prisma": "7.10.0"
  },
  "dependencies": {
    "@prisma/client": "7.10.0",
    "@prisma/adapter-pg": "^7.0.0",
    "pg": "^8.0.0",
    "dotenv": "^16.0.0"
  }
}
```

Also add these scripts to `turbo.json` in the root and ensure that `DATABASE_URL` is added to the environment:

```json title="turbo.json"
{
  "$schema": "https://turborepo.dev/schema.json",
  "ui": "tui",
  "globalEnv": ["DATABASE_URL"], // [!code ++]
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "check-types": {
      "dependsOn": ["^check-types"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "db:generate": { // [!code ++]
      "cache": false // [!code ++]
    }, // [!code ++]
    "db:migrate": { // [!code ++]
      "cache": false // [!code ++]
    }, // [!code ++]
    "db:deploy": { // [!code ++]
      "cache": false // [!code ++]
    } // [!code ++]
  }
}
```

Run your first migration and generate Prisma Client

Navigate to the project root and run the following command to create and apply your first migration:

  

#### bun

```bash
bunx turbo run db:migrate -- --name init
```

#### pnpm

```bash
pnpm dlx turbo run db:migrate -- --name init
```

#### yarn

```bash
yarn dlx turbo run db:migrate -- --name init
```

#### npm

```bash
npx turbo run db:migrate -- --name init
```

In Prisma 7, `migrate dev` no longer runs `prisma generate` automatically, so run generate explicitly:

  

#### bun

```bash
bunx turbo run db:generate
```

#### pnpm

```bash
pnpm dlx turbo run db:generate
```

#### yarn

```bash
yarn dlx turbo run db:generate
```

#### npm

```bash
npx turbo run db:generate
```

Use the same `npx turbo run db:generate` command after future schema changes.

### 2.4. Export the Prisma client and types [#24-export-the-prisma-client-and-types]

Next, export the generated types and an instance of `PrismaClient` so it can be used in your applications.

In the `packages/database` directory, create a `src` folder and add a `client.ts` file. This file will define an instance of `PrismaClient`:

```ts title="packages/database/src/client.ts"
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
});

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };

export const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    adapter,
  });

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
```

Then create an `index.ts` file in the `src` folder to re-export the generated prisma types and the `PrismaClient` instance:

```ts title="packages/database/src/index.ts"
export { prisma } from "./client"; // exports instance of prisma
export * from "../generated/prisma/client"; // exports generated types from prisma
```

Follow the [Just-in-Time packaging pattern](https://turborepo.dev/docs/core-concepts/internal-packages#just-in-time-packages) and create an entrypoint to the package inside `packages/database/package.json`:

> [!WARNING]
> If you're not using a bundler, use the [Compiled Packages](https://turborepo.dev/docs/core-concepts/internal-packages#compiled-packages) strategy instead.

```json title="packages/database/package.json"
{
  "name": "@repo/db",
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "db:generate": "prisma generate",
    "db:migrate": "prisma migrate dev",
    "db:deploy": "prisma migrate deploy"
  },
  "devDependencies": {
    "prisma": "7.10.0"
  },
  "dependencies": {
    "@prisma/client": "7.10.0",
    "@prisma/adapter-pg": "^7.0.0",
    "pg": "^8.0.0",
    "dotenv": "^16.0.0"
  },
  "exports": {
    // [!code ++]
    ".": "./src/index.ts" // [!code ++]
  } // [!code ++]
}
```

By completing these steps, you'll make the Prisma types and `PrismaClient` instance accessible throughout the monorepo.

## 3. Import the `database` package in the web app [#3-import-the-database-package-in-the-web-app]

The `turborepo-prisma` project should have an app called `web` at `apps/web`. Add the `database` dependency to `apps/web/package.json`:

  

#### npm

```json
{
  // ...
  "dependencies": {
    "@repo/db": "*" // [!code ++]
    // ...
  }
  // ...
}
```

#### pnpm

```json
{
  // ...
  "dependencies": {
    "@repo/db": "workspace:*" // [!code ++]
    // ...
  }
  // ...
}
```

#### bun

```json
{
  // ...
  "dependencies": {
    "@repo/db": "workspace:*" // [!code ++]
    // ...
  }
  // ...
}
```

Run your package manager's install command from the project root to link the workspace dependency:

  

#### bun

```bash
bun install
```

#### pnpm

```bash
pnpm install
```

#### yarn

```bash
yarn install
```

#### npm

```bash
npm install
```

Import the instantiated `prisma` client from the `database` package in the `web` app.

In the `apps/web/app` directory, open the `page.tsx` file and add the following code:

```tsx title="apps/web/app/page.tsx"
import styles from "./page.module.css";
import { prisma } from "@repo/db";

export default async function Home() {
  const user = await prisma.user.findFirst();
  return <div className={styles.page}>{user?.name ?? "No user added yet"}</div>;
}
```

Then, create a `.env` file in the `web` directory and copy into it the contents of the `.env` file from the `/database` directory containing the `DATABASE_URL`:

```text title="apps/web/.env"
DATABASE_URL="Same database URL as used in the database directory"
```

> [!NOTE]
> If you want to use a single `.env` file in the root directory across your apps and packages in a Turborepo setup, consider using a package like [`dotenvx`](https://dotenvx.com/docs/monorepos/turborepo).
> 
> To implement this, update the `package.json` files for each package or app to ensure they load the required environment variables from the shared `.env` file. For detailed instructions, refer to the [`dotenvx` guide for Turborepo](https://dotenvx.com/docs/monorepos/turborepo).
> 
> Turborepo [recommends using separate `.env` files for each package](https://turborepo.dev/docs/crafting-your-repository/using-environment-variables#use-env-files-in-packages) to promote modularity and avoid potential conflicts.

## 4. Configure task dependencies in Turborepo [#4-configure-task-dependencies-in-turborepo]

The `db:generate` script is essential for `dev` and `build` tasks in a monorepo setup.

If a new developer runs `turbo dev` on an application without first running `db:generate`, they will encounter errors.

To prevent this, ensure that `db:generate` is always executed before running `dev` or `build`. Keep `db:deploy` uncached for staging/production migration runs in CI. Here's how to configure this in your `turbo.json` file:

```json title="turbo.json"
{
  "$schema": "https://turborepo.dev/schema.json",
  "ui": "tui",
  "globalEnv": ["DATABASE_URL"],
  "tasks": {
    "build": {
      "dependsOn": ["^build", "^db:generate"], // [!code highlight]
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "check-types": {
      "dependsOn": ["^check-types"]
    },
    "dev": {
      "dependsOn": ["^db:generate"], // [!code ++]
      "cache": false,
      "persistent": true
    },
    "db:generate": {
      "cache": false
    },
    "db:migrate": {
      "cache": false
    },
    "db:deploy": {
      "cache": false
    }
  }
}
```

## 5. Run the project in development [#5-run-the-project-in-development]

Then from the project root run the project:

  

#### bun

```bash
bunx turbo run dev --filter=web
```

#### pnpm

```bash
pnpm dlx turbo run dev --filter=web
```

#### yarn

```bash
yarn dlx turbo run dev --filter=web
```

#### npm

```bash
npx turbo run dev --filter=web
```

Navigate to the `http://localhost:3000` and you should see the message:

```
No user added yet
```

> [!NOTE]
> You can add users to your database by creating a seed script or manually by using [Prisma Studio](https://www.prisma.io/docs/studio).
> 
> To use Prisma Studio to add manually data via a GUI, navigate inside the `packages/database` directory and run `prisma studio` using your package manager:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bunx prisma studio
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm prisma studio
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn prisma studio
>     ```
>
> 
>   #### npm

>     ```bash
>     npx prisma studio
>     ```
>
> 
> 
> This command starts a server with a GUI at [http://localhost:5555](http://localhost:5555), allowing you to view and modify your data.

Prisma ORM is now set up as a shared package in your Turborepo.

## Next Steps [#next-steps]

* Expand your Prisma models to handle more complex data relationships.
* Implement additional CRUD operations.
* Check out [Prisma Postgres](https://www.prisma.io/postgres) to see how you can scale your application.

### More Info [#more-info]

* [Turborepo Docs](https://turborepo.dev/docs)
* [Next.js Docs](https://nextjs.org/docs)
* [Prisma ORM Docs](https://www.prisma.io/docs/orm/v7)

## Related pages

- [`Bun workspaces`](https://www.prisma.io/docs/guides/v7/deployment/bun-workspaces): Learn step-by-step how to integrate Prisma ORM in a Bun workspaces monorepo through a shared database package
- [`Cloudflare D1`](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-d1): Learn how to use Prisma ORM with Cloudflare D1
- [`Cloudflare Workers`](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-workers): Learn how to use Prisma ORM and Prisma Postgres in a Cloudflare Workers project
- [`Docker`](https://www.prisma.io/docs/guides/v7/deployment/docker): Learn step-by-step configure a Prisma ORM app in Docker
- [`pnpm workspaces`](https://www.prisma.io/docs/guides/v7/deployment/pnpm-workspaces): Learn step-by-step how to integrate Prisma ORM in a pnpm workspaces monorepo through a shared database package

# Astro (Prisma ORM v7) (/docs/guides/v7/frameworks/astro)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in an Astro app

Location: Guides > v7 > Frameworks > Astro

## Introduction [#introduction]

[Astro](https://astro.build/) is a web framework for content-driven sites. In this guide, an Astro API route is where you call Prisma ORM to read from a [Prisma Postgres](https://www.prisma.io/postgres) database.

In this guide, you'll learn to integrate Prisma ORM with a Prisma Postgres database in an Astro project from scratch. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/astro).

## Quick start [#quick-start]

Run one command to scaffold an Astro project with Prisma ORM and Prisma Postgres ready to go:

  

#### bun

```bash
bunx create-prisma@stable --template astro
```

#### pnpm

```bash
pnpm create prisma@stable --template astro
```

#### yarn

```bash
yarn create prisma@stable --template astro
```

#### npm

```bash
npm create prisma@stable -- --template astro
```

Or follow the steps below to set it up manually.

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* [Astro VSCode extension (recommended)](https://marketplace.visualstudio.com/items?itemName=astro-build.astro-vscode)

## 1. Set up your project [#1-set-up-your-project]

Create a new Astro project:

  

#### bun

```bash
bunx create-astro@latest
```

#### pnpm

```bash
pnpm dlx create-astro@latest
```

#### yarn

```bash
yarn dlx create-astro@latest
```

#### npm

```bash
npx create-astro@latest
```

> [!NOTE]
> * *Where should we create your new project?* `astro-prisma`
> * *How would you like to start your new project?* `Use minimal (empty) template `
> * *Install dependencies? (recommended)* `Yes`
> * *Initialize a new git repository? (optional)* `Yes`

Navigate into the newly created project directory:

```bash
cd astro-prisma
```

## 2. Install and Configure Prisma [#2-install-and-configure-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../prisma/generated
```

#### pnpm

```bash
pnpm prisma init --output ../prisma/generated
```

#### yarn

```bash
yarn prisma init --output ../prisma/generated
```

#### npm

```bash
npx prisma init --output ../prisma/generated
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma/` directory with a `schema.prisma` file
* A `prisma.config.ts` file for configuring Prisma
* A `.env` file with a local `DATABASE_URL` already set

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define your Prisma Schema [#22-define-your-prisma-schema]

In the `prisma/schema.prisma` file, add the following models and change the generator to use the `prisma-client` provider:

```prisma title="prisma/schema.prisma"
generator client {
  provider   = "prisma-client"
  output     = "../prisma/generated"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]
```

This creates two models: `User` and `Post`, with a one-to-many relationship between them.

### 2.3 Add `dotenv` to `prisma.config.ts` [#23-add-dotenv-to-prismaconfigts]

To get access to the variables in the `.env` file, they can either be loaded by your runtime, or by using `dotenv`.
Include an import for `dotenv` at the top of the `prisma.config.ts`

```ts
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.4. Run migrations and generate Prisma Client [#24-run-migrations-and-generate-prisma-client]

Now, run the following command to create the database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

Then generate Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 2.5. Seed the database [#25-seed-the-database]

Add some seed data to populate the database with sample users and posts.

Create a new file called `seed.ts` in the `prisma/` directory:

```typescript title="prisma/seed.ts"
import { PrismaClient, Prisma } from "../prisma/generated/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

const userData: Prisma.UserCreateInput[] = [
  {
    name: "Alice",
    email: "alice@prisma.io",
    posts: {
      create: [
        {
          title: "Join the Prisma Discord",
          content: "https://pris.ly/discord",
          published: true,
        },
        {
          title: "Prisma on YouTube",
          content: "https://pris.ly/youtube",
        },
      ],
    },
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
    posts: {
      create: [
        {
          title: "Follow Prisma on Twitter",
          content: "https://www.twitter.com/prisma",
          published: true,
        },
      ],
    },
  },
];

export async function main() {
  console.log("Starting to seed...");

  for (const u of userData) {
    await prisma.user.upsert({
      where: { email: u.email },
      update: {},
      create: u,
    });
  }

  console.log("Seeding finished.");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

Now, tell Prisma how to run this script by updating your `prisma.config.ts`:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: `tsx prisma/seed.ts`,
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Run the seed script:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

And open Prisma Studio to inspect your data:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

## 3. Integrate Prisma into Astro [#3-integrate-prisma-into-astro]

### 3.1. Create TypeScript environment definitions [#31-create-typescript-environment-definitions]

First, create an `env.d.ts` file in your `src` directory to provide TypeScript definitions for environment variables:

```typescript title="src/env.d.ts"
interface ImportMetaEnv {
  readonly DATABASE_URL: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}
```

### 3.2. Create a Prisma Client [#32-create-a-prisma-client]

Inside of `/src`, create a `lib` directory and a `prisma.ts` file inside it. This file will be used to create and export your Prisma Client instance.

```bash
mkdir src/lib
touch src/lib/prisma.ts
```

Set up the Prisma client like this:

```typescript title="src/lib/prisma.ts"
import { PrismaClient } from "../../prisma/generated/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: import.meta.env.DATABASE_URL,
});

const prisma = new PrismaClient({
  adapter,
});

export default prisma;
```

> [!WARNING]
> We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently.
> 
> If you choose not to use one, **avoid** instantiating `PrismaClient` globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections.

### 3.3. Create an API route [#33-create-an-api-route]

An API route lets you query the database on the server and reuse the result from your pages.

Create a new file called `api/users.ts` in the `src/pages` directory:

```bash
mkdir src/pages/api
touch src/pages/api/users.ts
```

Now, create a GET route that fetches the `Users` data from your database, making sure to include each user's `Posts` by adding them to the `include` field:

```typescript title="src/pages/api/users.ts"
import type { APIRoute } from "astro";
import prisma from "../../lib/prisma";

export const GET: APIRoute = async () => {
  const users = await prisma.user.findMany({
    include: { posts: true },
  });

  return new Response(JSON.stringify(users), {
    headers: { "Content-Type": "application/json" },
  });
};
```

### 3.4. Fetch the data from the API route (Recommended Method) [#34-fetch-the-data-from-the-api-route-recommended-method]

Instead of using `fetch()` with HTTP requests, Astro recommends importing endpoint functions directly. This approach is more efficient and avoids URL parsing issues.

Start by creating a new type that combines the `User` and `Post` models called `UserWithPosts`:

```tsx title="src/pages/index.astro"
---
import type { User, Post } from "../../prisma/generated/client"; // [!code ++]
import { GET } from "./api/users.ts"; // [!code ++]
 // [!code ++]
type UserWithPosts = User & { posts: Post[] }; // [!code ++]
 // [!code ++]
const response = await GET(Astro); // [!code ++]
const users: UserWithPosts[] = await response.json(); // [!code ++]
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <meta name="generator" content={Astro.generator} />
    <title>Astro + Prisma</title>
  </head>
  <body>
    <h1>Astro + Prisma</h1>
    <ul> // [!code ++]
      {users.map((user: UserWithPosts) => ( // [!code ++]
        <li> // [!code ++]
          <h2>{user.name}</h2> // [!code ++]
          <ul> // [!code ++]
            {user.posts.map((post: Post) => ( // [!code ++]
              <li>{post.title}</li> // [!code ++]
            ))} // [!code ++]
          </ul> // [!code ++]
        </li> // [!code ++]
      ))} // [!code ++]
    </ul> // [!code ++]
  </body>
</html>
```

### 3.5. Run your app [#35-run-your-app]

Now start your development server to see your Astro app in action:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open your browser at [`http://localhost:4321`](http://localhost:4321) to see the users and their posts displayed on the page.

## Summary [#summary]

Your Astro app now reads users and their posts from a Prisma Postgres database through the API route.

## Next Steps [#next-steps]

Now that you have a working Astro app connected to a Prisma Postgres database, you can:

* Extend your Prisma schema with more models and relationships
* Add create/update/delete routes and forms
* Explore authentication and validation

### More Info [#more-info]

* [Prisma Documentation](https://www.prisma.io/docs/orm/v7)
* [Astro Documentation](https://astro.build/docs)

## Related pages

- [`Elysia`](https://www.prisma.io/docs/guides/v7/frameworks/elysia): Learn how to use Prisma ORM in an Elysia app
- [`Hono`](https://www.prisma.io/docs/guides/v7/frameworks/hono): Learn how to use Prisma ORM in a Hono app
- [`NestJS`](https://www.prisma.io/docs/guides/v7/frameworks/nestjs): Learn how to use Prisma ORM in a NestJS app
- [`Next.js`](https://www.prisma.io/docs/guides/v7/frameworks/nextjs): Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel
- [`Nuxt`](https://www.prisma.io/docs/guides/v7/frameworks/nuxt): A step-by-step guide to setting up and using Prisma ORM and Prisma Postgres in a Nuxt app

# Elysia (Prisma ORM v7) (/docs/guides/v7/frameworks/elysia)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in an Elysia app

Location: Guides > v7 > Frameworks > Elysia

## Introduction [#introduction]

[Elysia](https://elysiajs.com/) is a web framework for Bun with end-to-end type safety. Its route handlers are where you call Prisma ORM to read and write a [Prisma Postgres](https://www.prisma.io/postgres) database, and Prismabox keeps its request and response schemas in sync with your Prisma models.

In this guide, you'll learn to integrate Prisma ORM with a Prisma Postgres database in an Elysia application. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/elysia).

## Quick start [#quick-start]

Run one command to scaffold an Elysia project with Prisma ORM and Prisma Postgres ready to go:

  

#### bun

```bash
bunx create-prisma@stable --template elysia
```

#### pnpm

```bash
pnpm create prisma@stable --template elysia
```

#### yarn

```bash
yarn create prisma@stable --template elysia
```

#### npm

```bash
npm create prisma@stable -- --template elysia
```

Or follow the steps below to set it up manually.

## Prerequisites [#prerequisites]

* [Bun](https://bun.sh/docs/installation) installed on your system

## 1. Set up your project [#1-set-up-your-project]

Create a new Elysia project:

  

#### bun

```bash
bunx create-elysia elysia-prisma
```

#### pnpm

```bash
pnpm create elysia elysia-prisma
```

#### yarn

```bash
yarn create elysia elysia-prisma
```

#### npm

```bash
npm create elysia@latest elysia-prisma
```

Navigate to the project directory:

```bash
cd elysia-prisma
```

## 2. Install and configure Prisma [#2-install-and-configure-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

Install the required Prisma packages, database adapter, and Prismabox (for generated TypeBox schemas):

  

#### bun

```bash
bun add prisma@prev bun-types --dev
bun add @prisma/client@7 @prisma/adapter-pg pg prismabox
```

#### pnpm

```bash
pnpm add prisma@prev bun-types --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg prismabox
```

#### yarn

```bash
yarn add prisma@prev bun-types --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg prismabox
```

#### npm

```bash
npm install prisma@prev bun-types --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg prismabox
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../src/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../src/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../src/generated/prisma
```

#### npm

```bash
npx prisma init --output ../src/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma/` directory with a `schema.prisma` file
* A `prisma.config.ts` file for configuring Prisma
* A `.env` file with a local `DATABASE_URL` already set

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define your Prisma Schema [#22-define-your-prisma-schema]

In the `prisma/schema.prisma` file, mirror the example app structure with Prismabox TypeBox generators and a `Todo` model:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

generator prismabox {
  provider                    = "prismabox"
  typeboxImportDependencyName = "elysia"
  typeboxImportVariableName   = "t"
  inputModel                  = true
  output                      = "../src/generated/prismabox"
}

datasource db {
  provider = "postgresql"
}

model Todo { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  completed Boolean  @default(false) // [!code ++]
  createdAt DateTime @default(now()) // [!code ++]
  updatedAt DateTime @updatedAt // [!code ++]
} // [!code ++]
```

This matches the Prisma Elysia example: it generates Prisma Client to `src/generated/prisma` and Prismabox TypeBox schemas to `src/generated/prismabox`.

#### Prismabox [#prismabox]

* A Prisma generator that reads your Prisma schema and emits Elysia-friendly TypeBox models.
* Generates files like `src/generated/prismabox/Todo.ts` (and one per model) with `TodoPlain`, `TodoPlainInputCreate`, etc.
* Use those generated models in routes to validate requests/responses and keep Elysia types in sync with your Prisma schema (also useful for OpenAPI/Eden).

### 2.3. Run migrations and generate Prisma Client [#23-run-migrations-and-generate-prisma-client]

Run the following commands to create the database tables and generate the Prisma Client:

  

#### bun

```bash
bunx prisma migrate dev --name init
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
pnpm prisma generate
```

#### yarn

```bash
yarn prisma migrate dev --name init
yarn prisma generate
```

#### npm

```bash
npx prisma migrate dev --name init
npx prisma generate
```

### 2.4. Seed the database [#24-seed-the-database]

Add some seed data to populate the database with sample todos (mirrors the example repo).

Create a new file called `seed.ts` in the `prisma/` directory:

```typescript title="prisma/seed.ts"
import { PrismaClient } from "../src/generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";

if (!process.env.DATABASE_URL) {
  throw new Error("DATABASE_URL is not set");
}

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
const prisma = new PrismaClient({ adapter });

const todoData = [
  { title: "Learn Elysia" },
  { title: "Learn Prisma" },
  { title: "Build something awesome", completed: true },
];

async function main() {
  console.log("Start seeding...");
  for (const todo of todoData) {
    const created = await prisma.todo.create({
      data: todo,
    });
    console.log(`Created todo with id: ${created.id}`);
  }
  console.log("Seeding finished.");
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the seed script:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

And open Prisma Studio to inspect your data:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

## 3. Integrate Prisma into Elysia [#3-integrate-prisma-into-elysia]

### 3.1. Create a Prisma Client instance [#31-create-a-prisma-client-instance]

Inside the `src/` directory, create a `lib` directory with a `prisma.ts` file. This file will create and export your Prisma Client instance and add the following code:

```typescript title="src/lib/prisma.ts"
import { PrismaClient } from "../generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";

const databaseUrl = process.env.DATABASE_URL;

if (!databaseUrl) {
  throw new Error("DATABASE_URL is not set");
}

const adapter = new PrismaPg({ connectionString: databaseUrl });
export const prisma = new PrismaClient({ adapter });
```

### 3.2. Create API routes [#32-create-api-routes]

Update your `src/index.ts` file to match the Prisma Elysia example, including Prismabox-generated validation types:

```typescript title="src/index.ts"
import { Elysia, t } from "elysia";
import { prisma } from "./lib/prisma";
import { TodoPlain, TodoPlainInputCreate, TodoPlainInputUpdate } from "./generated/prismabox/Todo";

const app = new Elysia()
  // Health check
  .get("/", () => {
    return { message: "Hello Elysia with Prisma!" };
  })

  // Get all todos
  .get(
    "/todos",
    async () => {
      const todos = await prisma.todo.findMany({
        orderBy: { createdAt: "desc" },
      });
      return todos;
    },
    {
      response: t.Array(TodoPlain),
    },
  )

  // Get a single todo by ID
  .get(
    "/todos/:id",
    async ({ params, set }) => {
      const id = Number(params.id);
      const todo = await prisma.todo.findUnique({
        where: { id },
      });

      if (!todo) {
        set.status = 404;
        return { error: "Todo not found" };
      }

      return todo;
    },
    {
      params: t.Object({
        id: t.Numeric(),
      }),
      response: {
        200: TodoPlain,
        404: t.Object({
          error: t.String(),
        }),
      },
    },
  )

  // Create a new todo
  .post(
    "/todos",
    async ({ body }) => {
      const todo = await prisma.todo.create({
        data: {
          title: body.title,
        },
      });
      return todo;
    },
    {
      body: TodoPlainInputCreate,
      response: TodoPlain,
    },
  )

  // Update a todo
  .put(
    "/todos/:id",
    async ({ params, body, set }) => {
      const id = Number(params.id);

      try {
        const todo = await prisma.todo.update({
          where: { id },
          data: {
            title: body.title,
            completed: body.completed,
          },
        });
        return todo;
      } catch {
        set.status = 404;
        return { error: "Todo not found" };
      }
    },
    {
      params: t.Object({
        id: t.Numeric(),
      }),
      body: TodoPlainInputUpdate,
      response: {
        200: TodoPlain,
        404: t.Object({
          error: t.String(),
        }),
      },
    },
  )

  // Toggle todo completion
  .patch(
    "/todos/:id/toggle",
    async ({ params, set }) => {
      const id = Number(params.id);

      try {
        const todo = await prisma.todo.findUnique({
          where: { id },
        });

        if (!todo) {
          set.status = 404;
          return { error: "Todo not found" };
        }

        const updated = await prisma.todo.update({
          where: { id },
          data: { completed: !todo.completed },
        });

        return updated;
      } catch {
        set.status = 404;
        return { error: "Todo not found" };
      }
    },
    {
      params: t.Object({
        id: t.Numeric(),
      }),
      response: {
        200: TodoPlain,
        404: t.Object({
          error: t.String(),
        }),
      },
    },
  )

  // Delete a todo
  .delete(
    "/todos/:id",
    async ({ params, set }) => {
      const id = Number(params.id);

      try {
        const todo = await prisma.todo.delete({
          where: { id },
        });
        return todo;
      } catch {
        set.status = 404;
        return { error: "Todo not found" };
      }
    },
    {
      params: t.Object({
        id: t.Numeric(),
      }),
      response: {
        200: TodoPlain,
        404: t.Object({
          error: t.String(),
        }),
      },
    },
  )

  .listen(3000);

console.log(`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`);
```

This creates the same endpoints as the official example:

* `GET /` - Health check
* `GET /todos` - Fetch all todos (newest first)
* `GET /todos/:id` - Fetch a single todo
* `POST /todos` - Create a todo
* `PUT /todos/:id` - Update a todo
* `PATCH /todos/:id/toggle` - Toggle completion
* `DELETE /todos/:id` - Delete a todo

Prismabox generates the `TodoPlain`/`TodoPlainInput*` TypeBox schemas so responses and request bodies are validated and typed.

### 3.3. Run the application [#33-run-the-application]

Start your Elysia server:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

You should see `🦊 Elysia is running at localhost:3000` in the console.

### 3.4. Test the API [#34-test-the-api]

Test the endpoints using `curl`:

```bash
# Health check
curl http://localhost:3000/ | jq

# Get all todos
curl http://localhost:3000/todos | jq

# Get a single todo
curl http://localhost:3000/todos/1 | jq

# Create a new todo
curl -X POST http://localhost:3000/todos \
  -H "Content-Type: application/json" \
  -d '{"title": "Ship the Prisma + Elysia guide"}' | jq

# Toggle completion
curl -X PATCH http://localhost:3000/todos/1/toggle | jq

# Update a todo
curl -X PUT http://localhost:3000/todos/1 \
  -H "Content-Type: application/json" \
  -d '{"title": "Updated title", "completed": true}' | jq

# Delete a todo
curl -X DELETE http://localhost:3000/todos/1 | jq
```

Your Elysia app now serves a todo API backed by a Prisma Postgres database.

## Next steps [#next-steps]

Now that you have a working Elysia app connected to a Prisma Postgres database, you can:

* Extend your Prisma schema with more models and relationships
* Add update and delete endpoints
* Explore authentication with [Elysia plugins](https://elysiajs.com/plugins/overview.html)
* Use [Eden](https://elysiajs.com/eden/overview.html) for end-to-end type-safe API calls

### More info [#more-info]

* [Prisma Documentation](https://www.prisma.io/docs/orm/v7)
* [Elysia Documentation](https://elysiajs.com/)
* [Elysia with Prisma Guide](https://elysiajs.com/integrations/prisma.html)

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/v7/frameworks/astro): Learn how to use Prisma ORM in an Astro app
- [`Hono`](https://www.prisma.io/docs/guides/v7/frameworks/hono): Learn how to use Prisma ORM in a Hono app
- [`NestJS`](https://www.prisma.io/docs/guides/v7/frameworks/nestjs): Learn how to use Prisma ORM in a NestJS app
- [`Next.js`](https://www.prisma.io/docs/guides/v7/frameworks/nextjs): Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel
- [`Nuxt`](https://www.prisma.io/docs/guides/v7/frameworks/nuxt): A step-by-step guide to setting up and using Prisma ORM and Prisma Postgres in a Nuxt app

# Hono (Prisma ORM v7) (/docs/guides/v7/frameworks/hono)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a Hono app

Location: Guides > v7 > Frameworks > Hono

## Introduction [#introduction]

[Hono](https://hono.dev/) is a small web framework that runs on Node.js, Cloudflare Workers, and other runtimes. Its route handlers are where you call Prisma ORM to read from a [Prisma Postgres](https://www.prisma.io/postgres) database.

In this guide, you'll learn to integrate Prisma ORM with a Prisma Postgres database in a Hono backend application. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/hono).

## Quick start [#quick-start]

Run one command to scaffold a Hono project with Prisma ORM and Prisma Postgres ready to go:

  

#### bun

```bash
bunx create-prisma@stable --template hono
```

#### pnpm

```bash
pnpm create prisma@stable --template hono
```

#### yarn

```bash
yarn create prisma@stable --template hono
```

#### npm

```bash
npm create prisma@stable -- --template hono
```

Or follow the steps below to set it up manually.

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)

## 1. Set up your project [#1-set-up-your-project]

Create a new Hono project:

  

#### bun

```bash
bun create hono@latest
```

#### pnpm

```bash
pnpm create hono@latest
```

#### yarn

```bash
yarn create hono@latest
```

#### npm

```bash
npm create hono@latest
```

> [!NOTE]
> * *Target directory?* `my-app`
> * *Which template do you want to use?* `nodejs`
> * *Install dependencies? (recommended)* `Yes`
> * *Which package manager do you want to use?* `npm`

## 2. Install and configure Prisma [#2-install-and-configure-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../src/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../src/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../src/generated/prisma
```

#### npm

```bash
npx prisma init --output ../src/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma/` directory with a `schema.prisma` file
* A `prisma.config.ts` with your Prisma configuration
* A `.env` file with a local `DATABASE_URL` already set

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define your Prisma Schema [#22-define-your-prisma-schema]

In the `prisma/schema.prisma` file, add the following models and change the generator to use the `prisma-client` provider:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]
```

This creates two models: `User` and `Post`, with a one-to-many relationship between them.

In `prisma.config.ts`, import `dotenv` at the top of the file

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";
import "dotenv/config"; // [!code ++]

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.3. Configure the Prisma Client generator [#23-configure-the-prisma-client-generator]

Now, run the following command to create the database tables and generate the Prisma Client:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 2.4. Seed the database [#24-seed-the-database]

Add some seed data to populate the database with sample users and posts.

Create a new file called `seed.ts` in the `prisma/` directory:

```typescript title="prisma/seed.ts"
import { PrismaClient, Prisma } from "../src/generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

const userData: Prisma.UserCreateInput[] = [
  {
    name: "Alice",
    email: "alice@prisma.io",
    posts: {
      create: [
        {
          title: "Join the Prisma Discord",
          content: "https://pris.ly/discord",
          published: true,
        },
        {
          title: "Prisma on YouTube",
          content: "https://pris.ly/youtube",
        },
      ],
    },
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
    posts: {
      create: [
        {
          title: "Follow Prisma on Twitter",
          content: "https://www.twitter.com/prisma",
          published: true,
        },
      ],
    },
  },
];

export async function main() {
  for (const u of userData) {
    await prisma.user.create({ data: u });
  }
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

Now, tell Prisma how to run this script by updating your `prisma.config.ts`:

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";
import "dotenv/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "tsx prisma/seed.ts", // [!code ++]
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Run the seed script:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

And open Prisma Studio to inspect your data:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

## 3. Integrate Prisma into Hono [#3-integrate-prisma-into-hono]

### 3.1. Create a Prisma middleware [#31-create-a-prisma-middleware]

Inside of `/src`, create a `lib` directory and a `prisma.ts` file inside it. This file will be used to create and export your Prisma Client instance. Set up the Prisma client like this:

```tsx title="src/lib/prisma.ts"
import type { Context, Next } from "hono";
import { PrismaClient } from "../generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";
import "dotenv/config";

const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) {
  throw new Error("DATABASE_URL is not set");
}

const adapter = new PrismaPg({
  connectionString: databaseUrl,
});

const prisma = new PrismaClient({ adapter });

function withPrisma(c: Context, next: Next) {
  if (!c.get("prisma")) {
    c.set("prisma", prisma);
  }
  return next();
}

export default withPrisma;
```

> [!WARNING]
> We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently.
> 
> If you choose not to use one, in long-lived environments (for example, a Node.js server) instantiate a single `PrismaClient` and reuse it across requests to avoid exhausting database connections. In serverless environments or when using a pooler (for example, Accelerate), creating a client per request is acceptable.

### 3.2 Environment Variables & Types [#32-environment-variables--types]

By default, Hono does not load any environment variables from a `.env`. `dotenv` handles this and will be read that file and expose them via `process.env`. Hono can get additional types to know that the `withPrisma` middleware will set a `prisma`
key on the Hono context

```ts title="src/index.ts"
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import type { PrismaClient } from "./generated/prisma/client.js"; // [!code ++]

type ContextWithPrisma = {
  // [!code ++]
  Variables: {
    // [!code ++]
    prisma: PrismaClient; // [!code ++]
  }; // [!code ++]
}; // [!code ++]

const app = new Hono<ContextWithPrisma>(); // [!code highlight]

app.get("/", (c) => {
  return c.text("Hello Hono!");
});

serve(
  {
    fetch: app.fetch,
    port: 3000,
  },
  (info) => {
    console.log(`Server is running on http://localhost:${info.port}`);
  },
);
```

If using Cloudflare Workers, the environment variables will automatically be set to Hono's context, so `dotenv` can be skipped.

### 3.3. Create a GET route [#33-create-a-get-route]

Fetch data from the database using Hono's `app.get` function. This will perform any database queries
and return the data as JSON.

Create a new route inside of `src/index.ts`:

Now, create a GET route that fetches the `Users` data from your database, making sure to include each user's `Posts` by adding them to the `include` field:

```ts title="src/index.ts"
import withPrisma from "./lib/prisma.js";

app.get("/users", withPrisma, async (c) => {
  const prisma = c.get("prisma");
  const users = await prisma.user.findMany({
    include: { posts: true },
  });
  return c.json({ users });
});
```

### 3.4. Display the data [#34-display-the-data]

Start the Hono app by call the `dev` script in the `package.json`

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

There should be a "Server is running on [http://localhost:3000](http://localhost:3000)" log printed out. From here, the data
can be viewed by visiting `http://localhost:3000/users` or by running `curl` from the command line

```bash
curl http://localhost:3000/users | jq
```

Your Hono app now serves users and their posts from a Prisma Postgres database.

## Next Steps [#next-steps]

Now that you have a working Hono app connected to a Prisma Postgres database, you can:

* Extend your Prisma schema with more models and relationships
* Add create/update/delete routes and forms
* Explore authentication and validation

### More Info [#more-info]

* [Prisma Documentation](https://www.prisma.io/docs/orm/v7)
* [Hono Documentation](https://hono.dev/docs/)

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/v7/frameworks/astro): Learn how to use Prisma ORM in an Astro app
- [`Elysia`](https://www.prisma.io/docs/guides/v7/frameworks/elysia): Learn how to use Prisma ORM in an Elysia app
- [`NestJS`](https://www.prisma.io/docs/guides/v7/frameworks/nestjs): Learn how to use Prisma ORM in a NestJS app
- [`Next.js`](https://www.prisma.io/docs/guides/v7/frameworks/nextjs): Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel
- [`Nuxt`](https://www.prisma.io/docs/guides/v7/frameworks/nuxt): A step-by-step guide to setting up and using Prisma ORM and Prisma Postgres in a Nuxt app

# NestJS (Prisma ORM v7) (/docs/guides/v7/frameworks/nestjs)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a NestJS app

Location: Guides > v7 > Frameworks > NestJS

## Introduction [#introduction]

This guide shows you how to use Prisma ORM with [NestJS](https://nestjs.com/), a Node.js framework for building server-side applications with TypeScript. You'll build a REST API with NestJS that uses Prisma ORM to store and retrieve data from a database.

[Prisma ORM](https://www.prisma.io) is an open-source ORM for Node.js and TypeScript. It is used as an **alternative** to writing plain SQL, or using another database access tool such as SQL query builders (like [knex.js](https://knexjs.org/)) or ORMs (like [TypeORM](https://typeorm.io/) and [Sequelize](https://sequelize.org/)). Prisma currently supports PostgreSQL, MySQL, SQL Server, SQLite, MongoDB and CockroachDB.

While Prisma can be used with plain JavaScript, it is designed for TypeScript and generates types for your models and for the results of each query.

You can find a ready-to-run example in [the NestJS example on GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/nest)

## Quick start [#quick-start]

Run one command to scaffold a NestJS project with Prisma ORM and Prisma Postgres ready to go:

  

#### bun

```bash
bunx create-prisma@stable --template nest
```

#### pnpm

```bash
pnpm create prisma@stable --template nest
```

#### yarn

```bash
yarn create prisma@stable --template nest
```

#### npm

```bash
npm create prisma@stable -- --template nest
```

Or follow the steps below to set it up manually.

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)

## 1. Create your NestJS project [#1-create-your-nestjs-project]

Install the NestJS CLI and create a new project:

  

#### bun

```bash
bun add --global @nestjs/cli
```

#### pnpm

```bash
pnpm add -g @nestjs/cli
```

#### yarn

```bash
yarn global add @nestjs/cli
```

#### npm

```bash
npm install -g @nestjs/cli
```

```bash
nest new nestjs-prisma
```

When prompted, select **npm** as your package manager. Navigate to the project directory:

```bash
cd nestjs-prisma
```

You can run `npm start` to start your application at `http://localhost:3000/`. Over the course of this guide, you'll add routes to store and retrieve data about *users* and *posts*.

In `package.json`, add the `type` field set to `"module"`:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

## 2. Set up Prisma [#2-set-up-prisma]

### 2.1. Install Prisma and dependencies [#21-install-prisma-and-dependencies]

Install the necessary Prisma packages and database drivers:

  

#### bun

```bash
bun add prisma@prev --dev
```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
```

#### yarn

```bash
yarn add prisma@prev --dev
```

#### npm

```bash
npm install prisma@prev --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

### 2.2. Initialize Prisma [#22-initialize-prisma]

Initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../src/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../src/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../src/generated/prisma
```

#### npm

```bash
npx prisma init --output ../src/generated/prisma
```

This creates a new `prisma` directory with the following contents:

* `schema.prisma`: Specifies your database connection and contains the database schema
* `prisma.config.ts`: A configuration file for your projects
* `.env`: A [dotenv](https://github.com/motdotla/dotenv) file, typically used to store your database credentials in a group of environment variables

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.3. Set the generator output path [#23-set-the-generator-output-path]

Specify your output `path` for the generated Prisma client by either passing `--output ../src/generated/prisma` during `prisma init` or directly in your Prisma schema:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}
```

### 2.4. Configure your database connection [#24-configure-your-database-connection]

Your database connection is configured in the `datasource` block in your `schema.prisma` file. By default it's set to `postgresql` which is what you need for this guide.

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
}
```

Now, open up `.env` and you should see a `DATABASE_URL` already specified:

```text title=".env"
DATABASE_URL="postgres://..."
```

> [!NOTE]
> Make sure you have a [ConfigModule](https://docs.nestjs.com/techniques/configuration) configured, otherwise the `DATABASE_URL` variable will not be picked up from `.env`.

### 2.5. Define your data model [#25-define-your-data-model]

Add the following two models to your `schema.prisma` file:

```prisma title="prisma/schema.prisma"
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean? @default(false)
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}
```

### 2.6. Create and run your migration [#26-create-and-run-your-migration]

With your Prisma models in place, you can generate your SQL migration files and run them against the database. Run the following commands in your terminal:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This `prisma migrate dev` command generates SQL files and directly runs them against the database. In this case, the following migration files was created in the existing `prisma` directory:

```bash
$ tree prisma
prisma
├── migrations
│   └── 20201207100915_init
│       └── migration.sql
└── schema.prisma
```

### 2.7. Generate Prisma Client [#27-generate-prisma-client]

Once installed, you can run the generate command to generate the types and Client needed for your project. If any changes are made to your schema, you will need to rerun the `generate` command to keep those types in sync.

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 3. Create a Prisma service [#3-create-a-prisma-service]

You're now able to send database queries with Prisma Client. When setting up your NestJS application, you'll want to abstract away the Prisma Client API for database queries within a service. To get started, you can create a new `PrismaService` that takes care of instantiating `PrismaClient` and connecting to your database.

Inside the `src` directory, create a new file called `prisma.service.ts` and add the following code to it:

```typescript title="src/prisma.service.ts"
import { Injectable } from "@nestjs/common";
import { PrismaClient } from "./generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";

@Injectable()
export class PrismaService extends PrismaClient {
  constructor() {
    const adapter = new PrismaPg({
      connectionString: process.env.DATABASE_URL as string,
    });
    super({ adapter });
  }
}
```

## 4. Create User and Post services [#4-create-user-and-post-services]

Next, you can write services that you can use to make database calls for the `User` and `Post` models from your Prisma schema.

### 4.1. Create the User service [#41-create-the-user-service]

Still inside the `src` directory, create a new file called `user.service.ts` and add the following code to it:

```typescript title="src/user.service.ts"
import { Injectable } from "@nestjs/common";
import { PrismaService } from "./prisma.service.js";
import { User, Prisma } from "./generated/prisma/client.js";

@Injectable()
export class UserService {
  constructor(private prisma: PrismaService) {}

  async user(userWhereUniqueInput: Prisma.UserWhereUniqueInput): Promise<User | null> {
    return this.prisma.user.findUnique({
      where: userWhereUniqueInput,
    });
  }

  async users(params: {
    skip?: number;
    take?: number;
    cursor?: Prisma.UserWhereUniqueInput;
    where?: Prisma.UserWhereInput;
    orderBy?: Prisma.UserOrderByWithRelationInput;
  }): Promise<User[]> {
    const { skip, take, cursor, where, orderBy } = params;
    return this.prisma.user.findMany({
      skip,
      take,
      cursor,
      where,
      orderBy,
    });
  }

  async createUser(data: Prisma.UserCreateInput): Promise<User> {
    return this.prisma.user.create({
      data,
    });
  }

  async updateUser(params: {
    where: Prisma.UserWhereUniqueInput;
    data: Prisma.UserUpdateInput;
  }): Promise<User> {
    const { where, data } = params;
    return this.prisma.user.update({
      data,
      where,
    });
  }

  async deleteUser(where: Prisma.UserWhereUniqueInput): Promise<User> {
    return this.prisma.user.delete({
      where,
    });
  }
}
```

Notice how you're using Prisma Client's generated types to ensure that the methods that are exposed by your service are properly typed. You therefore save the boilerplate of typing your models and creating additional interface or DTO files.

### 4.2. Create the Post service [#42-create-the-post-service]

Now do the same for the `Post` model.

Still inside the `src` directory, create a new file called `post.service.ts` and add the following code to it:

```typescript title="src/post.service.ts"
import { Injectable } from "@nestjs/common";
import { PrismaService } from "./prisma.service.js";
import { Post, Prisma } from "./generated/prisma/client.js";

@Injectable()
export class PostService {
  constructor(private prisma: PrismaService) {}

  async post(postWhereUniqueInput: Prisma.PostWhereUniqueInput): Promise<Post | null> {
    return this.prisma.post.findUnique({
      where: postWhereUniqueInput,
    });
  }

  async posts(params: {
    skip?: number;
    take?: number;
    cursor?: Prisma.PostWhereUniqueInput;
    where?: Prisma.PostWhereInput;
    orderBy?: Prisma.PostOrderByWithRelationInput;
  }): Promise<Post[]> {
    const { skip, take, cursor, where, orderBy } = params;
    return this.prisma.post.findMany({
      skip,
      take,
      cursor,
      where,
      orderBy,
    });
  }

  async createPost(data: Prisma.PostCreateInput): Promise<Post> {
    return this.prisma.post.create({
      data,
    });
  }

  async updatePost(params: {
    where: Prisma.PostWhereUniqueInput;
    data: Prisma.PostUpdateInput;
  }): Promise<Post> {
    const { data, where } = params;
    return this.prisma.post.update({
      data,
      where,
    });
  }

  async deletePost(where: Prisma.PostWhereUniqueInput): Promise<Post> {
    return this.prisma.post.delete({
      where,
    });
  }
}
```

Your `UserService` and `PostService` currently wrap the CRUD queries that are available in Prisma Client. In a real world application, the service would also be the place to add business logic to your application. For example, you could have a method called `updatePassword` inside the `UserService` that would be responsible for updating the password of a user.

## 5. Implement REST API routes [#5-implement-rest-api-routes]

### 5.1. Create the controller [#51-create-the-controller]

Finally, you'll use the services you created in the previous sections to implement the different routes of your app. For the purpose of this guide, you'll put all your routes into the already existing `AppController` class.

Replace the contents of the `app.controller.ts` file with the following code:

```typescript title="src/app.controller.ts"
import { Controller, Get, Param, Post, Body, Put, Delete } from "@nestjs/common";
import { UserService } from "./user.service.js";
import { PostService } from "./post.service.js";
import { User as UserModel } from "./generated/prisma/client.js";
import { Post as PostModel } from "./generated/prisma/client.js";

@Controller()
export class AppController {
  constructor(
    private readonly UserService: UserService,
    private readonly postService: PostService,
  ) {}

  @Get("post/:id")
  async getPostById(@Param("id") id: string): Promise<PostModel | null> {
    return this.postService.post({ id: Number(id) });
  }

  @Get("feed")
  async getPublishedPosts(): Promise<PostModel[]> {
    return this.postService.posts({
      where: { published: true },
    });
  }

  @Get("filtered-posts/:searchString")
  async getFilteredPosts(@Param("searchString") searchString: string): Promise<PostModel[]> {
    return this.postService.posts({
      where: {
        OR: [
          {
            title: { contains: searchString },
          },
          {
            content: { contains: searchString },
          },
        ],
      },
    });
  }

  @Post("post")
  async createDraft(
    @Body() postData: { title: string; content?: string; authorEmail: string },
  ): Promise<PostModel> {
    const { title, content, authorEmail } = postData;
    return this.postService.createPost({
      title,
      content,
      author: {
        connect: { email: authorEmail },
      },
    });
  }

  @Post("user")
  async signupUser(@Body() userData: { name?: string; email: string }): Promise<UserModel> {
    return this.UserService.createUser(userData);
  }

  @Put("publish/:id")
  async publishPost(@Param("id") id: string): Promise<PostModel> {
    return this.postService.updatePost({
      where: { id: Number(id) },
      data: { published: true },
    });
  }

  @Delete("post/:id")
  async deletePost(@Param("id") id: string): Promise<PostModel> {
    return this.postService.deletePost({ id: Number(id) });
  }
}
```

This controller implements the following routes:

#### `GET` [#get]

* `/post/:id`: Fetch a single post by its `id`
* `/feed`: Fetch all *published* posts
* `/filtered-posts/:searchString`: Filter posts by `title` or `content`

#### `POST` [#post]

* `/post`: Create a new post
  * Body:
    * `title: String` (required): The title of the post
    * `content: String` (optional): The content of the post
    * `authorEmail: String` (required): The email of the user that creates the post
* `/user`: Create a new user
  * Body:
    * `email: String` (required): The email address of the user
    * `name: String` (optional): The name of the user

#### `PUT` [#put]

* `/publish/:id`: Publish a post by its `id`

#### `DELETE` [#delete]

* `/post/:id`: Delete a post by its `id`

### 5.2. Register services in the app module [#52-register-services-in-the-app-module]

Remember to register the new services in the app module.

Update `src/app.module.ts` to register all services:

```typescript title="src/app.module.ts"
import { Module } from "@nestjs/common";
import { AppController } from "./app.controller";
import { ConfigModule } from "@nestjs/config";
import { AppService } from "./app.service.js";
import { PrismaService } from "./prisma.service.js"; // [!code ++]
import { UserService } from "./user.service.js"; // [!code ++]
import { PostService } from "./post.service.js"; // [!code ++]

@Module({
  imports: [ConfigModule.forRoot()],
  controllers: [AppController],
  providers: [AppService, PrismaService, UserService, PostService], // [!code ++]
})
export class AppModule {}
```

## 6. Test your API [#6-test-your-api]

Start your application:

  

#### bun

```bash
bun start
```

#### pnpm

```bash
pnpm start
```

#### yarn

```bash
yarn start
```

#### npm

```bash
npm start
```

Test your endpoints with curl, [Postman](https://www.postman.com/), or [HTTPie](https://httpie.io/).

**Create a user:**

```bash
curl -X POST http://localhost:3000/user \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice", "email": "alice@prisma.io"}'
```

**Create a post:**

```bash
curl -X POST http://localhost:3000/post \
  -H "Content-Type: application/json" \
  -d '{"title": "Hello World", "authorEmail": "alice@prisma.io"}'
```

**Get published posts:**

```bash
curl http://localhost:3000/feed
```

**Publish a post:**

```bash
curl -X PUT http://localhost:3000/publish/1
```

**Search posts:**

```bash
curl http://localhost:3000/filtered-posts/hello
```

## Summary [#summary]

In this guide, you learned how to use Prisma ORM with NestJS to implement a REST API. The controller that implements the routes of the API is calling a `PrismaService` which in turn uses Prisma Client to send queries to a database to fulfill the data needs of incoming requests.

If you want to learn more about using NestJS with Prisma, be sure to check out the following resources:

* [NestJS & Prisma](https://www.prisma.io/nestjs)
* [Ready-to-run example projects for REST & GraphQL](https://github.com/prisma/prisma-examples/)
* [Production-ready starter kit](https://github.com/notiz-dev/nestjs-prisma-starter#instructions)
* [Video: Accessing Databases using NestJS with Prisma (5min)](https://www.youtube.com/watch?v=UlVJ340UEuk\&ab_channel=Prisma) by [Marc Stammerjohann](https://github.com/marcjulian)

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/v7/frameworks/astro): Learn how to use Prisma ORM in an Astro app
- [`Elysia`](https://www.prisma.io/docs/guides/v7/frameworks/elysia): Learn how to use Prisma ORM in an Elysia app
- [`Hono`](https://www.prisma.io/docs/guides/v7/frameworks/hono): Learn how to use Prisma ORM in a Hono app
- [`Next.js`](https://www.prisma.io/docs/guides/v7/frameworks/nextjs): Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel
- [`Nuxt`](https://www.prisma.io/docs/guides/v7/frameworks/nuxt): A step-by-step guide to setting up and using Prisma ORM and Prisma Postgres in a Nuxt app

# Next.js (Prisma ORM v7) (/docs/guides/v7/frameworks/nextjs)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel

Location: Guides > v7 > Frameworks > Next.js

## Introduction [#introduction]

This guide shows you how to use Prisma with Next.js, a fullstack React framework. You'll learn how to create a [Prisma Postgres](https://www.prisma.io/docs/postgres) instance, set up Prisma ORM with Next.js, handle migrations, and deploy your application to Vercel.

You can find a [deployment-ready example on GitHub](https://github.com/prisma/prisma-examples/blob/latest/orm/nextjs).

## Quick start [#quick-start]

Run one command to scaffold a Next.js project with Prisma ORM and Prisma Postgres ready to go:

  

#### bun

```bash
bunx create-prisma@stable --template next
```

#### pnpm

```bash
pnpm create prisma@stable --template next
```

#### yarn

```bash
yarn create prisma@stable --template next
```

#### npm

```bash
npm create prisma@stable -- --template next
```

Or follow the steps below to set it up manually.

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) v20.19+, v22.12+, or v24.0+
* A Vercel account (if you want to deploy your application)

## 1. Set up your project [#1-set-up-your-project]

From the directory where you want to create your project, run `create-next-app` to create a new Next.js app that you will be using for this guide.

  

#### bun

```bash
bunx create-next-app@latest nextjs-prisma
```

#### pnpm

```bash
pnpm dlx create-next-app@latest nextjs-prisma
```

#### yarn

```bash
yarn dlx create-next-app@latest nextjs-prisma
```

#### npm

```bash
npx create-next-app@latest nextjs-prisma
```

You will be prompted to answer a few questions about your project. Select all of the defaults.

> [!NOTE]
> For reference, those are:
> 
> * TypeScript
> * ESLint
> * Tailwind CSS
> * No `src` directory
> * App Router
> * Turbopack
> * No customized import alias

Then, navigate to the project directory:

```bash
cd nextjs-prisma
```

## 2. Install and Configure Prisma [#2-install-and-configure-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../app/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../app/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../app/generated/prisma
```

#### npm

```bash
npx prisma init --output ../app/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma` directory with a `schema.prisma` file.
* A `prisma.config.ts` file for configuring Prisma.
* A `.env` file containing a local `DATABASE_URL` at the project root.

The `app/generated/prisma` output directory for the generated Prisma Client will be created when you run `prisma generate` or `prisma migrate dev` in a later step.

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define your Prisma Schema [#22-define-your-prisma-schema]

In the `prisma/schema.prisma` file, add the following models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]
```

This creates two models: `User` and `Post`, with a one-to-many relationship between them.

### 2.3 Add `dotenv` to `prisma.config.ts` [#23-add-dotenv-to-prismaconfigts]

To get access to the variables in the `.env` file, they can either be loaded by your runtime, or by using `dotenv`.
Include an import for `dotenv` at the top of the `prisma.config.ts`

```typescript title="prisma.config.ts"
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.4. Run migrations and generate Prisma Client [#24-run-migrations-and-generate-prisma-client]

Now, run the following command to create the database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

Then generate Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 2.5. Seed the database [#25-seed-the-database]

Add some seed data to populate the database with sample users and posts.

Create a new file called `seed.ts` in the `prisma/` directory:

```typescript title="prisma/seed.ts"
import { PrismaClient, Prisma } from "../app/generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
import "dotenv/config";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
});

const prisma = new PrismaClient({
  adapter,
});

const userData: Prisma.UserCreateInput[] = [
  {
    name: "Alice",
    email: "alice@prisma.io",
    posts: {
      create: [
        {
          title: "Join the Prisma Discord",
          content: "https://pris.ly/discord",
          published: true,
        },
        {
          title: "Prisma on YouTube",
          content: "https://pris.ly/youtube",
        },
      ],
    },
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
    posts: {
      create: [
        {
          title: "Follow Prisma on Twitter",
          content: "https://www.twitter.com/prisma",
          published: true,
        },
      ],
    },
  },
];

export async function main() {
  for (const u of userData) {
    await prisma.user.create({ data: u });
  }
}

main();
```

Now, tell Prisma how to run this script by updating your `prisma.config.ts`:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: `tsx prisma/seed.ts`, // [!code ++]
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Finally, run `prisma db seed` to seed your database with the initial data we defined in the `seed.ts` file.

Run the seed script:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

And open Prisma Studio to inspect your data:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

### 2.6 Set up Prisma Client [#26-set-up-prisma-client]

Now that you have a database with some initial data, you can set up Prisma Client and connect it to your database.

At the root of your project, create a new `lib` directory and add a `prisma.ts` file to it.

```bash
mkdir -p lib && touch lib/prisma.ts
```

Now, add the following code to your `lib/prisma.ts` file:

```typescript title="lib/prisma.ts" showLineNumbers
import { PrismaClient } from "../app/generated/prisma/client"; // [!code ++]
import { PrismaPg } from "@prisma/adapter-pg"; // [!code ++]
// [!code ++]
const globalForPrisma = global as unknown as {
  // [!code ++]
  prisma: PrismaClient; // [!code ++]
}; // [!code ++]
// [!code ++]
const adapter = new PrismaPg({
  // [!code ++]
  connectionString: process.env.DATABASE_URL, // [!code ++]
}); // [!code ++]
// [!code ++]
const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    // [!code ++]
    adapter, // [!code ++]
  }); // [!code ++]
// [!code ++]
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma; // [!code ++]
// [!code ++]
export default prisma; // [!code ++]
```

This file creates a Prisma Client and attaches it to the global object so that only one instance of the client is created in your application. This helps resolve issues with hot reloading that can occur when using Prisma ORM with Next.js in development mode.

You'll use this client in the next section to run your first queries.

## 3. Query your database with Prisma ORM [#3-query-your-database-with-prisma-orm]

Now that you have an initialized Prisma Client, a connection to your database, and some initial data, you can start querying your data with Prisma ORM.

In this example, you'll make the "home" page of your application display all of your users.

Open the `app/page.tsx` file and replace the existing code with the following:

```tsx title="app/page.tsx"
export default async function Home() {
  return (
    <div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center -mt-16">
      <h1 className="text-4xl font-bold mb-8 font-[family-name:var(--font-geist-sans)] text-[#333333]">
        Superblog
      </h1>
      <ol className="list-decimal list-inside font-[family-name:var(--font-geist-sans)]">
        <li className="mb-2">Alice</li>
        <li>Bob</li>
      </ol>
    </div>
  );
}
```

This gives you a basic page with a title and a list of users. However, that list is static with hardcoded values. Update the page to fetch the users from your database and make it dynamic.

```tsx title="app/page.tsx"
import prisma from "@/lib/prisma";

export default async function Home() {
  const users = await prisma.user.findMany();
  return (
    <div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center -mt-16">
      <h1 className="text-4xl font-bold mb-8 font-[family-name:var(--font-geist-sans)] text-[#333333]">
        Superblog
      </h1>
      <ol className="list-decimal list-inside font-[family-name:var(--font-geist-sans)]">
        {users.map((user) => (
          <li key={user.id} className="mb-2">
            {user.name}
          </li>
        ))}
      </ol>
    </div>
  );
}
```

You are now importing your client, querying the `User` model for all users, and then displaying them in a list.

Now your home page is dynamic and will display the users from your database.

### 3.1 Update your data (optional) [#31-update-your-data-optional]

If you want to see what happens when data is updated, you could:

* update your `User` table via a SQL browser of your choice
* change your `seed.ts` file to add more users
* change the call to `prisma.user.findMany` to re-order the users, filter the users, or similar.

Reload the page to see the changes.

## 4. Add a new Posts list page [#4-add-a-new-posts-list-page]

You have your home page working, but you should add a new page that displays all of your posts.

First create a new `posts` directory in the `app` directory and create a new `page.tsx` file inside of it.

```bash
mkdir -p app/posts && touch app/posts/page.tsx
```

Second, add the following code to the `app/posts/page.tsx` file:

```tsx title="app/posts/page.tsx"
import prisma from "@/lib/prisma";

export default async function Posts() {
  return (
    <div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center -mt-16 text-[#333333]">
      <h1 className="text-4xl font-bold mb-8 font-[family-name:var(--font-geist-sans)]">Posts</h1>
      <ul className="font-[family-name:var(--font-geist-sans)] max-w-2xl space-y-4">
        <li>My first post</li>
      </ul>
    </div>
  );
}
```

Now `localhost:3000/posts` will load, but the content is hardcoded again. Update it to be dynamic, similarly to the home page:

```tsx title="app/posts/page.tsx"
import prisma from "@/lib/prisma";

export default async function Posts() {
  const posts = await prisma.post.findMany({
    include: {
      author: true,
    },
  });

  return (
    <div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center -mt-16 text-[#333333]">
      <h1 className="text-4xl font-bold mb-8 font-[family-name:var(--font-geist-sans)]">Posts</h1>
      <ul className="font-[family-name:var(--font-geist-sans)] max-w-2xl space-y-4">
        {posts.map((post) => (
          <li key={post.id}>
            <span className="font-semibold">{post.title}</span>
            <span className="text-sm text-gray-600 ml-2">by {post.author.name}</span>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

This works similarly to the home page, but instead of displaying users, it displays posts. You can also see that you've used `include` in your Prisma Client query to fetch the author of each post so you can display the author's name.

This "list view" is one of the most common patterns in web applications. You're going to add two more pages to your application which you'll also commonly need: a "detail view" and a "create view".

## 5. Add a new Posts detail page [#5-add-a-new-posts-detail-page]

To complement the Posts list page, you'll add a Posts detail page.

In the `posts` directory, create a new `[id]` directory and a new `page.tsx` file inside of that.

```bash
mkdir -p "app/posts/[id]" && touch "app/posts/[id]/page.tsx"
```

This page will display a single post's title, content, and author. Just like your other pages, add the following code to the `app/posts/[id]/page.tsx` file:

```tsx title="app/posts/[id]/page.tsx"
import prisma from "@/lib/prisma";

export default async function Post({ params }: { params: Promise<{ id: string }> }) {
  return (
    <div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center -mt-16">
      <article className="max-w-2xl space-y-4 font-[family-name:var(--font-geist-sans)]">
        <h1 className="text-4xl font-bold mb-8 text-[#333333]">My first post</h1>
        <p className="text-gray-600 text-center">by Anonymous</p>
        <div className="prose prose-gray mt-8">No content available.</div>
      </article>
    </div>
  );
}
```

As before, this page is static with hardcoded content. Update it to be dynamic based on the `params` passed to the page:

```tsx title="app/posts/[id]/page.tsx"
import prisma from "@/lib/prisma";
import { notFound } from "next/navigation";

export default async function Post({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  const post = await prisma.post.findUnique({
    where: { id: parseInt(id) },
    include: {
      author: true,
    },
  });

  if (!post) {
    notFound();
  }

  return (
    <div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center -mt-16">
      <article className="max-w-2xl space-y-4 font-[family-name:var(--font-geist-sans)]">
        <h1 className="text-4xl font-bold mb-8 text-[#333333]">{post.title}</h1>
        <p className="text-gray-600 text-center">by {post.author.name}</p>
        <div className="prose prose-gray mt-8">{post.content || "No content available."}</div>
      </article>
    </div>
  );
}
```

There's a lot of changes here, so here is what each part does:

* You're using Prisma Client to fetch the post by its `id`, which you get from the `params` object.
* In case the post doesn't exist (maybe it was deleted or maybe you typed a wrong ID), you call `notFound()` to display a 404 page.
* You then display the post's title, content, and author. If the post doesn't have content, you display a placeholder message.

It's not the prettiest page, but it's a good start. Try it out by navigating to `localhost:3000/posts/1` and `localhost:3000/posts/2`. You can also test the 404 page by navigating to `localhost:3000/posts/999`.

## 6. Add a new Posts create page [#6-add-a-new-posts-create-page]

To round out your application, you'll add a "create" page for posts. This will let you write your own posts and save them to the database.

As with the other pages, you'll start with a static page and then update it to be dynamic.

```bash
mkdir -p app/posts/new && touch app/posts/new/page.tsx
```

Now, add the following code to the `app/posts/new/page.tsx` file:

```tsx title="app/posts/new/page.tsx"
import Form from "next/form";

export default function NewPost() {
  async function createPost(formData: FormData) {
    "use server";

    const title = formData.get("title") as string;
    const content = formData.get("content") as string;
  }

  return (
    <div className="max-w-2xl mx-auto p-4">
      <h1 className="text-2xl font-bold mb-6">Create New Post</h1>
      <Form action={createPost} className="space-y-6">
        <div>
          <label htmlFor="title" className="block text-lg mb-2">
            Title
          </label>
          <input
            type="text"
            id="title"
            name="title"
            placeholder="Enter your post title"
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
        <div>
          <label htmlFor="content" className="block text-lg mb-2">
            Content
          </label>
          <textarea
            id="content"
            name="content"
            placeholder="Write your post content here..."
            rows={6}
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-3 rounded-lg hover:bg-blue-600"
        >
          Create Post
        </button>
      </Form>
    </div>
  );
}
```

The form renders, but it doesn't do anything yet. Update the `createPost` function to save the post to the database:

```tsx title="app/posts/new/page.tsx"
import Form from "next/form";
import prisma from "@/lib/prisma";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";

export default function NewPost() {
  async function createPost(formData: FormData) {
    "use server";

    const title = formData.get("title") as string;
    const content = formData.get("content") as string;

    await prisma.post.create({
      data: {
        title,
        content,
        authorId: 1,
      },
    });

    revalidatePath("/posts");
    redirect("/posts");
  }

  return (
    <div className="max-w-2xl mx-auto p-4">
      <h1 className="text-2xl font-bold mb-6">Create New Post</h1>
      <Form action={createPost} className="space-y-6">
        <div>
          <label htmlFor="title" className="block text-lg mb-2">
            Title
          </label>
          <input
            type="text"
            id="title"
            name="title"
            placeholder="Enter your post title"
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
        <div>
          <label htmlFor="content" className="block text-lg mb-2">
            Content
          </label>
          <textarea
            id="content"
            name="content"
            placeholder="Write your post content here..."
            rows={6}
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-3 rounded-lg hover:bg-blue-600"
        >
          Create Post
        </button>
      </Form>
    </div>
  );
}
```

When you submit the form, the `createPost` action creates a new post in the database and redirects you to the posts list page.

You also added a `revalidatePath` call to revalidate the posts list page so that it will be updated with the new post. That way everyone can read the new post immediately.

Try it out by navigating to `localhost:3000/posts/new` and submitting the form.

## 7. Deploy your application to Vercel (Optional) [#7-deploy-your-application-to-vercel-optional]

The quickest way to deploy your application to Vercel is to use the [Vercel CLI](https://vercel.com/docs/cli).

First, install the Vercel CLI:

  

#### bun

```bash
bun add --global vercel
```

#### pnpm

```bash
pnpm add -g vercel
```

#### yarn

```bash
yarn global add vercel
```

#### npm

```bash
npm install -g vercel
```

Then, run `vercel login` to log in to your Vercel account.

```bash
vercel login
```

Before you deploy, you also need to tell Vercel to make sure that the Prisma Client is generated. You can do this by adding a `postinstall` script to your `package.json` file.

```json title="package.json"
{
  "name": "nextjs-prisma",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "postinstall": "prisma generate",
    "start": "next start",
    "lint": "next lint"
  },
  "prisma": {
    "seed": "tsx prisma/seed.ts"
  },
  "dependencies": {
    "@prisma/adapter-pg": "^6.2.1",
    "@prisma/client": "^6.2.1",
    "next": "15.1.4",
    "pg": "^8.13.1",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@eslint/eslintrc": "^3",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9",
    "eslint-config-next": "15.1.4",
    "postcss": "^8",
    "prisma": "^6.2.1",
    "tailwindcss": "^3.4.1",
    "tsx": "^4.19.2",
    "typescript": "^5"
  }
}
```

After this change, you can deploy your application to Vercel by running `vercel`.

```bash
vercel
```

After the deployment is complete, you can visit your application at the URL that Vercel provides. Your Next.js application with Prisma ORM is now live on Vercel.

## 8. Next steps [#8-next-steps]

Now that you have a working Next.js application with Prisma ORM, here are some ways you can expand and improve your application:

* Add authentication to protect your routes
* Add the ability to edit and delete posts
* Add comments to posts
* Use [Prisma Studio](https://www.prisma.io/docs/studio) for visual database management

For more information:

* [Prisma ORM documentation](https://www.prisma.io/docs/orm/v7)
* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction)
* [Next.js documentation](https://nextjs.org/docs)

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/v7/frameworks/astro): Learn how to use Prisma ORM in an Astro app
- [`Elysia`](https://www.prisma.io/docs/guides/v7/frameworks/elysia): Learn how to use Prisma ORM in an Elysia app
- [`Hono`](https://www.prisma.io/docs/guides/v7/frameworks/hono): Learn how to use Prisma ORM in a Hono app
- [`NestJS`](https://www.prisma.io/docs/guides/v7/frameworks/nestjs): Learn how to use Prisma ORM in a NestJS app
- [`Nuxt`](https://www.prisma.io/docs/guides/v7/frameworks/nuxt): A step-by-step guide to setting up and using Prisma ORM and Prisma Postgres in a Nuxt app

# Nuxt (Prisma ORM v7) (/docs/guides/v7/frameworks/nuxt)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A step-by-step guide to setting up and using Prisma ORM and Prisma Postgres in a Nuxt app

Location: Guides > v7 > Frameworks > Nuxt

This guide shows you how to set up Prisma ORM in a Nuxt application with [Prisma Postgres](https://prisma.io/postgres).

## Quick start [#quick-start]

Run one command to scaffold a Nuxt project with Prisma ORM and Prisma Postgres ready to go:

  

#### bun

```bash
bunx create-prisma@stable --template nuxt
```

#### pnpm

```bash
pnpm create prisma@stable --template nuxt
```

#### yarn

```bash
yarn create prisma@stable --template nuxt
```

#### npm

```bash
npm create prisma@stable -- --template nuxt
```

Or follow the steps below to set it up manually.

## Prerequisites [#prerequisites]

* Node.js 18+
* A [Prisma Postgres](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=guides) database (or any PostgreSQL database)

## 1. Create a Nuxt project [#1-create-a-nuxt-project]

Create a new Nuxt project:

  

#### bun

```bash
bunx nuxi@latest init hello-prisma
```

#### pnpm

```bash
pnpm dlx nuxi@latest init hello-prisma
```

#### yarn

```bash
yarn dlx nuxi@latest init hello-prisma
```

#### npm

```bash
npx nuxi@latest init hello-prisma
```

Navigate to the project and install dependencies:

```bash
cd hello-prisma
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg pg
```

  

#### bun

```bash
bun add --dev prisma@prev @types/pg dotenv tsx
```

#### pnpm

```bash
pnpm add -D prisma@prev @types/pg dotenv tsx
```

#### yarn

```bash
yarn add --dev prisma@prev @types/pg dotenv tsx
```

#### npm

```bash
npm install -D prisma@prev @types/pg dotenv tsx
```

## 2. Initialize Prisma [#2-initialize-prisma]

Initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

Update your `prisma/schema.prisma`:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider = "postgresql"
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}
```

Create a `prisma.config.ts` file in the root of your project:

```ts title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";
import "dotenv/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "tsx ./prisma/seed.ts",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Update your `.env` file with your database connection string:

```text title=".env"
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
```

Run the migration to create your database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

## 3. Set up Prisma Client [#3-set-up-prisma-client]

Create `server/utils/db.ts`. Nuxt auto-imports exports from `server/utils`, making `prisma` available in all API routes:

```ts title="server/utils/db.ts"
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../../prisma/generated/client";

const prismaClientSingleton = () => {
  const pool = new PrismaPg({ connectionString: process.env.DATABASE_URL! });
  return new PrismaClient({ adapter: pool });
};

type PrismaClientSingleton = ReturnType<typeof prismaClientSingleton>;

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClientSingleton | undefined;
};

export const prisma = globalForPrisma.prisma ?? prismaClientSingleton();

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
```

## 4. Create API routes [#4-create-api-routes]

Create an API route to fetch users. The `prisma` instance is auto-imported:

```ts title="server/api/users.get.ts"
export default defineEventHandler(async () => {
  const users = await prisma.user.findMany({
    include: { posts: true },
  });
  return users;
});
```

Create an API route to create a user:

```ts title="server/api/users.post.ts"
export default defineEventHandler(async (event) => {
  const body = await readBody<{ name: string; email: string }>(event);

  const user = await prisma.user.create({
    data: {
      name: body.name,
      email: body.email,
    },
  });

  return user;
});
```

## 5. Create a page [#5-create-a-page]

Update `app.vue` to display users:

```html title="app.vue"
<template>
  <div>
    <h1>Users</h1>
    <ul v-if="users?.length">
      <li v-for="user in users" :key="user.id">{{ user.name }} ({{ user.email }})</li>
    </ul>
    <p v-else>No users yet.</p>
  </div>
</template>

<script setup>
  const { data: users } = await useFetch('/api/users')
</script>
```

## 6. Run the app [#6-run-the-app]

Start the development server:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open `http://localhost:3000` to see your app.

## 7. Seed your database (optional) [#7-seed-your-database-optional]

Create a seed file to populate your database with sample data:

```ts title="prisma/seed.ts"
import "dotenv/config";
import { PrismaClient } from "./generated/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! });
const prisma = new PrismaClient({ adapter });

async function main() {
  const alice = await prisma.user.create({
    data: {
      name: "Alice",
      email: "alice@prisma.io",
      posts: {
        create: { title: "Hello World", published: true },
      },
    },
  });
  console.log(`Created user: ${alice.name}`);
}

main()
  .then(() => prisma.$disconnect())
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the seed:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

## 8. Deploy to Vercel [#8-deploy-to-vercel]

You can deploy your Nuxt application to Vercel using one of two methods:

### Option A: Deploy using Vercel CLI [#option-a-deploy-using-vercel-cli]

1. Install the Vercel CLI (if not already installed):

   
     

#### bun

```bash
bun add --global vercel
```

#### pnpm

```bash
pnpm add -g vercel
```

#### yarn

```bash
yarn global add vercel
```

#### npm

```bash
npm install -g vercel
```
   

2. Deploy your project:

   
     

#### bun

```bash
bunx vercel
```

#### pnpm

```bash
pnpm dlx vercel
```

#### yarn

```bash
yarn dlx vercel
```

#### npm

```bash
npx vercel
```
   

3. Set the `DATABASE_URL` environment variable:
   * Go to your [Vercel dashboard](https://vercel.com/)
   * Select your project
   * Navigate to **Settings** → **Environment Variables**
   * Add `DATABASE_URL` with your database connection string

4. Redeploy your application to apply the environment variable:
   
     

#### bun

```bash
bunx vercel --prod
```

#### pnpm

```bash
pnpm dlx vercel --prod
```

#### yarn

```bash
yarn dlx vercel --prod
```

#### npm

```bash
npx vercel --prod
```
   

### Option B: Deploy using Git integration [#option-b-deploy-using-git-integration]

1. Push your code to a Git repository (GitHub, GitLab, or Bitbucket).

2. Add `prisma generate` to your `postinstall` script in `package.json` to ensure Prisma Client is generated during deployment:

   ```json title="package.json"
   {
     "scripts": {
       "postinstall": "prisma generate",
       "build": "nuxt build",
       "dev": "nuxt dev"
     }
   }
   ```

3. Import your project in Vercel:
   * Go to [Vercel dashboard](https://vercel.com/)
   * Click **Add New** → **Project**
   * Import your Git repository
   * Vercel will automatically detect it as a Nuxt project

4. Configure environment variables:
   * Before deploying, go to **Environment Variables**
   * Add `DATABASE_URL` with your database connection string
   * Click **Deploy**

Vercel will automatically build and deploy your Nuxt application. The deployment process is the same as any other Node.js application, and Prisma Client will be generated during the build process thanks to the `postinstall` script.

## Next steps [#next-steps]

* Explore the [full Nuxt + Prisma example](https://github.com/prisma/prisma-examples/tree/latest/orm/nuxt) for a complete blog application
* Learn about [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction)
* Set up [Prisma Postgres](https://www.prisma.io/docs/postgres) for a managed database

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/v7/frameworks/astro): Learn how to use Prisma ORM in an Astro app
- [`Elysia`](https://www.prisma.io/docs/guides/v7/frameworks/elysia): Learn how to use Prisma ORM in an Elysia app
- [`Hono`](https://www.prisma.io/docs/guides/v7/frameworks/hono): Learn how to use Prisma ORM in a Hono app
- [`NestJS`](https://www.prisma.io/docs/guides/v7/frameworks/nestjs): Learn how to use Prisma ORM in a NestJS app
- [`Next.js`](https://www.prisma.io/docs/guides/v7/frameworks/nextjs): Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel

# React Router 7 (Prisma ORM v7) (/docs/guides/v7/frameworks/react-router-7)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM and Prisma Postgres in a React Router 7 app

Location: Guides > v7 > Frameworks > React Router 7

## Introduction [#introduction]

This guide shows you how to use Prisma ORM with [React Router 7](https://reactrouter.com/), a multi-strategy router that can be as minimal as declarative routing or as full-featured as a fullstack framework.

You'll learn how to set up Prisma ORM and Prisma Postgres with React Router 7 and handle migrations. You can find a [deployment-ready example on GitHub](https://github.com/prisma/prisma-examples/blob/latest/orm/react-router-7).

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)

## 1. Set up your project [#1-set-up-your-project]

From the directory where you want to create your project, run `create-react-router` to create a new React Router app that you will be using for this guide.

  

#### bun

```bash
bunx create-react-router@latest react-router-7-prisma
```

#### pnpm

```bash
pnpm dlx create-react-router@latest react-router-7-prisma
```

#### yarn

```bash
yarn dlx create-react-router@latest react-router-7-prisma
```

#### npm

```bash
npx create-react-router@latest react-router-7-prisma
```

You'll be prompted to select the following, select `Yes` for both:

> [!NOTE]
> * *Initialize a new git repository?* `Yes`
> * *Install dependencies with npm?* `Yes`

Now, navigate to the project directory:

```bash
cd react-router-7-prisma
```

## 2. Install and Configure Prisma [#2-install-and-configure-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../app/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../app/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../app/generated/prisma
```

#### npm

```bash
npx prisma init --output ../app/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma` directory with a `schema.prisma` file.
* A `prisma.config.ts` file for configuring Prisma
* A `.env` file containing a local `DATABASE_URL` at the project root.
* An `output` directory for the generated Prisma Client as `app/generated/prisma`.

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define your Prisma Schema [#22-define-your-prisma-schema]

In the `prisma/schema.prisma` file, add the following models and change the generator to use the `prisma-client` provider:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]
```

This creates two models: `User` and `Post`, with a one-to-many relationship between them.

### 2.3 Add `dotenv` to `prisma.config.ts` [#23-add-dotenv-to-prismaconfigts]

To get access to the variables in the `.env` file, they can either be loaded by your runtime, or by using `dotenv`.
Include an import for `dotenv` at the top of the `prisma.config.ts`

```ts
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.4. Configure the Prisma Client generator [#24-configure-the-prisma-client-generator]

Now, run the following command to create the database tables and generate the Prisma Client:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 2.5. Seed the database [#25-seed-the-database]

Add some seed data to populate the database with sample users and posts.

Create a new file called `seed.ts` in the `prisma/` directory:

```typescript title="prisma/seed.ts"
import { PrismaClient, Prisma } from "../app/generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

const userData: Prisma.UserCreateInput[] = [
  {
    name: "Alice",
    email: "alice@prisma.io",
    posts: {
      create: [
        {
          title: "Join the Prisma Discord",
          content: "https://pris.ly/discord",
          published: true,
        },
        {
          title: "Prisma on YouTube",
          content: "https://pris.ly/youtube",
        },
      ],
    },
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
    posts: {
      create: [
        {
          title: "Follow Prisma on Twitter",
          content: "https://www.twitter.com/prisma",
          published: true,
        },
      ],
    },
  },
];

export async function main() {
  for (const u of userData) {
    await prisma.user.create({ data: u });
  }
}

main();
```

Now, tell Prisma how to run this script by updating your `prisma.config.ts`:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: `tsx prisma/seed.ts`, // [!code ++]
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Run the seed script:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

And open Prisma Studio to inspect your data:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

## 3. Integrate Prisma into React Router 7 [#3-integrate-prisma-into-react-router-7]

### 3.1. Create a Prisma Client [#31-create-a-prisma-client]

Inside of your `app` directory, create a new `lib` directory and add a `prisma.ts` file to it. This file will be used to create and export your Prisma Client instance.

Set up the Prisma client like this:

```typescript title="app/lib/prisma.ts"
import { PrismaClient } from "../generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const globalForPrisma = global as unknown as {
  prisma: PrismaClient;
};

const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    adapter,
  });

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

export default prisma;
```

> [!WARNING]
> We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently.
> 
> If you choose not to use one, **avoid** instantiating `PrismaClient` globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections.

You'll use this client in the next section to run your first queries.

### 3.2. Query your database with Prisma [#32-query-your-database-with-prisma]

Now that you have an initialized Prisma Client, a connection to your database, and some initial data, you can start querying your data with Prisma ORM.

In this example, you'll be making the "home" page of your application display all of your users.

Open the `app/routes/home.tsx` file and replace the existing code with the following:

```tsx title="app/routes/home.tsx"
import type { Route } from "./+types/home";

export function meta({}: Route.MetaArgs) {
  return [
    { title: "New React Router App" },
    { name: "description", content: "Welcome to React Router!" },
  ];
}

export default function Home({ loaderData }: Route.ComponentProps) {
  return (
    <div className="min-h-screen flex flex-col items-center justify-center -mt-16">
      <h1 className="text-4xl font-bold mb-8 font-[family-name:var(--font-geist-sans)]">
        Superblog
      </h1>
      <ol className="list-decimal list-inside font-[family-name:var(--font-geist-sans)]">
        <li className="mb-2">Alice</li>
        <li>Bob</li>
      </ol>
    </div>
  );
}
```

> [!NOTE]
> If you see an error on the first line, `import type { Route } from "./+types/home";`, make sure you run `npm run dev` so React Router generates needed types.

This gives you a basic page with a title and a list of users. However, the list of users is static. Update the page to fetch the users from your database and make it dynamic.

```tsx title="app/routes/home.tsx"
import type { Route } from "./+types/home";
import prisma from "~/lib/prisma"; // [!code ++]

export function meta({}: Route.MetaArgs) {
  return [
    { title: "New React Router App" },
    { name: "description", content: "Welcome to React Router!" },
  ];
}

export async function loader() {
  // [!code ++]
  const users = await prisma.user.findMany(); // [!code ++]
  return { users }; // [!code ++]
} // [!code ++]

export default function Home({ loaderData }: Route.ComponentProps) {
  const { users } = loaderData; // [!code ++]
  return (
    <div className="min-h-screen flex flex-col items-center justify-center -mt-16">
      <h1 className="text-4xl font-bold mb-8 font-[family-name:var(--font-geist-sans)]">
        Superblog
      </h1>
      <ol className="list-decimal list-inside font-[family-name:var(--font-geist-sans)]">
        {users.map((user) => (
          <li key={user.id} className="mb-2">
            {user.name}
          </li>
        ))}
      </ol>
    </div>
  );
}
```

You are now importing your client, using [a React Router loader](https://reactrouter.com/start/framework/data-loading#server-data-loading) to query the `User` model for all users, and then displaying them in a list.

Now your home page is dynamic and will display the users from your database.

### 3.4 Update your data (optional) [#34-update-your-data-optional]

If you want to see what happens when data is updated, you could:

* update your `User` table via an SQL browser of your choice
* change your `seed.ts` file to add more users
* change the call to `prisma.user.findMany` to re-order the users, filter the users, or similar.

Reload the page to see the changes.

## 4. Add a new Posts list page [#4-add-a-new-posts-list-page]

You have your home page working, but you should add a new page that displays all of your posts.

First, create a new `posts` directory under the `app/routes` directory and add a `home.tsx` file:

```bash
mkdir -p app/routes/posts && touch app/routes/posts/home.tsx
```

Second, add the following code to the `app/routes/posts/home.tsx` file:

```tsx title="app/routes/posts/home.tsx"
import type { Route } from "./+types/home";
import prisma from "~/lib/prisma";

export default function Home() {
  return (
    <div className="min-h-screen flex flex-col items-center justify-center -mt-16">
      <h1 className="text-4xl font-bold mb-8 font-[family-name:var(--font-geist-sans)]">Posts</h1>
      <ul className="font-[family-name:var(--font-geist-sans)] max-w-2xl space-y-4">
        <li>My first post</li>
      </ul>
    </div>
  );
}
```

Second, update the `app/routes.ts` file so when you visit the `/posts` route, the `posts/home.tsx` page is shown:

```tsx title="app/routes.ts"
import { type RouteConfig, index, route } from "@react-router/dev/routes"; // [!code highlight]

export default [
  index("routes/home.tsx"),
  route("posts", "routes/posts/home.tsx"), // [!code ++]
] satisfies RouteConfig;
```

Now `localhost:5173/posts` will load, but the content is static. Update it to be dynamic, similarly to the home page:

```tsx title="app/routes/posts/home.tsx"
import type { Route } from "./+types/home";
import prisma from "~/lib/prisma";

export async function loader() {
  // [!code ++]
  const posts = await prisma.post.findMany({
    // [!code ++]
    include: {
      // [!code ++]
      author: true, // [!code ++]
    }, // [!code ++]
  }); // [!code ++]
  return { posts }; // [!code ++]
} // [!code ++]

export default function Posts({ loaderData }: Route.ComponentProps) {
  const { posts } = loaderData; // [!code ++]
  return (
    <div className="min-h-screen flex flex-col items-center justify-center -mt-16">
      <h1 className="text-4xl font-bold mb-8 font-[family-name:var(--font-geist-sans)]">Posts</h1>
      <ul className="font-[family-name:var(--font-geist-sans)] max-w-2xl space-y-4">
        {posts.map(
          (
            post, // [!code ++]
          ) => (
            <li key={post.id}>
              {" "}
              // [!code ++]
              <span className="font-semibold">{post.title}</span> // [!code ++]
              <span className="text-sm text-gray-600 ml-2">
                {" "}
                // [!code ++] by {post.author.name} // [!code ++]
              </span>{" "}
              // [!code ++]
            </li> // [!code ++]
          ),
        )}{" "}
        // [!code ++]
      </ul>
    </div>
  );
}
```

This works similarly to the home page, but instead of displaying users, it displays posts. You can also see that you've used `include` in your Prisma Client query to fetch the author of each post so you can display the author's name.

This "list view" is one of the most common patterns in web applications. You're going to add two more pages to your application which you'll also commonly need: a "detail view" and a "create view".

## 5. Add a new Posts detail page [#5-add-a-new-posts-detail-page]

To complement the Posts list page, you'll add a Posts detail page.

In the `routes/posts` directory, create a new `post.tsx` file.

```bash
touch app/routes/posts/post.tsx
```

This page will display a single post's title, content, and author. Just like your other pages, add the following code to the `app/routes/posts/post.tsx` file:

```tsx title="app/routes/posts/post.tsx"
import type { Route } from "./+types/post";
import prisma from "~/lib/prisma";

export default function Post({ loaderData }: Route.ComponentProps) {
  return (
    <div className="min-h-screen flex flex-col items-center justify-center -mt-16">
      <article className="max-w-2xl space-y-4 font-[family-name:var(--font-geist-sans)]">
        <h1 className="text-4xl font-bold mb-8">My first post</h1>
        <p className="text-gray-600 text-center">by Anonymous</p>
        <div className="prose prose-gray mt-8">No content available.</div>
      </article>
    </div>
  );
}
```

And then add a new route for this page:

```tsx title="app/routes.ts"
export default [
  index("routes/home.tsx"),
  route("posts", "routes/posts/home.tsx"),
  route("posts/:postId", "routes/posts/post.tsx"), // [!code ++]
] satisfies RouteConfig;
```

As before, this page is static. Update it to be dynamic based on the `params` passed to the page:

```tsx title="app/routes/posts/post.tsx"
import { data } from "react-router"; // [!code ++]
import type { Route } from "./+types/post";
import prisma from "~/lib/prisma";

export async function loader({ params }: Route.LoaderArgs) {
  // [!code ++]
  const { postId } = params; // [!code ++]
  const post = await prisma.post.findUnique({
    // [!code ++]
    where: { id: parseInt(postId) }, // [!code ++]
    include: {
      // [!code ++]
      author: true, // [!code ++]
    }, // [!code ++]
  }); // [!code ++]
  // [!code ++]
  if (!post) {
    // [!code ++]
    throw data("Post Not Found", { status: 404 }); // [!code ++]
  } // [!code ++]
  return { post }; // [!code ++]
} // [!code ++]

export default function Post({ loaderData }: Route.ComponentProps) {
  const { post } = loaderData; // [!code ++]
  return (
    <div className="min-h-screen flex flex-col items-center justify-center -mt-16">
      <article className="max-w-2xl space-y-4 font-[family-name:var(--font-geist-sans)]">
        <h1 className="text-4xl font-bold mb-8">{post.title}</h1> // [!code ++]
        <p className="text-gray-600 text-center">by {post.author.name}</p> // [!code ++]
        <div className="prose prose-gray mt-8">
          {" "}
          // [!code ++]
          {post.content || "No content available."} // [!code ++]
        </div>{" "}
        // [!code ++]
      </article>
    </div>
  );
}
```

There's a lot of changes here, so break it down:

* You're using Prisma Client to fetch the post by its `id`, which you get from the `params` object.
* In case the post doesn't exist (maybe it was deleted or maybe you typed a wrong ID), you throw an error to display a 404 page.
* You then display the post's title, content, and author. If the post doesn't have content, you display a placeholder message.

It's not the prettiest page, but it's a good start. Try it out by navigating to `localhost:5173/posts/1` and `localhost:5173/posts/2`. You can also test the 404 page by navigating to `localhost:5173/posts/999`.

## 6. Add a new Posts create page [#6-add-a-new-posts-create-page]

To round out your application, you'll add a "create" page for posts. This will allow you to write your own posts and save them to the database.

As with the other pages, you'll start with a static page and then update it to be dynamic.

```bash
touch app/routes/posts/new.tsx
```

Now, add the following code to the `app/routes/posts/new.tsx` file:

```tsx title="app/routes/posts/new.tsx"
import type { Route } from "./+types/new";
import { Form } from "react-router";

export async function action({ request }: Route.ActionArgs) {
  const formData = await request.formData();
  const title = formData.get("title") as string;
  const content = formData.get("content") as string;
}

export default function NewPost() {
  return (
    <div className="max-w-2xl mx-auto p-4">
      <h1 className="text-2xl font-bold mb-6">Create New Post</h1>
      <Form method="post" className="space-y-6">
        <div>
          <label htmlFor="title" className="block text-lg mb-2">
            Title
          </label>
          <input
            type="text"
            id="title"
            name="title"
            placeholder="Enter your post title"
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
        <div>
          <label htmlFor="content" className="block text-lg mb-2">
            Content
          </label>
          <textarea
            id="content"
            name="content"
            placeholder="Write your post content here..."
            rows={6}
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-3 rounded-lg hover:bg-blue-600"
        >
          Create Post
        </button>
      </Form>
    </div>
  );
}
```

You can't open the `posts/new` page in your app yet. To do that, you need to add it to `routes.tsx` again:

```tsx title="app/routes.ts"
export default [
  index("routes/home.tsx"),
  route("posts", "routes/posts/home.tsx"),
  route("posts/:postId", "routes/posts/post.tsx"),
  route("posts/new", "routes/posts/new.tsx"), // [!code ++]
] satisfies RouteConfig;
```

Now you can view the form at the new URL. It looks good, but it doesn't do anything yet. Update the `action` to save the post to the database:

```tsx title="app/routes/posts/new.tsx"
import type { Route } from "./+types/new";
import { Form, redirect } from "react-router"; // [!code ++]
import prisma from "~/lib/prisma"; // [!code ++]

export async function action({ request }: Route.ActionArgs) {
  const formData = await request.formData();
  const title = formData.get("title") as string;
  const content = formData.get("content") as string;

  try {
    // [!code ++]
    await prisma.post.create({
      // [!code ++]
      data: {
        // [!code ++]
        title, // [!code ++]
        content, // [!code ++]
        authorId: 1, // [!code ++]
      }, // [!code ++]
    }); // [!code ++]
  } catch (error) {
    // [!code ++]
    console.error(error); // [!code ++]
    return Response.json({ error: "Failed to create post" }, { status: 500 }); // [!code ++]
  } // [!code ++]
  // [!code ++]
  return redirect("/posts"); // [!code ++]
}

export default function NewPost() {
  return (
    <div className="max-w-2xl mx-auto p-4">
      <h1 className="text-2xl font-bold mb-6">Create New Post</h1>
      <Form method="post" className="space-y-6">
        <div>
          <label htmlFor="title" className="block text-lg mb-2">
            Title
          </label>
          <input
            type="text"
            id="title"
            name="title"
            placeholder="Enter your post title"
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
        <div>
          <label htmlFor="content" className="block text-lg mb-2">
            Content
          </label>
          <textarea
            id="content"
            name="content"
            placeholder="Write your post content here..."
            rows={6}
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-3 rounded-lg hover:bg-blue-600"
        >
          Create Post
        </button>
      </Form>
    </div>
  );
}
```

When you submit the form, the action creates a new post in the database and redirects you to the posts list page.

Try it out by navigating to `localhost:5173/posts/new` and submitting the form.

## 7. Next steps [#7-next-steps]

Now that you have a working React Router application with Prisma ORM, here are some ways you can expand and improve your application:

* Add authentication to protect your routes
* Add the ability to edit and delete posts
* Add comments to posts
* Use [Prisma Studio](https://www.prisma.io/docs/studio) for visual database management

For more information and updates:

* [Prisma ORM documentation](https://www.prisma.io/docs/orm/v7)
* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction)
* [React Router documentation](https://reactrouter.com/home)
* Join our [Discord community](https://pris.ly/discord)
* Follow us on [Twitter](https://twitter.com/prisma) and [YouTube](https://youtube.com/prismadata)

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/v7/frameworks/astro): Learn how to use Prisma ORM in an Astro app
- [`Elysia`](https://www.prisma.io/docs/guides/v7/frameworks/elysia): Learn how to use Prisma ORM in an Elysia app
- [`Hono`](https://www.prisma.io/docs/guides/v7/frameworks/hono): Learn how to use Prisma ORM in a Hono app
- [`NestJS`](https://www.prisma.io/docs/guides/v7/frameworks/nestjs): Learn how to use Prisma ORM in a NestJS app
- [`Next.js`](https://www.prisma.io/docs/guides/v7/frameworks/nextjs): Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel

# SolidStart (Prisma ORM v7) (/docs/guides/v7/frameworks/solid-start)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a SolidStart app

Location: Guides > v7 > Frameworks > SolidStart

## Introduction [#introduction]

SolidStart is a full-stack framework for building reactive web apps with SolidJS. Its API routes run on the server, which is where you call Prisma ORM to read from a Prisma Postgres database.

In this guide, you'll learn how to integrate Prisma ORM with a Prisma Postgres database in a SolidStart project from scratch. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/solid-start).

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)

## 1. Set up your project [#1-set-up-your-project]

Begin by creating a new SolidStart app. In your terminal, run:

  

#### bun

```bash
bunx create-solid
```

#### pnpm

```bash
pnpm create solid
```

#### yarn

```bash
yarn create solid
```

#### npm

```bash
npm init solid@latest
```

Use the following options when prompted:

> [!NOTE]
> * *Project name:* `my-solid-prisma-app`
> * *Is this a SolidStart project:* `Yes`
> * *Template:* `bare`
> * *Use TypeScript:* `Yes`

Next, navigate into your new project, install dependencies, and start the development server:

  

#### bun

```bash
cd my-solid-prisma-app
bun install
bun run dev
```

#### pnpm

```bash
cd my-solid-prisma-app
pnpm install
pnpm run dev
```

#### yarn

```bash
cd my-solid-prisma-app
yarn install
yarn dev
```

#### npm

```bash
cd my-solid-prisma-app
npm install
npm run dev
```

Once the dev server is running, open `http://localhost:3000` in your browser. You should see the SolidStart welcome screen.

Clean up the default UI by editing the `app.tsx` file and replacing its content with the following code:

```typescript title="src/app.tsx"
import "./app.css";

export default function App() {
  return (
    <main>
      <h1>SolidStart + Prisma</h1>
    </main>
  );
}
```

## 2. Install and Configure Prisma [#2-install-and-configure-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../src/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../src/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../src/generated/prisma
```

#### npm

```bash
npx prisma init --output ../src/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma` directory with a `schema.prisma` file.
* A `prisma.config.ts` file for configuring Prisma
* A `.env` file containing a local `DATABASE_URL` at the project root.
* An `output` directory for the generated Prisma Client as `src/generated/prisma`.

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define your Prisma Schema [#22-define-your-prisma-schema]

In the `prisma/schema.prisma` file, add the following models and change the generator to use the `prisma-client` provider:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]
```

This creates two models: `User` and `Post`, with a one-to-many relationship between them.

### 2.3 Add `dotenv` to `prisma.config.ts` [#23-add-dotenv-to-prismaconfigts]

To get access to the variables in the `.env` file, they can either be loaded by your runtime, or by using `dotenv`.
Include an import for `dotenv` at the top of the `prisma.config.ts`

```ts
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.4. Configure the Prisma Client generator [#24-configure-the-prisma-client-generator]

Now, run the following command to create the database tables and generate the Prisma Client:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 2.5. Seed the database [#25-seed-the-database]

Add some seed data to populate the database with sample users and posts.

Create a new file called `seed.ts` in the `prisma/` directory:

```typescript title="prisma/seed.ts"
import { PrismaClient, Prisma } from "../src/generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

const userData: Prisma.UserCreateInput[] = [
  {
    name: "Alice",
    email: "alice@prisma.io",
    posts: {
      create: [
        {
          title: "Join the Prisma Discord",
          content: "https://pris.ly/discord",
          published: true,
        },
        {
          title: "Prisma on YouTube",
          content: "https://pris.ly/youtube",
        },
      ],
    },
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
    posts: {
      create: [
        {
          title: "Follow Prisma on Twitter",
          content: "https://www.twitter.com/prisma",
          published: true,
        },
      ],
    },
  },
];

export async function main() {
  for (const u of userData) {
    await prisma.user.create({ data: u });
  }
}

main();
```

Now, tell Prisma how to run this script by updating your `prisma.config.ts`:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: `tsx prisma/seed.ts`, // [!code ++]
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Run the seed script:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

And open Prisma Studio to inspect your data:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

## 3. Integrate Prisma into SolidStart [#3-integrate-prisma-into-solidstart]

### 3.1. Create a Prisma Client [#31-create-a-prisma-client]

At the root of your project, create a new `lib` folder and a `prisma.ts` file inside it:

```bash
mkdir -p lib && touch lib/prisma.ts
```

Add the following code to create a Prisma Client instance:

```typescript title="lib/prisma.ts"
import { PrismaClient } from "../src/generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

export default prisma;
```

> [!WARNING]
> We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently.
> 
> If you choose not to use one, **avoid** instantiating `PrismaClient` globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections.

### 3.2. Create an API Route [#32-create-an-api-route]

Next, fetch data from the database through an API route.

Create a new file at `src/routes/api/users.ts`:

```typescript title="src/routes/api/users.ts"
import prisma from "../../../lib/prisma";

export async function GET() {
  const users = await prisma.user.findMany({
    include: {
      posts: true,
    },
  });
  return new Response(JSON.stringify(users), {
    headers: { "Content-Type": "application/json" },
  });
}
```

### 3.3. Fetch data in your component [#33-fetch-data-in-your-component]

In your `app.tsx` file, use `createResource` to fetch data from your new API route:

```typescript title="src/app.tsx"
import "./app.css";
import { createResource } from "solid-js"; // [!code ++]
import { User, Post } from "./generated/prisma/client"; // [!code ++]
 // [!code ++]
type UserWithPosts = User & { // [!code ++]
  posts: Post[]; // [!code ++]
}; // [!code ++]
 // [!code ++]
const fetchUsers = async () => { // [!code ++]
  const res = await fetch("http://localhost:3000/api/users"); // [!code ++]
  return res.json(); // [!code ++]
}; // [!code ++]

export default function App() {
  const [users, { mutate, refetch }] = createResource<UserWithPosts[]>(fetchUsers); // [!code ++]

  return (
    <main>
      <h1>SolidStart + Prisma</h1>
    </main>
  );
}
```

> [!NOTE]
> `createResource` is a SolidJS hook for managing async data. It tracks loading and error states automatically. Learn more about [SolidJS `createResource`](https://docs.solidjs.com/reference/basic-reactivity/create-resource#createresource).

### 3.4. Display the Data [#34-display-the-data]

To show the users and their posts, use SolidJS's `<For>` component:

```typescript title="src/app.tsx"
import "./app.css";
import { createResource, For } from "solid-js"; // [!code highlight]
import { User, Post } from "./generated/prisma/client";

type UserWithPosts = User & {
  posts: Post[];
};

const fetchUsers = async () => {
  const res = await fetch("http://localhost:3000/api/users");
  return res.json();
};

export default function App() {
  const [users, { mutate, refetch }] =
    createResource<UserWithPosts[]>(fetchUsers);

  return (
    <main>
      <h1>SolidJS + Prisma</h1>
      <For each={users() ?? []}> // [!code ++]
        {(user) => ( // [!code ++]
          <div> // [!code ++]
            <h3>{user.name}</h3> // [!code ++]
            <For each={user.posts}>{(post) => <p>{post.title}</p>}</For> // [!code ++]
          </div> // [!code ++]
        )} // [!code ++]
      </For> // [!code ++]
    </main>
  );
}
```

> [!NOTE]
> `<For>` loops through an array reactively. Think of it like `.map()` in React. Learn more about [SolidJS `<For>`](https://docs.solidjs.com/reference/components/for)

### 3.5. Add Loading and Error States [#35-add-loading-and-error-states]

Use SolidJS's `<Show>` component to handle loading and error conditions:

```typescript title="src/app.tsx"
import "./app.css";
import { createResource, For, Show } from "solid-js"; // [!code highlight]
import { User, Post } from "./generated/prisma/client";

type UserWithPosts = User & {
  posts: Post[];
};

const fetchUsers = async () => {
  const res = await fetch("http://localhost:3000/api/users");
  return res.json();
};

export default function App() {
  const [users, { mutate, refetch }] =
    createResource<UserWithPosts[]>(fetchUsers);

  return (
    <main>
      <h1>SolidJS + Prisma</h1>
      <Show when={!users.loading} fallback={<p>Loading...</p>}> // [!code ++]
        <Show when={!users.error} fallback={<p>Error loading data</p>}> // [!code ++]
          <For each={users()}>
            {(user) => (
              <div>
                <h3>{user.name}</h3>
                <For each={user.posts}>{(post) => <p>{post.title}</p>}</For>
              </div>
            )}
          </For>
        </Show> // [!code ++]
      </Show> // [!code ++]
    </main>
  );
}
```

> [!NOTE]
> `<Show>` conditionally renders content. It's similar to an `if` statement. Learn more about [SolidJS `<Show>`](https://docs.solidjs.com/reference/components/show)

Your SolidStart app now reads users and their posts from a Prisma Postgres database through the API route.

## Next Steps [#next-steps]

Now that you have a working SolidStart app connected to a Prisma Postgres database, you can:

* Extend your Prisma schema with more models and relationships
* Add create/update/delete routes and forms
* Explore authentication, validation, and optimistic updates

## More Info [#more-info]

* [Prisma ORM Docs](https://www.prisma.io/docs/orm/v7)
* [SolidStart Documentation](https://start.solidjs.com/)

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/v7/frameworks/astro): Learn how to use Prisma ORM in an Astro app
- [`Elysia`](https://www.prisma.io/docs/guides/v7/frameworks/elysia): Learn how to use Prisma ORM in an Elysia app
- [`Hono`](https://www.prisma.io/docs/guides/v7/frameworks/hono): Learn how to use Prisma ORM in a Hono app
- [`NestJS`](https://www.prisma.io/docs/guides/v7/frameworks/nestjs): Learn how to use Prisma ORM in a NestJS app
- [`Next.js`](https://www.prisma.io/docs/guides/v7/frameworks/nextjs): Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel

# SvelteKit (Prisma ORM v7) (/docs/guides/v7/frameworks/sveltekit)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a SvelteKit app

Location: Guides > v7 > Frameworks > SvelteKit

## Introduction [#introduction]

[SvelteKit](https://svelte.dev/docs/kit) runs `load` functions on the server before a page renders, which is where you call Prisma ORM to read from a Prisma Postgres database.

In this guide, you'll learn to integrate Prisma ORM with a Prisma Postgres database in a SvelteKit project from scratch. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/sveltekit).

## Quick start [#quick-start]

Run one command to scaffold a SvelteKit project with Prisma ORM and Prisma Postgres ready to go:

  

#### bun

```bash
bunx create-prisma@stable --template svelte
```

#### pnpm

```bash
pnpm create prisma@stable --template svelte
```

#### yarn

```bash
yarn create prisma@stable --template svelte
```

#### npm

```bash
npm create prisma@stable -- --template svelte
```

Or follow the steps below to set it up manually.

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* [Svelte VSCode extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) (Recommended by Svelte)

## 1. Set up your project [#1-set-up-your-project]

You'll be using [Svelte CLI](https://github.com/sveltejs/cli) instead of `npx create svelte@latest`. This CLI provides a more interactive setup and built-in support for popular tooling like ESLint and Prettier

Create a new Svelte project:

  

#### bun

```bash
bunx sv create sveltekit-prisma
```

#### pnpm

```bash
pnpm dlx sv create sveltekit-prisma
```

#### yarn

```bash
yarn dlx sv create sveltekit-prisma
```

#### npm

```bash
npx sv create sveltekit-prisma
```

It will prompt you to customize your setup. Here are the options you'll choose:

> [!NOTE]
> * *Which template would you like?* `SvelteKit minimal`
> * *Add type checking with TypeScript?* `Yes, using TypeScript syntax`
> * *What would you like to add to your project?*
>   * `prettier`
>   * `eslint`
> * *Which package manager do you want to install dependencies with?* `npm`

Once the setup completes, navigate into your project and start the development server:

  

#### bun

```bash
cd sveltekit-prisma
bun run dev
```

#### pnpm

```bash
cd sveltekit-prisma
pnpm run dev
```

#### yarn

```bash
cd sveltekit-prisma
yarn dev
```

#### npm

```bash
cd sveltekit-prisma
npm run dev
```

At this point, your project is ready to integrate Prisma and connect to a Prisma Postgres database.

## 2. Install and Configure Prisma [#2-install-and-configure-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output src/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output src/generated/prisma
```

#### yarn

```bash
yarn prisma init --output src/generated/prisma
```

#### npm

```bash
npx prisma init --output src/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma` directory with a `schema.prisma` file.
* A `prisma.config.ts` file for configuring Prisma
* A `.env` file containing a local `DATABASE_URL` at the project root.
* An `output` directory for the generated Prisma Client as `src/generated/prisma`.

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define your Prisma Schema [#22-define-your-prisma-schema]

In the `prisma/schema.prisma` file, add the following models and change the generator to use the `prisma-client` provider:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]
```

This creates two models: `User` and `Post`, with a one-to-many relationship between them.

### 2.3 Add `dotenv` to `prisma.config.ts` [#23-add-dotenv-to-prismaconfigts]

To get access to the variables in the `.env` file, they can either be loaded by your runtime, or by using `dotenv`.
Include an import for `dotenv` at the top of the `prisma.config.ts`

```ts
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.4. Configure the Prisma Client generator [#24-configure-the-prisma-client-generator]

Now, run the following command to create the database tables and generate the Prisma Client:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 2.5. Seed the database [#25-seed-the-database]

Add some seed data to populate the database with sample users and posts.

Create a new file called `seed.ts` in the `prisma/` directory:

```typescript title="prisma/seed.ts"
import { PrismaClient, Prisma } from "../src/generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

const userData: Prisma.UserCreateInput[] = [
  {
    name: "Alice",
    email: "alice@prisma.io",
    posts: {
      create: [
        {
          title: "Join the Prisma Discord",
          content: "https://pris.ly/discord",
          published: true,
        },
        {
          title: "Prisma on YouTube",
          content: "https://pris.ly/youtube",
        },
      ],
    },
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
    posts: {
      create: [
        {
          title: "Follow Prisma on Twitter",
          content: "https://www.twitter.com/prisma",
          published: true,
        },
      ],
    },
  },
];

export async function main() {
  for (const u of userData) {
    await prisma.user.create({ data: u });
  }
}

main();
```

Now, tell Prisma how to run this script by updating your `prisma.config.ts`:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: `tsx prisma/seed.ts`, // [!code ++]
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Run the seed script:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

And open Prisma Studio to inspect your data:

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

## 3. Integrate Prisma into SvelteKit [#3-integrate-prisma-into-sveltekit]

### 3.1. Create a Prisma Client [#31-create-a-prisma-client]

Inside your `/src/lib` directory, rename `index.ts` to `prisma.ts`. This file will be used to create and export your Prisma Client instance.

> [!NOTE]
> Files in `src/lib` can be accessed from anywhere using the `$lib` alias.

The `DATABASE_URL` is stored in the `.env` file. To access it, you'll need to import it from the [`$env/static/private`](https://svelte.dev/docs/kit/$env-static-private) namespace.

Set up the Prisma client like this:

```tsx title="src/lib/prisma.ts"
import { PrismaClient } from "../generated/prisma/client.js";
import { DATABASE_URL } from "$env/static/private";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: DATABASE_URL,
});

const prisma = new PrismaClient({
  adapter,
});

export default prisma;
```

> [!WARNING]
> We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently.
> 
> If you choose not to use one, **avoid** instantiating `PrismaClient` globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections.

### 3.2. Create a server route [#32-create-a-server-route]

To fetch data from the database on the server side, create a `+page.server.ts` file in your `routes` directory. This file should export a `load` function, which runs on the server before your page renders.

Use the `findMany()` method within a basic `load` function to get a list of users.

Update your `+page.server.ts` file like this:

```typescript title="src/routes/+page.server.ts"
import prisma from "$lib/prisma";

export async function load() {
  const users = await prisma.user.findMany({});
  return {
    users,
  };
}
```

At this point, you're only getting data directly on the `User` model; no relations like posts are included yet.

To also fetch each user's posts, expand the query using the `include` option. This tells Prisma to join the related `Posts` table in the result.

Update your `findMany()` call like this:

```typescript title="src/routes/+page.server.ts"
import prisma from "$lib/prisma";

export async function load() {
  const users = await prisma.user.findMany({
    include: {
      // [!code ++]
      posts: true, // [!code ++]
    }, // [!code ++]
  });

  return {
    users,
  };
}
```

Now, every user in the result will also include a `posts` array.

### 3.3. Populate the page [#33-populate-the-page]

In `src/routes/+page.svelte`, strip the file down to the basics and add a `<script>` fragment. The file should look like this:

```html title="src/routes/+page.svelte"
<script lang="ts"></script>

<h1>SvelteKit + Prisma</h1>
```

Read the data exported from `+page.server.ts`:

```html title="src/routes/+page.svelte"
<script lang="ts">
  let { data } = $props(); // [!code ++]
</script>

<h1>SvelteKit + Prisma</h1>
```

With the data available, map through the users and their posts with Svelte's [`each`](https://svelte.dev/docs/svelte/each) block:

```html title="src/routes/+page.svelte"
<script lang="ts">
  let { data } = $props();
</script>

<h1>SvelteKit + Prisma</h1>

{#each data.users as user} // [!code ++]
<h2>{user.name}</h2>
// [!code ++] {#each user.posts as post} // [!code ++]
<ul>
  // [!code ++]
  <li><a href="{post.content}">{post.title}</a></li>
  // [!code ++]
</ul>
// [!code ++] {/each} // [!code ++] {/each} // [!code ++]
```

Your SvelteKit app now renders users and their posts from a Prisma Postgres database.

## Next Steps [#next-steps]

Now that you have a working SvelteKit app connected to a Prisma Postgres database, you can:

* Extend your Prisma schema with more models and relationships
* Add create/update/delete routes and forms
* Explore authentication and validation

### More Info [#more-info]

* [Prisma Documentation](https://www.prisma.io/docs/orm/v7)
* [SvelteKit Documentation](https://svelte.dev/docs/kit)

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/v7/frameworks/astro): Learn how to use Prisma ORM in an Astro app
- [`Elysia`](https://www.prisma.io/docs/guides/v7/frameworks/elysia): Learn how to use Prisma ORM in an Elysia app
- [`Hono`](https://www.prisma.io/docs/guides/v7/frameworks/hono): Learn how to use Prisma ORM in a Hono app
- [`NestJS`](https://www.prisma.io/docs/guides/v7/frameworks/nestjs): Learn how to use Prisma ORM in a NestJS app
- [`Next.js`](https://www.prisma.io/docs/guides/v7/frameworks/nextjs): Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel

# TanStack Start (Prisma ORM v7) (/docs/guides/v7/frameworks/tanstack-start)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a TanStack Start app

Location: Guides > v7 > Frameworks > TanStack Start

## Introduction [#introduction]

[TanStack Start](https://tanstack.com/start/latest/docs/framework/react/guide/server-functions) runs server functions alongside your React routes, which is where you call Prisma ORM to read from a [Prisma Postgres](https://www.prisma.io/postgres) database.

This guide shows you how to integrate Prisma ORM with a Prisma Postgres database in a TanStack Start project from scratch.

## Quick start [#quick-start]

Run one command to scaffold a TanStack Start project with Prisma ORM and Prisma Postgres ready to go:

  

#### bun

```bash
bunx create-prisma@stable --template tanstack-start
```

#### pnpm

```bash
pnpm create prisma@stable --template tanstack-start
```

#### yarn

```bash
yarn create prisma@stable --template tanstack-start
```

#### npm

```bash
npm create prisma@stable -- --template tanstack-start
```

Or follow the steps below to set it up manually.

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)

## 1. Set up your project [#1-set-up-your-project]

To begin, create a new TanStack Start project.

  

#### bun

```bash
bun create @tanstack/start@latest
```

#### pnpm

```bash
pnpm create @tanstack/start@latest
```

#### yarn

```bash
yarn create @tanstack/start@latest
```

#### npm

```bash
npm create @tanstack/start@latest
```

> [!NOTE]
> * *What would you like to name your project?* tanstack-start-prisma
> * *Would you like to use Tailwind CSS?* No
> * *Select Toolchain* None
> * *Select deployment adapter* Nitro
> * *What add-ons would you like for your project?* Prisma
> * *Would you like any examples?* No
> * *Prisma: Database Provider* Prisma PostgresSQL

This will create a new folder called `tanstack-start-prisma` and provision a new Prisma Postgres database. At the end of the setup, the CLI will display the database connection string:

```
●  Database Connection
│
│    Connection String:
│
│    postgresql://username:password@db.prisma.io:5432/postgres
●
```

> [!WARNING]
> The database is **temporary** and will be deleted after 24 hours. To keep it permanently, follow the claim link shown in the CLI output.

Navigate to your project directory:

```bash
cd tanstack-start-prisma
```

Then, add the connection string you copied to your `.env` file:

```bash title=".env"
DATABASE_URL="postgresql://username:password@db.prisma.io:5432/postgres"
```

## 2. Configure Prisma [#2-configure-prisma]

### 2.1. Define your Prisma Schema [#21-define-your-prisma-schema]

In `schema.prisma`, the model for our todos is defined below the generator and datasource blocks:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model Todo {
  id        Int      @id @default(autoincrement())
  title     String
  createdAt DateTime @default(now())
}
```

This creates a `Todo` model that will be pushed to the database

### 2.2. Run migrations and generate Prisma Client [#22-run-migrations-and-generate-prisma-client]

Now, run the following command to create the database tables:

  

#### bun

```bash
bun run db:migrate --name init
```

#### pnpm

```bash
pnpm run db:migrate --name init
```

#### yarn

```bash
yarn db:migrate --name init
```

#### npm

```bash
npm run db:migrate -- --name init
```

Generate the Prisma Client needed for the project:

  

#### bun

```bash
bun run db:generate
```

#### pnpm

```bash
pnpm run db:generate
```

#### yarn

```bash
yarn db:generate
```

#### npm

```bash
npm run db:generate
```

### 2.3. Seed the database [#23-seed-the-database]

Then seed the project with the `seed.ts` file in the `prisma/` directory:

  

#### bun

```bash
bun run db:seed
```

#### pnpm

```bash
pnpm run db:seed
```

#### yarn

```bash
yarn db:seed
```

#### npm

```bash
npm run db:seed
```

And open Prisma Studio to inspect your data:

  

#### bun

```bash
bun run db:studio
```

#### pnpm

```bash
pnpm run db:studio
```

#### yarn

```bash
yarn db:studio
```

#### npm

```bash
npm run db:studio
```

## 3. Integrate Prisma into TanStack Start [#3-integrate-prisma-into-tanstack-start]

### 3.1 The Prisma Client [#31-the-prisma-client]

Instead of creating a new Prisma Client instance in each file, TanStack Start has a `db.ts` that
creates a single instance that can be shared globally

```tsx title="src/db.ts"
import { PrismaClient } from "./generated/prisma/client.js";

import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

declare global {
  var __prisma: PrismaClient | undefined;
}

export const prisma = globalThis.__prisma || new PrismaClient({ adapter });

if (process.env.NODE_ENV !== "production") {
  globalThis.__prisma = prisma;
}
```

### 3.2 Fetch data on load [#32-fetch-data-on-load]

First, import the necessary modules. Then, create a server function using the [`createServerFn`](https://tanstack.com/start/latest/docs/framework/react/guide/server-functions) function. This function will fetch the data from the database using the `.findMany()` method

```typescript title="src/routes/index.tsx"
import { createFileRoute } from "@tanstack/react-router";
import { createServerFn } from "@tanstack/react-start"; // [!code ++]
import { prisma } from '../db'; // [!code ++]

export const Route = createFileRoute("/")({
  component: Home,
});

const getTodos = createServerFn({ method: "GET" }).handler(async () => { // [!code ++]
  return prisma.todo.findMany(); // [!code ++]
}); // [!code ++]

function Home() {
  return (
    <div>
    </div>
  );
}
```

TanStack Start allows functions to run on load with loader functions in the [`createFileRoute`](https://tanstack.com/router/latest/docs/framework/react/api/router/createFileRouteFunction) function. Fetch the users and their posts on load with this code:

```typescript title="app/routes/index.tsx"
import { createFileRoute } from '@tanstack/react-router';
import { createServerFn } from '@tanstack/react-start';
import { prisma } from '../db';

export const Route = createFileRoute("/")({
  component: Home,
  loader: () => { // [!code ++]
    return getTodos(); // [!code ++]
  }, // [!code ++]
});

const getTodos = createServerFn({ method: "GET" }).handler(async () => {
  return prisma.todo.findMany();
});

function Home() {
  return (
    <div>
      <h1>Todos</h1>
    </div>
  );
}
```

Store the response from the loader in the main component using [`Route.useLoaderData()`](https://tanstack.com/router/latest/docs/framework/react/api/router/useLoaderDataHook):

```typescript title="app/routes/index.tsx"
import { createServerFn } from "@tanstack/react-start";
import { createFileRoute } from "@tanstack/react-router";
import { prisma } from '../db';

export const Route = createFileRoute("/")({
  component: Home,
  loader: () => {
    return getTodos();
  },
});

const getTodos = createServerFn({ method: "GET" }).handler(async () => {
  return prisma.todo.findMany();
});

function Home() {
  const todos = Route.useLoaderData(); // [!code ++]

  return (
    <div>
      <h1>Todos</h1>
    </div>
  );
}
```

### 3.3 Display the todos [#33-display-the-todos]

Next, you'll update the home page to display the data retrieved from your database.

Map over the `todos` and display them in a list:

```typescript title="app/routes/index.tsx"
import { createFileRoute } from '@tanstack/react-router';
import { createServerFn } from '@tanstack/react-start';
import { prisma } from '../db';

export const Route = createFileRoute('/')({
  component: App,
  loader: () => getTodos(),
});

const getTodos = createServerFn({ method: 'GET' }).handler(async () => {
  return prisma.todo.findMany();
});

function App() {
  const todos = Route.useLoaderData();

  return (
    <div>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  );
}
```

This setup will display the todos on your page, fetched directly from your database.

## Next steps [#next-steps]

Your TanStack Start app now loads todos from a Prisma Postgres database through a server function. A few suggestions for what to do next:

* Expand your Prisma models to handle more complex data relationships.
* Implement additional CRUD operations.
* Check out [Prisma Postgres](https://www.prisma.io/postgres) to see how you can scale your application.

## More info [#more-info]

* [Prisma ORM Documentation](https://www.prisma.io/docs/orm/v7)
* [TanStack Start Documentation](https://tanstack.com/start/latest/docs/framework/react/overview)

## Related pages

- [`Astro`](https://www.prisma.io/docs/guides/v7/frameworks/astro): Learn how to use Prisma ORM in an Astro app
- [`Elysia`](https://www.prisma.io/docs/guides/v7/frameworks/elysia): Learn how to use Prisma ORM in an Elysia app
- [`Hono`](https://www.prisma.io/docs/guides/v7/frameworks/hono): Learn how to use Prisma ORM in a Hono app
- [`NestJS`](https://www.prisma.io/docs/guides/v7/frameworks/nestjs): Learn how to use Prisma ORM in a NestJS app
- [`Next.js`](https://www.prisma.io/docs/guides/v7/frameworks/nextjs): Learn how to use Prisma ORM in a Next.js app and deploy it to Vercel

# AI SDK (with Next.js) (Prisma ORM v7) (/docs/guides/v7/integrations/ai-sdk)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Build a chat application with AI SDK, Prisma, and Next.js to store chat sessions and messages

Location: Guides > v7 > Integrations > AI SDK (with Next.js)

## Introduction [#introduction]

[AI SDK](https://sdk.vercel.ai/) streams model responses to the browser, and a [Next.js](https://nextjs.org/) route handler gives you a place to persist each exchange with Prisma ORM, so a conversation survives page reloads.

In this guide, you'll learn to build a chat application using AI SDK with Next.js and Prisma ORM to store chat sessions and messages in a Prisma Postgres database. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/ai-sdk-nextjs).

## Prerequisites [#prerequisites]

* [Node.js 20+](https://nodejs.org)
* An [OpenAI API key](https://platform.openai.com/api-keys) or other AI provider API key

## 1. Set up your project [#1-set-up-your-project]

To get started, you'll need to create a new Next.js project.

  

#### bun

```bash
bunx create-next-app@latest ai-sdk-prisma
```

#### pnpm

```bash
pnpm dlx create-next-app@latest ai-sdk-prisma
```

#### yarn

```bash
yarn dlx create-next-app@latest ai-sdk-prisma
```

#### npm

```bash
npx create-next-app@latest ai-sdk-prisma
```

It will prompt you to customize your setup. Choose the defaults:

> [!NOTE]
> * *Would you like to use TypeScript?* `Yes`
> * *Would you like to use ESLint?* `Yes`
> * *Would you like to use Tailwind CSS?* `Yes`
> * *Would you like your code inside a `src/` directory?* `No`
> * *Would you like to use App Router?* (recommended) `Yes`
> * *Would you like to use Turbopack for `next dev`?* `Yes`
> * *Would you like to customize the import alias (`@/*` by default)?* `No`

Navigate to the project directory:

```bash
cd ai-sdk-prisma
```

## 2. Install and Configure Prisma [#2-install-and-configure-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

To get started with Prisma, you'll need to install a few dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma in your project:

  

#### bun

```bash
bunx --bun prisma init --output ../app/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../app/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../app/generated/prisma
```

#### npm

```bash
npx prisma init --output ../app/generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This will create:

* A `prisma` directory with a `schema.prisma` file.
* A `prisma.config.ts` file for configuring Prisma
* A `.env` file containing a local `DATABASE_URL` at the project root.
* The `output` field specifies where the generated Prisma Client will be stored.

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define your Prisma Schema [#22-define-your-prisma-schema]

In the `prisma/schema.prisma` file, add the following models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model Session { // [!code ++]
  id        String    @id // [!code ++]
  createdAt DateTime  @default(now()) // [!code ++]
  updatedAt DateTime  @updatedAt // [!code ++]
  messages  Message[] // [!code ++]
} // [!code ++]
 // [!code ++]
model Message { // [!code ++]
  id        String      @id @default(cuid()) // [!code ++]
  role      MessageRole // [!code ++]
  content   String // [!code ++]
  createdAt DateTime    @default(now()) // [!code ++]
  sessionId String // [!code ++]
  session   Session     @relation(fields: [sessionId], references: [id], onDelete: Cascade) // [!code ++]
} // [!code ++]
 // [!code ++]
enum MessageRole { // [!code ++]
  USER // [!code ++]
  ASSISTANT // [!code ++]
} // [!code ++]
```

This creates three models: `Session`, `Message`, and `MessageRole`.

### 2.3 Add `dotenv` to `prisma.config.ts` [#23-add-dotenv-to-prismaconfigts]

To get access to the variables in the `.env` file, they can either be loaded by your runtime, or by using `dotenv`.
Include an import for `dotenv` at the top of the `prisma.config.ts`

```ts
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.4. Configure the Prisma Client generator [#24-configure-the-prisma-client-generator]

Now, run the following command to create the database tables and generate the Prisma Client:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 3. Integrate Prisma into Next.js [#3-integrate-prisma-into-nextjs]

Create a `/lib` directory and a `prisma.ts` file inside it. This file will be used to create and export your Prisma Client instance.

```bash
mkdir lib
touch lib/prisma.ts
```

Set up the Prisma client like this:

```tsx title="lib/prisma.ts"
import { PrismaClient } from "../app/generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const globalForPrisma = global as unknown as {
  prisma: PrismaClient;
};

const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    adapter,
  });

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

export default prisma;
```

> [!WARNING]
> We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently.
> 
> If you choose not to use one, **avoid** instantiating `PrismaClient` globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections.

## 4. Set up AI SDK [#4-set-up-ai-sdk]

### 4.1. Install AI SDK and get an API key [#41-install-ai-sdk-and-get-an-api-key]

Install the AI SDK package:

  

#### bun

```bash
bun add ai @ai-sdk/react @ai-sdk/openai zod
```

#### pnpm

```bash
pnpm add ai @ai-sdk/react @ai-sdk/openai zod
```

#### yarn

```bash
yarn add ai @ai-sdk/react @ai-sdk/openai zod
```

#### npm

```bash
npm install ai @ai-sdk/react @ai-sdk/openai zod
```

To use AI SDK, you'll need to obtain an API key from [OpenAI](https://platform.openai.com/api-keys).

1. Navigate to [OpenAI API Keys](https://platform.openai.com/api-keys)
2. Click on `Create new secret key`
3. Fill in the form:
   * Give your key a name like `Next.js AI SDK Project`
   * Select `All` access
4. Click on `Create secret key`
5. Copy the API key
6. Add the API key to the `.env` file:

```text title=".env"
DATABASE_URL=<YOUR_DATABASE_URL_HERE>
OPENAI_API_KEY=<YOUR_OPENAI_API_KEY_HERE>
```

### 4.2. Create a route handler [#42-create-a-route-handler]

You need to create a route handler to handle the AI SDK requests. This handler will process chat messages and stream AI responses back to the client.

```bash
mkdir -p app/api/chat
touch app/api/chat/route.ts
```

Set up the basic route handler:

```tsx title="app/api/chat/route.ts"
import { openai } from "@ai-sdk/openai";
import { streamText, UIMessage, convertToModelMessages } from "ai";

export const maxDuration = 300;

export async function POST(req: Request) {
  const { messages }: { messages: UIMessage[] } = await req.json();

  const result = streamText({
    model: openai("gpt-4o"),
    messages: convertToModelMessages(messages),
  });

  return result.toUIMessageStreamResponse();
}
```

This route handler:

1. Extracts the conversation history from the request body
2. Converts UI messages to the format expected by the AI model
3. Streams the AI response back to the client in real-time

To save chat sessions and messages to the database, we need to:

1. Add a session `id` parameter to the request
2. Include an `onFinish` callback in the response
3. Pass the `id` and `messages` parameters to the `saveChat` function (which we'll build next)

```tsx title="app/api/chat/route.ts"
import { openai } from "@ai-sdk/openai";
import { streamText, UIMessage, convertToModelMessages } from "ai";
import { saveChat } from "@/lib/save-chat"; // [!code ++]

export const maxDuration = 300;

export async function POST(req: Request) {
  const { messages, id }: { messages: UIMessage[]; id: string } = await req.json(); // [!code highlight]

  const result = streamText({
    model: openai("gpt-4o"),
    messages: convertToModelMessages(messages),
  });

  return result.toUIMessageStreamResponse({
    originalMessages: messages, // [!code ++]
    onFinish: async ({ messages }) => {
      // [!code ++]
      await saveChat(messages, id); // [!code ++]
    }, // [!code ++]
  });
}
```

### 4.3. Create a `saveChat` function [#43-create-a-savechat-function]

Create a new file at `lib/save-chat.ts` to save the chat sessions and messages to the database:

```bash
touch lib/save-chat.ts
```

To start, create a basic function called `saveChat` that will be used to save the chat sessions and messages to the database.

Pass into it the `messages` and `id` parameters typed as `UIMessage[]` and `string` respectively:

```tsx title="lib/save-chat.ts"
import { UIMessage } from "ai";

export async function saveChat(messages: UIMessage[], id: string) {}
```

Now, add the logic to create a session with the given `id`:

```tsx title="lib/save-chat.ts"
import prisma from "./prisma"; // [!code ++]
import { UIMessage } from "ai";

export async function saveChat(messages: UIMessage[], id: string) {
  const session = await prisma.session.upsert({
    // [!code ++]
    where: { id }, // [!code ++]
    update: {}, // [!code ++]
    create: { id }, // [!code ++]
  }); // [!code ++]
  // [!code ++]
  if (!session) throw new Error("Session not found"); // [!code ++]
}
```

Add the logic to save the messages to the database. You'll only be saving the last two messages &#x2A;(Users and Assistants last messages)* to avoid any overlapping messages.

```tsx title="lib/save-chat.ts"
import prisma from "./prisma";
import { UIMessage } from "ai";

export async function saveChat(messages: UIMessage[], id: string) {
  const session = await prisma.session.upsert({
    where: { id },
    update: {},
    create: { id },
  });

  if (!session) throw new Error("Session not found");

  const lastTwoMessages = messages.slice(-2); // [!code ++]
  // [!code ++]
  for (const msg of lastTwoMessages) {
    // [!code ++]
    let content = JSON.stringify(msg.parts); // [!code ++]
    if (msg.role === "assistant") {
      // [!code ++]
      const textParts = msg.parts.filter((part) => part.type === "text"); // [!code ++]
      content = JSON.stringify(textParts); // [!code ++]
    } // [!code ++]
    // [!code ++]
    await prisma.message.create({
      // [!code ++]
      data: {
        // [!code ++]
        role: msg.role === "user" ? "USER" : "ASSISTANT", // [!code ++]
        content: content, // [!code ++]
        sessionId: session.id, // [!code ++]
      }, // [!code ++]
    }); // [!code ++]
  } // [!code ++]
}
```

This function:

1. Upserts a session with the given `id` to create a session if it doesn't exist
2. Saves the messages to the database under the `sessionId`

## 5. Create a messages API route [#5-create-a-messages-api-route]

Create a new file at `app/api/messages/route.ts` to fetch the messages from the database:

```bash
mkdir -p app/api/messages
touch app/api/messages/route.ts
```

Create a basic API route to fetch the messages from the database.

```tsx title="app/api/messages/route.ts"
import { NextResponse } from "next/server";
import prisma from "@/lib/prisma";

export async function GET() {
  try {
    const messages = await prisma.message.findMany({
      orderBy: { createdAt: "asc" },
    });

    const uiMessages = messages.map((msg) => ({
      id: msg.id,
      role: msg.role.toLowerCase(),
      parts: JSON.parse(msg.content),
    }));

    return NextResponse.json({ messages: uiMessages });
  } catch (error) {
    console.error("Error fetching messages:", error);
    return NextResponse.json({ messages: [] });
  }
}
```

## 6. Create the UI [#6-create-the-ui]

Replace the content of the `app/page.tsx` file with the following:

```tsx title="app/page.tsx"
"use client";

export default function Page() {}
```

### 6.1. Set up the basic imports and state [#61-set-up-the-basic-imports-and-state]

Start by importing the required dependencies and setting up the state variables that will manage the chat interface:

```tsx title="app/page.tsx"
"use client";

import { useChat } from "@ai-sdk/react"; // [!code ++]
import { useState, useEffect } from "react"; // [!code ++]

export default function Chat() {
  const [input, setInput] = useState(""); // [!code ++]
  const [isLoading, setIsLoading] = useState(true); // [!code ++]
  // [!code ++]
  const { messages, sendMessage, setMessages } = useChat(); // [!code ++]
}
```

### 6.2. Load existing messages [#62-load-existing-messages]

Create a `useEffect` hook that will automatically fetch and display any previously saved messages when the chat component loads:

```tsx title="app/page.tsx"
"use client";

import { useChat } from "@ai-sdk/react";
import { useState, useEffect } from "react";

export default function Chat() {
  const [input, setInput] = useState("");
  const [isLoading, setIsLoading] = useState(true);

  const { messages, sendMessage, setMessages } = useChat();

  useEffect(() => {
    // [!code ++]
    fetch("/api/messages") // [!code ++]
      .then((res) => res.json()) // [!code ++]
      .then((data) => {
        // [!code ++]
        if (data.messages && data.messages.length > 0) {
          // [!code ++]
          setMessages(data.messages); // [!code ++]
        } // [!code ++]
        setIsLoading(false); // [!code ++]
      }) // [!code ++]
      .catch(() => setIsLoading(false)); // [!code ++]
  }, [setMessages]); // [!code ++]
}
```

This loads any existing messages from your database when the component first mounts, so users can see their previous conversation history.

### 6.3. Add message display [#63-add-message-display]

Build the UI components that will show a loading indicator while fetching data and render the chat messages with proper styling:

```tsx title="app/page.tsx"
'use client';

import { useChat } from '@ai-sdk/react';
import { useState, useEffect } from 'react';

export default function Chat() {
  const [input, setInput] = useState('');
  const [isLoading, setIsLoading] = useState(true);

  const { messages, sendMessage, setMessages } = useChat();

  useEffect(() => {
    fetch('/api/messages')
      .then(res => res.json())
      .then(data => {
        if (data.messages && data.messages.length > 0) {
          setMessages(data.messages);
        }
        setIsLoading(false);
      })
      .catch(() => setIsLoading(false));
  }, [setMessages]);

  if (isLoading) { // [!code ++]
    return <div className="flex justify-center items-center h-screen">Loading...</div>; // [!code ++]
  } // [!code ++]
 // [!code ++]
  return ( // [!code ++]
    <div className="flex flex-col w-full max-w-md py-24 mx-auto stretch"> // [!code ++]
      {messages.map(message => ( // [!code ++]
        <div key={message.id} className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'} mb-4`}> // [!code ++]
          <div className={`max-w-[80%] rounded-lg px-4 py-3 ${ // [!code ++]
            message.role === 'user' // [!code ++]
              ? 'bg-neutral-600 text-white' // [!code ++]
              : 'bg-neutral-200 dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100' // [!code ++]
          }`}> // [!code ++]
            <div className="whitespace-pre-wrap"> // [!code ++]
              <p className="text-xs font-extralight mb-1 opacity-70">{message.role === 'user' ? 'YOU ' : 'AI '}</p> // [!code ++]
              {message.parts.map((part, i) => { // [!code ++]
                switch (part.type) { // [!code ++]
                  case 'text': // [!code ++]
                    return <div key={`${message.id}-${i}`}>{part.text}</div>; // [!code ++]
                } // [!code ++]
              })} // [!code ++]
            </div> // [!code ++]
          </div> // [!code ++]
        </div> // [!code ++]
      ))} // [!code ++]
```

The message rendering logic handles different message types and applies appropriate styling - user messages appear on the right with a dark background, while AI responses appear on the left with a light background.

### 6.4. Add the input form [#64-add-the-input-form]

Now we need to create the input interface that allows users to type and send messages to the AI:

```tsx title="app/page.tsx"
"use client";

import { useChat } from "@ai-sdk/react";
import { useState, useEffect } from "react";

export default function Chat() {
  const [input, setInput] = useState("");
  const [isLoading, setIsLoading] = useState(true);

  const { messages, sendMessage, setMessages } = useChat();

  useEffect(() => {
    fetch("/api/messages")
      .then((res) => res.json())
      .then((data) => {
        if (data.messages && data.messages.length > 0) {
          setMessages(data.messages);
        }
        setIsLoading(false);
      })
      .catch(() => setIsLoading(false));
  }, [setMessages]);

  if (isLoading) {
    return <div className="flex justify-center items-center h-screen">Loading...</div>;
  }

  return (
    <div className="flex flex-col w-full max-w-md py-24 mx-auto stretch">
      {messages.map((message) => (
        <div
          key={message.id}
          className={`flex ${message.role === "user" ? "justify-end" : "justify-start"} mb-4`}
        >
          <div
            className={`max-w-[80%] rounded-lg px-4 py-3 ${
              message.role === "user"
                ? "bg-neutral-600 text-white"
                : "bg-neutral-200 dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100"
            }`}
          >
            <div className="whitespace-pre-wrap">
              <p className="text-xs font-extralight mb-1 opacity-70">
                {message.role === "user" ? "YOU " : "AI "}
              </p>
              {message.parts.map((part, i) => {
                switch (part.type) {
                  case "text":
                    return <div key={`${message.id}-${i}`}>{part.text}</div>;
                }
              })}
            </div>
          </div>
        </div>
      ))}
      <form // [!code ++]
        onSubmit={(e) => { // [!code ++]
          e.preventDefault(); // [!code ++]
          sendMessage({ text: input }); // [!code ++]
          setInput(""); // [!code ++]
        }} // [!code ++]
      > // [!code ++]
        <input // [!code ++]
          className="fixed dark:bg-zinc-900 bottom-0 w-full max-w-md p-2 mb-8 border border-zinc-300 dark:border-zinc-800 rounded shadow-xl" // [!code ++]
          value={input} // [!code ++]
          placeholder="Say something..." // [!code ++]
          onChange={(e) => setInput(e.currentTarget.value)} // [!code ++]
        /> // [!code ++]
      </form> // [!code ++]
    </div>
  );
}
```

## 7. Test your application [#7-test-your-application]

To test your application, run the following command:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

Open your browser and navigate to [`http://localhost:3000`](http://localhost:3000) to see your application in action.

Test it by sending a message to the AI and see if it's saved to the database. Check Prisma Studio to see the messages in the database.

  

#### bun

```bash
bunx prisma studio
```

#### pnpm

```bash
pnpm prisma studio
```

#### yarn

```bash
yarn prisma studio
```

#### npm

```bash
npx prisma studio
```

Your AI SDK chat application now stores every session and message in Prisma Postgres and reloads them when the page opens.

## Next Steps [#next-steps]

Now that you have a working AI SDK chat application connected to a Prisma Postgres database, you can:

* Extend your Prisma schema with more models and relationships
* Add create/update/delete routes and forms
* Explore authentication and validation

### More Info [#more-info]

* [Prisma Documentation](https://www.prisma.io/docs/orm/v7)
* [AI SDK Documentation](https://ai-sdk.dev/)

## Related pages

- [`GitHub Actions`](https://www.prisma.io/docs/guides/v7/integrations/github-actions): Provision and manage Prisma Postgres databases per pull request using GitHub Actions and Prisma REST API
- [`Neon with Accelerate`](https://www.prisma.io/docs/guides/v7/integrations/neon-accelerate): Learn how to set up PostgreSQL on Neon with Prisma Accelerate's Connection Pool
- [`Supabase with Accelerate`](https://www.prisma.io/docs/guides/v7/integrations/supabase-accelerate): Learn how to set up PostgreSQL on Supabase with Prisma Accelerate's Connection Pool

# GitHub Actions (Prisma ORM v7) (/docs/guides/v7/integrations/github-actions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Provision and manage Prisma Postgres databases per pull request using GitHub Actions and Prisma REST API

Location: Guides > v7 > Integrations > GitHub Actions

## Overview [#overview]

This guide shows you how to automatically create and delete [Prisma Postgres](https://www.prisma.io/postgres) databases using GitHub Actions and [the Prisma Postgres REST API](https://api.prisma.io/v1/swagger-editor). The setup provisions a new database for every pull request, seeds it with sample data, and the `github-actions` bot leaves a comment with the database name and the status.

![GitHub Actions comment](https://www.prisma.io/img/guides/github-comment.png)

After the PR is closed, the database is automatically deleted. This allows you to test changes in isolation without affecting the main development database.

## Prerequisites [#prerequisites]

Make sure you have the following:

* Node.js 20 or later
* A [Prisma Data Platform](https://console.prisma.io?utm_source=actions_guide\&utm_medium=docs) account
* GitHub repository

## 1. Set up your project [#1-set-up-your-project]

Initialize your project:

  

#### bun

```bash
mkdir prisma-gha-demo && cd prisma-gha-demo
bun init
```

#### pnpm

```bash
mkdir prisma-gha-demo && cd prisma-gha-demo
pnpm init
```

#### yarn

```bash
mkdir prisma-gha-demo && cd prisma-gha-demo
yarn init
```

#### npm

```bash
mkdir prisma-gha-demo && cd prisma-gha-demo
npm init
```

## 2. Install and configure Prisma [#2-install-and-configure-prisma]

In this section, you'll set up Prisma in your project and verify that it works locally before integrating it into GitHub Actions. This involves installing Prisma's dependencies, connecting to a Prisma Postgres database, defining your data models, applying your schema, and seeding the database with sample data.

By the end of this section, your project will be fully prepared to use Prisma both locally and in a CI workflow.

### 2.1. Install dependencies [#21-install-dependencies]

To get started with Prisma, install the required dependencies:

  

#### bun

```bash
bun add prisma@prev tsx @types/pg dotenv --dev
```

#### pnpm

```bash
pnpm add prisma@prev tsx @types/pg dotenv --save-dev
```

#### yarn

```bash
yarn add prisma@prev tsx @types/pg dotenv --dev
```

#### npm

```bash
npm install prisma@prev tsx @types/pg dotenv --save-dev
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-pg pg
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-pg pg
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-pg pg
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-pg pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Once installed, initialize Prisma:

  

#### bun

```bash
bunx --bun prisma init --output ../src/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../src/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../src/generated/prisma
```

#### npm

```bash
npx prisma init --output ../src/generated/prisma
```

This creates:

* A `prisma/` directory with `schema.prisma`
* A `.env` file with `DATABASE_URL`
* A generated client in `src/generated/prisma`

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

### 2.2. Define your Prisma schema [#22-define-your-prisma-schema]

Edit `prisma/schema.prisma` to:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  authorId  Int
  author    User    @relation(fields: [authorId], references: [id])
}
```

Create a `prisma.config.ts` file to configure Prisma with seeding:

```typescript title="prisma.config.ts"
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config"; // [!code ++]
// [!code ++]
export default defineConfig({
  // [!code ++]
  schema: "prisma/schema.prisma", // [!code ++]
  migrations: {
    // [!code ++]
    path: "prisma/migrations", // [!code ++]
    seed: `tsx src/seed.ts`, // [!code ++]
  }, // [!code ++]
  datasource: {
    // [!code ++]
    url: env("DATABASE_URL"), // [!code ++]
  }, // [!code ++]
}); // [!code ++]
```

> [!NOTE]
> You'll need to install the `dotenv` package:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 

### 2.3. Run initial migration and generate client [#23-run-initial-migration-and-generate-client]

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

Then generate Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This pushes your schema and prepares the client.

### 2.4. Seed the database [#24-seed-the-database]

Create a file at `src/seed.ts`:

```tsx title="src/seed.ts"
import { PrismaClient } from "../src/generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
import "dotenv/config";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

const userData = [
  {
    name: "Alice",
    email: "alice@prisma.io",
    posts: {
      create: [
        {
          title: "Join the Prisma Discord",
          content: "https://pris.ly/discord",
          published: true,
        },
        {
          title: "Prisma on YouTube",
          content: "https://pris.ly/youtube",
        },
      ],
    },
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
    posts: {
      create: [
        {
          title: "Follow Prisma on Twitter",
          content: "https://twitter.com/prisma",
          published: true,
        },
      ],
    },
  },
];

export async function main() {
  for (const u of userData) {
    await prisma.user.create({ data: u });
  }
}

main()
  .catch(console.error)
  .finally(() => prisma.$disconnect());
```

Update your `package.json`:

```json title="package.json"
{
  "name": "prisma-gha-demo",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "seed": "tsx src/seed.ts" // [!code ++]
  },
  // other configurations...
}
```

Then run:

  

#### bun

```bash
bun run seed
bunx prisma studio
```

#### pnpm

```bash
pnpm run seed
pnpm prisma studio
```

#### yarn

```bash
yarn seed
yarn prisma studio
```

#### npm

```bash
npm run seed
npx prisma studio
```

Navigate to `http://localhost:5555` and verify that the database has been seeded with sample data. Now you're ready to automate this process with GitHub Actions.

## 3. Add the GitHub Actions workflow [#3-add-the-github-actions-workflow]

In this step, you will set up a GitHub Actions workflow that automatically provisions a Prisma Postgres database when a new pull request (PR) is opened. Once the PR is closed, the workflow will clean up the database.

### 3.1 Create the workflow file [#31-create-the-workflow-file]

Start by creating the required directory and file:

```bash
mkdir -p .github/workflows
touch .github/workflows/prisma-postgres-rest-api.yml
```

This file will contain the logic to manage databases on a per-PR basis. This GitHub Actions workflow:

* Provisions a temporary Prisma Postgres database when a PR is opened
* Seeds the database with test data
* Cleans up the database when the PR is closed
* Supports manual execution for both provisioning and cleanup

> [!NOTE]
> This workflow uses `us-east-1` as the default region for Prisma Postgres. You can change this to your preferred region by modifying the `region` parameter in the API calls, or even by adding a `region` input to the workflow.

### 3.2. Add the base configuration [#32-add-the-base-configuration]

Paste the following into `.github/workflows/prisma-postgres-rest-api.yml`. This sets up when the workflow runs and provides required environment variables.

```yaml title=".github/workflows/prisma-postgres-rest-api.yml"
name: Prisma Postgres REST API Workflow

on:
  pull_request:
    types: [opened, reopened, closed]
  workflow_dispatch:
    inputs:
      action:
        description: "Action to perform"
        required: true
        default: "provision"
        type: choice
        options:
          - provision
          - cleanup
      database_name:
        description: "Database name (for testing, will be sanitized)"
        required: false
        type: string

env:
  PRISMA_POSTGRES_SERVICE_TOKEN: ${{ secrets.PRISMA_POSTGRES_SERVICE_TOKEN }}
  PRISMA_PROJECT_ID: ${{ secrets.PRISMA_PROJECT_ID }}
  # Sanitize database name once at workflow level
  DB_NAME: ${{ github.event.pull_request.number != null && format('pr-{0}-{1}', github.event.pull_request.number, github.event.pull_request.head.ref) || (inputs.database_name != '' && inputs.database_name || format('test-{0}', github.run_number)) }}

# Prevent concurrent runs of the same PR
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
```

Now you will be adding the provision and cleanup jobs to this workflow. These jobs will handle the creation and deletion of Prisma Postgres databases based on the pull request events.

### 3.3. Add a provision job to the workflow [#33-add-a-provision-job-to-the-workflow]

Now add a job to provision the database when the PR is opened or when triggered manually. The provision job:

* Installs dependencies
* Checks for existing databases
* Creates a new one if needed
* Seeds the database
* Comments on the PR with status

Append the following under the `jobs:` key in your workflow file:

```yaml title=".github/workflows/prisma-postgres-rest-api.yml"
jobs:
  provision-database:
    if: (github.event_name == 'pull_request' && github.event.action != 'closed') || (github.event_name == 'workflow_dispatch' && inputs.action == 'provision')
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    timeout-minutes: 15
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "22"
          cache: "npm"

      - name: Install Dependencies
        run: npm install

      - name: Validate Environment Variables
        run: |
          if [ -z "${{ env.PRISMA_POSTGRES_SERVICE_TOKEN }}" ]; then
            echo "Error: PRISMA_POSTGRES_SERVICE_TOKEN secret is not set"
            exit 1
          fi
          if [ -z "${{ env.PRISMA_PROJECT_ID }}" ]; then
            echo "Error: PRISMA_PROJECT_ID secret is not set"
            exit 1
          fi

      - name: Sanitize Database Name
        run: |
          # Sanitize the database name to match Prisma's requirements
          DB_NAME="$(echo "${{ env.DB_NAME }}" | tr '/' '_' | tr '-' '_' | tr '[:upper:]' '[:lower:]')"
          echo "DB_NAME=$DB_NAME" >> $GITHUB_ENV

      - name: Check If Database Exists
        id: check-db
        run: |
          echo "Fetching all databases..."
          RESPONSE=$(curl -s -X GET \
            -H "Authorization: Bearer ${{ env.PRISMA_POSTGRES_SERVICE_TOKEN }}" \
            -H "Content-Type: application/json" \
            "https://api.prisma.io/v1/projects/${{ env.PRISMA_PROJECT_ID }}/databases")

          echo "Looking for database with name: ${{ env.DB_NAME }}"

          # Extract database ID using jq to properly parse JSON
          DB_EXISTS=$(echo "$RESPONSE" | jq -r ".data[]? | select(.name == \"${{ env.DB_NAME }}\") | .id")

          if [ ! -z "$DB_EXISTS" ] && [ "$DB_EXISTS" != "null" ]; then
            echo "Database ${{ env.DB_NAME }} exists with ID: $DB_EXISTS."
            echo "exists=true" >> $GITHUB_OUTPUT
            echo "db-id=$DB_EXISTS" >> $GITHUB_OUTPUT
          else
            echo "No existing database found with name ${{ env.DB_NAME }}"
            echo "exists=false" >> $GITHUB_OUTPUT
          fi

      - name: Create Database
        id: create-db
        if: steps.check-db.outputs.exists != 'true'
        run: |
          echo "Creating database ${{ env.DB_NAME }}..."
          RESPONSE=$(curl -s -X POST \
            -H "Authorization: Bearer ${{ env.PRISMA_POSTGRES_SERVICE_TOKEN }}" \
            -H "Content-Type: application/json" \
            -d "{\"name\": \"${{ env.DB_NAME }}\", \"region\": \"us-east-1\"}" \
            "https://api.prisma.io/v1/projects/${{ env.PRISMA_PROJECT_ID }}/databases")

          # Check if response contains an id (success case)
          if echo "$RESPONSE" | grep -q '"id":'; then
            echo "Database created successfully"
            CONNECTION_STRING=$(echo "$RESPONSE" | jq -r '.data.connectionString')
            echo "connection-string=$CONNECTION_STRING" >> $GITHUB_OUTPUT
          else
            echo "Failed to create database"
            echo "$RESPONSE"
            exit 1
          fi

      - name: Get Connection String for Existing Database
        id: get-connection
        if: steps.check-db.outputs.exists == 'true'
        run: |
          echo "Creating new connection string for existing database..."
          CONNECTION_RESPONSE=$(curl -s -X POST \
            -H "Authorization: Bearer ${{ env.PRISMA_POSTGRES_SERVICE_TOKEN }}" \
            -H "Content-Type: application/json" \
            -d '{"name":"read_write_key"}' \
            "https://api.prisma.io/v1/databases/${{ steps.check-db.outputs.db-id }}/connections")

          CONNECTION_STRING=$(echo "$CONNECTION_RESPONSE" | jq -r '.data.connectionString')
          echo "connection-string=$CONNECTION_STRING" >> $GITHUB_OUTPUT

      - name: Setup Database Schema
        run: |
          # Get connection string from appropriate step
          if [ "${{ steps.check-db.outputs.exists }}" = "true" ]; then
            CONNECTION_STRING="${{ steps.get-connection.outputs.connection-string }}"
          else
            CONNECTION_STRING="${{ steps.create-db.outputs.connection-string }}"
          fi

          # Set the DATABASE_URL
          export DATABASE_URL="$CONNECTION_STRING"

          # Generate Prisma Client
          npx prisma generate

          # Push schema to database
          npx prisma db push

      - name: Seed Database
        run: |
          # Get connection string from appropriate step
          if [ "${{ steps.check-db.outputs.exists }}" = "true" ]; then
            CONNECTION_STRING="${{ steps.get-connection.outputs.connection-string }}"
          else
            CONNECTION_STRING="${{ steps.create-db.outputs.connection-string }}"
          fi

          # Set the DATABASE_URL environment variable for the seed script
          export DATABASE_URL="$CONNECTION_STRING"

          # Generate Prisma Client
          npx prisma generate

          # Run the seed script
          npm run seed

      - name: Comment PR
        if: success() && github.event_name == 'pull_request'
        uses: actions/github-script@v7
        env:
          DB_NAME: ${{ env.DB_NAME }}
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `🗄️ Database provisioned successfully!\n\nDatabase name: ${process.env.DB_NAME}\nStatus: Ready and seeded with sample data`
            })

      - name: Output Database Info
        if: success() && github.event_name == 'workflow_dispatch'
        run: |
          echo "🗄️ Database provisioned successfully!"
          echo "Database name: ${{ env.DB_NAME }}"
          echo "Status: Ready and seeded with sample data"
```

### 3.4. Add a cleanup job to the workflow [#34-add-a-cleanup-job-to-the-workflow]

When a pull request is closed, you can automatically remove the associated database by adding a cleanup job. The cleanup job:

* Finds the database by name
* Deletes it from the Prisma Postgres project
* Can also be triggered manually with `action: cleanup`

Append the following to your `jobs:` section, after the `provision-database` job:

```yaml title=".github/workflows/prisma-postgres-rest-api.yml"
cleanup-database:
  if: (github.event_name == 'pull_request' && github.event.action == 'closed') || (github.event_name == 'workflow_dispatch' && inputs.action == 'cleanup')
  runs-on: ubuntu-latest
  timeout-minutes: 5
  steps:
    - name: Checkout
      uses: actions/checkout@v4

    - name: Validate Environment Variables
      run: |
        if [ -z "${{ env.PRISMA_POSTGRES_SERVICE_TOKEN }}" ]; then
          echo "Error: PRISMA_POSTGRES_SERVICE_TOKEN secret is not set"
          exit 1
        fi
        if [ -z "${{ env.PRISMA_PROJECT_ID }}" ]; then
          echo "Error: PRISMA_PROJECT_ID secret is not set"
          exit 1
        fi

    - name: Sanitize Database Name
      run: |
        # Sanitize the database name
        DB_NAME="$(echo "${{ env.DB_NAME }}" | tr '/' '_' | tr '-' '_' | tr '[:upper:]' '[:lower:]')"
        echo "DB_NAME=$DB_NAME" >> $GITHUB_ENV

    - name: Delete Database
      run: |
        echo "Fetching all databases..."
        RESPONSE=$(curl -s -X GET \
          -H "Authorization: Bearer ${{ env.PRISMA_POSTGRES_SERVICE_TOKEN }}" \
          -H "Content-Type: application/json" \
          "https://api.prisma.io/v1/projects/${{ env.PRISMA_PROJECT_ID }}/databases")

        echo "Looking for database with name: ${{ env.DB_NAME }}"

        # Extract database ID using jq to properly parse JSON
        DB_EXISTS=$(echo "$RESPONSE" | jq -r ".data[]? | select(.name == \"${{ env.DB_NAME }}\") | .id")

        if [ ! -z "$DB_EXISTS" ] && [ "$DB_EXISTS" != "null" ]; then
          echo "Database ${{ env.DB_NAME }} exists with ID: $DB_EXISTS. Deleting..."
          DELETE_RESPONSE=$(curl -s -X DELETE \
            -H "Authorization: Bearer ${{ env.PRISMA_POSTGRES_SERVICE_TOKEN }}" \
            -H "Content-Type: application/json" \
            "https://api.prisma.io/v1/databases/$DB_EXISTS")

          echo "Delete API Response: $DELETE_RESPONSE"

          if echo "$DELETE_RESPONSE" | grep -q '"error":'; then
            ERROR_MSG=$(echo "$DELETE_RESPONSE" | jq -r '.message // "Unknown error"')
            echo "Failed to delete database: $ERROR_MSG"
            exit 1
          else
            echo "Database deletion initiated successfully"
          fi
        else
          echo "No existing database found with name ${{ env.DB_NAME }}"
        fi
```

This completes your Prisma Postgres management workflow setup. In the next step, you'll configure the required GitHub secrets to authenticate with the Prisma API.

## 4. Store the code in GitHub [#4-store-the-code-in-github]

Initialize a git repository and push to [GitHub](https://github.com/):

If you don't have a repository in GitHub yet, [create one on GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository). Once the repository is ready, run the following commands:

```bash
git add .
git commit -m "Initial commit with Prisma Postgres integration"
git branch -M main
git remote add origin https://github.com/<your-username>/<repository-name>.git
git push -u origin main
```

> [!NOTE]
> Replace `<your-username>` and `<repository-name>` with your GitHub username and the name of your repository.

## 5. Retrieve the secrets for the workflow [#5-retrieve-the-secrets-for-the-workflow]

### 5.1. Retrieve your Prisma Postgres service token [#51-retrieve-your-prisma-postgres-service-token]

To manage Prisma Postgres databases, you also need a service token. Follow these steps to retrieve it:

1. Make sure you are in the same workspace where you created your project in the last step.
2. Navigate to the **Settings** page of your workspace and select **Service Tokens**.
3. Click **New Service Token**.
4. Copy the generated token and save it in your `.env` file as `PRISMA_POSTGRES_SERVICE_TOKEN`. This token is required for the next step's script and must also be added to your GitHub Actions secrets.

### 5.2 Retrieve the project ID where you want to provision Prisma Postgres databases [#52-retrieve-the-project-id-where-you-want-to-provision-prisma-postgres-databases]

To avoid conflicts with your development databases, you'll now create a dedicated project specifically for CI workflows. Use the following curl command to create a new Prisma Postgres project using the Prisma Postgres REST API:

```bash
curl -X POST https://api.prisma.io/v1/projects \
  -H "Authorization: Bearer $PRISMA_POSTGRES_SERVICE_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"region\": \"us-east-1\", \"name\": \"$PROJECT_NAME\"}"
```

> [!NOTE]
> Make sure to replace the `$PRISMA_POSTGRES_SERVICE_TOKEN` variable with the service token you stored earlier.

Replace the $PRISMA_POSTGRES_SERVICE_TOKEN with the service token and the `$PROJECT_NAME`with a name for your project (e.g.,`my-gha-preview`). The script will create a new Prisma Postgres project in the `us-east-1` region.

The CLI output will then look like this:

```json
{
  "data": {
    "id": "$PRISMA_PROJECT_ID",
    "type": "project",
    "name": "$PROJECT_NAME",
    "createdAt": "2025-07-15T08:35:10.546Z",
    "workspace": {
      "id": "$PRISMA_WORKSPACE_ID",
      "name": "$PRISMA_WORKSPACE_NAME"
    }
  }
}
```

Copy and store the `$PRISMA_PROJECT_ID` from the output. This is your Prisma project ID, which you will use in the next step.

## 6. Add secrets in GitHub [#6-add-secrets-in-github]

To add secrets:

1. Go to your GitHub repository.
2. Navigate to **Settings**.
3. Click and expand the **Secrets and variables** section.
4. Click **Actions**.
5. Click **New repository secret**.
6. Add the following:
   * `PRISMA_PROJECT_ID` - Your Prisma project ID from the Prisma Console.
   * `PRISMA_POSTGRES_SERVICE_TOKEN` - Your service token.

These secrets will be accessed in the workflow file via `env`.

## 7. Try the workflow [#7-try-the-workflow]

You can test the setup in two ways:

**Option 1: Automatic trigger via PR**

1. Open a pull request on the repository.
2. GitHub Actions will provision a new Prisma Postgres database.
3. It will push your schema and seed the database.
4. A comment will be added to the PR confirming database creation.
5. When the PR is closed, the database will be deleted automatically.

**Option 2: Manual trigger**

1. Go to the **Actions** tab in your repository.
2. Select the **Prisma Postgres REST API Workflow** on the left sidebar.
3. Click the **Run workflow** dropdown
4. Choose `provision` as the action and optionally provide a custom database name. You can also choose `cleanup` to delete an *existing* database.
5. Click **Run workflow**.

## Next steps [#next-steps]

You now have a fully automated GitHub Actions setup for managing ephemeral Prisma Postgres databases.

This gives you:

* Isolated databases for every pull request.
* Automatic schema sync and seed.
* Cleanup of unused databases after merges.

Because each pull request gets its own database, changes can be tested without touching a shared development database. You can extend this by running your test suite against the provisioned database.

## Related pages

- [`AI SDK (with Next.js)`](https://www.prisma.io/docs/guides/v7/integrations/ai-sdk): Build a chat application with AI SDK, Prisma, and Next.js to store chat sessions and messages
- [`Neon with Accelerate`](https://www.prisma.io/docs/guides/v7/integrations/neon-accelerate): Learn how to set up PostgreSQL on Neon with Prisma Accelerate's Connection Pool
- [`Supabase with Accelerate`](https://www.prisma.io/docs/guides/v7/integrations/supabase-accelerate): Learn how to set up PostgreSQL on Supabase with Prisma Accelerate's Connection Pool

# Bun (Prisma ORM v7) (/docs/guides/v7/runtimes/bun)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a Bun application with Prisma Postgres

Location: Guides > v7 > Runtimes > Bun

## Introduction [#introduction]

[Bun](https://bun.sh) is a fast JavaScript runtime that includes a bundler, test runner, and package manager. In this guide, you will set up a Bun project with Prisma ORM and a Prisma Postgres database. You will create a small HTTP server and build a Bun executable for deployment.

[How to use Prisma ORM with Bun and Prisma Postgres](https://www.youtube.com/watch?v=gE6l4eX0v_I)

## Prerequisites [#prerequisites]

* [Bun](https://bun.sh/docs/installation) installed in your system
* A [Prisma Postgres database](https://www.prisma.io/docs/postgres) (created during setup)
* Basic knowledge of JavaScript/TypeScript

## 1. Setting up your Bun project [#1-setting-up-your-bun-project]

First, create a directory for your project and navigate to it:

```bash
mkdir bun-prisma
cd bun-prisma
```

Then, initialise a new Bun project:

  

#### bun

```bash
bun init
```

#### pnpm

```bash
pnpm init
```

#### yarn

```bash
yarn init
```

#### npm

```bash
npm init
```

This creates a basic Bun project that includes a `package.json` file and an `index.ts` file.

## 2. Installing and configuring Prisma [#2-installing-and-configuring-prisma]

### 2.1. Install dependencies [#21-install-dependencies]

Install the required Prisma packages and other dependencies:

  

#### bun

```bash
bun add prisma@prev @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg
```

#### pnpm

```bash
pnpm add prisma@prev @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg
```

#### yarn

```bash
yarn add prisma@prev @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg
```

#### npm

```bash
npm install prisma@prev @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

### 2.2. Initialize Prisma ORM with Prisma Postgres [#22-initialize-prisma-orm-with-prisma-postgres]

Initialize Prisma ORM with Prisma Postgres in your project:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

> [!NOTE]
> When using the Bun tab for `prisma init`, the `--bun` flag ensures Prisma runs with the Bun runtime instead of falling back to Node.js due to the `#!/usr/bin/env node` shebang in the CLI.

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This command creates:

* A `prisma/` directory with your `schema.prisma` file
* A `prisma.config.ts` file
* A `.env` file with your `DATABASE_URL`

### 2.3. Create a Prisma Postgres database [#23-create-a-prisma-postgres-database]

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

Update your `.env` file:

```bash title=".env"
DATABASE_URL="postgres://..."
```

### 2.4. Update your Prisma schema [#24-update-your-prisma-schema]

Open `prisma/schema.prisma` and update it to include your data model:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
} // [!code ++]
```

## 3. Generate Prisma Client and run migrations [#3-generate-prisma-client-and-run-migrations]

Generate the Prisma client and apply your schema to the database:

  

#### bun

```bash
bunx prisma migrate dev --name init
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
pnpm prisma generate
```

#### yarn

```bash
yarn prisma migrate dev --name init
yarn prisma generate
```

#### npm

```bash
npx prisma migrate dev --name init
npx prisma generate
```

This command:

* Creates the database tables based on your schema
* Generates the Prisma client in the `generated/prisma` directory

## 4. Setting up database configuration and creating a seed script [#4-setting-up-database-configuration-and-creating-a-seed-script]

### 4.1. Create a database utility file [#41-create-a-database-utility-file]

Create a `db.ts` file in your project root to configure `PrismaClient`:

```typescript title="db.ts"
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

export const prisma = new PrismaClient({
  adapter,
});
```

### 4.2. Create a seed script [#42-create-a-seed-script]

Create a seed script in the `prisma` folder to populate your database with sample data:

```typescript title="prisma/seed.ts"
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const prisma = new PrismaClient({
  adapter,
});

async function main() {
  // Create multiple users
  await prisma.user.createMany({
    data: [
      { email: "alice@example.com", name: "Alice" },
      { email: "bob@example.com", name: "Bob" },
      { email: "charlie@example.com", name: "Charlie" },
      { email: "diana@example.com", name: "Diana" },
      { email: "eve@example.com", name: "Eve" },
      { email: "frank@example.com", name: "Frank" },
      { email: "grace@example.com", name: "Grace" },
      { email: "henry@example.com", name: "Henry" },
      { email: "isabella@example.com", name: "Isabella" },
      { email: "jack@example.com", name: "Jack" },
    ],
    skipDuplicates: true, // prevents errors if you run the seed multiple times
  });

  console.log("Seed data inserted!");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

### 3.3. Add the seed script to Prisma Config [#33-add-the-seed-script-to-prisma-config]

Add the following content to the file:

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: `bun run prisma/seed.ts`, // [!code ++]
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

> [!NOTE]
> Unlike Node.js, Bun automatically loads `.env` files, so the `import 'dotenv/config'` line is not needed. If you see this import in your generated `prisma.config.ts`, you can safely remove it.

Run the seed script to populate your database:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

## 5. Creating your Bun server [#5-creating-your-bun-server]

Replace the `index.ts` file contents with the following code to build a small HTTP server that uses Prisma ORM to fetch and display users:

```typescript title="index.ts"
import { prisma } from "./db";

const server = Bun.serve({
  port: 3000,
  async fetch(req) {
    const { pathname } = new URL(req.url);

    // Skip favicon route
    if (pathname === "/favicon.ico") {
      return new Response(null, { status: 204 }); // or serve an icon if you have one
    }

    // Return all users
    const users = await prisma.user.findMany();

    // Count all users
    const count = await prisma.user.count();

    // Format the response with JSON
    return new Response(
      JSON.stringify({
        users: users,
        totalUsers: count,
      }),
      { headers: { "Content-Type": "application/json" } },
    );
  },
});

console.log(`Listening on http://localhost:${server.port}`);
```

## 6. Running your application [#6-running-your-application]

Start your Bun server:

```bash
bun run index.ts
```

You should see `Listening on http://localhost:3000` in the console. When you visit `http://localhost:3000` in your browser, you'll see a JSON response with all the users in your database and the total count.

## 7. Building and running a Bun executable [#7-building-and-running-a-bun-executable]

Bun can compile your [TypeScript application into a single executable file](https://bun.com/docs/bundler/executables), which is useful for deployment and distribution.

### 7.1. Build the executable [#71-build-the-executable]

Build your application into an executable:

```bash
bun build --compile index.ts
```

This creates an executable file named `index` (or `index.exe` on Windows) in your project directory.

### 7.2. Run the executable [#72-run-the-executable]

Run the compiled executable:

```bash
./index
```

You should see the same `Listening on http://localhost:3000` message, and your application will work exactly the same as before. The executable includes all dependencies and can be deployed to any compatible system without requiring Bun or Node.js to be installed.

> [!NOTE]
> Bun executables are useful for:
> 
> * **Deployment**: Ship a single file instead of managing dependencies
> * **Distribution**: Share your application without requiring users to install Bun
> * **Performance**: Faster startup times compared to running TypeScript files
> * **Security**: Your source code is compiled and not easily readable

## Next steps [#next-steps]

You can explore [this example](https://pris.ly/bun_ppg_example) to see a sample application built with Bun and Prisma.

Now that you have a Bun application connected to a Prisma Postgres database, you can continue by:

* Extending your Prisma schema with additional models and relationships
* Implementing authentication and authorization
* Adding input validation and error handling
* Exploring Bun's built-in testing tools
* Deploying your executable to production servers

### More info [#more-info]

* [Bun Documentation](https://bun.sh/docs)
* [Prisma Config File](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Prisma Postgres](https://www.prisma.io/docs/postgres)

## Related pages

- [`Deno`](https://www.prisma.io/docs/guides/v7/runtimes/deno): Learn how to use Prisma ORM in a Deno application with Prisma Postgres

# Deno (Prisma ORM v7) (/docs/guides/v7/runtimes/deno)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use Prisma ORM in a Deno application with Prisma Postgres

Location: Guides > v7 > Runtimes > Deno

## Introduction [#introduction]

[Deno](https://deno.com) is a secure JavaScript and TypeScript runtime built on V8 with built-in TypeScript support, a permissions system, and web-standard APIs. In this guide, you will set up a Deno project with Prisma ORM and a Prisma Postgres database. You will create a small HTTP server that reads from the database and returns the results.

[How to use Prisma ORM with Deno and Prisma Postgres](https://www.youtube.com/watch?v=hAL2J3yQf7I)

## Prerequisites [#prerequisites]

* [Deno](https://docs.deno.com/runtime/#install-deno) v2.0 or later installed on your system
* A [Prisma Postgres database](https://www.prisma.io/docs/postgres) (created during setup)
* Basic knowledge of JavaScript/TypeScript
* [Deno extension for VS Code](https://docs.deno.com/runtime/reference/vscode/) (recommended)

## 1. Setting up your Deno project [#1-setting-up-your-deno-project]

First, create a directory for your project and navigate to it:

```bash
mkdir deno-prisma
cd deno-prisma
```

Then, initialize a new Deno project:

```bash
deno init
```

This creates a basic Deno project with a `deno.json` configuration file and a `main.ts` file.

### 1.1. Configure Deno for Prisma [#11-configure-deno-for-prisma]

Update the `deno.json` file with the following configuration to set up Node.js compatibility, import maps, and Prisma-related task scripts:

```json title="deno.json"
{
  "nodeModulesDir": "auto",
  "compilerOptions": {
    "lib": ["deno.window"],
    "types": ["node"]
  },
  "imports": {
    "@prisma/adapter-pg": "npm:@prisma/adapter-pg@^7.0.0",
    "@prisma/client": "npm:@prisma/client@7",
    "prisma": "npm:prisma@prev"
  },
  "tasks": {
    "dev": "deno run -A --env=.env --watch main.ts",
    "db:generate": "deno run -A --env=.env npm:prisma@prev generate",
    "db:push": "deno run -A --env=.env npm:prisma@prev db push",
    "db:migrate": "deno run -A --env=.env npm:prisma@prev migrate dev",
    "db:seed": "deno run -A --env=.env npm:prisma@prev db seed"
  }
}
```

> [!NOTE]
> The `nodeModulesDir: "auto"` setting allows Deno to automatically manage a `node_modules` directory, which is needed for Prisma's generated client. The import map entries let you use bare specifiers like `@prisma/client` in your code.

## 2. Installing and configuring Prisma [#2-installing-and-configuring-prisma]

### 2.1. Initialize Prisma ORM with Prisma Postgres [#21-initialize-prisma-orm-with-prisma-postgres]

Initialize Prisma ORM with Prisma Postgres in your project:

```bash
deno run -A npm:prisma@prev init
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, you will create a Prisma Postgres database and replace that value with a direct `postgres://...` connection string.

This command creates:

* A `prisma/` directory with your `schema.prisma` file
* A `prisma.config.ts` file
* A `.env` file with your `DATABASE_URL`

### 2.2. Update the Prisma config file [#22-update-the-prisma-config-file]

Open the generated `prisma.config.ts` file. Since Deno loads environment variables using the `--env=.env` flag (configured in `deno.json` tasks), you can remove the `dotenv/config` import if it was generated:

```typescript title="prisma.config.ts"
import "dotenv/config"; // [!code --]
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### 2.3. Create a Prisma Postgres database [#23-create-a-prisma-postgres-database]

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

```bash
npx create-db
```

Update your `.env` file:

```bash title=".env"
DATABASE_URL="postgres://..."
```

### 2.4. Update your Prisma schema [#24-update-your-prisma-schema]

Open `prisma/schema.prisma` and update it to include the Deno runtime and your data model:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
  runtime  = "deno" // [!code ++]
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
} // [!code ++]
```

> [!NOTE]
> The `runtime = "deno"` setting in the generator block is required for Prisma Client to work correctly with the Deno runtime.

## 3. Generate Prisma Client and run migrations [#3-generate-prisma-client-and-run-migrations]

Generate the Prisma Client and apply your schema to the database:

```bash
deno task db:migrate --name init
deno task db:generate
```

This command:

* Creates the database tables based on your schema
* Generates the Prisma Client in the `generated/prisma` directory

## 4. Setting up database configuration and creating a seed script [#4-setting-up-database-configuration-and-creating-a-seed-script]

### 4.1. Create a database utility file [#41-create-a-database-utility-file]

Create a `db.ts` file in your project root to configure `PrismaClient`:

```typescript title="db.ts"
import { PrismaClient } from "./generated/prisma/client.ts";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: Deno.env.get("DATABASE_URL")!,
});

export const prisma = new PrismaClient({
  adapter,
});
```

### 4.2. Create a seed script [#42-create-a-seed-script]

Create a seed script in the `prisma` folder to populate your database with sample data:

```typescript title="prisma/seed.ts"
import { PrismaClient } from "../generated/prisma/client.ts";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: Deno.env.get("DATABASE_URL")!,
});

const prisma = new PrismaClient({
  adapter,
});

async function main() {
  // Create multiple users
  await prisma.user.createMany({
    data: [
      { email: "alice@example.com", name: "Alice" },
      { email: "bob@example.com", name: "Bob" },
      { email: "charlie@example.com", name: "Charlie" },
      { email: "diana@example.com", name: "Diana" },
      { email: "eve@example.com", name: "Eve" },
      { email: "frank@example.com", name: "Frank" },
      { email: "grace@example.com", name: "Grace" },
      { email: "henry@example.com", name: "Henry" },
      { email: "isabella@example.com", name: "Isabella" },
      { email: "jack@example.com", name: "Jack" },
    ],
    skipDuplicates: true, // prevents errors if you run the seed multiple times
  });

  console.log("Seed data inserted!");
}

main()
  .catch((e) => {
    console.error(e);
    Deno.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

### 4.3. Add the seed script to Prisma Config [#43-add-the-seed-script-to-prisma-config]

Update the `prisma.config.ts` file to include the seed command:

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "deno run -A --env=.env ./prisma/seed.ts", // [!code ++]
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Run the seed script to populate your database:

```bash
deno task db:seed
```

## 5. Creating your Deno server [#5-creating-your-deno-server]

Replace the `main.ts` file contents with the following code to build a small HTTP server that uses Prisma ORM to fetch and display users:

```typescript title="main.ts"
import { prisma } from "./db.ts";

async function handler(req: Request): Promise<Response> {
  const { pathname } = new URL(req.url);

  // Skip favicon route
  if (pathname === "/favicon.ico") {
    return new Response(null, { status: 204 });
  }

  // Return all users
  const users = await prisma.user.findMany();

  // Count all users
  const count = await prisma.user.count();

  // Format the response with JSON
  return new Response(
    JSON.stringify({
      users: users,
      totalUsers: count,
    }),
    { headers: { "Content-Type": "application/json" } },
  );
}

Deno.serve({ port: 8000 }, handler);
```

## 6. Running your application [#6-running-your-application]

Start your Deno server:

```bash
deno task dev
```

You should see the server running on `http://localhost:8000` in the console. When you visit `http://localhost:8000` in your browser, you'll see a JSON response with all the users in your database and the total count.

## Next steps [#next-steps]

Now that you have a Deno application connected to a Prisma Postgres database, you can continue by:

* Extending your Prisma schema with additional models and relationships
* Implementing authentication and authorization
* Adding input validation with Zod
* Exploring Deno's built-in testing tools
* Deploying your application to [Deno Deploy](https://www.prisma.io/docs/guides/integrations/deno)

### More info [#more-info]

* [Deno Documentation](https://docs.deno.com)
* [Prisma Config File](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Prisma Postgres](https://www.prisma.io/docs/postgres)

## Related pages

- [`Bun`](https://www.prisma.io/docs/guides/v7/runtimes/bun): Learn how to use Prisma ORM in a Bun application with Prisma Postgres

# Drizzle (Prisma ORM v7) (/docs/guides/v7/switch-to-prisma-orm/from-drizzle)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to migrate from Drizzle to Prisma ORM

Location: Guides > v7 > Switch to Prisma ORM > Drizzle

## Introduction [#introduction]

This guide shows you how to migrate your application from Drizzle to Prisma ORM. The examples use a sample project based off of the [Drizzle Next.js example](https://orm.drizzle.team/docs/tutorials/drizzle-nextjs-neon). You can find the example used for this guide on [GitHub](https://github.com/prisma/migrate-from-drizzle-to-prisma).

You can learn how Prisma ORM compares to Drizzle on the [Prisma ORM vs Drizzle](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-drizzle) page.

## Prerequisites [#prerequisites]

Before starting this guide, make sure you have:

* A Drizzle project you want to migrate
* Node.js installed ([a supported version](https://www.prisma.io/docs/orm/v7/reference/system-requirements))
* PostgreSQL or another supported database
* Basic familiarity with Drizzle and Next.js

> [!NOTE]
> this migration guide uses Neon PostgreSQL as the example database, but it equally applies to any other relational database that are [supported by Prisma ORM](https://www.prisma.io/docs/orm/v7/reference/supported-databases).

## Overview of the migration process [#overview-of-the-migration-process]

Note that the steps for migrating from Drizzle to Prisma ORM are always the same, no matter what kind of application or API layer you're building:

1. Install the Prisma CLI
2. Introspect your database
3. Create a baseline migration
4. Install Prisma Client
5. Gradually replace your Drizzle queries with Prisma Client

These steps apply, no matter if you're building a REST API (e.g. with Express, koa or NestJS), a GraphQL API (e.g. with Apollo Server, TypeGraphQL or Nexus) or any other kind of application that uses Drizzle for database access.

Prisma ORM supports **incremental adoption**, so you don't have to migrate your entire project from Drizzle at once. You can move your database queries to Prisma ORM one at a time.

## Step 1. Install the Prisma CLI [#step-1-install-the-prisma-cli]

The first step to adopt Prisma ORM is to [install the Prisma CLI](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference) in your project:

  

#### bun

```bash
bun add prisma@prev @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg
```

#### pnpm

```bash
pnpm add prisma@prev @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg
```

#### yarn

```bash
yarn add prisma@prev @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg
```

#### npm

```bash
npm install prisma@prev @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg
```

> [!NOTE]
> If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of `@prisma/adapter-pg`. For more information, see [Database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

## Step 2. Introspect your database [#step-2-introspect-your-database]

### 2.1. Set up Prisma ORM [#21-set-up-prisma-orm]

Before you can introspect your database, you need to set up your [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) and connect Prisma to your database. Run the following command in the root of your project to create a basic Prisma schema file:

  

#### bun

```bash
bunx --bun prisma init --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../generated/prisma
```

#### npm

```bash
npx prisma init --output ../generated/prisma
```

This command created a new directory called `prisma` with the following files for you:

* `schema.prisma`: Your Prisma schema that specifies your database connection and models
* `.env`: A [`dotenv`](https://github.com/motdotla/dotenv) to configure your database connection URL as an environment variable

> [!NOTE]
> You may already have a `.env` file. If so, the `prisma init` command will append lines to it rather than creating a new file.

The Prisma schema currently looks as follows:

```prisma title="prisma/schema.prisma" showLineNumbers
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

datasource db {
  provider = "postgresql"
}

generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}
```

> [!NOTE]
> If you're using VS Code, be sure to install the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) for syntax highlighting, formatting, and auto-completion.

### 2.2. Connect your database [#22-connect-your-database]

If you're not using PostgreSQL, you need to adjust the `provider` field on the `datasource` block to the database you currently use:

  

#### PostgreSQL

```prisma title="schema.prisma" showLineNumbers 
datasource db {
  provider = "postgresql"
}
```

#### MySQL

```prisma title="schema.prisma" showLineNumbers 
datasource db {
  provider = "mysql"
}
```

#### Microsoft SQL Server

```prisma title="schema.prisma" showLineNumbers 
datasource db {
  provider = "sqlserver"
}
```

#### SQLite

```prisma title="schema.prisma" showLineNumbers 
datasource db {
  provider = "sqlite"
}
```

Once that's done, you can configure your [database connection URL](https://www.prisma.io/docs/orm/v7/reference/connection-urls) in the `.env` file. Drizzle and Prisma ORM use the same format for connection URLs, so your existing connection URL should work fine.

### 2.3. Configure Prisma [#23-configure-prisma]

Create a `prisma.config.ts` file in the root of your project with the following content:

```typescript title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

> [!NOTE]
> You'll need to install the `dotenv` package to load environment variables. If you haven't already, install it using your package manager:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bun add dotenv
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm add dotenv
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn add dotenv
>     ```
>
> 
>   #### npm

>     ```bash
>     npm install dotenv
>     ```
>
> 

### 2.4. Introspect your database using Prisma ORM [#24-introspect-your-database-using-prisma-orm]

With your connection URL in place, you can [introspect](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) your database to generate your Prisma models:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

If you're using the [sample project](https://github.com/prisma/migrate-from-drizzle-to-prisma) the following model would be created:

```prisma title="prisma/schema.prisma" showLineNumbers
model todo {
  id   Int     @id
  text String
  done Boolean @default(false)
}
```

The generated Prisma model represents a database table. Prisma models are the foundation for your programmatic Prisma Client API which allows you to send queries to your database.

### 2.5. Create a baseline migration [#25-create-a-baseline-migration]

To continue using Prisma Migrate to evolve your database schema, you will need to [baseline your database](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started).

First, create a `migrations` directory and add a directory inside with your preferred name for the migration. In this example, we will use `0_init` as the migration name:

```bash
mkdir -p prisma/migrations/0_init
```

Next, generate the migration file with `prisma migrate diff`. Use the following arguments:

* `--from-empty`: assumes the data model you're migrating from is empty
* `--to-schema`: the current database state using the URL in the `datasource` block
* `--script`: output a SQL script

  

#### bun

```bash
bunx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### pnpm

```bash
pnpm prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### yarn

```bash
yarn prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### npm

```bash
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

Review the generated migration to ensure everything is correct.

Next, mark the migration as applied using `prisma migrate resolve` with the `--applied` argument.

  

#### bun

```bash
bunx prisma migrate resolve --applied 0_init
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied 0_init
```

#### yarn

```bash
yarn prisma migrate resolve --applied 0_init
```

#### npm

```bash
npx prisma migrate resolve --applied 0_init
```

The command will mark `0_init` as applied by adding it to the `_prisma_migrations` table.

You now have a baseline for your current database schema. To make further changes to your database schema, you can update your Prisma schema and use `prisma migrate dev` to apply the changes to your database.

### 2.6. Adjust the Prisma schema (optional) [#26-adjust-the-prisma-schema-optional]

Models that are generated via introspection currently *exactly* map to your database tables. In this section, you'll learn how you can adjust the naming of the Prisma models to adhere to [Prisma ORM's naming conventions](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#naming-conventions).

All of these adjustment are entirely optional and you are free to skip to the next step already if you don't want to adjust anything for now. You can go back and make the adjustments at any later point.

As opposed to the current camelCase notation of Drizzle models, Prisma ORM's naming conventions are:

* PascalCase for model names
* camelCase for field names

You can adjust the naming by *mapping* the Prisma model and field names to the existing table and column names in the underlying database using `@@map` and `@map`.

Here's an example on how you could modify the model above:

```prisma title="prisma/schema.prisma" showLineNumbers
model Todo {
  id   Int     @id
  text String
  done Boolean @default(false)

  @@map("todo")
}
```

## Step 3. Generate Prisma Client [#step-3-generate-prisma-client]

Now that you have installed Prisma Client in Step 1, you need to run `generate` in order to have your schema reflected in TypeScript types and autocomplete.

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## Step 4. Replace your Drizzle queries with Prisma Client [#step-4-replace-your-drizzle-queries-with-prisma-client]

This section shows a few sample queries migrated from Drizzle to Prisma Client based on the example routes from the sample REST API project. For a comprehensive overview of how the Prisma Client API differs from Drizzle, check out the [comparison page](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-drizzle#).

First, to set up the `PrismaClient` instance that you'll use to send database queries from the various route handlers. Create a new file named `prisma.ts` in the `db` directory:

```bash copy
touch db/prisma.ts
```

Now, instantiate `PrismaClient` and export it from the file so you can use it in your route handlers later:

```ts copy title="db/prisma.ts" showLineNumbers
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
import "dotenv/config";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
});

export const prisma = new PrismaClient({
  adapter,
});
```

### 4.1. Replacing `getData` queries [#41-replacing-getdata-queries]

The fullstack Next.js app has several `actions` including `getData`.

The `getData` action is currently implemented as follows:

```ts title="actions/todoActions.ts" showLineNumbers
import db from "@/db/drizzle";
import { todo } from "@/db/schema";

export const getData = async () => {
  const data = await db.select().from(todo);
  return data;
};
```

Here is the same action implemented using Prisma Client:

```ts title="src/controllers/FeedAction.ts" showLineNumbers
import { prisma } from "@/db/prisma";

export const getData = async () => {
  const data = await prisma.todo.findMany();
  return data;
};
```

### 4.2. Replacing queries in `POST` requests [#42-replacing-queries-in-post-requests]

The [sample project](https://github.com/prisma/migrate-from-drizzle-to-prisma) has four actions that are used during `POST` requests:

* `addTodo`: Creates a new `Todo` record
* `deleteTodo`: Deletes an existing `Todo` record
* `toggleTodo`: Toggles the boolean `done` field on an existing `Todo` record
* `editTodo`: Edits the `text` field on an existing `Todo` record

#### `addTodo` [#addtodo]

The `addTodo` action is currently implemented as follows:

```ts title="actions/todoActions.ts" showLineNumbers
import { revalidatePath } from "next/cache";

import db from "@/db/drizzle";
import { todo } from "@/db/schema";

export const addTodo = async (id: number, text: string) => {
  await db.insert(todo).values({
    id: id,
    text: text,
  });
  revalidatePath("/");
};
```

Here is the same action implemented using Prisma Client:

```ts title="actions/todoActions.ts" showLineNumbers
import { revalidatePath } from "next/cache";

import { prisma } from "@/db/prisma";

export const addTodo = async (id: number, text: string) => {
  await prisma.todo.create({
    data: { id, text },
  });
  revalidatePath("/");
};
```

#### `deleteTodo` [#deletetodo]

The `deleteTodo` action is currently implemented as follows:

```ts title="actions/todoActions.ts" showLineNumbers
import { eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";

import db from "@/db/drizzle";
import { todo } from "@/db/schema";

export const deleteTodo = async (id: number) => {
  await db.delete(todo).where(eq(todo.id, id));
  revalidatePath("/");
};
```

Here is the same action implemented using Prisma Client:

```ts title="actions/todoActions.ts" showLineNumbers
import { revalidatePath } from "next/cache";

import { prisma } from "@/db/prisma";

export const deleteTodo = async (id: number) => {
  await prisma.todo.delete({ where: { id } });
  revalidatePath("/");
};
```

#### `toggleTodo` [#toggletodo]

The `ToggleTodo` action is currently implemented as follows:

```ts title="actions/todoActions.ts" showLineNumbers
import { eq, not } from "drizzle-orm";
import { revalidatePath } from "next/cache";

import db from "@/db/drizzle";
import { todo } from "@/db/schema";

export const toggleTodo = async (id: number) => {
  await db
    .update(todo)
    .set({
      done: not(todo.done),
    })
    .where(eq(todo.id, id));
  revalidatePath("/");
};
```

Here is the same action implemented using Prisma Client:

```ts title="actions/todoActions.ts" showLineNumbers
import { revalidatePath } from "next/cache";

import { prisma } from "@/db/prisma";

export const toggleTodo = async (id: number) => {
  const todo = await prisma.todo.findUnique({ where: { id } });
  if (todo) {
    await prisma.todo.update({
      where: { id: todo.id },
      data: { done: !todo.done },
    });
    revalidatePath("/");
  }
};
```

Note that Prisma ORM does not have the ability to edit a boolean field "in place", so the record must be fetched before hand.

#### `editTodo` [#edittodo]

The `editTodo` action is currently implemented as follows:

```ts title="actions/todoActions.ts" showLineNumbers
import { eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";

import db from "@/db/drizzle";
import { todo } from "@/db/schema";

export const editTodo = async (id: number, text: string) => {
  await db
    .update(todo)
    .set({
      text: text,
    })
    .where(eq(todo.id, id));

  revalidatePath("/");
};
```

Here is the same action implemented using Prisma Client:

```ts title="actions/todoActions.ts" showLineNumbers
import { revalidatePath } from "next/cache";

import { prisma } from "@/db/prisma";

export const editTodo = async (id: number, text: string) => {
  await prisma.todo.update({
    where: { id },
    data: { text },
  });
  revalidatePath("/");
};
```

## More [#more]

### Implicit many-to-many relations [#implicit-many-to-many-relations]

Unlike Drizzle, Prisma ORM allows you to [model many-to-many relations *implicitly*](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations). That is, a many-to-many relation where you do not have to manage the [relation table](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#relation-table-conventions) (also sometimes called JOIN table) *explicitly* in your schema. Here is an example comparing Drizzle with Prisma ORM:

```ts title="schema.ts"
import { boolean, integer, pgTable, primaryKey, serial, text } from "drizzle-orm/pg-core";

export const posts = pgTable("post", {
  id: serial("serial").primaryKey(),
  title: text("title").notNull(),
  content: text("content"),
  published: boolean("published").default(false).notNull(),
});

export const categories = pgTable("category", {
  id: serial("serial").primaryKey(),
  name: text("name").notNull(),
});

export const postsToCategories = pgTable(
  "posts_to_categories",
  {
    postId: integer("post_id")
      .notNull()
      .references(() => posts.id),
    categoryId: integer("category_id")
      .notNull()
      .references(() => categories.id),
  },
  (t) => [primaryKey({ columns: [t.postId, t.categoryId] })],
);
```

This schema is equivalent to the following Prisma schema:

```prisma title="schema.prisma"
model Post {
  id                Int                @id @default(autoincrement())
  title             String
  content           String?
  published         Boolean            @default(false)
  postsToCategories PostToCategories[]

  @@map("post")
}

model Category {
  id                Int                @id @default(autoincrement())
  name              String
  postsToCategories PostToCategories[]

  @@map("category")
}

model PostToCategories {
  postId     Int
  categoryId Int
  category   Category @relation(fields: [categoryId], references: [id])
  post       Post     @relation(fields: [postId], references: [id])

  @@id([postId, categoryId])
  @@index([postId])
  @@index([categoryId])
  @@map("posts_to_categories")
}
```

In this Prisma schema, the many-to-many relation is modeled *explicitly* via the relation table `PostToCategories`.

By instead adhering to the conventions for Prisma ORM relation tables, the relation could look as follows:

```prisma title="schema.prisma" showLineNumbers
model Post {
  id         Int        @id @default(autoincrement())
  title      String
  content    String?
  published  Boolean    @default(false)
  categories Category[]
}

model Category {
  id    Int    @id @default(autoincrement())
  name  String
  posts Post[]
}
```

This would also result in a more ergonomic and less verbose Prisma Client API to modify the records in this relation, because you have a direct path from `Post` to `Category` (and the other way around) instead of needing to traverse the `PostToCategories` model first.

> [!WARNING]
> If your database provider requires tables to have primary keys then you have to use explicit syntax, and manually create the join model with a primary key. This is because relation tables (JOIN tables) created by Prisma ORM (expressed via `@relation`) for many-to-many relations using implicit syntax do not have primary keys.

## Related pages

- [`Mongoose`](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-mongoose): Learn how to migrate from Mongoose to Prisma ORM
- [`SQL ORMs`](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-sql-orms): Learn how to migrate from Sequelize or TypeORM to Prisma ORM

# Mongoose (Prisma ORM v7) (/docs/guides/v7/switch-to-prisma-orm/from-mongoose)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to migrate from Mongoose to Prisma ORM

Location: Guides > v7 > Switch to Prisma ORM > Mongoose

## Introduction [#introduction]

This guide shows you how to migrate your application from Mongoose to Prisma ORM. The examples use a [sample project](https://github.com/prisma/migrate-from-mongoose-to-prisma).

> [!WARNING]
> MongoDB support for Prisma ORM v7
> 
> **MongoDB support for Prisma ORM v7 is coming in the near future.** In the meantime, please use **Prisma ORM v6.19** (the latest v6 release) when working with MongoDB.
> 
> This guide uses Prisma ORM v6.19 to ensure full compatibility with MongoDB.

You can learn how Prisma ORM compares to Mongoose on the [Prisma ORM vs Mongoose](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-mongoose) page.

> [!WARNING]
> This guide currently assumes you are using **Prisma ORM v6**. Support for Prisma ORM v7 with MongoDB is in progress.

## Prerequisites [#prerequisites]

Before starting this guide, make sure you have:

* A Mongoose project you want to migrate
* Node.js installed [with the supported version](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v6#minimum-supported-nodejs-versions)
* MongoDB database (4.2+ with replica set deployment recommended)
* Basic familiarity with Mongoose and Express.js

## 1. Prepare for migration [#1-prepare-for-migration]

### 1.1. Understand the migration process [#11-understand-the-migration-process]

The steps for migrating from Mongoose to Prisma ORM are always the same, no matter what kind of application or API layer you're building:

1. Install the Prisma CLI
2. Introspect your database
3. Install and generate Prisma Client
4. Gradually replace your Mongoose queries with Prisma Client

These steps apply whether you're building a REST API (e.g., with Express, Koa, or NestJS), a GraphQL API (e.g., with Apollo Server, TypeGraphQL, or Nexus), or any other kind of application that uses Mongoose for database access.

### 1.2. Install Prisma dependencies [#12-install-prisma-dependencies]

First, install the required Prisma packages:

  

#### bun

```bash
bun add prisma@6.19.3 @types/node --dev
```

#### pnpm

```bash
pnpm add prisma@6.19.3 @types/node --save-dev
```

#### yarn

```bash
yarn add prisma@6.19.3 @types/node --dev
```

#### npm

```bash
npm install prisma@6.19.3 @types/node --save-dev
```

  

#### bun

```bash
bun add @prisma/client@6.19.3 dotenv
```

#### pnpm

```bash
pnpm add @prisma/client@6.19.3 dotenv
```

#### yarn

```bash
yarn add @prisma/client@6.19.3 dotenv
```

#### npm

```bash
npm install @prisma/client@6.19.3 dotenv
```

> [!NOTE]
> Why Prisma v6.19?
> 
> This is the latest stable version of Prisma ORM v6 that fully supports MongoDB. MongoDB support for Prisma ORM v7 is coming soon.
> 
> You can also install `prisma@6` and `@prisma/client@6` to automatically get the latest v6 release.

### 1.3. Set up Prisma configuration [#13-set-up-prisma-configuration]

Create a new Prisma schema file:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider mongodb --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider mongodb --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider mongodb --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider mongodb --output ../generated/prisma
```

This command creates:

* A new directory called `prisma` that contains a `schema.prisma` file; your Prisma schema specifies your database connection and models
* `.env`: A [`dotenv`](https://github.com/motdotla/dotenv) file at the root of your project (if it doesn't already exist), used to configure your database connection URL as an environment variable
* `prisma.config.ts`: Configuration file for Prisma

The Prisma schema uses the ESM-first `prisma-client` generator:

```prisma title="prisma/schema.prisma" showLineNumbers
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}
```

<br />

> [!NOTE]
> For syntax highlighting, formatting, and auto-completion in your editor, see [editor setup](https://www.prisma.io/docs/orm/v7/more/dev-environment/editor-setup).

Update the `DATABASE_URL` in the `.env` file with your MongoDB connection string:

```text
DATABASE_URL="mongodb+srv://username:password@cluster.mongodb.net/mydb"
```

> [!NOTE]
> Replace `username`, `password`, `cluster`, and `mydb` with your actual MongoDB credentials and database name. You can get your connection string from [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) or your MongoDB deployment.

### 1.4. Configure Prisma [#14-configure-prisma]

The generated `prisma.config.ts` file should look like this:

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  engine: "classic",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Add `dotenv` to load environment variables from your `.env` file:

```typescript title="prisma.config.ts"
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  engine: "classic",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

## 2. Migrate the database schema [#2-migrate-the-database-schema]

### 2.1. Introspect your database [#21-introspect-your-database]

> [!WARNING]
> MongoDB is a *schemaless* database. To incrementally adopt Prisma ORM in your project, ensure your database is populated with sample data. Prisma ORM introspects a MongoDB schema by sampling data stored and inferring the schema from the data in the database.

Run Prisma's introspection to create the Prisma schema from your existing database:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This will create a `schema.prisma` file with your database schema.

```prisma title="prisma/schema.prisma" showLineNumbers
type UsersProfile {
  bio String
}

model categories {
  id   String @id @default(auto()) @map("_id") @db.ObjectId
  v    Int    @map("__v")
  name String
}

model posts {
  id         String   @id @default(auto()) @map("_id") @db.ObjectId
  v          Int      @map("__v")
  author     String   @db.ObjectId
  categories String[] @db.ObjectId
  content    String
  published  Boolean
  title      String
}

model users {
  id      String        @id @default(auto()) @map("_id") @db.ObjectId
  v       Int           @map("__v")
  email   String        @unique(map: "email_1")
  name    String
  profile UsersProfile?
}
```

### 2.2. Update relations [#22-update-relations]

MongoDB doesn't support relations between different collections. However, you can create references between documents using the [`ObjectId`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb#using-objectid) field type or from one document to many using an array of `ObjectIds` in the collection. The reference will store id(s) of the related document(s). You can use the `populate()` method that Mongoose provides to populate the reference with the data of the related document.

Update the 1-n relationship between `posts` \<-> `users` as follows:

* Rename the existing `author` reference in the `posts` model to `authorId` and add the `@map("author")` attribute
* Add the `author` relation field in the `posts` model and it's `@relation` attribute specifying the `fields` and `references`
* Add the `posts` relation in the `users` model

Your schema should now look like this:

```prisma title="schema.prisma"
type UsersProfile {
  bio String
}

model categories {
  id   String @id @default(auto()) @map("_id") @db.ObjectId
  v    Int    @map("__v")
  name String
}

model posts {
  id        String  @id @default(auto()) @map("_id") @db.ObjectId
  title     String
  content   String
  published Boolean
  v         Int     @map("__v")
  author   String   @db.ObjectId // [!code --]
  author   users  @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId String @map("author") @db.ObjectId // [!code ++]

  categories String[] @db.ObjectId
}

model users {
  id      String        @id @default(auto()) @map("_id") @db.ObjectId
  v       Int           @map("__v")
  email   String        @unique(map: "email_1")
  name    String
  profile UsersProfile?
  posts   posts[] // [!code ++]
}
```

Then, update the m-n between `posts` \<-> `categories` references as follows:

* Rename the `categories` field to `categoryIds` and map it using `@map("categories")` in the `posts` model
* Add a new `categories` relation field in the `posts` model
* Add the `postIds` scalar list field in the `categories` model
* Add the `posts` relation in the `categories` model
* Add a [relation scalar](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#annotated-relation-fields) on both models
* Add the `@relation` attribute specifying the `fields` and `references` arguments on both sides

Your schema should now look like this:

```prisma title="schema.prisma"
type UsersProfile {
  bio String
}

model categories {
  id   String @id @default(auto()) @map("_id") @db.ObjectId
  v    Int    @map("__v")
  name String
  posts    posts[]  @relation(fields: [postIds], references: [id]) // [!code ++]
  postIds String[] @db.ObjectId // [!code ++]
}

model posts {
  id        String  @id @default(auto()) @map("_id") @db.ObjectId
  title     String
  content   String
  published Boolean
  v         Int     @map("__v")

  author   users  @relation(fields: [authorId], references: [id])
  authorId String @map("author") @db.ObjectId

  categories  String[] @db.ObjectId // [!code --]
  categories  categories[] @relation(fields: [categoryIds], references: [id]) // [!code ++]
  categoryIds String[] @map("categories") @db.ObjectId // [!code ++]
}

model users {
  id      String        @id @default(auto()) @map("_id") @db.ObjectId
  v       Int           @map("__v")
  email   String        @unique(map: "email_1")
  name    String
  profile UsersProfile?
  posts   posts[]
}
```

## 3. Update your application code [#3-update-your-application-code]

### 3.1. Generate Prisma Client [#31-generate-prisma-client]

Generate Prisma Client based on your schema:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This creates a type-safe Prisma Client in the `generated/prisma` directory.

Create a module that instantiates the client once, so your controllers can import it:

```typescript title="src/client.ts"
import { PrismaClient } from "../generated/prisma/client";

export const prisma = new PrismaClient();
```

### 3.2. Replace Mongoose queries [#32-replace-mongoose-queries]

Start replacing your Mongoose queries with Prisma Client. Here's an example of how to convert some common queries:

  

#### Mongoose

```typescript
// Find one
const user = await User.findById(id);

// Create
const user = await User.create({
  email: "alice@prisma.io",
  name: "Alice",
});

// Update
await User.findByIdAndUpdate(id, {
  name: "New name",
});

// Delete
await User.findByIdAndDelete(id);
```

#### Prisma Client

```typescript
// Find one
const user = await prisma.users.findUnique({
  where: { id },
});

// Create
const user = await prisma.users.create({
  data: {
    email: "alice@prisma.io",
    name: "Alice",
  },
});

// Update
await prisma.users.update({
  where: { id },
  data: { name: "New name" },
});

// Delete
await prisma.users.delete({
  where: { id },
});
```

### 3.3. Update your controllers [#33-update-your-controllers]

Update your Express controllers to use Prisma Client. For example, here's how to update a user controller:

```typescript
import { prisma } from "../client";

export class UserController {
  async create(req: Request, res: Response) {
    const { email, name } = req.body;

    const result = await prisma.users.create({
      data: {
        email,
        name,
      },
    });

    return res.json(result);
  }
}
```

## Next steps [#next-steps]

Now that you've migrated to Prisma ORM, you can:

* Add more complex queries, such as filters, relations, and aggregations
* Set up Prisma Studio for database management
* Implement database monitoring
* Add automated tests using Prisma's testing utilities

For more information:

* [Prisma ORM documentation](https://www.prisma.io/docs/orm/v7)
* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction)

## Related pages

- [`Drizzle`](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-drizzle): Learn how to migrate from Drizzle to Prisma ORM
- [`SQL ORMs`](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-sql-orms): Learn how to migrate from Sequelize or TypeORM to Prisma ORM

# SQL ORMs (Prisma ORM v7) (/docs/guides/v7/switch-to-prisma-orm/from-sql-orms)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to migrate from Sequelize or TypeORM to Prisma ORM

Location: Guides > v7 > Switch to Prisma ORM > SQL ORMs

## Introduction [#introduction]

This guide shows you how to migrate your application from Sequelize or TypeORM to Prisma ORM.

You can learn how Prisma ORM compares to these ORMs on the comparison pages:

* [Prisma ORM vs Sequelize](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-sequelize)
* [Prisma ORM vs TypeORM](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-typeorm)

## Prerequisites [#prerequisites]

Before starting this guide, make sure you have:

* A Sequelize or TypeORM project you want to migrate
* Node.js installed ([a supported version](https://www.prisma.io/docs/orm/v7/reference/system-requirements))
* PostgreSQL, MySQL, or another [supported database](https://www.prisma.io/docs/orm/v7/reference/supported-databases)

## Overview of the migration process [#overview-of-the-migration-process]

The steps for migrating from Sequelize or TypeORM to Prisma ORM are always the same:

1. Install the Prisma CLI
2. Introspect your database
3. Create a baseline migration
4. Install and generate Prisma Client
5. Gradually replace your ORM queries with Prisma Client

Prisma ORM supports **incremental adoption**, so you can migrate your project step-by-step rather than all at once.

## Step 1. Install the Prisma CLI [#step-1-install-the-prisma-cli]

  

#### bun

```bash
bun add prisma@prev --dev
bun add @prisma/client@7
```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
pnpm add @prisma/client@7
```

#### yarn

```bash
yarn add prisma@prev --dev
yarn add @prisma/client@7
```

#### npm

```bash
npm install prisma@prev --save-dev
npm install @prisma/client@7
```

## Step 2. Introspect your database [#step-2-introspect-your-database]

Run the following command to create a basic Prisma setup:

  

#### bun

```bash
bunx --bun prisma init
```

#### pnpm

```bash
pnpm prisma init
```

#### yarn

```bash
yarn prisma init
```

#### npm

```bash
npx prisma init
```

This creates a `prisma` directory with a `schema.prisma` file and a `.env` file. Update the `DATABASE_URL` in `.env` with your connection string:

```bash
DATABASE_URL="postgresql://user:password@localhost:5432/mydb?schema=public"
```

Then introspect your database to generate Prisma models:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

To create a baseline migration, run:

  

#### bun

```bash
mkdir -p prisma/migrations/0_init
bunx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
bunx prisma migrate resolve --applied 0_init
```

#### pnpm

```bash
mkdir -p prisma/migrations/0_init
pnpm prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
pnpm prisma migrate resolve --applied 0_init
```

#### yarn

```bash
mkdir -p prisma/migrations/0_init
yarn prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
yarn prisma migrate resolve --applied 0_init
```

#### npm

```bash
mkdir -p prisma/migrations/0_init
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
npx prisma migrate resolve --applied 0_init
```

## Step 3. Install and generate Prisma Client [#step-3-install-and-generate-prisma-client]

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

Create a file to instantiate Prisma Client (e.g., `db/prisma.ts`):

```typescript
import { PrismaClient } from "@prisma/client";

export const prisma = new PrismaClient();
```

## Step 4. Replace your ORM queries with Prisma Client [#step-4-replace-your-orm-queries-with-prisma-client]

  

#### Sequelize

```typescript
// Find records
const user = await User.findOne({ where: { id: 1 } });
const users = await User.findAll({
  where: { active: true },
  limit: 10,
  order: [['createdAt', 'DESC']]
});

// Create
const user = await User.create({
  name: 'Alice',
  email: 'alice@example.com'
});

// Update
await User.update(
  { name: 'Alicia' },
  { where: { id: 1 } }
);

// Delete
await User.destroy({ where: { id: 1 } });

// With relations
const posts = await Post.findAll({
  include: [{ model: User }],
  limit: 10
});

// Transaction
const result = await sequelize.transaction(async (t) => {
  const user = await User.create({ name: 'Alice' }, { transaction: t });
  const post = await Post.create({ title: 'Hello', userId: user.id }, { transaction: t });
  return { user, post };
});
```

#### TypeORM

```typescript
// Find records
const user = await userRepository.findOne({ where: { id: 1 } });
const users = await userRepository.find({
  where: { active: true },
  take: 10,
  order: { createdAt: 'DESC' }
});

// Create
const user = userRepository.create({
  name: 'Alice',
  email: 'alice@example.com'
});
await userRepository.save(user);

// Update
await userRepository.update(1, { name: 'Alicia' });

// Delete
await userRepository.delete(1);

// With relations
const posts = await postRepository.find({
  relations: ['author'],
  take: 10
});

// Transaction
await connection.transaction(async (manager) => {
  const user = manager.create(User, { name: 'Alice' });
  await manager.save(user);
  const post = manager.create(Post, { title: 'Hello', author: user });
  await manager.save(post);
});
```

#### Prisma

```typescript
// Find records
const user = await prisma.user.findUnique({ where: { id: 1 } });
const users = await prisma.user.findMany({
  where: { active: true },
  take: 10,
  orderBy: { createdAt: 'desc' }
});

// Create
const user = await prisma.user.create({
  data: {
    name: 'Alice',
    email: 'alice@example.com'
  }
});

// Update
await prisma.user.update({
  where: { id: 1 },
  data: { name: 'Alicia' }
});

// Delete
await prisma.user.delete({ where: { id: 1 } });

// With relations
const posts = await prisma.post.findMany({
  include: { author: true },
  take: 10
});

// Transaction
const result = await prisma.$transaction(async (tx) => {
  const user = await tx.user.create({
    data: {
      name: 'Alice',
      posts: { create: { title: 'Hello' } }
    },
    include: { posts: true }
  });
  return user;
});
```

## Migration tips [#migration-tips]

* **Incremental adoption**: Start by replacing read operations, then gradually move to write operations
* **Schema naming**: Use `@map` and `@@map` to map Prisma model names to existing table/column names
* **Type safety**: Run `npx prisma generate` after any schema changes
* **Performance**: Use `select` to fetch only needed fields and avoid N+1 issues with `include`

## Next steps [#next-steps]

* [Prisma Client API Reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference)
* [Schema Reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference)
* [Prisma ORM vs Sequelize](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-sequelize)
* [Prisma ORM vs TypeORM](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-typeorm)

## Related pages

- [`Drizzle`](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-drizzle): Learn how to migrate from Drizzle to Prisma ORM
- [`Mongoose`](https://www.prisma.io/docs/guides/v7/switch-to-prisma-orm/from-mongoose): Learn how to migrate from Mongoose to Prisma ORM

# API patterns (Prisma ORM v7) (/docs/orm/v7/core-concepts/api-patterns)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to use Prisma ORM with REST APIs, GraphQL servers, and fullstack frameworks

Location: ORM > v7 > Core Concepts > API patterns

Prisma Client can be used to query your database from any server-side JavaScript or TypeScript application. This page covers common patterns for REST APIs, GraphQL servers, and fullstack frameworks.

## REST APIs [#rest-apis]

When building REST APIs, use Prisma Client inside your route controllers to execute database queries.

### Supported frameworks [#supported-frameworks]

* [Express](https://expressjs.com/)
* [Fastify](https://fastify.dev/)
* [hapi](https://hapi.dev/)
* [koa](https://koajs.com/)
* [NestJS](https://nestjs.com/)
* [Next.js API Routes](https://nextjs.org/)

### Example routes [#example-routes]

```ts
// GET /feed - fetch published posts
app.get("/feed", async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true },
  });
  res.json(posts);
});

// POST /post - create a post
app.post("/post", async (req, res) => {
  const { title, content, authorEmail } = req.body;
  const result = await prisma.post.create({
    data: {
      title,
      content,
      author: { connect: { email: authorEmail } },
    },
  });
  res.json(result);
});

// PUT /publish/:id - publish a post
app.put("/publish/:id", async (req, res) => {
  const post = await prisma.post.update({
    where: { id: Number(req.params.id) },
    data: { published: true },
  });
  res.json(post);
});

// DELETE /post/:id - delete a post
app.delete("/post/:id", async (req, res) => {
  const post = await prisma.post.delete({
    where: { id: Number(req.params.id) },
  });
  res.json(post);
});
```

## GraphQL [#graphql]

Prisma ORM works with any GraphQL library. Use Prisma Client inside your resolvers to read and write data.

### Supported tools [#supported-tools]

| Library         | Purpose        |
| :-------------- | :------------- |
| `graphql-yoga`  | HTTP server    |
| `apollo-server` | HTTP server    |
| `pothos`        | Schema builder |
| `nexus`         | Schema builder |
| `type-graphql`  | Schema builder |

### Framework integrations [#framework-integrations]

* [Redwood.js](https://rwsdk.com/) - Built on Prisma ORM

### Prisma's role [#prismas-role]

Prisma ORM is used inside GraphQL resolvers the same way you'd use any other ORM:

* **Queries**: Read data from the database to return in the response
* **Mutations**: Write data to the database (create, update, delete)

## Fullstack frameworks [#fullstack-frameworks]

Fullstack frameworks blur server/client boundaries. Use Prisma Client in the server-side portion of your application.

### Supported frameworks [#supported-frameworks-1]

* [Next.js](https://nextjs.org/)
* [Remix](https://remix.run)
* [SvelteKit](https://svelte.dev/)
* [Nuxt](https://nuxt.com/)
* [Redwood](https://rwsdk.com/)
* [Wasp](https://wasp-lang.dev/)

### Supported runtimes [#supported-runtimes]

* [Node.js](https://nodejs.org/)
* [Bun](https://bun.sh/)
* [Deno](https://deno.com/)

### Next.js example [#nextjs-example]

```ts
// In getServerSideProps or API routes
export const getServerSideProps = async () => {
  const feed = await prisma.post.findMany({
    where: { published: true },
  });
  return { props: { feed } };
};
```

## Example projects [#example-projects]

Find ready-to-run examples in the [`prisma-examples`](https://github.com/prisma/prisma-examples/) repository:

| Example                                      | Type      | Description                    |
| :------------------------------------------- | :-------- | :----------------------------- |
| [Next.js](https://pris.ly/e/orm/nextjs)      | Fullstack | Next.js 15 app                 |
| [Express](https://pris.ly/e/ts/rest-express) | REST      | Express REST API               |
| [Fastify](https://pris.ly/e/ts/rest-fastify) | REST      | Fastify REST API               |
| [GraphQL Yoga](https://pris.ly/e/ts/graphql) | GraphQL   | GraphQL server with Pothos     |
| [NestJS](https://pris.ly/e/ts/rest-nestjs)   | REST      | NestJS REST API                |
| [Remix](https://pris.ly/e/ts/remix)          | Fullstack | Remix with actions and loaders |
| [SvelteKit](https://pris.ly/e/ts/sveltekit)  | Fullstack | SvelteKit app                  |

## Related pages

- [`Data modeling`](https://www.prisma.io/docs/orm/v7/core-concepts/data-modeling): Learn how data modeling with Prisma differs from data modeling with SQL or ORMs. Prisma uses a declarative data modeling language to describe a database schema
- [`Overview`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases): Prisma ORM supports PostgreSQL, MySQL, SQLite, MongoDB, SQL Server, CockroachDB, and serverless databases

# Data modeling (Prisma ORM v7) (/docs/orm/v7/core-concepts/data-modeling)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how data modeling with Prisma differs from data modeling with SQL or ORMs. Prisma uses a declarative data modeling language to describe a database schema

Location: ORM > v7 > Core Concepts > Data modeling

## What is data modeling? [#what-is-data-modeling]

The term *data modeling* refers to the **process of defining the shape and structure of the objects in an application**. These objects are often called "application models". In relational databases (like PostgreSQL), they are stored in *tables* . When using document databases (like MongoDB), they are stored in *collections*.

Depending on the domain of your application, the models will be different. For example, if you're writing a blogging application, you might have models such as *blog*, *author*, *article*. When writing a car-sharing app, you probably have models like *driver*, *car*, *route*. Application models enable you to represent these different entities in your code by creating respective *data structures*.

When modeling data, you typically ask questions like:

* What are the main entities/concepts in my application?
* How do they relate to each other?
* What are their main characteristics/properties?
* How can they be represented with my technology stack?

## Data modeling without Prisma ORM [#data-modeling-without-prisma-orm]

Data modeling typically needs to happen on (at least) two levels:

* On the **database** level
* On the **application** level (i.e., in your programming language)

The way that the application models are represented on both levels might differ due to a few reasons:

* Databases and programming languages use different data types
* Relations are represented differently in a database than in a programming language
* Databases typically have more data modeling capabilities, like indexes, cascading deletes, or a variety of additional constraints (e.g. unique, not null, ...)
* Databases and programming languages have different technical constraints

### Data modeling on the database level [#data-modeling-on-the-database-level]

#### Relational databases [#relational-databases]

In relational databases, models are represented by *tables*. For example, you might define a `users` table to store information about the users of your application. Using PostgreSQL, you'd define it as follows:

```sql
CREATE TABLE users (
  user_id SERIAL PRIMARY KEY NOT NULL,
  name VARCHAR(255),
  email VARCHAR(255) UNIQUE NOT NULL,
  isAdmin BOOLEAN NOT NULL DEFAULT false
);
```

A visual representation of the `users` table with some random data might look as follows:

| `user_id` | `name`  | `email`           | `isAdmin` |
| :-------- | :------ | :---------------- | :-------- |
| `1`       | `Alice` | `alice@prisma.io` | `false`   |
| `2`       | `Bob`   | `bob@prisma.io`   | `false`   |
| `3`       | `Sarah` | `sarah@prisma.io` | `true`    |

It has the following columns:

* `user_id`: An integer that increments with every new record in the `users` table. It also represents the [primary key](https://en.wikipedia.org/wiki/Primary_key) for each record.
* `name`: A string with at most 255 characters.
* `email`: A string with at most 255 characters. Additionally, the added constraints express that no two records can have duplicate values for the `email` column, and that *every* record needs to have a value for it.
* `isAdmin`: A boolean that indicates whether the user has admin rights (default value: `false`)

#### MongoDB [#mongodb]

In MongoDB databases, models are represented by *collections* and contain *documents* that can have any structure:

```js
{
  _id: '607ee94800bbe41f001fd568',
  slug: 'prisma-loves-mongodb',
  title: 'Prisma <3 MongoDB',
  body: "This is my first post. Isn't MongoDB + Prisma awesome?!"
}
```

Prisma Client currently expects a consistent model and [normalized model design](https://www.mongodb.com/docs/manual/data-modeling/best-practices/#std-label-data-modeling-best-practices). This means that:

* If a model or field is not present in the Prisma schema, it is ignored
* If a field is mandatory but not present in the MongoDB dataset, you will get an error

### Data modeling on the application level [#data-modeling-on-the-application-level]

In addition to creating the tables that represent the entities from your application domain, you also need to create application models in your programming language. In object-oriented languages, this is often done by creating *classes* to represent your models. Depending on the programming language, this might also be done with *interfaces* or *structs*.

There often is a strong correlation between the tables in your database and the models you define in your code. For example, to represent records from the aforementioned `users` table in your application, you might define a JavaScript (ES6) class looking similar to this:

```js
class User {
  constructor(user_id, name, email, isAdmin) {
    this.user_id = user_id;
    this.name = name;
    this.email = email;
    this.isAdmin = isAdmin;
  }
}
```

When using TypeScript, you might define an interface instead:

```js
interface User {
  user_id: number
  name: string
  email: string
  isAdmin: boolean
}
```

Notice how the `User` model in both cases has the same properties as the `users` table in the previous example. While it's often the case that there's a 1:1 mapping between database tables and application models, it can also happen that models are represented completely differently in the database and your application.

With this setup, you can retrieve records from the `users` table and store them as instances of your `User` type. The following example code snippet uses [`pg`](https://node-postgres.com/) as the driver for PostgreSQL and creates a `User` instance based on the above defined JavaScript class:

```js
const resultRows = await client.query("SELECT * FROM users WHERE user_id = 1");
const userData = resultRows[0];
const user = new User(userData.user_id, userData.name, userData.email, userData.isAdmin);
// user = {
//   user_id: 1,
//   name: "Alice",
//   email: "alice@prisma.io",
//   isAdmin: false
// }
```

Notice that in these examples, the application models are "dumb", meaning they don't implement any logic but their sole purpose is to carry data as *plain old JavaScript objects*.

### Data modeling with ORMs [#data-modeling-with-orms]

ORMs are commonly used in object-oriented languages to make it easier for developers to work with a database. The key characteristic of an ORM is that it lets you model your application data in terms of *classes* which are mapped to *tables* in the underlying database.

The main difference compared to the approaches explained above is these classes not only carry data but also implement a substantial amount of logic. Mostly for storage, retrieval, serialization, and deserialization, but sometimes they also implement business logic that's specific to your application.

This means, you don't write SQL statements to read and write data in the database, but instead the instances of your model classes provide an API to store and retrieve data.

[Sequelize](https://sequelize.org/) is a popular ORM in the Node.js ecosystem, this is how you'd define the same `User` model from the sections before using Sequelize's modeling approach:

```js
class User extends Model {}
User.init(
  {
    user_id: {
      type: Sequelize.INTEGER,
      primaryKey: true,
      autoIncrement: true,
    },
    name: Sequelize.STRING(255),
    email: {
      type: Sequelize.STRING(255),
      unique: true,
    },
    isAdmin: Sequelize.BOOLEAN,
  },
  { sequelize, modelName: "user" },
);
```

To get an example with this `User` class to work, you still need to create the corresponding table in the database. With Sequelize, you have two ways of doing this:

* Run `User.sync()` (typically not recommended for production)
* Use [Sequelize migrations](https://sequelize.org/v5/manual/migrations.html) to change your database schema

Note that you'll never instantiate the `User` class manually (using `new User(...)`) as was shown in the previous section, but rather call *static* methods on the `User` class which then return the `User` model instances:

```js
const user = await User.findByPk(42);
```

The call to `findByPk` creates a SQL statement to retrieve the `User` record that's identified by the ID value `42`.

The resulting `user` object is an instance of Sequelize's `Model` class (because `User` inherits from `Model`). It's not a POJO (Plain Old JavaScript Object), but an object that implements additional behavior from Sequelize.

## Data modeling with Prisma ORM [#data-modeling-with-prisma-orm]

Depending on which parts of Prisma ORM you want to use in your application, the data modeling flow looks slightly different. The following two sections explain the workflows for using [**only Prisma Client**](#using-only-prisma-client) and using [**Prisma Client and Prisma Migrate**](#using-prisma-client-and-prisma-migrate).

No matter which approach though, with Prisma ORM you never create application models in your programming language by manually defining classes, interfaces, or structs. Instead, the application models are defined in your [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview):

* **Only Prisma Client**: Application models in the Prisma schema are *generated based on the introspection of your database schema*. Data modeling happens primarily on the database-level.
* **Prisma Client and Prisma Migrate**: Data modeling happens in the Prisma schema by *manually adding application models* to it. Prisma Migrate maps these application models to tables in the underlying database (currently only supported for relational databases).

As an example, the `User` model from the previous example would be represented as follows in the Prisma schema:

```prisma
model User {
  user_id Int     @id @default(autoincrement())
  name    String?
  email   String  @unique
  isAdmin Boolean @default(false)
}
```

Once the application models are in your Prisma schema (whether they were added through introspection or manually by you), the next step typically is to generate Prisma Client which provides a programmatic and type-safe API to read and write data in the shape of your application models.

Prisma Client uses TypeScript [type aliases](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-aliases) to represent your application models in your code. For example, the `User` model would be represented as follows in the generated Prisma Client library:

```ts
export type User = {
  id: number;
  name: string | null;
  email: string;
  isAdmin: boolean;
};
```

In addition to the generated types, Prisma Client also provides a data access API that you can use once you've installed the `@prisma/client` package:

```js
import { PrismaClient } from '../prisma/generated/client'
// or
// const { PrismaClient } = require('../prisma/generated/client')

const prisma = new PrismaClient()

// use inside an `async` function to `await` the result
await prisma.user.findUnique(...)
await prisma.user.findMany(...)
await prisma.user.create(...)
await prisma.user.update(...)
await prisma.user.delete(...)
await prisma.user.upsert(...)
```

### Using only Prisma Client [#using-only-prisma-client]

When using only Prisma Client and *not* using Prisma Migrate in your application, data modeling needs to happen on the database level via SQL. Once your SQL schema is ready, you use Prisma's introspection feature to add the application models to your Prisma schema. Finally, you generate Prisma Client which creates the types as well as the programmatic API for you to read and write data in your database.

Here is an overview of the main workflow:

1. Change your database schema using SQL (e.g. `CREATE TABLE`, `ALTER TABLE`, ...)
2. Run `prisma db pull` to introspect the database and add application models to the Prisma schema
3. Run `prisma generate` to update your Prisma Client API

### Using Prisma Client and Prisma Migrate [#using-prisma-client-and-prisma-migrate]

When using [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate), you define your application model in the Prisma schema and with relational databases use the `prisma migrate` subcommand to generate plain SQL migration files, which you can edit before applying. With MongoDB, you use `prisma db push` instead which applies the changes to your database directly.

Here is an overview of the main workflow:

1. Manually change your application models in the Prisma schema (e.g. add a new model, remove an existing one, ...)
2. Run `prisma migrate dev` to create and apply a migration or run `prisma db push` to apply the changes directly (in both cases Prisma Client is automatically generated)

## Related pages

- [`API patterns`](https://www.prisma.io/docs/orm/v7/core-concepts/api-patterns): How to use Prisma ORM with REST APIs, GraphQL servers, and fullstack frameworks
- [`Overview`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases): Prisma ORM supports PostgreSQL, MySQL, SQLite, MongoDB, SQL Server, CockroachDB, and serverless databases

# Best practices (Prisma ORM v7) (/docs/orm/v7/more/best-practices)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn production-ready patterns for schema design, query optimization, type safety, security, and deployment with Prisma ORM.

Location: ORM > v7 > More > Best practices

## Schema design and modeling [#schema-design-and-modeling]

### Naming conventions [#naming-conventions]

Use **PascalCase** for model names (singular) and **camelCase** for field names. Map to legacy database naming with `@map` and `@@map`:

```prisma title="prisma/schema.prisma"
model Comment {
  id      Int    @id @default(autoincrement())
  content String @map("comment_text")
  email   String @map("commenter_email")

  @@map("comments")
}
```

This keeps your Prisma schema readable while supporting any database naming convention.

### Model relations explicitly [#model-relations-explicitly]

Always define both sides of a relation to keep your schema clear and maintainable:

```prisma title="prisma/schema.prisma"
model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int
}
```

> [!WARNING]
> For databases that don't enforce foreign keys (like PlanetScale), Prisma ORM emulates relations and you should manually add indexes on relation scalar fields to avoid full table scans:
> 
> ```prisma title="prisma/schema.prisma"
> model Comment {
>   postId Int
>   post   Post @relation(fields: [postId], references: [id])
>
>   @@index([postId])
> }
> ```

### Index strategy [#index-strategy]

Index fields used in `where`, `orderBy`, and relations. Without indexes, the database can be forced to scan entire tables to find matching rows, which becomes slower as tables grow.

```prisma title="prisma/schema.prisma"
model Comment {
  id      Int    @id @default(autoincrement())
  postId  Int
  status  String
  post    Post   @relation(fields: [postId], references: [id])

  @@index([postId])
  @@index([status])
}
```

### Enum vs string fields [#enum-vs-string-fields]

Enums provide type-safe, finite sets of values. You can map enum values to match your database naming:

```prisma title="prisma/schema.prisma"
enum Role {
  USER  @map("user")
  ADMIN @map("admin")

  @@map("user_role")
}

model User {
  id   Int  @id @default(autoincrement())
  role Role @default(USER)
}
```

For values that change frequently or are user-generated, `String` avoids schema changes.

### Multi-file schema organization [#multi-file-schema-organization]

For large projects, use multi-file Prisma schemas (available since v6.7.0):

```
prisma/
├── schema.prisma        # Main schema with generator and datasource
├── migrations/          # Migration files
├── user.prisma         # User-related models
├── product.prisma      # Product-related models
└── order.prisma        # Order-related models
```

The `schema.prisma` file (containing the `generator` block) and `migrations/` directory must be at the same level. You can also group additional schema files under a subdirectory such as `prisma/models/`.

## Query optimization [#query-optimization]

### Connection pooling [#connection-pooling]

Create one global `PrismaClient` instance and reuse it throughout your application. Creating multiple instances creates multiple connection pools, which can exhaust your database's connection limit and slow down queries.

```ts title="lib/prisma.ts"
import { PrismaClient } from '../generated/prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL
})

export const prisma = new PrismaClient({ adapter })
```

**Serverless environments:**

* Instantiate `PrismaClient` **outside** the handler function to reuse connections across warm invocations
* Consider [Prisma Postgres](https://www.prisma.io/docs/postgres) for built-in connection pooling or external poolers like PgBouncer

### Preventing N+1 queries [#preventing-n1-queries]

The N+1 problem occurs when you run 1 query to fetch a list, then 1 additional query per item in that list. This creates many unnecessary round-trips to the database instead of a few efficient queries.

```ts title="n-plus-one.ts"
// ❌ Bad: N+1 queries (1 + N queries)
const users = await prisma.user.findMany()
for (const user of users) {
  const posts = await prisma.post.findMany({
    where: { authorId: user.id }
  })
}

// ✅ Good: Single query with include
const users = await prisma.user.findMany({
  include: { posts: true }
})

// ✅ Good: Batch with IN filter
const users = await prisma.user.findMany()
const posts = await prisma.post.findMany({
  where: { authorId: { in: users.map(u => u.id) } }
})
```

### Select only needed fields [#select-only-needed-fields]

By default, Prisma ORM returns all scalar fields. Use `select` to whitelist specific fields you want returned:

```ts title="select.ts"
const user = await prisma.user.findFirst({
  select: {
    id: true,
    email: true,
    role: true
  }
})
```

Use `omit` to blacklist fields you want excluded (useful for sensitive data):

```ts title="omit.ts"
import { PrismaClient } from '../generated/prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL
})

const prisma = new PrismaClient({
  adapter,
  omit: {
    user: { secretValue: true }
  }
})
```

You cannot combine `select` and `omit` in the same query.

### Pagination [#pagination]

Use **offset pagination** for small datasets where jumping to arbitrary pages is needed:

```ts title="offset-pagination.ts"
const posts = await prisma.post.findMany({
  skip: 40,
  take: 10,
  where: { email: { contains: 'prisma.io' } },
})
```

Use **cursor-based pagination** for large datasets or infinite scroll. Cursor-based pagination scales better because it uses indexed columns to find the starting position instead of traversing skipped rows:

```ts title="cursor-pagination.ts"
const posts = await prisma.post.findMany({
  take: 10,
  skip: 1,
  cursor: {
    id: lastPost.id,
  },
  orderBy: {
    id: 'asc',
  },
})
```

### Batch operations [#batch-operations]

Use bulk methods when operating on multiple records:

```ts title="batch-operations.ts"
await prisma.user.createMany({
  data: [
    { email: 'alice@prisma.io' },
    { email: 'bob@prisma.io' }
  ]
})

await prisma.post.updateMany({
  where: { published: false },
  data: { published: true }
})
```

Bulk operations (`createMany`, `createManyAndReturn`, `updateMany`, `updateManyAndReturn`, and `deleteMany`) [automatically run as transactions](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#batch-operations), so all writes either succeed together or are rolled back if something fails.

### Raw queries [#raw-queries]

Prefer Prisma ORM's query API. Use raw SQL only when you need features not supported by Prisma ORM or heavily optimized queries:

```ts title="raw-query.ts"
const email = 'user@example.com'
const users = await prisma.$queryRaw`
  SELECT * FROM "User" WHERE email = ${email}
`
```

> [!WARNING]
> Never concatenate user input into SQL strings. Always use parameterized queries or tagged templates to prevent SQL injection.

## Type safety and validation [#type-safety-and-validation]

### Use generated types [#use-generated-types]

Use Prisma ORM's generated types instead of duplicating interfaces:

```ts title="generated-types.ts"
import type { User } from '../generated/prisma/client'

async function getAdminEmails(): Promise<string[]> {
  const admins: User[] = await prisma.user.findMany({
    where: { role: 'ADMIN' }
  })

  return admins.map(a => a.email)
}
```

### Input validation [#input-validation]

Always validate and sanitize user input before database operations:

```ts title="input-validation.ts"
import { z } from 'zod'

const createUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1).max(100)
})

async function createUser(input: unknown) {
  const data = createUserSchema.parse(input)
  return prisma.user.create({ data })
}
```

## Security [#security]

### SQL injection prevention [#sql-injection-prevention]

Prisma ORM's API is safe by default. For raw queries, always use parameterized queries. String concatenation with untrusted input allows attackers to inject arbitrary SQL into your queries.

```ts title="sql-injection-prevention.ts"
// ✅ Safe: tagged template
const result = await prisma.$queryRaw`
  SELECT * FROM "User" WHERE email = ${email}
`

// ✅ Safe: parameterized
const result = await prisma.$queryRawUnsafe(
  'SELECT * FROM "User" WHERE email = $1',
  email
)

// ❌ Unsafe: string concatenation
const query = `SELECT * FROM "User" WHERE email = '${email}'`
const result = await prisma.$queryRawUnsafe(query)
```

### Sensitive data handling [#sensitive-data-handling]

Exclude sensitive fields from query results:

```ts title="sensitive-data.ts"
import { PrismaClient } from '../generated/prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL
})

// Global exclusion
const prisma = new PrismaClient({
  adapter,
  omit: {
    user: { secretValue: true }
  }
})

// Per-query exclusion
const user = await prisma.user.findUnique({
  where: { id: 1 },
  omit: { secretValue: true }
})
```

## Testing [#testing]

### Database setup [#database-setup]

Use a dedicated test database that can be reset freely:

1. Start test database (often in Docker)
2. Apply schema via migrations
3. Seed test data
4. Run tests
5. Clean up or reset database

### Unit tests with mocking [#unit-tests-with-mocking]

Mock Prisma ORM using `jest-mock-extended`:

```ts title="unit-test.ts"
import { PrismaClient } from '../generated/prisma/client'
import { mockDeep } from 'jest-mock-extended'

const prismaMock = mockDeep<PrismaClient>()

test('finds user by email', async () => {
  prismaMock.user.findUnique.mockResolvedValue({
    id: 1,
    email: 'test@example.com',
    name: 'Test User'
  })

  const user = await prismaMock.user.findUnique({
    where: { email: 'test@example.com' }
  })

  expect(user).toBeDefined()
})
```

### Integration tests with real database [#integration-tests-with-real-database]

Use a real database with Prisma Migrate:

```ts title="integration-test.ts"
import { PrismaClient } from '../generated/prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL
})

const prisma = new PrismaClient({ adapter })

beforeEach(async () => {
  await prisma.user.create({
    data: { email: 'test@example.com', name: 'Test' }
  })
})

afterEach(async () => {
  await prisma.user.deleteMany()
})

test('creates user', async () => {
  const user = await prisma.user.create({
    data: { email: 'new@example.com', name: 'New User' }
  })

  expect(user.email).toBe('new@example.com')
})
```

## Production deployment [#production-deployment]

### Migration strategies [#migration-strategies]

**Development:**

* Use `prisma migrate dev` to create and apply migrations
* Use `prisma db push` only for quick prototyping (may reset data)

**Production:**

* Use **only** `prisma migrate deploy` with committed migrations
* Never use `migrate dev` (can prompt to reset DB) or `db push` (can be destructive and locks you into a migrationless workflow)

`prisma migrate deploy` applies existing migrations in a non-interactive way, uses advisory locking to prevent concurrent runs, and is safe for production data.

Example CI/CD workflow:

```yaml title=".github/workflows/deploy.yml"
- name: Apply migrations
  run: npx prisma migrate deploy
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
```

### Serverless considerations [#serverless-considerations]

For AWS Lambda, Vercel, Cloudflare Workers, or similar platforms:

1. Instantiate `PrismaClient` **outside** the handler function to reuse connections across warm invocations
2. Do **not** call `$disconnect()` at the end of each invocation (the container may be reused)
3. Consider external connection poolers (like PgBouncer) for high-concurrency workloads

```ts title="serverless-handler.ts"
import { PrismaClient } from '../generated/prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL
})

const prisma = new PrismaClient({ adapter })

export async function handler(event) {
  const users = await prisma.user.findMany()
  return {
    statusCode: 200,
    body: JSON.stringify(users)
  }
}
```

Creating a new client inside the handler on every invocation risks exhausting database connections. Each concurrent function creates its own connection pool, quickly multiplying connection counts.

## Next steps [#next-steps]

* [Query optimization](https://www.prisma.io/docs/query-insights)
* [Raw queries](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries)
* [Prisma Migrate workflows](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production)

## Related pages

- [`Dev environment`](https://www.prisma.io/docs/orm/v7/more/dev-environment): Set up your local Prisma ORM development environment, including editor tooling and environment variables.
- [`ORM releases and maturity levels`](https://www.prisma.io/docs/orm/v7/more/releases): Learn about the release process, versioning, and maturity of Prisma ORM components and how to deal with breaking changes that might happen throughout releases

# ORM releases and maturity levels (Prisma ORM v7) (/docs/orm/v7/more/releases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn about the release process, versioning, and maturity of Prisma ORM components and how to deal with breaking changes that might happen throughout releases

Location: ORM > v7 > More > ORM releases and maturity levels

This page explains the release process of Prisma ORM, how it's versioned and how to deal with breaking changes that might happen throughout releases.

## Releases [#releases]

Prisma ORM releases typically happen every two weeks. Note that this is *not* a hard rule – releases might be postponed for internal reasons.

[Check out all the releases notes in GitHub](https://github.com/prisma/orm/releases).

## Product maturity levels [#product-maturity-levels]

A release can include products or features at different maturity levels. Maturity level describes a product or feature's completeness and what users can expect in terms of breaking changes.

> **Note**: As of version [2.13.0](https://github.com/prisma/orm/releases/2.13.0), 'Experimental' is no longer part of the product maturity scale.

### Early Access [#early-access]

If a feature or product is **Early Access**:

* It is ready to try out and represents the cutting edge of Prisma ORM.
* It can still evolve based on feedback from our users, so we welcome your input on how it works.
* Its API surface won't change drastically, though we may make refinements as it matures.

Early Access features and products are available to try today. Share your feedback to help shape them as they move toward General Availability.

### Preview [#preview]

If a feature or product is a **Preview**:

* We have validated the feature or product in terms of direction and surface.
* Users can count on the feature or product and associated API to be mostly stable unless stated otherwise in the release notes and documentation.
* There are no significant known issues, although minor bugs may exist.
* We welcome feedback on these to make the solution stable as quickly as possible.

Previews are typically available behind a feature flag or require some form of opt-in (for example, by providing a `--preview-feature` flag in the CLI or [adding them to a `previewFeatures` property in the `generator` block](https://www.prisma.io/docs/orm/v7/reference/preview-features/cli-preview-features) for Prisma Client in your Prisma schema).

Preview features and products are close to stable. We recommend validating them in a staging environment before rolling them out to production.

See also: [All currently available Preview features](https://www.prisma.io/docs/orm/v7/reference/preview-features/client-preview-features).

### Generally Available (GA) [#generally-available-ga]

If a feature or product is **Generally Available**:

* The solution has been tested for some time and we received enough feedback to consider it stable and ready for production use.
* There should be no bugs in 99% of cases (completely bug-free software cannot be guaranteed)

## Versioning [#versioning]

Prisma ORM's release scheme adheres to Semantic Versioning ([SemVer](https://semver.org/)) starting with version `3.x.x`.

### Prisma ORM and Semantic Versioning (SemVer) [#prisma-orm-and-semantic-versioning-semver]

#### How does SemVer versioning work? [#how-does-semver-versioning-work]

Semantic Versioning (SemVer) uses the following rules for version upgrade (quoted from the [SemVer](https://semver.org/) spec):

*Given a version number `MAJOR.MINOR.PATCH`, increment the:*

1. *`MAJOR` version when you make incompatible API changes,*
2. *`MINOR` version when you add functionality in a backward compatible manner, and*
3. *`PATCH` version when you make backward compatible bug fixes.*

#### How does Prisma ORM versioning follow SemVer? [#how-does-prisma-orm-versioning-follow-semver]

Beginning with version `3.x.x`, Prisma ORM adheres strictly to the [SemVer](https://semver.org/) versioning scheme.

Here is a brief overview of how Prisma ORM's follows SemVer:

* Breaking changes in stable surface (i.e. [General Availability](#generally-available-ga)) will only be introduced in new `MAJOR` releases.
* Breaking changes can still be rolled out in `MINOR` but only for opt-in Preview and Early Access features that are not active by default (e.g. via a Preview feature flag or a specific opt-in option or new CLI command).
* Opt-in breaking changes, i.e. Preview and Early Access, released in `MINOR`, will only be promoted to General Availability (no requirement for opt-in) in new `MAJOR` releases.

Given a version number `MAJOR.MINOR.PATCH`, Prisma ORM's version number is incremented as follows:

1. `MAJOR` version is incremented when major product updates **with breaking changes** are released to General Availability.
2. `MINOR` version is incremented when product updates adding backward compatible new functionality are released. Features with breaking changes may only be introduced if they are **opt-in**, i.e. Early Access and Preview.
3. `PATCH` version is incremented when functionality bugs are fixed and are always **backward compatible**.

> **Note:** Up until version `2.28.0`, Prisma ORM did not follow SemVer versioning strictly. This means that releases in the `2.MINOR.PATCH` range, `MINOR` versions may have included breaking changes. To learn more about Prisma ORM's adoption of SemVer, check out the [blog post](https://www.prisma.io/blog/prisma-adopts-semver-strictly).

## Related pages

- [`Best practices`](https://www.prisma.io/docs/orm/v7/more/best-practices): Learn production-ready patterns for schema design, query optimization, type safety, security, and deployment with Prisma ORM.
- [`Dev environment`](https://www.prisma.io/docs/orm/v7/more/dev-environment): Set up your local Prisma ORM development environment, including editor tooling and environment variables.

# Prisma Client (Prisma ORM v7) (/docs/orm/v7/prisma-client)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma Client is Prisma ORM's generated, type-safe query builder for Node.js, Bun, and Deno applications.

Location: ORM > v7 > Prisma Client

Prisma Client is Prisma ORM's generated query builder. It is tailored to your schema, fully typed, and designed to make common database work feel like ordinary application code.

## What Prisma Client gives you [#what-prisma-client-gives-you]

* Typed query methods based on your models
* Autocomplete for filters, relations, ordering, and nested writes
* Predictable plain JavaScript objects as query results
* A single client API that works across PostgreSQL, MySQL, SQLite, MongoDB, and more

## Quick start [#quick-start]

### 1. Define a generator in your schema [#1-define-a-generator-in-your-schema]

```prisma title="schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "./generated"
}
```

### 2. Install Prisma Client [#2-install-prisma-client]

  

#### bun

```bash
bun add @prisma/client@7
```

#### pnpm

```bash
pnpm add @prisma/client@7
```

#### yarn

```bash
yarn add @prisma/client@7
```

#### npm

```bash
npm install @prisma/client@7
```

### 3. Generate the client [#3-generate-the-client]

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

If you want more detail on this step, see [Generating Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client).

### 4. Import and use the generated client [#4-import-and-use-the-generated-client]

```ts
import { PrismaClient } from "./generated/client";

const prisma = new PrismaClient();

const users = await prisma.user.findMany();
```

## Common tasks [#common-tasks]

* [Set up and configure Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction)
* [Generate Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client)
* [Run CRUD queries](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud)
* [Work with relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries)
* [Use transactions](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions)
* [Use raw SQL when you need it](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql)

## Related reference docs [#related-reference-docs]

* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference)
* [Prisma schema generators](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators)
* [Prisma CLI generate command](https://www.prisma.io/docs/cli/v7/generate)

## Related pages

- [`Overview of Prisma Migrate`](https://www.prisma.io/docs/orm/v7/prisma-migrate): Learn how Prisma Migrate keeps your database schema in sync with your Prisma schema

# Getting started with Prisma Migrate (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/getting-started)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to migrate your schema in a development environment using Prisma Migrate

Location: ORM > v7 > Prisma Migrate > Getting started with Prisma Migrate

## Adding to a new project [#adding-to-a-new-project]

To use Prisma Migrate, add some models to your `schema.prisma`:

```prisma title="schema.prisma"
datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int    @id @default(autoincrement()) // [!code ++]
  name  String // [!code ++]
  posts Post[] // [!code ++]
}

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  published Boolean @default(true) // [!code ++]
  authorId  Int // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]
```

> [!NOTE]
> You can use [native type mapping attributes](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-types) in your schema to decide which exact database type to create (for example, `String` can map to `varchar(100)` or `text`).

### Create an initial migration [#create-an-initial-migration]

Create an initial migration using the `prisma migrate` command:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This will generate a migration with the appropriate commands for your database.

```sql no-copy title="migration.sql"
CREATE TABLE "User" (
  "id" SERIAL,
  "name" TEXT NOT NULL,
  PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Post" (
  "id" SERIAL,
  "title" TEXT NOT NULL,
  "published" BOOLEAN NOT NULL DEFAULT true,
  "authorId" INTEGER NOT NULL,
  PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE
  "Post"
ADD
  FOREIGN KEY("authorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
```

Your Prisma schema is now in sync with your database schema and you have initialized a migration history:

```text
migrations/
  └─ 20210313140442_init/
    └─ migration.sql
```

> **Note**: The folder name will be different for you. Folder naming is in the format of YYYYMMDDHHMMSS_your_text_from_name_flag.

### Additional migrations [#additional-migrations]

Suppose you add a field to your model:

```prisma title="schema.prisma"
model User {
  id       Int    @id @default(autoincrement())
  jobTitle String // [!code ++]
  name     String
  posts    Post[]
}
```

You can run `prisma migrate` again to update your migrations

  

#### bun

```bash
bunx prisma migrate dev --name added_job_title
```

#### pnpm

```bash
pnpm prisma migrate dev --name added_job_title
```

#### yarn

```bash
yarn prisma migrate dev --name added_job_title
```

#### npm

```bash
npx prisma migrate dev --name added_job_title
```

```sql no-copy title="migration.sql"
  -- AlterTable
ALTER TABLE
  "User"
ADD
  COLUMN "jobTitle" TEXT NOT NULL;
```

Your Prisma schema is once again in sync with your database schema, and your migration history contains two migrations:

```
migrations/
  └─ 20210313140442_init/
    └─ migration.sql
  └─ 20210313140442_added_job_title/
    └─ migration.sql
```

### Committing to versions control [#committing-to-versions-control]

Your migration history can be [committed to version control](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/migration-histories#committing-the-migration-history-to-source-control) and use to [deploy changes to test environments and production](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production#production-and-testing-environments).

## Adding to an existing project [#adding-to-an-existing-project]

It's possible to integrate Prisma migrations to an existing project.

### Introspect to create or update your Prisma schema [#introspect-to-create-or-update-your-prisma-schema]

Make sure your Prisma schema is in sync with your database schema. This should already be true if you are using a previous version of Prisma Migrate.

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

### Create a baseline migration [#create-a-baseline-migration]

Create a baseline migration that creates an initial history of the database before using Prisma migrate. This migrations contains the data that must be maintained, which means the database cannot be reset. This tells Prisma migrate to assume that one or more migrations have **already been applied**. This prevents generated migrations from failing when they try to create tables and fields that already exist.

To create a baseline migration:

* If you already have a `prisma/migrations` folder, delete, move, rename, or archive this folder.
* Create a new `prisma/migrations` directory.
* Then create another new directory with your preferred name. What's important is to use a prefix of `0_` so that Prisma migrate applies migrations in a [lexicographic order](https://en.wikipedia.org/wiki/Lexicographic_order). You can use a different value such as the current timestamp.
* Generate a migration and save it to a file using `prisma migrate diff`:

  

#### bun

```bash
bunx prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0_init/migration.sql
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0_init/migration.sql
```

#### yarn

```bash
yarn prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0_init/migration.sql
```

#### npm

```bash
npx prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0_init/migration.sql
```

* Review the generated migration.

### Work around features not supported by Prisma Schema Language [#work-around-features-not-supported-by-prisma-schema-language]

To include [unsupported database features](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/unsupported-database-features) that already exist in the database, you must replace or modify the initial migration SQL:

* Open the `migration.sql` file generated in the [Create a baseline migration](#create-a-baseline-migration) section.
* Modify the generated SQL. For example:

  * If the changes are minor, you can append additional custom SQL to the generated migration. The following example creates a trigger function:

```sql title="migration.sql"
/* Generated migration SQL */

CREATE OR REPLACE FUNCTION notify_on_insert() -- [!code ++]
RETURNS TRIGGER AS $$ -- [!code ++]
BEGIN -- [!code ++]
  PERFORM pg_notify('new_record', NEW.id::text); -- [!code ++]
  RETURN NEW; -- [!code ++]
END; -- [!code ++]
$$ LANGUAGE plpgsql; -- [!code ++]
```

* If the changes are significant, it can be easier to replace the entire migration file with the result of a database dump:

  * [`mysqldump`](https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html)
  * [`pg_dump`](https://www.postgresql.org/docs/12/app-pgdump.html).

  When using `pg_dump` for this, you'll need to update the `search_path` as follows with this command: `SELECT pg_catalog.set_config('search_path', '', false);`, otherwise you'll run into the following error: `The underlying table for model '_prisma_migrations' does not exist.`

> [!NOTE]
> Note that the order of the tables matters when creating all of them at once, since foreign keys are created at the same step. Therefore, either re-order them or move constraint creation to the last step after all tables are created, so you won't face `can't create constraint` errors

### Apply the initial migrations [#apply-the-initial-migrations]

To apply your initial migration(s):

* Run the following command against your database:

  

#### bun

```bash
bunx prisma migrate resolve --applied 0_init
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied 0_init
```

#### yarn

```bash
yarn prisma migrate resolve --applied 0_init
```

#### npm

```bash
npx prisma migrate resolve --applied 0_init
```

* Review the database schema to ensure the migration leads to the desired end-state (for example, by comparing the schema to the production database).

The new migration history and the database schema should now be in sync with your Prisma schema.

### Commit the migration history and Prisma schema [#commit-the-migration-history-and-prisma-schema]

Commit the following to source control:

* The entire migration history folder
* The `schema.prisma` file

## Going further [#going-further]

* Refer to the [Deploying database changes with Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-database-changes-with-prisma-migrate) guide for more on deploying migrations to production.
* Refer to the [Production Troubleshooting](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing#fixing-failed-migrations-with-migrate-diff-and-db-execute) guide to learn how to debug and resolve failed migrations in production using `prisma migrate diff`, `prisma db execute` and/ or `prisma migrate resolve`.

## Where to go next [#where-to-go-next]

* [Prisma Client CRUD guide](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud) once your schema changes are in place and you want to start querying data
* [Generating Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client) if you need to adjust client output or runtime behavior after migrations
* [Quickstart with Prisma Postgres](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres) if you want a managed Postgres database without running one yourself
* [Review pricing](https://www.prisma.io/pricing) if you're evaluating Prisma Postgres or managed workflows for production use

# Overview of Prisma Migrate (Prisma ORM v7) (/docs/orm/v7/prisma-migrate)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how Prisma Migrate keeps your database schema in sync with your Prisma schema

Location: ORM > v7 > Overview of Prisma Migrate

Prisma Migrate enables you to:

* Keep your database schema in sync with your [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) as it evolves
* Maintain existing data in your database

Prisma Migrate generates [a history of `.sql` migration files](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/migration-histories), and plays a role in both [development and production](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production).

Prisma Migrate can be considered a *hybrid* database schema migration tool, meaning it has both of *declarative* and *imperative* elements:

* Declarative: The data model is described in a declarative way in the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview). Prisma Migrate generates SQL migration files from that data model.
* Imperative: All generated SQL migration files are fully customizable. Prisma Migrate hence provides the flexibility of an imperative migration tool by enabling you to modify what and how migrations are executed (and allows you to run custom SQL to e.g. make use of native database feature, perform data migrations, ...).

If you are prototyping, consider using the [`db push`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-push) command - see [Schema prototyping with `db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) for examples.

See the [Prisma Migrate reference](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#prisma-migrate) for detailed information about the Prisma Migrate CLI commands.

> [!NOTE]
> Does not apply for MongoDB
> 
> Instead of `migrate dev` and related commands, use [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) for [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

## Related pages

- [`Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client): Prisma Client is Prisma ORM's generated, type-safe query builder for Node.js, Bun, and Deno applications.

# What is introspection? (Prisma ORM v7) (/docs/orm/v7/prisma-schema/introspection)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how you can introspect your database to generate a data model into your Prisma schema

Location: ORM > v7 > Prisma Schema > What is introspection?

You can introspect your database using the Prisma CLI in order to generate the [data model](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models) in your [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview). The data model is needed to [generate Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names).

Introspection is often used to generate an *initial* version of the data model when [adding Prisma ORM to an existing project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql).

However, it can also be [used *repeatedly* in an application](#introspection-with-an-existing-schema). This is most commonly the case when you're *not* using [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) but perform schema migrations using plain SQL or another migration tool. In that case, you also need to re-introspect your database and subsequently re-generate Prisma Client to reflect the schema changes in your [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction).

## What does introspection do? [#what-does-introspection-do]

Introspection has one main function: Populate your Prisma schema with a data model that reflects the current database schema.

![Introspect your database with Prisma](https://www.prisma.io/img/orm/prisma-db-pull-generate-schema.png)

Here's an overview of its main functions on SQL databases:

* Map *tables* in the database to [Prisma models](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-models)
* Map *columns* in the database to the [fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-fields) of Prisma models
* Map *indexes* in the database to [indexes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-an-index) in the Prisma schema
* Map *database constraints* to [attributes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-attributes) or [type modifiers](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#type-modifiers) in the Prisma schema

On MongoDB, the main functions are the following:

* Map *collections* in the database to [Prisma models](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-models). Because a *collection* in MongoDB doesn't have a predefined structure, Prisma ORM *samples* the *documents* in the collection and derives the model structure accordingly (i.e. it maps the fields of the *document* to the [fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-fields) of the Prisma model). If *embedded types* are detected in a collection, these will be mapped to [composite types](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models) in the Prisma schema.
* Map *indexes* in the database to [indexes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-an-index) in the Prisma schema, if the collection contains at least one document contains a field included in the index

You can learn more about how Prisma ORM maps types from the database to the types available in the Prisma schema on the respective docs page for the data source connector:

* [PostgreSQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#prisma-to-postgresql)
* [MySQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#type-mapping-between-mysql-and-prisma-schema)
* [SQLite](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite#type-mappings)
* [Microsoft SQL Server](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server#type-mappings)

## The `prisma db pull` command [#the-prisma-db-pull-command]

You can introspect your database using the `prisma db pull` command of the [Prisma CLI](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference). Note that using this command requires your [connection URL](https://www.prisma.io/docs/orm/v7/reference/connection-urls) to be set in your Prisma config [`datasource`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference#datasourceurl).

Here's a high-level overview of the steps that `prisma db pull` performs internally:

1. Read the [connection URL](https://www.prisma.io/docs/orm/v7/reference/connection-urls) from the `datasource` configuration in the Prisma config
2. Open a connection to the database
3. Introspect database schema (i.e. read tables, columns and other structures ...)
4. Transform database schema into Prisma schema data model
5. Write data model into Prisma schema or [update existing schema](#introspection-with-an-existing-schema)

## Introspection workflow [#introspection-workflow]

The typical workflow for projects that are not using Prisma Migrate, but instead use plain SQL or another migration tool looks as follows:

1. Change the database schema (e.g. using plain SQL)
2. Run `prisma db pull` to update the Prisma schema
3. Run `prisma generate` to update Prisma Client
4. Use the updated Prisma Client in your application

Note that as you evolve the application, [this process can be repeated for an indefinite number of times](#introspection-with-an-existing-schema).

![Introspect workflow](https://www.prisma.io/img/orm/prisma-evolve-app-workflow.png)

## Rules and conventions [#rules-and-conventions]

Prisma ORM employs a number of conventions for translating a database schema into a data model in the Prisma schema:

### Model, field and enum names [#model-field-and-enum-names]

Field, model and enum names (identifiers) must start with a letter and generally must only contain underscores, letters and digits. You can find the naming rules and conventions for each of these identifiers on the respective docs page:

* [Naming models](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#naming-conventions)
* [Naming fields](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference)
* [Naming enums](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference)

The general rule for identifiers is that they need to adhere to this regular expression:

```
[A-Za-z][A-Za-z0-9_]*
```

#### Sanitization of invalid characters [#sanitization-of-invalid-characters]

**Invalid characters** are being sanitized during introspection:

* If they appear *before* a letter in an identifier, they get dropped.
* If they appear *after* the first letter, they get replaced by an underscore.

Additionally, the transformed name is mapped to the database using `@map` or `@@map` to retain the original name.

Consider the following table as an example:

```sql
CREATE TABLE "42User" (
  _id SERIAL PRIMARY KEY,
  _name VARCHAR(255),
  two$two INTEGER
);
```

Because the leading `42` in the table name as well as the leading underscores and the `$` on the columns are forbidden in Prisma ORM, introspection adds the `@map` and `@@map` attributes so that these names adhere to Prisma ORM's naming conventions:

```prisma
model User {
  id      Int     @id @default(autoincrement()) @map("_id")
  name    String? @map("_name")
  two_two Int?    @map("two$two")

  @@map("42User")
}
```

#### Duplicate Identifiers after Sanitization [#duplicate-identifiers-after-sanitization]

If sanitization results in duplicate identifiers, no immediate error handling is in place. You get the error later and can manually fix it.

Consider the case of the following two tables:

```sql
CREATE TABLE "42User" (
  _id SERIAL PRIMARY KEY
);

CREATE TABLE "24User" (
  _id SERIAL PRIMARY KEY
);
```

This would result in the following introspection result:

```prisma
model User {
  id Int @id @default(autoincrement()) @map("_id")

  @@map("42User")
}

model User {
  id Int @id @default(autoincrement()) @map("_id")

  @@map("24User")
}
```

Trying to generate your Prisma Client with `prisma generate` you would get the following error:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

```text no-copy
$ npx prisma generate
Error: Schema parsing
error: The model "User" cannot be defined because a model with that name already exists.
  */}  schema.prisma:17
   |
16 | }
17 | model User {
   |

Validation Error Count: 1
```

In this case, you must manually change the name of one of the two generated `User` models because duplicate model names are not allowed in the Prisma schema.

### Order of fields [#order-of-fields]

Introspection lists model fields in the same order as the corresponding table columns in the database.

### Order of attributes [#order-of-attributes]

Introspection adds attributes in the following order (this order is mirrored by `prisma format`):

* Block level: `@@id`, `@@unique`, `@@index`, `@@map`
* Field level : `@id`, `@unique`, `@default`, `@updatedAt`, `@map`, `@relation`

### Relations [#relations]

Prisma ORM translates foreign keys that are defined on your database tables into [relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations).

#### One-to-one relations [#one-to-one-relations]

Prisma ORM adds a [one-to-one](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-one-relations) relation to your data model when the foreign key on a table has a `UNIQUE` constraint, e.g.:

```sql
CREATE TABLE "User" (
    id SERIAL PRIMARY KEY
);
CREATE TABLE "Profile" (
    id SERIAL PRIMARY KEY,
    "user" integer NOT NULL UNIQUE,
    FOREIGN KEY ("user") REFERENCES "User"(id)
);
```

Prisma ORM translates this into the following data model:

```prisma
model User {
  id      Int      @id @default(autoincrement())
  Profile Profile?
}

model Profile {
  id   Int  @id @default(autoincrement())
  user Int  @unique
  User User @relation(fields: [user], references: [id])
}
```

#### One-to-many relations [#one-to-many-relations]

By default, Prisma ORM adds a [one-to-many](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-many-relations) relation to your data model for a foreign key it finds in your database schema:

```sql
CREATE TABLE "User" (
    id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
    id SERIAL PRIMARY KEY,
    "author" integer NOT NULL,
    FOREIGN KEY ("author") REFERENCES "User"(id)
);
```

These tables are transformed into the following models:

```prisma
model User {
  id   Int    @id @default(autoincrement())
  Post Post[]
}

model Post {
  id     Int  @id @default(autoincrement())
  author Int
  User   User @relation(fields: [author], references: [id])
}
```

#### Many-to-many relations [#many-to-many-relations]

[Many-to-many](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations) relations are commonly represented as [relation tables](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#relation-table-conventions) in relational databases.

Prisma ORM supports two ways for defining many-to-many relations in the Prisma schema:

* [Implicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations) (Prisma ORM manages the relation table under the hood)
* [Explicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#explicit-many-to-many-relations) (the relation table is present as a [model](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-models))

*Implicit* many-to-many relations are recognized if they adhere to Prisma ORM's [conventions for relation tables](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#relation-table-conventions). Otherwise the relation table is rendered in the Prisma schema as a model (therefore making it an *explicit* many-to-many relation).

This topic is covered extensively on the docs page about [Relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations).

#### Disambiguating relations [#disambiguating-relations]

Prisma ORM generally omits the `name` argument on the [`@relation`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#the-relation-attribute) attribute if it's not needed. Consider the `User` ↔ `Post` example from the previous section. The `@relation` attribute only has the `references` argument, `name` is omitted because it's not needed in this case:

```prisma
model Post {
  id     Int  @id @default(autoincrement())
  author Int
  User   User @relation(fields: [author], references: [id])
}
```

It would be needed if there were *two* foreign keys defined on the `Post` table:

```sql
CREATE TABLE "User" (
    id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
    id SERIAL PRIMARY KEY,
    "author" integer NOT NULL,
    "favoritedBy" INTEGER,
    FOREIGN KEY ("author") REFERENCES "User"(id),
    FOREIGN KEY ("favoritedBy") REFERENCES "User"(id)
);
```

In this case, Prisma ORM needs to [disambiguate the relation](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#disambiguating-relations) using a dedicated relation name:

```prisma
model Post {
  id                          Int   @id @default(autoincrement())
  author                      Int
  favoritedBy                 Int?
  User_Post_authorToUser      User  @relation("Post_authorToUser", fields: [author], references: [id])
  User_Post_favoritedByToUser User? @relation("Post_favoritedByToUser", fields: [favoritedBy], references: [id])
}

model User {
  id                          Int    @id @default(autoincrement())
  Post_Post_authorToUser      Post[] @relation("Post_authorToUser")
  Post_Post_favoritedByToUser Post[] @relation("Post_favoritedByToUser")
}
```

Note that you can rename the [Prisma-ORM level](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields) relation field to anything you like so that it looks friendlier in the generated Prisma Client API.

## Introspection with an existing schema [#introspection-with-an-existing-schema]

Running `prisma db pull` for relational databases with an existing Prisma Schema merges manual changes made to the schema, with changes made in the database. For MongoDB, Introspection for now is meant to be done only once for the initial data model. Running it repeatedly will lead to loss of custom changes, as the ones listed below.

Introspection for relational databases maintains the following manual changes:

* Order of `model` blocks
* Order of `enum` blocks
* Comments
* `@map` and `@@map` attributes
* `@updatedAt`
* `@default(cuid())` (`cuid()` is a Prisma-ORM level function)
* `@default(uuid())` (`uuid()` is a Prisma-ORM level function)
* Custom `@relation` names

> **Note**: Only relations between models on the database level will be picked up. This means that there **must be a foreign key set**.

The following properties of the schema are determined by the database:

* Order of fields within `model` blocks
* Order of values within `enum` blocks

> **Note**: All `enum` blocks are listed below `model` blocks.

### Force overwrite [#force-overwrite]

To overwrite manual changes, and generate a schema based solely on the introspected database and ignore any existing Prisma Schema, add the `--force` flag to the `db pull` command:

  

#### bun

```bash
bunx prisma db pull --force
```

#### pnpm

```bash
pnpm prisma db pull --force
```

#### yarn

```bash
yarn prisma db pull --force
```

#### npm

```bash
npx prisma db pull --force
```

Use cases include:

* You want to start from scratch with a schema generated from the underlying database
* You have an invalid schema and must use `--force` to make introspection succeed

## Introspecting only a subset of your database schema [#introspecting-only-a-subset-of-your-database-schema]

Introspecting only a subset of your database schema is [not yet officially supported](https://github.com/prisma/orm/issues/807) by Prisma ORM.

However, you can achieve this by creating a new database user that only has access to the tables which you'd like to see represented in your Prisma schema, and then perform the introspection using that user. The introspection will then only include the tables the new user has access to.

If your goal is to exclude certain models from the [Prisma Client generation](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction), you can add the [`@@ignore` attribute](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) to the model definition in your Prisma schema. Ignored models are excluded from the generated Prisma Client.

## Introspection warnings for unsupported features [#introspection-warnings-for-unsupported-features]

The Prisma Schema Language (PSL) can express a majority of the database features of the [target databases](https://www.prisma.io/docs/orm/v7/reference/supported-databases) Prisma ORM supports. However, there are features and functionality the Prisma Schema Language still needs to express.

For these features, the Prisma CLI will surface detect usage of the feature in your database and return a warning. The Prisma CLI will also add a comment in the models and fields the features are in use in the Prisma schema. The warnings will also contain a workaround suggestion.

The `prisma db pull` command will surface the following unsupported features:

* [Partitioned tables](https://github.com/prisma/orm/issues/1708)
* [PostgreSQL Row Level Security](https://github.com/prisma/orm/issues/12735)
* [Index sort order, `NULLS FIRST` / `NULLS LAST`](https://github.com/prisma/orm/issues/15466)
* [CockroachDB row-level TTL](https://github.com/prisma/orm/issues/13982)
* [Comments](https://github.com/prisma/orm/issues/8703)
* [PostgreSQL deferred constraints](https://github.com/prisma/orm/issues/8807)
* [Check Constraints](https://github.com/prisma/orm/issues/3388) (MySQL + PostgreSQL)
* [Exclusion Constraints](https://github.com/prisma/orm/issues/17514)
* [MongoDB $jsonSchema](https://github.com/prisma/orm/issues/8135)
* [Expression indexes](https://github.com/prisma/orm/issues/2504)

You can find the list of features we intend to support on [GitHub (labeled with `topic:database-functionality`)](https://github.com/prisma/orm/issues?q=is%3Aopen+label%3A%22topic%3A+database-functionality%22+label%3Ateam%2Fschema+sort%3Aupdated-desc+).

### Workaround for introspection warnings for unsupported features [#workaround-for-introspection-warnings-for-unsupported-features]

If you are using a relational database and either one of the above features listed in the previous section:

1. Create a draft migration:
   
     

#### bun

```bash
bunx prisma migrate dev --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --create-only
```

#### yarn

```bash
yarn prisma migrate dev --create-only
```

#### npm

```bash
npx prisma migrate dev --create-only
```
   
2. Add the SQL that adds the feature surfaced in the warnings.
3. Apply the draft migration to your database:
   
     

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

## Related pages

- [`Overview of Prisma Schema`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview): The Prisma schema is the main method of configuration when using Prisma. It is typically called schema.prisma and contains your database connection and data model
- [`PostgreSQL extensions`](https://www.prisma.io/docs/orm/v7/prisma-schema/postgresql-extensions): How to install and manage PostgreSQL extensions with Prisma ORM using customized migrations, and how to use them in Prisma Client

# PostgreSQL extensions (Prisma ORM v7) (/docs/orm/v7/prisma-schema/postgresql-extensions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to install and manage PostgreSQL extensions with Prisma ORM using customized migrations, and how to use them in Prisma Client

Location: ORM > v7 > Prisma Schema > PostgreSQL extensions

This page is about [PostgreSQL extensions](https://www.postgresql.org/docs/current/external-extensions.html) and explains how to use them with Prisma ORM.

## What are PostgreSQL extensions? [#what-are-postgresql-extensions]

PostgreSQL allows you to extend your database functionality by installing and activating packages known as *extensions*. For example, the `citext` extension adds a case-insensitive string data type. Some extensions, such as `citext`, are supplied directly by PostgreSQL, while other extensions are developed externally. For more information on extensions, see [the PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-createextension.html).

To use an extension, it must first be *installed* on the local file system of your database server. You then need to *activate* the extension, which runs a script file that adds the new functionality.

## Using a PostgreSQL extension with Prisma ORM [#using-a-postgresql-extension-with-prisma-orm]

The following example installs the `citext` extension.

### 1. Create an empty migration [#1-create-an-empty-migration]

Run the following command to create an empty migration that you can [customize](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations):

  

#### bun

```bash
bunx prisma migrate dev --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --create-only
```

#### yarn

```bash
yarn prisma migrate dev --create-only
```

#### npm

```bash
npx prisma migrate dev --create-only
```

### 2. Add a SQL statement to install the extension [#2-add-a-sql-statement-to-install-the-extension]

In the new migration file that was created in the `migrations` directory, add the following statement:

```sql
CREATE EXTENSION IF NOT EXISTS citext;
```

### 3. Deploy the migration [#3-deploy-the-migration]

Run the following command to deploy the migration and apply to your database:

  

#### bun

```bash
bunx prisma migrate deploy
```

#### pnpm

```bash
pnpm prisma migrate deploy
```

#### yarn

```bash
yarn prisma migrate deploy
```

#### npm

```bash
npx prisma migrate deploy
```

### 4. Use the extension [#4-use-the-extension]

You can now use the extension in your queries with Prisma Client. If the extension has special data types that currently can't be natively represented in the Prisma schema, you can still define fields of that type on your models using the [`Unsupported`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#unsupported-types) fallback type.

## Related pages

- [`Overview of Prisma Schema`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview): The Prisma schema is the main method of configuration when using Prisma. It is typically called schema.prisma and contains your database connection and data model
- [`What is introspection?`](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection): Learn how you can introspect your database to generate a data model into your Prisma schema

# Connection URLs (Prisma ORM v7) (/docs/orm/v7/reference/connection-urls)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite

Location: ORM > v7 > Reference > Connection URLs

Prisma ORM needs a connection URL to be able to connect to your database, e.g. when sending queries with [Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) or when changing the database schema with [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate).

The connection URL is provided via the `url` field of a `datasource` block in your Prisma config (or Prisma schema if on version 6). It usually consists of the following components (except for SQLite and [Prisma Postgres](https://www.prisma.io/docs/postgres)):

* **User**: The name of your database user
* **Password**: The password for your database user
* **Host**: The IP or domain name of the machine where your database server is running
* **Port**: The port on which your database server is running
* **Database name**: The name of the database you want to use

Make sure you have this information at hand when getting started with Prisma ORM. If you don't have a database server running yet, you can either use a local SQLite database file (see the [Quickstart](https://www.prisma.io/docs/v7/prisma-orm/quickstart/sqlite)) or [setup a free PostgreSQL database with Prisma Postgres](https://www.prisma.io/docs/postgres).

## Format [#format]

The format of the connection URL depends on the *database connector* you're using. Prisma ORM generally supports the standard formats for each database. You can find out more about the connection URL of your database on the dedicated docs page:

* [PostgreSQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql)
* [MySQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql)
* [SQLite](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite)
* [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb)
* [Microsoft SQL Server](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server)
* [CockroachDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#cockroachdb)

### Special characters [#special-characters]

For MySQL, PostgreSQL and CockroachDB you must [percentage-encode special characters](https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding) in any part of your connection URL - including passwords. For example, `p@$$w0rd` becomes `p%40%24%24w0rd`.

For Microsoft SQL Server, you must [escape special characters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server#connection-details) in any part of your connection string.

## Examples [#examples]

Here are examples for the connection URLs of the databases Prisma ORM supports:

### Prisma Postgres [#prisma-postgres]

[Prisma Postgres](https://www.prisma.io/docs/postgres) is a managed PostgreSQL service running on unikernels. There are several ways to connect to Prisma Postgres:

* via direct TCP connections (lets you connect via any ORM or database tool)
* via pooled TCP connections (recommended for serverless and high-concurrency workloads)
* via the hosted [Prisma Accelerate](https://www.prisma.io/docs/accelerate) connection (retiring December 1, 2026)
* locally

The connection string formats of these are covered below.

#### Direct TCP [#direct-tcp]

When you connect to Prisma Postgres via direct TCP, your connection string looks as follows:

```bash
DATABASE_URL="postgres://USER:PASSWORD@db.prisma.io:5432/postgres?sslmode=require"
```

The `USER` and `PASSWORD` values are provided when you generate credentials for your Prisma Postgres instance in the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=orm).

#### Pooled TCP [#pooled-tcp]

When you connect to Prisma Postgres via pooled TCP, your connection string looks as follows:

```bash
DATABASE_URL="postgres://USER:PASSWORD@pooled.db.prisma.io:5432/?sslmode=require"
```

Use a pooled TCP connection string for serverless, bursty, or high-concurrency workloads. Learn more in [Connection pooling](https://www.prisma.io/docs/postgres/database/connection-pooling).

#### Via Prisma Accelerate (HTTP, retiring) [#via-prisma-accelerate-http-retiring]

> [!WARNING]
> Hosted Accelerate connection retirement
> 
> The hosted `prisma+postgres://accelerate.prisma-data.net` connection ends on December 1, 2026. Existing Prisma Postgres customers should [switch to pooled TCP or the Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/switch-from-accelerate).
> 
> This does not affect Local Postgres `prisma+postgres://localhost` URLs.

When connecting via Prisma Accelerate, the connection string doesn't require a user/password like a conventional connection string does. Instead, authentication works via an API key:

```ts title="prisma.config.ts"
export default defineConfig({
  datasource: {
    url: "prisma+postgres://accelerate.prisma-data.net/?api_key=API_KEY"
  },
});
```

In this snippet, `API_KEY` is a placeholder for the API key generated by the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=orm).

#### Local Prisma Postgres [#local-prisma-postgres]

The connection string for connecting to a [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) instance mirrors the structure of a remote instance via Accelerate:

```ts title="prisma.config.ts"
export default defineConfig({
  datasource: {
    url: "prisma+postgres://localhost:51213/?api_key=__API_KEY__"
  },
});
```

However, in this case the `API_KEY` doesn't provide authentication details. Instead, it encodes information about the local Prisma Postgres instance. You can obtain a local connection string via the [`prisma dev`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#dev) command.

### PostgreSQL [#postgresql]

```ts title="prisma.config.ts"
export default defineConfig({
  datasource: {
    url: "postgresql://janedoe:mypassword@localhost:5432/mydb?schema=sample"
  },
});
```

### MySQL [#mysql]

```ts title="prisma.config.ts"
export default defineConfig({
  datasource: {
    url: "mysql://janedoe:mypassword@localhost:3306/mydb"
  },
});
```

### Microsoft SQL Server [#microsoft-sql-server]

```ts title="prisma.config.ts"
export default defineConfig({
  datasource: {
    url: "sqlserver://localhost:1433;initial catalog=sample;user=sa;password=mypassword;"
  },
});
```

### SQLite [#sqlite]

```ts title="prisma.config.ts"
export default defineConfig({
  datasource: {
    url: "file:./dev.db"
  },
});
```

### CockroachDB [#cockroachdb]

```ts title="prisma.config.ts"
export default defineConfig({
  datasource: {
    url: "postgresql://janedoe:mypassword@localhost:26257/mydb?schema=public"
  },
});
```

### MongoDB [#mongodb]

*Support for MongoDB is limited to [Prisma 6](https://www.prisma.io/docs/orm/v6/reference/connection-urls#mongodb) as of now. We're working on support for MongoDB in Prisma v7*

## .env [#env]

You can also provide the connection URL as an environment variable:

```prisma title="schema.prisma"
datasource db {
  provider = "postgresql"
}
```

You can then either set the environment variable in your terminal or by providing a [dotenv](https://github.com/motdotla/dotenv) file named `.env`. This will automatically be picked up by the Prisma CLI.

Prisma ORM reads the connection URL from the dotenv file in the following situations:

* When it updates the schema during build time
* When it connects to the database during run time

```
DATABASE_URL=postgresql://janedoe:mypassword@localhost:5432/mydb
```

## Related pages

- [`Config API`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference): Complete reference for prisma.config.ts configuration options
- [`Database Features`](https://www.prisma.io/docs/orm/v7/reference/database-features): Database features supported in Prisma ORM
- [`Environment Variables`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference): Reference for Prisma environment variables
- [`Error Reference`](https://www.prisma.io/docs/orm/v7/reference/error-reference): Prisma Client, Migrate, and Introspection error codes
- [`Prisma CLI reference`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference): This page gives an overview of all available Prisma CLI commands, explains their options and shows numerous usage examples

# Database Features (Prisma ORM v7) (/docs/orm/v7/reference/database-features)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Database features supported in Prisma ORM

Location: ORM > v7 > Reference > Database Features

This page gives an overview of the features which are provided by the databases that Prisma ORM supports. Additionally, it explains how each of these features can be used in Prisma ORM with pointers to further documentation.

## Relational database features [#relational-database-features]

This section describes which database features exist on the relational databases that are currently supported by Prisma ORM. The **Prisma schema** column indicates how a certain feature can be represented in the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) and links to its documentation. Note that database features can be used in **Prisma Client** even though they might not yet be representable in the Prisma schema.

> [!NOTE]
> These features are *only* for relational databases. Supported features for NoSQL databases, like MongoDB, can [be found below](#nosql-database-features).

### Constraints [#constraints]

| Constraint    | Supported |                                        Prisma schema                                        | Prisma Client | Prisma Migrate |
| ------------- | :-------: | :-----------------------------------------------------------------------------------------: | :-----------: | :------------: |
| `PRIMARY KEY` |     ✔️    |       [`@id` and `@@id`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-an-id-field)      |       ✔️      |       ✔️       |
| `FOREIGN KEY` |     ✔️    |        [Relation fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields)        |       ✔️      |       ✔️       |
| `UNIQUE`      |    ✔️\*   | [`@unique` and `@@unique`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-a-unique-field) |       ✔️      |       ✔️       |
| `CHECK`       |    ✔️†    |                                           Not yet                                           |       ✔️      |     Not yet    |
| `NOT NULL`    |     ✔️    |                [`?`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#type-modifiers)                |       ✔️      |       ✔️       |
| `DEFAULT`     |     ✔️    |        [`@default`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-a-default-value)       |       ✔️      |       ✔️       |
| `EXCLUDE`     |    ✔️‡    |                                           Not yet                                           |       ✔️      |     Not yet    |

> \* [Caveats apply when using the `UNIQUE` constraint with Microsoft SQL Server](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server#common-considerations)
> † Only supported in MySQL in [version 8 and higher](https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html).
> ‡ Only supported in PostgreSQL.

### Referential Actions (Delete and Update behaviors for foreign key references) [#referential-actions-delete-and-update-behaviors-for-foreign-key-references]

| Deletion behavior | Supported | Prisma schema | Prisma Client | Prisma Migrate |
| ----------------- | :-------: | :-----------: | :-----------: | :------------: |
| `CASCADE`         |     ✔️    |       ✔️      |       ✔️      |       ✔️       |
| `RESTRICT`        |    ✔️\*   |       ✔️      |       ✔️      |       ✔️       |
| `NO ACTION`       |     ✔️    |       ✔️      |       ✔️      |       ✔️       |
| `SET DEFAULT`     |     ✔️    |       ✔️      |       ✔️      |       ✔️       |
| `SET NULL`        |     ✔️    |       ✔️      |       ✔️      |       ✔️       |

> \* `RESTRICT` is not supported in Microsoft SQL Server.

### Indexes [#indexes]

| Index          |                 Supported                |                                                  Prisma schema                                                 | Prisma Client | Prisma Migrate |
| -------------- | :--------------------------------------: | :------------------------------------------------------------------------------------------------------------: | :-----------: | :------------: |
| `UNIQUE`       |                    ✔️                    |           [`@unique` and `@@unique`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-a-unique-field)          |       ✔️      |       ✔️       |
| `USING`        |              PostgreSQL only             | [`type`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#configuring-the-access-type-of-indexes-with-type-postgresql) |       ✔️      |       ✔️       |
| `WHERE`        |                    ✔️                    |      [`where`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#configuring-partial-indexes-with-where) (Preview)      |       ✔️      |       ✔️       |
| `(expression)` |                    ✔️                    |                                                     Not yet                                                    |       ✔️      |     Not yet    |
| `INCLUDE`      | PostgreSQL and Microsoft SQL Server only |                                                     Not yet                                                    |       ✔️      |     Not yet    |

Algorithm specified via `USING`:

| Index type (Algorithm) | Supported | Prisma schema | Prisma Client | Prisma Migrate |
| ---------------------- | :-------: | :-----------: | :-----------: | :------------: |
| B-tree                 |     ✔️    |      ✔️†      |       ✔️      |     Not yet    |
| Hash                   |     ✔️    |      ✔️†      |       ✔️      |     Not yet    |
| GiST                   |    ✔️\*   |      ✔️†      |      ✔️\*     |     Not yet    |
| GIN                    |    ✔️\*   |      ✔️†      |      ✔️\*     |     Not yet    |
| BRIN                   |    ✔️\*   |      ✔️†      |      ✔️\*     |     Not yet    |
| SP-GiST                |    ✔️\*   |      ✔️†      |      ✔️\*     |     Not yet    |

* \* Not supported for MySQL and SQLite
* † Available with the PostgreSQL connector only in Prisma ORM versions `4.0.0` and later.

### Misc [#misc]

| Feature                           |                 Supported                |                                     Prisma schema                                     | Prisma Client | Prisma Migrate |
| --------------------------------- | :--------------------------------------: | :-----------------------------------------------------------------------------------: | :-----------: | :------------: |
| Autoincrementing IDs              |                    ✔️                    | [`autoincrement()`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-a-default-value) |       ✔️      |       ✔️       |
| Arrays                            |              PostgreSQL only             |             [`[]`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#type-modifiers)            |       ✔️      |       ✔️       |
| Enums                             |                   ✔️\*†                  |            [`enum`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-enums)           |       ✔️      |       ✔️       |
| Native database types             |                    ✔️                    |                                           ✔️                                          |       ✔️      |     Not yet    |
| SQL Views                         |                    ✔️                    |                                        Not yet                                        |    Not yet    |     Not yet    |
| JSON support                      |                    ✔️†                   |                                           ✔️                                          |       ✔️      |       ✔️       |
| Fuzzy/Phrase full text search     |                    ✔️‡                   |                                        Not yet                                        |    Not yet    |     Not yet    |
| Table inheritance                 | PostgreSQL and Microsoft SQL Server only |                                        Not yet                                        |       ✔️      |     Not yet    |
| Authorization and user management |                    ✔️‡                   |                                        Not yet                                        |    Not yet    |     Not yet    |

* \* Not supported by Microsoft SQL Server
* † JSON and Enum types are supported in SQLite as of Prisma ORM 6.2.0.
* ‡ Not supported by SQLite

## NoSQL database features [#nosql-database-features]

This section describes which database features exist on the NoSQL databases that are currently supported by Prisma ORM.

### MongoDB [#mongodb]

The following table lists common MongoDB features and describes the level of support offered by Prisma ORM:

| Feature                                   | Supported by Prisma ORM |                                                Notes                                               |
| ----------------------------------------- | :---------------------: | :------------------------------------------------------------------------------------------------: |
| Embedded documents                        |            ✔️           |                                                                                                    |
| Transactions                              |            ✔️           |                                                                                                    |
| Indexes                                   |     ✔️ with caveats     |      Indexes can only be introspected if the field they refer to includes at least some data.      |
| Autoincrementing IDs                      |            No           |                                                                                                    |
| Compound IDs                              |            No           |                           MongoDB does not support composite IDs (`@@id`)                          |
| Generated `ObjectId`                      |            ✔️           |  See: [Defining IDs for MongoDB](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-ids-in-mongodb)  |
| Arrays                                    |            ✔️           |                                                                                                    |
| Enums                                     |            ✔️           |                                   Implemented at Prisma ORM level                                  |
| Native database types                     |            ✔️           | See: [Field mapping reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) |
| JSON support                              |            ✔️           |                        Advanced `Json` field filtering is not yet supported.                       |
| DBrefs                                    |            No           |                                                                                                    |
| Change streams                            |            No           |                                                                                                    |
| Direct access to the aggregation pipeline |            No           |                                                                                                    |

## Related pages

- [`Config API`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference): Complete reference for prisma.config.ts configuration options
- [`Connection URLs`](https://www.prisma.io/docs/orm/v7/reference/connection-urls): Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite
- [`Environment Variables`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference): Reference for Prisma environment variables
- [`Error Reference`](https://www.prisma.io/docs/orm/v7/reference/error-reference): Prisma Client, Migrate, and Introspection error codes
- [`Prisma CLI reference`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference): This page gives an overview of all available Prisma CLI commands, explains their options and shows numerous usage examples

# Environment Variables (Prisma ORM v7) (/docs/orm/v7/reference/environment-variables-reference)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Reference for Prisma environment variables

Location: ORM > v7 > Reference > Environment Variables

This document describes different environment variables and their use cases.

## Prisma Client [#prisma-client]

### `DEBUG` [#debug]

`DEBUG` is used to enable debugging output in Prisma Client.

Example setting Prisma Client level debugging output:

```bash
# enable only `prisma:client`-level debugging output
export DEBUG="prisma:client"
```

See [Debugging](https://www.prisma.io/docs/orm/v7/prisma-client/debugging-and-troubleshooting/debugging) for more information.

### `NO_COLOR` [#no_color]

`NO_COLOR` if [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) will activate the `colorless` setting for error formatting and strip colors from error messages.

See [Formatting via environment variables](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/error-formatting#formatting-via-environment-variables) for more information.

## Prisma Studio [#prisma-studio]

### `BROWSER` [#browser]

`BROWSER` is for Prisma Studio to force which browser it should be open in, if not set it will open in the default browser.

```bash
BROWSER=firefox prisma studio --port 5555
```

Alternatively you can set this when starting Studio from the CLI as well:

```bash
prisma studio --browser firefox
```

See [Studio](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#studio) documentation for more information.

## Prisma CLI [#prisma-cli]

### `PRISMA_HIDE_PREVIEW_FLAG_WARNINGS` [#prisma_hide_preview_flag_warnings]

`PRISMA_HIDE_PREVIEW_FLAG_WARNINGS` hides the warning message that states that a preview feature flag can be removed. It is a truthy value.

### `PRISMA_HIDE_UPDATE_MESSAGE` [#prisma_hide_update_message]

`PRISMA_HIDE_UPDATE_MESSAGE` is used to hide the update notification message that is shown when a newer Prisma CLI version is available. It's a truthy value.

### `PRISMA_DISABLE_WARNINGS` [#prisma_disable_warnings]

Disables all CLI warnings generated by `logger.warn`.

### `PRISMA_SCHEMA_DISABLE_ADVISORY_LOCK` [#prisma_schema_disable_advisory_lock]

Disables the [advisory locking](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production#advisory-locking) used by Prisma Migrate. Useful for certain database configurations like Percona-XtraDB-Cluster or MariaDB Galera Cluster.

## Proxy environment variables [#proxy-environment-variables]

The Prisma CLI supports custom HTTP(S) proxies to download the Prisma engines. These can be helpful to use when working behind a corporate firewall. See [Using a HTTP proxy for the CLI](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#using-a-http-proxy-for-the-cli) for more information.

### `NO_PROXY` [#no_proxy]

`NO_PROXY` is a comma-separated list of hostnames or IP addresses that do not require a proxy.

```bash
NO_PROXY=myhostname.com,10.11.12.0/16,172.30.0.0/16
```

### `HTTP_PROXY` [#http_proxy]

`HTTP_PROXY` is set with the hostname or IP address of a proxy server.

```bash
HTTP_PROXY=http://proxy.example.com
```

### `HTTPS_PROXY` [#https_proxy]

`HTTPS_PROXY` is set with the hostname or IP address of a proxy server.

```bash
HTTPS_PROXY=https://proxy.example.com
```

## Related pages

- [`Config API`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference): Complete reference for prisma.config.ts configuration options
- [`Connection URLs`](https://www.prisma.io/docs/orm/v7/reference/connection-urls): Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite
- [`Database Features`](https://www.prisma.io/docs/orm/v7/reference/database-features): Database features supported in Prisma ORM
- [`Error Reference`](https://www.prisma.io/docs/orm/v7/reference/error-reference): Prisma Client, Migrate, and Introspection error codes
- [`Prisma CLI reference`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference): This page gives an overview of all available Prisma CLI commands, explains their options and shows numerous usage examples

# Error Reference (Prisma ORM v7) (/docs/orm/v7/reference/error-reference)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma Client, Migrate, and Introspection error codes

Location: ORM > v7 > Reference > Error Reference

For more information about how to work with exceptions and error codes, see [Handling exceptions and errors](https://www.prisma.io/docs/orm/v7/prisma-client/debugging-and-troubleshooting/handling-exceptions-and-errors).

## Prisma Client error types [#prisma-client-error-types]

Prisma Client throws different kinds of errors. The following lists the exception types, and their documented data fields:

### `PrismaClientKnownRequestError` [#prismaclientknownrequesterror]

Prisma Client throws a `PrismaClientKnownRequestError` exception if the query engine returns a known error related to the request - for example, a unique constraint violation.

| **Property**    | **Description**                                                                                                  |
| :-------------- | :--------------------------------------------------------------------------------------------------------------- |
| `code`          | A Prisma-specific [error code](#error-codes).                                                                    |
| `meta`          | Additional information about the error - for example, the field that caused the error: `{ target: [ 'email' ] }` |
| `message`       | Error message associated with [error code](#error-codes).                                                        |
| `clientVersion` | Version of Prisma Client (for example, `2.19.0`)                                                                 |

### `PrismaClientUnknownRequestError` [#prismaclientunknownrequesterror]

Prisma Client throws a `PrismaClientUnknownRequestError` exception if the query engine returns an error related to a request that does not have an error code.

| **Property**    | **Description**                                           |
| :-------------- | :-------------------------------------------------------- |
| `message`       | Error message associated with [error code](#error-codes). |
| `clientVersion` | Version of Prisma Client (for example, `2.19.0`)          |

### `PrismaClientRustPanicError` [#prismaclientrustpanicerror]

Prisma Client throws a `PrismaClientRustPanicError` exception if the underlying engine crashes and exits with a non-zero exit code. In this case, Prisma Client or the whole Node process must be restarted.

| **Property**    | **Description**                                           |
| :-------------- | :-------------------------------------------------------- |
| `message`       | Error message associated with [error code](#error-codes). |
| `clientVersion` | Version of Prisma Client (for example, `2.19.0`)          |

### `PrismaClientInitializationError` [#prismaclientinitializationerror]

Prisma Client throws a `PrismaClientInitializationError` exception if something goes wrong when the query engine is started and the connection to the database is created. This happens either:

* When `prisma.$connect()` is called OR
* When the first query is executed

Errors that can occur include:

* The provided credentials for the database are invalid
* There is no database server running under the provided hostname and port
* The port that the query engine HTTP server wants to bind to is already taken
* A missing or inaccessible environment variable
* The query engine binary for the current platform could not be found (`generator` block)

| **Property**    | **Description**                                           |
| :-------------- | :-------------------------------------------------------- |
| `errorCode`     | A Prisma-specific error code.                             |
| `message`       | Error message associated with [error code](#error-codes). |
| `clientVersion` | Version of Prisma Client (for example, `2.19.0`)          |

### `PrismaClientValidationError` [#prismaclientvalidationerror]

Prisma Client throws a `PrismaClientValidationError` exception if validation fails - for example:

* Missing field - for example, an empty `data: {}` property when creating a new record
* Incorrect field type provided (for example, setting a `Boolean` field to `"Hello, I like cheese and gold!"`)

| **Property**    | **Description**                                  |
| :-------------- | :----------------------------------------------- |
| `message`       | Error message.                                   |
| `clientVersion` | Version of Prisma Client (for example, `2.19.0`) |

## Error codes [#error-codes]

### Common [#common]

#### `P1000` [#p1000]

"Authentication failed against database server at `{database_host}`, the provided database credentials for `{database_user}` are not valid. Please make sure to provide valid database credentials for the database server at `{database_host}`."

#### `P1001` [#p1001]

"Can't reach database server at `{database_host}`:`{database_port}` Please make sure your database server is running at `{database_host}`:`{database_port}`."

#### `P1002` [#p1002]

"The database server at `{database_host}`:`{database_port}` was reached but timed out. Please try again. Please make sure your database server is running at `{database_host}`:`{database_port}`. "

#### `P1003` [#p1003]

"Database {database_file_name} does not exist at {database_file_path}"

"Database `{database_name}.{database_schema_name}` does not exist on the database server at `{database_host}:{database_port}`."

"Database `{database_name}` does not exist on the database server at `{database_host}:{database_port}`."

#### `P1008` [#p1008]

"Operations timed out after `{time}`"

#### `P1009` [#p1009]

"Database `{database_name}` already exists on the database server at `{database_host}:{database_port}`"

#### `P1010` [#p1010]

"User `{database_user}` was denied access on the database `{database_name}`"

#### `P1011` [#p1011]

"Error opening a TLS connection: {message}"

#### `P1012` [#p1012]

> [!NOTE]
> If you get error code P1012 after you upgrade Prisma ORM to version 4.0.0 or later, see the [version 4.0.0 upgrade guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v4#update-schema). A schema that was valid before version 4.0.0 might be invalid in version 4.0.0 and later. The upgrade guide explains how to update your schema to make it valid.

"{full_error}"

Possible P1012 error messages:

* "Argument `{}` is missing."
* "Function `{}` takes {} arguments, but received {}."
* "Argument `{}` is missing in attribute `@{}`."
* "Argument `{}` is missing in data source block `{}`."
* "Argument `{}` is missing in generator block `{}`."
* "Error parsing attribute `@{}`: {}"
* "Attribute `@{}` is defined twice."
* "The model with database name `{}` could not be defined because another model with this name exists: `{}`"
* "`{}` is a reserved scalar type name and can not be used."
* "The {} `{}` cannot be defined because a {} with that name already exists."
* "Key `{}` is already defined in {}."
* "Argument `{}` is already specified as unnamed argument."
* "Argument `{}` is already specified."
* "No such argument.""
* "Field `{}` is already defined on model `{}`."
* "Field `{}` in model `{}` can't be a list. The current connector does not support lists of primitive types."
* "The index name `{}` is declared multiple times. With the current connector index names have to be globally unique."
* "Value `{}` is already defined on enum `{}`."
* "Attribute not known: `@{}`."
* "Function not known: `{}`."
* "Datasource provider not known: `{}`."
* "shadowDatabaseUrl is the same as url for datasource `{}`. Please specify a different database as shadow database."
* "The preview feature `{}` is not known. Expected one of: {}"
* "`{}` is not a valid value for {}."
* "Type `{}` is neither a built-in type, nor refers to another model, custom type, or enum."
* "Type `{}` is not a built-in type."
* "Unexpected token. Expected one of: {}"
* "Environment variable not found: {}."
* "Expected a {} value, but received {} value `{}`."
* "Expected a {} value, but failed while parsing `{}`: {}."
* "Error validating model `{}`: {}"
* "Error validating field `{}` in model `{}`: {}"
* "Error validating datasource `{datasource}`: {message}"
* "Error validating enum `{}`: {}"
* "Error validating: {}"

#### `P1013` [#p1013]

"The provided database string is invalid. {details}"

#### `P1014` [#p1014]

"The underlying {kind} for model `{model}` does not exist."

#### `P1015` [#p1015]

"Your Prisma schema is using features that are not supported for the version of the database.<br />Database version: {database_version}<br />Errors:<br />{errors}"

#### `P1016` [#p1016]

"Your raw query had an incorrect number of parameters. Expected: `{expected}`, actual: `{actual}`."

#### `P1017` [#p1017]

"Server has closed the connection."

### Prisma Client (Query Engine) [#prisma-client-query-engine]

#### `P2000` [#p2000]

"The provided value for the column is too long for the column's type. Column: {column_name}"

#### `P2001` [#p2001]

"The record searched for in the where condition (`{model_name}.{argument_name} = {argument_value}`) does not exist"

#### `P2002` [#p2002]

"Unique constraint failed on the {constraint}"

#### `P2003` [#p2003]

"Foreign key constraint failed on the field: `{field_name}`"

#### `P2004` [#p2004]

"A constraint failed on the database: `{database_error}`"

#### `P2005` [#p2005]

"The value `{field_value}` stored in the database for the field `{field_name}` is invalid for the field's type"

#### `P2006` [#p2006]

"The provided value `{field_value}` for `{model_name}` field `{field_name}` is not valid"

#### `P2007` [#p2007]

"Data validation error `{database_error}`"

#### `P2008` [#p2008]

"Failed to parse the query `{query_parsing_error}` at `{query_position}`"

#### `P2009` [#p2009]

"Failed to validate the query: `{query_validation_error}` at `{query_position}`"

#### `P2010` [#p2010]

"Raw query failed. Code: `{code}`. Message: `{message}`"

#### `P2011` [#p2011]

"Null constraint violation on the {constraint}"

#### `P2012` [#p2012]

"Missing a required value at `{path}`"

#### `P2013` [#p2013]

"Missing the required argument `{argument_name}` for field `{field_name}` on `{object_name}`."

#### `P2014` [#p2014]

"The change you are trying to make would violate the required relation '{relation_name}' between the `{model_a_name}` and `{model_b_name}` models."

#### `P2015` [#p2015]

"A related record could not be found. {details}"

#### `P2016` [#p2016]

"Query interpretation error. {details}"

#### `P2017` [#p2017]

"The records for relation `{relation_name}` between the `{parent_name}` and `{child_name}` models are not connected."

#### `P2018` [#p2018]

"The required connected records were not found. {details}"

#### `P2019` [#p2019]

"Input error. {details}"

#### `P2020` [#p2020]

"Value out of range for the type. {details}"

#### `P2021` [#p2021]

"The table `{table}` does not exist in the current database."

#### `P2022` [#p2022]

"The column `{column}` does not exist in the current database."

#### `P2023` [#p2023]

"Inconsistent column data: {message}"

#### `P2024` [#p2024]

"Timed out fetching a new connection from the connection pool. (More info: [http://pris.ly/d/connection-pool](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool) (Current connection pool timeout: {timeout}, connection limit: {connection_limit})"

In Prisma ORM v7, pool size and timeout are configured per [driver adapter](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool)—see the connection pool reference for your adapter.

#### `P2025` [#p2025]

"An operation failed because it depends on one or more records that were required but not found. {cause}"

#### `P2026` [#p2026]

"The current database provider doesn't support a feature that the query used: {feature}"

#### `P2027` [#p2027]

"Multiple errors occurred on the database during query execution: {errors}"

#### `P2028` [#p2028]

"Transaction API error: {error}"

#### `P2029` [#p2029]

"Query parameter limit exceeded error: {message}"

#### `P2030` [#p2030]

"Cannot find a fulltext index to use for the search, try adding a @@fulltext(\[Fields...]) to your schema"

#### `P2031` [#p2031]

"Prisma needs to perform transactions, which requires your MongoDB server to be run as a replica set. See details: [https://pris.ly/d/mongodb-replica-set](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb#replica-set-configuration)"

#### `P2033` [#p2033]

"A number used in the query does not fit into a 64 bit signed integer. Consider using `BigInt` as field type if you're trying to store large integers"

#### `P2034` [#p2034]

"Transaction failed due to a write conflict or a deadlock. Please retry your transaction"

#### `P2035` [#p2035]

"Assertion violation on the database: {database_error}"

#### `P2036` [#p2036]

"Error in external connector (id {id})"

#### `P2037` [#p2037]

"Too many database connections opened: {message}"

### Prisma Migrate (Schema Engine) [#prisma-migrate-schema-engine]

> [!WARNING]
> The Schema Engine was previously called Migration Engine. This change was introduced in version [5.0.0](https://github.com/prisma/orm/releases/tag/5.0.0).

#### `P3000` [#p3000]

"Failed to create database: {database_error}"

#### `P3001` [#p3001]

"Migration possible with destructive changes and possible data loss: {migration_engine_destructive_details}"

#### `P3002` [#p3002]

"The attempted migration was rolled back: {database_error}"

#### `P3003` [#p3003]

"The format of migrations changed, the saved migrations are no longer valid. To solve this problem, please follow the steps at: [https://pris.ly/d/migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)"

#### `P3004` [#p3004]

"The `{database_name}` database is a system database, it should not be altered with prisma migrate. Please connect to another database."

#### `P3005` [#p3005]

"The database schema is not empty. Read more about how to baseline an existing production database: [https://pris.ly/d/migrate-baseline](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining)"

#### `P3006` [#p3006]

"Migration `{migration_name}` failed to apply cleanly to the shadow database. <br />{error_code}Error:<br />{inner_error}"

#### `P3007` [#p3007]

"Some of the requested preview features are not yet allowed in schema engine. Please remove them from your data model before using migrations. (blocked: {list_of_blocked_features})"

#### `P3008` [#p3008]

"The migration `{migration_name}` is already recorded as applied in the database."

#### `P3009` [#p3009]

"migrate found failed migrations in the target database, new migrations will not be applied. Read more about how to resolve migration issues in a production database: [https://pris.ly/d/migrate-resolve](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/troubleshooting)<br />{details}"

#### `P3010` [#p3010]

"The name of the migration is too long. It must not be longer than 200 characters (bytes)."

#### `P3011` [#p3011]

"Migration `{migration_name}` cannot be rolled back because it was never applied to the database. Hint: did you pass in the whole migration name? (example: "20201207184859_initial_migration")"

#### `P3012` [#p3012]

"Migration `{migration_name}` cannot be rolled back because it is not in a failed state."

#### `P3013` [#p3013]

"Datasource provider arrays are no longer supported in migrate. Please change your datasource to use a single provider. Read more at [https://pris.ly/multi-provider-deprecation](https://github.com/prisma/orm/issues/3834)"

#### `P3014` [#p3014]

"Prisma Migrate could not create the shadow database. Please make sure the database user has permission to create databases. Read more about the shadow database (and workarounds) at [https://pris.ly/d/migrate-shadow](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database).

Original error: {error_code}<br />{inner_error}"

#### `P3015` [#p3015]

"Could not find the migration file at {migration_file_path}. Please delete the directory or restore the migration file."

#### `P3016` [#p3016]

"The fallback method for database resets failed, meaning Migrate could not clean up the database entirely. Original error: {error_code}<br />{inner_error}"

#### `P3017` [#p3017]

"The migration {migration_name} could not be found. Please make sure that the migration exists, and that you included the whole name of the directory. (example: "20201207184859_initial_migration")"

#### `P3018` [#p3018]

"A migration failed to apply. New migrations cannot be applied before the error is recovered from. Read more about how to resolve migration issues in a production database: [https://pris.ly/d/migrate-resolve](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/troubleshooting)"<br /><br />Migration name: {migration_name}<br /><br />Database error code: {database_error_code}<br /><br />Database error:<br />{database_error} "

#### `P3019` [#p3019]

"The datasource provider `{provider}` specified in your schema does not match the one specified in the migration_lock.toml, `{expected_provider}`. Please remove your current migration directory and start a new migration history with prisma migrate dev. Read more: [https://pris.ly/d/migrate-provider-switch](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/troubleshooting)"

#### `P3020` [#p3020]

"The automatic creation of shadow databases is disabled on Azure SQL. Please set up a shadow database using the `shadowDatabaseUrl` datasource attribute.<br />Read the docs page for more details: [https://pris.ly/d/migrate-shadow](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database)"

#### `P3021` [#p3021]

"Foreign keys cannot be created on this database. Learn more how to handle this: [https://pris.ly/d/migrate-no-foreign-keys](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale)"

#### `P3022` [#p3022]

"Direct execution of DDL (Data Definition Language) SQL statements is disabled on this database. Please read more here about how to handle this: [https://pris.ly/d/migrate-no-direct-ddl](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale)"

#### `P3023` [#p3023]

"For the current database, `externalTables` & `externalEnums` in your prisma config must contain only fully qualified identifiers (e.g. `schema_name.table_name`)."

#### `P3024` [#p3024]

"For the current database, `externalTables` & `externalEnums` in your prisma config must contain only simple identifiers without a schema name."

### `prisma db pull` [#prisma-db-pull]

#### `P4000` [#p4000]

"Introspection operation failed to produce a schema file: {introspection_error}"

#### `P4001` [#p4001]

"The introspected database was empty."

#### `P4002` [#p4002]

"The schema of the introspected database was inconsistent: {explanation}"

### Prisma Accelerate [#prisma-accelerate]

Prisma Accelerate-related errors start with `P6xxx` except for [`P5011`](https://www.prisma.io/docs/orm/v7/reference/error-reference#p5011-too-many-requests).

#### `P6000` (`ServerError`) [#p6000-servererror]

Generic error to catch all other errors.

#### `P6001` (`InvalidDataSource`) [#p6001-invaliddatasource]

The URL is malformed; for instance, it does not use the `prisma://` protocol.

#### `P6002` (`Unauthorized`) [#p6002-unauthorized]

The API Key in the connection string is invalid.

#### `P6003` (`PlanLimitReached`) [#p6003-planlimitreached]

The included usage of the current plan has been exceeded. This can only occur on the [free plan](https://www.prisma.io/pricing).

#### `P6004` (`QueryTimeout`) [#p6004-querytimeout]

The global timeout of Accelerate has been exceeded.

> Also see the [troubleshooting guide](https://www.prisma.io/docs/accelerate/more/troubleshoot#p6004-querytimeout) for more information.

#### `P6005` (`InvalidParameters`) [#p6005-invalidparameters]

The user supplied invalid parameters. Currently only relevant for transaction methods. For example, setting a timeout that is too high.

#### `P6006` (`VersionNotSupported`) [#p6006-versionnotsupported]

The chosen Prisma version is not compatible with Accelerate. This may occur when a user uses an unstable development version that we occasionally prune.

#### `P6008` (`ConnectionError|EngineStartError`) [#p6008-connectionerrorenginestarterror]

The engine failed to start. For example, it couldn't establish a connection to the database.

> Also see the [troubleshooting guide](https://www.prisma.io/docs/accelerate/more/troubleshoot#p6008-connectionerrorenginestarterror) for more information.

#### `P6009` (`ResponseSizeLimitExceeded`) [#p6009-responsesizelimitexceeded]

The global response size limit of Accelerate has been exceeded.

> Also see the [troubleshooting guide](https://www.prisma.io/docs/accelerate/more/troubleshoot#p6009-responsesizelimitexceeded) for more information.

#### `P6010` (`ProjectDisabledError`) [#p6010-projectdisablederror]

Your accelerate project is disabled. Please [enable](https://www.prisma.io/docs/accelerate/getting-started#1-enable-accelerate) it again to use it.

#### `P5011` (`Too Many Requests`) [#p5011-too-many-requests]

This error indicates that the request volume exceeded. Implement a back-off strategy and try again later. For assistance with expected high workloads, contact [support](https://www.prisma.io/docs/console/more/support).

## Related pages

- [`Config API`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference): Complete reference for prisma.config.ts configuration options
- [`Connection URLs`](https://www.prisma.io/docs/orm/v7/reference/connection-urls): Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite
- [`Database Features`](https://www.prisma.io/docs/orm/v7/reference/database-features): Database features supported in Prisma ORM
- [`Environment Variables`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference): Reference for Prisma environment variables
- [`Prisma CLI reference`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference): This page gives an overview of all available Prisma CLI commands, explains their options and shows numerous usage examples

# Prisma CLI reference (Prisma ORM v7) (/docs/orm/v7/reference/prisma-cli-reference)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

This page gives an overview of all available Prisma CLI commands, explains their options and shows numerous usage examples

Location: ORM > v7 > Reference > Prisma CLI reference

This document describes the Prisma CLI commands, arguments, and options.

## Commands [#commands]

### `version` (`-v`) [#version--v]

The `version` command outputs information about your current `prisma` version, platform, and engine binaries.

#### Options [#options]

The `version` command recognizes the following options to modify its behavior:

| Option   | Required | Description                                 |
| -------- | -------- | ------------------------------------------- |
| `--json` | No       | Outputs version information in JSON format. |

#### Examples [#examples]

##### Output version information [#output-version-information]

```bash
prisma version
```

```text no-copy
Environment variables loaded from .env
prisma               : 2.21.0-dev.4
@prisma/client       : 2.21.0-dev.4
Current platform     : windows
Query Engine         : query-engine 2fb8f444d9cdf7c0beee7b041194b42d7a9ce1e6 (at C:\Users\veroh\AppData\Roaming\npm\node_modules\@prisma\cli\query-engine-windows.exe)
Migration Engine     : migration-engine-cli 2fb8f444d9cdf7c0beee7b041194b42d7a9ce1e6 (at C:\Users\veroh\AppData\Roaming\npm\node_modules\@prisma\cli\migration-engine-windows.exe)
Format Binary        : prisma-fmt 60ba6551f29b17d7d6ce479e5733c70d9c00860e (at node_modules\@prisma\engines\prisma-fmt-windows.exe)
Default Engines Hash : 60ba6551f29b17d7d6ce479e5733c70d9c00860e
Studio               : 0.365.0
```

##### Output version information (`-v`) [#output-version-information--v]

```bash
prisma -v
```

```text no-copy
Environment variables loaded from .env
prisma               : 2.21.0-dev.4
@prisma/client       : 2.21.0-dev.4
Current platform     : windows
Query Engine         : query-engine 2fb8f444d9cdf7c0beee7b041194b42d7a9ce1e6 (at C:\Users\veroh\AppData\Roaming\npm\node_modules\@prisma\cli\query-engine-windows.exe)
Migration Engine     : migration-engine-cli 2fb8f444d9cdf7c0beee7b041194b42d7a9ce1e6 (at C:\Users\veroh\AppData\Roaming\npm\node_modules\@prisma\cli\migration-engine-windows.exe)
Format Binary        : prisma-fmt 60ba6551f29b17d7d6ce479e5733c70d9c00860e (at node_modules\@prisma\engines\prisma-fmt-windows.exe)
Default Engines Hash : 60ba6551f29b17d7d6ce479e5733c70d9c00860e
Studio               : 0.365.0
```

##### Output version information as JSON [#output-version-information-as-json]

```bash
prisma version --json
```

```text no-copy
Environment variables loaded from .env
{
  "prisma": "2.21.0-dev.4",
  "@prisma/client": "2.21.0-dev.4",
  "current-platform": "windows",
  "query-engine": "query-engine 60ba6551f29b17d7d6ce479e5733c70d9c00860e (at node_modules\\@prisma\\engines\\query-engine-windows.exe)",
  "migration-engine": "migration-engine-cli 60ba6551f29b17d7d6ce479e5733c70d9c00860e (at node_modules\\@prisma\\engines\\migration-engine-windows.exe)",
  "format-binary": "prisma-fmt 60ba6551f29b17d7d6ce479e5733c70d9c00860e (at node_modules\\@prisma\\engines\\prisma-fmt-windows.exe)",
  "default-engines-hash": "60ba6551f29b17d7d6ce479e5733c70d9c00860e",
  "studio": "0.365.0"
}
```

### `init` [#init]

Bootstraps a fresh Prisma ORM project within the current directory.

The `init` command does not interpret any existing files. Instead, it creates a `prisma` directory containing a bare-bones `schema.prisma` file within your current directory.

By default, the project sets up a [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) instance but you can choose a different database using the `--datasource-provider` option.

#### Arguments [#arguments]

| Argument                 | Required | Description                                                                                                                                                                                                                                       | Default               |
| ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `--datasource-provider`  | No       | Specifies the value for the `provider` field in the `datasource` block. Options are `prisma+postgres`, `sqlite`, `postgresql`, `mysql`, `sqlserver`, `mongodb` and `cockroachdb`.                                                                 | `postgresql`          |
| `--db`                   | No       | Shorthand syntax for `--datasource-provider prisma+postgres`; creates a new [Prisma Postgres](https://www.prisma.io/docs/postgres) instance. Requires authentication in the [PDP Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=orm). |                       |
| `--prompt` (or `--vibe`) | No       | Scaffolds a Prisma schema based on the prompt and deploys it to a fresh Prisma Postgres instance. Requires authentication in the [PDP Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=orm).                  |                       |
| `--url`                  | No       | Define a custom `datasource` url.                                                                                                                                                                                                                 |                       |
| `--generator-provider`   | No       | Define the generator provider to use.                                                                                                                                                                                                             | `prisma-client`       |
| `--preview-feature`      | No       | Define the [Preview features](https://www.prisma.io/docs/orm/v7/reference/preview-features/cli-preview-features) to use. To define multiple Preview features, you have to provide the flag multiple times for each Preview feature. See examples.                           |                       |
| `--output`               | No       | Specifies the [output location for the generated client](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider).                                                                                                            | `../generated/prisma` |
| `--with-model`           | No       | Adds a simple `User` model to the initial Prisma schema. Available since version `5.14.0`.                                                                                                                                                        |                       |

#### Examples [#examples-1]

**Run `prisma init`**

```bash
prisma init
```

```text no-copy wrap
npx prisma init

Initialized Prisma in your project

  prisma/
    schema.prisma
  prisma.config.ts

Next, choose how you want to set up your database:

CONNECT EXISTING DATABASE:
  1. Configure your DATABASE_URL in `prisma.config.ts`
  2. Run `npx prisma db pull` to introspect your database.

CREATE NEW DATABASE:
  Local: npx prisma dev (runs Postgres locally in your terminal)
  Cloud: npx create-db (creates a free Prisma Postgres database)

  Then, define your models in `prisma/schema.prisma` and run `npx prisma migrate dev` to apply your schema.

Learn more: https://pris.ly/getting-started
```

Next, run the `prisma dev` command to interact with your local Prisma Postgres instance (e.g. to run migrations or execute queries).

**Run `prisma init --datasource-provider sqlite`**

```bash
prisma init --datasource-provider sqlite
```

The command output contains helpful information on how to use the generated files and begin using Prisma ORM with your project.

**Run `prisma init --db`**

```bash
prisma init --db
```

```text no-copy wrap
✓ Select an authentication method Google
Authenticating to Prisma Platform via browser.

Visit the following URL in your browser to authenticate:
https://console.prisma.io/auth/cli?state=eyJjb6ll...

Successfully authenticated as amanyoyoyo@gmail.com.
Let's set up your Prisma Postgres database!
✓ Select your region: ap-southeast-1 - Asia Pacific (Singapore)
✓ Enter a project name: My Prisma Project
✓ Success! Your Prisma Postgres database is ready ✅

We found an existing schema.prisma file in your current project directory.

--- Database URL ---

Connect Prisma ORM to your Prisma Postgres database with this URL:

--- Next steps ---

Go to https://pris.ly/ppg-init for detailed instructions.

1. Install the Postgres adapter
npm install @prisma/adapter-pg

...and add it to your Prisma Client instance:

import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

2. Apply migrations
Run the following command to create and apply a migration:
npx prisma migrate dev

3. Manage your data
View and edit your data locally by running this command:
npx prisma studio

...or online in Console:
https://console.prisma.io/cmhyn0uwl0q6903foel16ff31/cmhyn143t074tyLfoezs684ag/cmhyn143t074uylfon8hfre5z/studio

4. Send queries from your app
If you already have an existing app with Prisma ORM, you can now run it and it will send queries against your newly created Prisma Postgres instance.

5. Learn more
For more info, visit the Prisma Postgres docs: https://pris.ly/ppg-docs
```

The command creates a new [Prisma Postgres](https://www.prisma.io/postgres) instance. Note that it requires you to be authenticated with the [PDP Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=orm), If you run it for the first time without being authenticated, the command will open the browser for you to log into Console.

**Run `prisma init --prompt "Simple habit tracker application"`**

```bash
prisma init --prompt "Simple habit tracker application"
```

The command scaffolds a Prisma schema and deploys it to a fresh [Prisma Postgres](https://www.prisma.io/postgres) instance. Note that it requires you to be authenticated with the [PDP Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=orm), If you run it for the first time without being authenticated, the command will open the browser for you to log into Console.

**Run `prisma init --preview-feature`**

```bash
prisma init --preview-feature metrics
```

```prisma
datasource db {
  provider = "postgresql"
}

generator client {
  provider        = "prisma-client"
  previewFeatures = ["metrics"]
}
```

```bash
prisma init --preview-feature view --preview-feature metrics
```

```prisma
datasource db {
  provider = "postgresql"
}

generator client {
  provider        = "prisma-client"
  previewFeatures = ["views", "metrics"]
}
```

#### Generated Assets [#generated-assets]

**`prisma/schema.prisma`**

An initial `schema.prisma` file to define your schema in:

```prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}
```

**`prisma.config.ts`**

A TypeScript configuration file for Prisma that defines your datasource URL and other settings:

```typescript
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

See the [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference) for more details.

**`.env`**

A file to define environment variables for your project:

```bash
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
```

**`.gitignore`**

A file to specify what folders/files git should ignore in your project.

```bash
node_modules
# Keep environment variables out of version control
.env

/generated/prisma
```

**Run `prisma init --url mysql://user:password@localhost:3306/mydb`**

The `init` command with the `--url` argument allows you to specify a custom datasource URL during Prisma initialization, instead of relying on a placeholder database URL:

```bash
prisma init --url mysql://user:password@localhost:3306/mydb
```

#### Generated Assets [#generated-assets-1]

**`prisma/schema.prisma`**

A minimal `schema.prisma` file to define your schema in:

```prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

datasource db {
  provider = "mysql"
}

generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}
```

**`prisma.config.ts`**

A TypeScript configuration file for Prisma with the custom URL:

```typescript
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

**`.env`**

A file to define environment variables for your project:

```
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="mysql://user:password@localhost:3306/mydb"
```

### `generate` [#generate]

The `generate` command generates assets like Prisma Client based on the [`generator`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators) and [`data model`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models) blocks defined in your `prisma/schema.prisma` file.

The `generate` command is most often used to generate Prisma Client with the `prisma-client` generator. This does the following:

1. Inspects the current directory to find a Prisma Schema to process.
2. Generates a customized Prisma Client based on your schema into the output directory specified in the generator block.

#### Prerequisites [#prerequisites]

To use the `generate` command, you must add a generator definition in your `schema.prisma` file. The `prisma-client` generator, used to generate Prisma Client, can be added by including the following in your `schema.prisma` file:

```prisma
generator client {
  provider = "prisma-client"
  output   = "./generated"
}
```

#### Options [#options-1]

| Option              | Required | Description                                                                                                                                                                                                                         | Default |
| ------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `--data-proxy`      | No       | The `generate` command will generate Prisma Client for use with [Prisma Accelerate](https://www.prisma.io/docs/accelerate) prior to Prisma 5.0.0. Mutually exclusive with `--accelerate` and `--no-engine`.                                                   |         |
| `--accelerate`      | No       | The `generate` command will generate Prisma Client for use with [Prisma Accelerate](https://www.prisma.io/docs/accelerate). Mutually exclusive with `--data-proxy` and `--no-engine`. Available in Prisma 5.1.0 and later.                                    |         |
| `--no-engine`       | No       | The `generate` command will generate Prisma Client without an accompanied engine for use with [Prisma Accelerate](https://www.prisma.io/docs/accelerate). Mutually exclusive with `--data-proxy` and `--accelerate`. Available in Prisma ORM 5.2.0 and later. |         |
| `--no-hints`        | No       | The `generate` command will generate Prisma Client without usage hints, surveys or info banners being printed to the terminal. Available in Prisma ORM 5.16.0 and later.                                                            |         |
| `--allow-no-models` | No       | The `generate` command will generate Prisma Client without generating any models.                                                                                                                                                   |         |
| `--watch`           | No       | The `generate` command will continue to watch the `schema.prisma` file and re-generate Prisma Client on file changes.                                                                                                               |         |

> [!WARNING]
> **Deprecation Warning**
> 
> As of Prisma 5.2.0, `--data-proxy` and `--accelerate` are deprecated in favor of `--no-engine` as Prisma Client no longer requires an option to work with Prisma Accelerate. All options are available and work similarly, but we recommend `--no-engine` as it prevents an engine from being downloaded which will greatly impact the size of apps deployed to serverless and edge functions.

#### Arguments [#arguments-1]

| Argument      | Required | Description                                                                                                                                                                                  | Default                                     |   |
| ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | - |
| `--schema`    | No       | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported.                                          | `./schema.prisma`, `./prisma/schema.prisma` |   |
| `--generator` | No       | Specifies which generator to use to generate assets. This option may be provided multiple times to include multiple generators. By default, all generators in the target schema will be run. |                                             |   |

#### Examples [#examples-2]

##### Generate Prisma Client using the default `schema.prisma` path [#generate-prisma-client-using-the-default-schemaprisma-path]

```bash
prisma generate
```

```text no-copy
✔ Generated Prisma Client to ./node_modules/.prisma/client in 61ms

You can now start using Prisma Client in your code:

import { PrismaClient } from '../prisma/generated/client'
// or const { PrismaClient } = require('@prisma/client')

const prisma = new PrismaClient()

Explore the full API: https://pris.ly/d/client
```

##### Generate Prisma Client using a non-default `schema.prisma` path [#generate-prisma-client-using-a-non-default-schemaprisma-path]

```bash
prisma generate --schema=./alternative/schema.prisma
```

##### Continue watching the `schema.prisma` file for changes to automatically re-generate Prisma Client [#continue-watching-the-schemaprisma-file-for-changes-to-automatically-re-generate-prisma-client]

```bash
prisma generate --watch
```

```text no-copy
Watching... /home/prismauser/prisma/prisma-play/prisma/schema.prisma

✔ Generated Prisma Client to ./node_modules/.prisma/client in 45ms
```

##### Run the `generate` command with only a specific generator [#run-the-generate-command-with-only-a-specific-generator]

```bash
prisma generate --generator client
```

##### Run the `generate` command with multiple specific generators [#run-the-generate-command-with-multiple-specific-generators]

```bash
prisma generate --generator client --generator zod_schemas
```

#### Generated Assets [#generated-assets-2]

The `prisma-client` generator creates a customized client for working with your database in a custom output directory specified by the `output` field - you can [customize the output folder](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider).

### `validate` [#validate]

Validates the [Prisma Schema Language](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) of the Prisma schema file.

#### Arguments [#arguments-2]

| Argument   | Required | Description                                                                                                                                         | Default                                     |
| ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `--schema` | No       | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`, `./prisma/schema.prisma` |

#### Examples [#examples-3]

##### Validate a schema without errors [#validate-a-schema-without-errors]

```bash
prisma validate
```

```text no-copy
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
The schema at /absolute/path/prisma/schema.prisma is valid 🚀
```

##### Validate a schema with validation errors [#validate-a-schema-with-validation-errors]

```bash
prisma validate
```

```text no-copy
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Error: Schema validation error - Error (query-engine-node-api library)
Error code: P1012
error: The preview feature "unknownFeatureFlag" is not known. Expected one of: [...]
  */}  schema.prisma:3
   |
 2 |     provider        = "prisma-client"
 3 |     previewFeatures = ["unknownFeatureFlag"]
   |

Validation Error Count: 1
[Context: getDmmf]

Prisma CLI Version : 4.5.0
```

### `format` [#format]

Formats the Prisma schema file, which includes validating, formatting, and persisting the schema.

#### Arguments [#arguments-3]

| Argument   | Required | Description                                                                                                                                         | Default                                     |
| ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `--schema` | No       | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`, `./prisma/schema.prisma` |
| `--check`  | No       | Fails if any files are unformatted. This can be used in CI to detect if the schema is formatted correctly                                           |                                             |

#### Examples [#examples-4]

##### Validate a schema without errors [#validate-a-schema-without-errors-1]

```bash
prisma format
```

```text no-copy
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Formatted prisma/schema.prisma in 116ms �
```

##### Formatting a schema with validation errors [#formatting-a-schema-with-validation-errors]

```bash
prisma format
```

```text no-copy
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Error: Schema validation error - Error (query-engine-node-api library)
Error code: P1012
error: The preview feature "unknownFeatureFlag" is not known. Expected one of: [...]
  */}  schema.prisma:3
   |
 2 |     provider        = "prisma-client"
 3 |     previewFeatures = ["unknownFeatureFlag"]
   |

Validation Error Count: 1
[Context: getDmmf]

Prisma CLI Version : 4.5.0
```

### `debug` [#debug]

Prints information for debugging and bug reports.

> [!NOTE]
> This is available from version 5.6.0 and newer.

#### Arguments [#arguments-4]

| Argument         | Required | Description                                                                                                                                         | Default                                     |
| ---------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `--schema`       | No       | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`, `./prisma/schema.prisma` |
| `--help` / `--h` | No       | Displays the help message                                                                                                                           |                                             |

#### Example [#example]

```bash
prisma debug
```

```text no-copy
-- Prisma schema --
Path: /prisma/schema.prisma

-- Local cache directory for engines files --
Path: /.cache/prisma

-- Environment variables --
When not set, the line is dimmed and no value is displayed.
When set, the line is bold and the value is inside the `` backticks.

For general debugging
 - CI:
 - DEBUG:
 - NODE_ENV:
 - RUST_LOG:
 - RUST_BACKTRACE:
 - NO_COLOR:
 - TERM: `xterm-256color`
 - NODE_TLS_REJECT_UNAUTHORIZED:
 - NO_PROXY:
 - http_proxy:
 - HTTP_PROXY:
 - https_proxy:
 - HTTPS_PROXY:

For more information see our [environment variable documentation](/orm/v7/reference/environment-variables-reference)

For hiding messages
 - PRISMA_DISABLE_WARNINGS:
 - PRISMA_HIDE_PREVIEW_FLAG_WARNINGS:
 - PRISMA_HIDE_UPDATE_MESSAGE:

For downloading engines
 - PRISMA_ENGINES_MIRROR:
 - PRISMA_BINARIES_MIRROR (deprecated):
 - PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING:
 - BINARY_DOWNLOAD_VERSION:

For configuring the Query Engine Type
 - PRISMA_CLI_QUERY_ENGINE_TYPE: (Not supported in Prisma ORM v7)
 - PRISMA_CLIENT_ENGINE_TYPE: (Not supported in Prisma ORM v7)

For custom engines
 - PRISMA_QUERY_ENGINE_BINARY: (Not supported in Prisma ORM v7)
 - PRISMA_QUERY_ENGINE_LIBRARY: (Not supported in Prisma ORM v7)
 - PRISMA_SCHEMA_ENGINE_BINARY:
 - PRISMA_MIGRATION_ENGINE_BINARY:

For the "postinstall" npm hook
 - PRISMA_GENERATE_SKIP_AUTOINSTALL: (Not supported in Prisma ORM v7)
 - PRISMA_SKIP_POSTINSTALL_GENERATE: (Not supported in Prisma ORM v7)
 - PRISMA_GENERATE_IN_POSTINSTALL: (Not supported in Prisma ORM v7)

For "prisma generate"
 - PRISMA_GENERATE_DATAPROXY: (Not supported in Prisma ORM v7)
 - PRISMA_GENERATE_NO_ENGINE: (Not supported in Prisma ORM v7)

For Prisma Client
 - PRISMA_SHOW_ALL_TRACES:
 - PRISMA_CLIENT_NO_RETRY (Binary engine only): (Not supported in Prisma ORM v7)

For Prisma Migrate
 - PRISMA_SCHEMA_DISABLE_ADVISORY_LOCK:
 - PRISMA_MIGRATE_SKIP_GENERATE: (Not supported in Prisma ORM v7)
 - PRISMA_MIGRATE_SKIP_SEED: (Not supported in Prisma ORM v7)

For Prisma Studio
 - BROWSER:

-- Terminal is interactive? --
true

-- CI detected? --
false
```

If you're using an older version of Prisma, you can use this command by running:

  

#### bun

```bash
bunx prisma@prev debug
```

#### pnpm

```bash
pnpm dlx prisma@prev debug
```

#### yarn

```bash
yarn dlx prisma@prev debug
```

#### npm

```bash
npx prisma@prev debug
```

## `dev` [#dev]

The `dev` command starts a [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) database that you can run Prisma ORM commands against. It is useful for development and testing, and lets you switch to [Prisma Postgres](https://www.prisma.io/docs/postgres) in production.

### Arguments [#arguments-5]

| Argument              | Required | Description                                                                                                                                                                                      | Default   |
| --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- |
| `--name` (or `-n`)    | No       | Enables targeting a specific database instance. Learn more about [using different local Prisma Postgres instances](https://www.prisma.io/docs/local-development/postgres#using-different-local-prisma-postgres-instances). | `default` |
| `--port` (or `-p`)    | No       | Main port number the local Prisma Postgres HTTP server will listen on.                                                                                                                           | `51213`   |
| `--db-port` (or `-P`) | No       | Port number the local Prisma Postgres database server will listen on.                                                                                                                            | `51214`   |
| `--shadow-db-port`    | No       | Port number the shadow database server will listen on.                                                                                                                                           | `51215`   |
| `--detach` (or `-d`)  | No       | Run the server in the background.                                                                                                                                                                | `false`   |
| `--debug`             | No       | Enable debug logging.                                                                                                                                                                            | `false`   |

### Examples [#examples-5]

**Run `prisma dev`**

```bash
prisma dev
```

```bash no-copy wrap
$ npx prisma dev
Fetching latest updates for this subcommand...
✔  Great Success! 😉👍

   Your  prisma dev  server default is ready and listening on ports 63567-63569.

╭──────────────────────────────╮
│[q]uit  [h]ttp url  [t]cp urls│
╰──────────────────────────────╯
```

**Run `prisma dev` with a specific name**

  

#### bun

```bash
bunx prisma dev --name="mydbname"
```

#### pnpm

```bash
pnpm prisma dev --name="mydbname"
```

#### yarn

```bash
yarn prisma dev --name="mydbname"
```

#### npm

```bash
npx prisma dev --name="mydbname"
```

This creates a named instance called `mydbname` that you can later start, stop, or manage using the instance management commands.

**Run `prisma dev` in detached mode**

  

#### bun

```bash
bunx prisma dev --detach
```

#### pnpm

```bash
pnpm prisma dev --detach
```

#### yarn

```bash
yarn prisma dev --detach
```

#### npm

```bash
npx prisma dev --detach
```

This runs the server in the background, freeing up your terminal for other commands. Use `prisma dev ls` to see running servers and `prisma dev stop` to stop them.

### `dev start` [#dev-start]

Starts existing [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) instances in the background.

> [!NOTE]
> This command only works with instances that already exist.

  

#### bun

```bash
bunx prisma dev start <glob>
```

#### pnpm

```bash
pnpm prisma dev start <glob>
```

#### yarn

```bash
yarn prisma dev start <glob>
```

#### npm

```bash
npx prisma dev start <glob>
```

`<glob>` is a placeholder for a glob pattern to specify which local Prisma Postgres instances should be started, for example:

  

#### bun

```bash
bunx prisma dev start mydb # starts a DB called `mydb` in the background (only if it already exists)
```

#### pnpm

```bash
pnpm prisma dev start mydb # starts a DB called `mydb` in the background (only if it already exists)
```

#### yarn

```bash
yarn prisma dev start mydb # starts a DB called `mydb` in the background (only if it already exists)
```

#### npm

```bash
npx prisma dev start mydb # starts a DB called `mydb` in the background (only if it already exists)
```

To start all databases that begin with `mydb` (e.g. `mydb-dev` and `mydb-prod`), you can use a glob:

  

#### bun

```bash
bunx prisma dev start mydb* # starts all existing DBs starting with `mydb`
```

#### pnpm

```bash
pnpm prisma dev start mydb* # starts all existing DBs starting with `mydb`
```

#### yarn

```bash
yarn prisma dev start mydb* # starts all existing DBs starting with `mydb`
```

#### npm

```bash
npx prisma dev start mydb* # starts all existing DBs starting with `mydb`
```

This enables background instance management outside of the VS Code extension.

### `dev ls` [#dev-ls]

Lists all available [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) instances:

  

#### bun

```bash
bunx prisma dev ls
```

#### pnpm

```bash
pnpm prisma dev ls
```

#### yarn

```bash
yarn prisma dev ls
```

#### npm

```bash
npx prisma dev ls
```

This command shows all instances on your system with their current status and configuration.

### `dev stop` [#dev-stop]

Stops one or more [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) databases:

  

#### bun

```bash
bunx prisma dev stop <glob>
```

#### pnpm

```bash
pnpm prisma dev stop <glob>
```

#### yarn

```bash
yarn prisma dev stop <glob>
```

#### npm

```bash
npx prisma dev stop <glob>
```

`<glob>` is a placeholder for a glob pattern to specify which local Prisma Postgres instances should be stopped, for example:

  

#### bun

```bash
bunx prisma dev stop mydb # stops a DB called `mydb`
```

#### pnpm

```bash
pnpm prisma dev stop mydb # stops a DB called `mydb`
```

#### yarn

```bash
yarn prisma dev stop mydb # stops a DB called `mydb`
```

#### npm

```bash
npx prisma dev stop mydb # stops a DB called `mydb`
```

To stop all databases that begin with `mydb` (e.g. `mydb-dev` and `mydb-prod`), you can use a glob:

  

#### bun

```bash
bunx prisma dev stop mydb* # stops all DBs starting with `mydb`
```

#### pnpm

```bash
pnpm prisma dev stop mydb* # stops all DBs starting with `mydb`
```

#### yarn

```bash
yarn prisma dev stop mydb* # stops all DBs starting with `mydb`
```

#### npm

```bash
npx prisma dev stop mydb* # stops all DBs starting with `mydb`
```

> [!NOTE]
> The `stop` command is interactive and includes safety prompts to prevent accidental operations.

### `dev rm` [#dev-rm]

Removes the data of one or more [local Prisma Postgres](https://www.prisma.io/docs/local-development/postgres) databases from your file system:

  

#### bun

```bash
bunx prisma dev rm <glob>
```

#### pnpm

```bash
pnpm prisma dev rm <glob>
```

#### yarn

```bash
yarn prisma dev rm <glob>
```

#### npm

```bash
npx prisma dev rm <glob>
```

`<glob>` is a placeholder for a glob pattern to specify which local Prisma Postgres instances should be removed, for example:

  

#### bun

```bash
bunx prisma dev rm mydb # removes a DB called `mydb`
```

#### pnpm

```bash
pnpm prisma dev rm mydb # removes a DB called `mydb`
```

#### yarn

```bash
yarn prisma dev rm mydb # removes a DB called `mydb`
```

#### npm

```bash
npx prisma dev rm mydb # removes a DB called `mydb`
```

To remove all databases that begin with `mydb` (e.g. `mydb-dev` and `mydb-prod`), you can use a glob:

  

#### bun

```bash
bunx prisma dev rm mydb* # removes all DBs starting with `mydb`
```

#### pnpm

```bash
pnpm prisma dev rm mydb* # removes all DBs starting with `mydb`
```

#### yarn

```bash
yarn prisma dev rm mydb* # removes all DBs starting with `mydb`
```

#### npm

```bash
npx prisma dev rm mydb* # removes all DBs starting with `mydb`
```

#### Arguments [#arguments-6]

| Argument  | Required | Description                                                                                                        | Default |
| --------- | -------- | ------------------------------------------------------------------------------------------------------------------ | ------- |
| `--force` | No       | Stops any running servers before removing them. Without this flag, the command will fail if any server is running. | `false` |

> [!NOTE]
> The `rm` command is interactive and includes safety prompts to prevent accidental data loss.

## `db` [#db]

### `db pull` [#db-pull]

The `db pull` command connects to your database and adds Prisma models to your Prisma schema that reflect the current database schema.

> [!WARNING]
> **Warning**: The command will overwrite the current `schema.prisma` file with the new schema. Some manual changes or customization can be lost. Be sure to back up your current `schema.prisma` file (or commit your current state to version control to be able to revert any changes) before running `db pull` if it contains important modifications.

> [!NOTE]
> Introspection with the `db pull` command on the [MongoDB connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb) samples the data instead of reading a schema.

#### Prerequisites [#prerequisites-1]

Before using the `db pull` command, you must configure your database connection in your `prisma.config.ts` file.

For example:

```prisma title="schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

#### Options [#options-2]

| Option    | Required | Description                                                                                                           | Default |
| --------- | -------- | --------------------------------------------------------------------------------------------------------------------- | ------- |
| `--force` | No       | Force overwrite of manual changes made to schema. The generated schema will be based on the introspected schema only. |         |
| `--print` | No       | Prints the created `schema.prisma` to the screen instead of writing it to the filesystem.                             |         |

#### Arguments [#arguments-7]

| Argument   | Required | Description                                                                                                                                         | Default                                     |
| ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `--schema` | No       | Specifies the path to the desired `schema.prisma` file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`, `./prisma/schema.prisma` |

#### Examples [#examples-6]

##### Analyze the database and write its schema to the `schema.prisma` file [#analyze-the-database-and-write-its-schema-to-the-schemaprisma-file]

```bash
prisma db pull
```

```text no-copy
Introspecting based on datasource defined in schema.prisma …

✔ Introspected 2 models and wrote them into schema.prisma in 38ms

Run prisma generate to generate Prisma Client.
```

##### Specify an alternative `schema.prisma` file to read and write to [#specify-an-alternative-schemaprisma-file-to-read-and-write-to]

```bash
prisma db pull --schema=./alternative/schema.prisma
```

```text no-copy
Introspecting based on datasource defined in alternative/schema.prisma …

✔ Introspected 2 models and wrote them into alternative/schema.prisma in 60ms

Run prisma generate to generate Prisma Client.
```

##### Display the generated `schema.prisma` file instead of writing it to the filesystem [#display-the-generated-schemaprisma-file-instead-of-writing-it-to-the-filesystem]

```bash
prisma db pull --print
```

```prisma no-copy
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider = "sqlite"
  url      = "file:./hello-prisma.db"
}

model User {
  email   String    @unique
  name    String?
  user_id Int       @id @default(autoincrement())
  post    Post[]
  profile Profile[]
}

model Post {
  content   String?
  post_id   Int     @id @default(autoincrement())
  title     String
  author    User?   @relation(fields: [author_id], references: [user_id])
  author_id Int?
}

model Profile {
  bio        String?
  profile_id Int     @id @default(autoincrement())
  user       User    @relation(fields: [user_id], references: [user_id])
  user_id    Int     @unique
}
```

### `db push` [#db-push]

The `db push` command pushes the state of your Prisma schema to the database without using migrations. It creates the database if the database does not exist.

This command is a good choice when you do not need to version schema changes, such as during prototyping and local development.

See also:

* [Conceptual overview of `db push` and when to use it over Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema)
* [Schema prototyping with `db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema)

#### Prerequisites [#prerequisites-2]

Before using the `db push` command, you must configure your database connection in your `prisma.config.ts` file.

For example:

```prisma title="schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

#### Options [#options-3]

| Options              | Required | Description                                                                                                                |
| :------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------- |
| `--force-reset`      | No       | Resets the database and then updates the schema - useful if you need to start from scratch due to unexecutable migrations. |
| `--accept-data-loss` | No       | Ignore data loss warnings. This option is required if as a result of making the schema changes, data may be lost.          |
| `--help` / `--h`     | No       | Displays the help message                                                                                                  |

> [!WARNING]
> The `--skip-generate` flag was removed in Prisma v7. `db push` no longer runs `prisma generate` automatically. Run it explicitly if needed.

#### Arguments [#arguments-8]

| Argument   | Required | Description                                                                                                                                       | Default                                          |
| :--------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------- |
| `--schema` | No       | Specifies the path to the desired schema.prisma file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`<br /> `./prisma/schema.prisma` |

#### Examples [#examples-7]

Push the schema:

```bash
prisma db push
```

Push the schema, accepting data loss:

```bash
prisma db push --accept-data-loss
```

Push the schema with a custom schema location:

```bash
prisma db push --schema=/tmp/schema.prisma
```

### `db seed` [#db-seed]

`db seed` changed from Preview to Generally Available (GA) in 3.0.1.

See [Seeding your database](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/seeding)

#### Options [#options-4]

| Options          | Required | Description                                               |
| :--------------- | :------- | :-------------------------------------------------------- |
| `--help` / `--h` | No       | Displays the help message                                 |
| `--`             | No       | Allows the use of custom arguments defined in a seed file |

The `--` argument/ [delimiter](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02)/ double-dash is available from version 4.15.0 or later.

#### Examples [#examples-8]

```bash
prisma db seed
```

### `db execute` [#db-execute]

> [!NOTE]
> The `db execute` command is Generally Available in versions 3.13.0 and later. If you're using a version between 3.9.0 and 3.13.0, it is available behind a `--preview-feature` CLI flag.

> [!WARNING]
> This command is currently not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

This command applies a SQL script to the database without interacting with the Prisma migrations table. The datasource URL configuration is read from the Prisma config file (e.g., `prisma.config.ts`).

The output of the command is connector-specific, and is not meant for returning data, but only to report success or failure.

See also:

* [Migration troubleshooting in production](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing#fixing-failed-migrations-with-migrate-diff-and-db-execute)

#### Prerequisites [#prerequisites-3]

Before using the `db execute` command, you must configure your database connection in your `prisma.config.ts` file.

For example:

```prisma title="schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

Your `prisma.config.ts` file should look like this:

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

#### Options [#options-5]

| Options    | Required | Description                                                           |
| :--------- | :------- | :-------------------------------------------------------------------- |
| `--file`   | Yes\*    | Path to a file. The content will be sent as the script to be executed |
| `--stdin`  | No       | Use the terminal standard input as the script to be executed          |
| `--config` | No       | Custom path to your Prisma config file                                |
| `--help`   | No       | Displays the help message                                             |

\* Either `--file` or `--stdin` is required to provide the script input.

> [!NOTE]
> **Prisma v7 breaking change**: The `--schema` and `--url` options have been removed. Configure your database connection in `prisma.config.ts` instead.

#### Examples [#examples-9]

* Execute the content of a SQL script file using the datasource configured in `prisma.config.ts`:

  ```bash
  prisma db execute --file ./script.sql
  ```

* Execute the SQL script from stdin using the configured datasource:

  ```bash wrap
  echo 'TRUNCATE TABLE dev;' | prisma db execute --stdin
  ```

## Prisma Migrate [#prisma-migrate]

Prisma Migrate changed from Preview to Generally Available (GA) in 2.19.0.

> [!NOTE]
> **Does not apply for MongoDB** <br />
> Instead of `migrate dev` and related commands, [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) is used for [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

### `migrate dev` [#migrate-dev]

**For use in development environments only, requires shadow database**

The `migrate dev` command:

1. Reruns the existing migration history in the [shadow database](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database) in order to detect schema drift (edited or deleted migration file, or a manual changes to the database schema)
2. Applies pending migrations to the shadow database (for example, new migrations created by colleagues)
3. Generates a new migration from any changes you made to the Prisma schema before running `migrate dev`
4. Applies all unapplied migrations to the development database and updates the `_prisma_migrations` table

> [!WARNING]
> This command is not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). Use [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) instead.

> [!NOTE]
> **Prisma v7**: `migrate dev` no longer automatically triggers `prisma generate` or seed scripts. Run `prisma generate` explicitly if needed.

See also:

* [Conceptual overview of Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)
* [Developing with Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)

#### Options [#options-6]

| Option          | Required | Description                                                                                                                                                                                        | Default |
| :-------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
| `--create-only` | No       | Creates a new migration but does not apply it. This also works if you haven't made any changes to your schema (in that case, an empty migration is created). Run `migrate dev` to apply migration. |         |
| `--name` / `-n` | No       | Name the migration (e.g. `prisma migrate dev --name added_job_title`)                                                                                                                              |         |
| `--help` / `-h` | No       | Displays the help message                                                                                                                                                                          |         |

> [!WARNING]
> The `--skip-generate` and `--skip-seed` flags were removed in Prisma v7. `migrate dev` no longer runs `prisma generate` or seeds automatically. Run them explicitly if needed.

> [!NOTE]
> If a [schema drift](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database#detecting-schema-drift) is detected while running `prisma migrate dev` using `--create-only`, you will be prompted to reset your database.

#### Arguments [#arguments-9]

| Argument   | Required | Description                                                                                                                                       | Default                                          |
| :--------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------- |
| `--name`   | No       | The name of the migration. If no name is provided, the CLI will prompt you.                                                                       |                                                  |
| `--schema` | No       | Specifies the path to the desired schema.prisma file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`<br /> `./prisma/schema.prisma` |

#### Examples [#examples-10]

Apply all migrations, then create and apply any new migrations:

```bash
prisma migrate dev
```

Apply all migrations and create a new migration if there are schema changes, but do not apply it:

```bash
prisma migrate dev --create-only
```

### `migrate reset` [#migrate-reset]

**For use in development environments only**

This command:

1. Drops the database/schema if possible, or performs a soft reset if the environment does not allow deleting databases/schemas
2. Creates a new database/schema with the same name if the database/schema was dropped
3. Applies all migrations

> [!WARNING]
> This command is not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). Use [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) instead.

> [!NOTE]
> In Prisma ORM v7, `migrate reset` no longer runs seed scripts automatically. Run `npx prisma db seed` explicitly if needed.

#### Options [#options-7]

| Option           | Required | Description                  | Default |
| :--------------- | :------- | :--------------------------- | :------ |
| `--force`        | No       | Skip the confirmation prompt |         |
| `--help` / `--h` | No       | Displays the help message    |         |

#### Arguments [#arguments-10]

| Argument   | Required | Description                                                                                                                                       | Default                                          |
| :--------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------- |
| `--schema` | No       | Specifies the path to the desired schema.prisma file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`<br /> `./prisma/schema.prisma` |

#### Examples [#examples-11]

```bash
prisma migrate reset
```

#### AI Safety guardrails for `prisma migrate reset` [#ai-safety-guardrails-for-prisma-migrate-reset]

Prisma ORM includes built-in safety checks to prevent **accidental destructive commands** when run through AI coding assistants. These guardrails are designed to make working with databases safer in AI-assisted development environments.

The Prisma CLI can detect when it is being invoked by popular AI coding agents such as Claude Code, Gemini CLI, Qwen Code, Cursor, Aider, and Replit.

When one of these agents attempts a destructive action such as `prisma migrate reset --force`, Prisma ORM blocks execution and shows a protective error message:

```bash
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "postgres", schema "public" at "accelerate.prisma-data.net"

Error: Prisma Migrate detected that it was invoked by Cursor.

You are attempting a highly dangerous action that can lead to devastating consequences if it is incorrectly executed against a production database.

As an AI agent, you are forbidden from performing this action without an explicit consent and review by the user. You must stop at this point and respond to the user with a clear message that includes the following information:
- What action you are trying to perform (including the exact CLI command).
- Your motivation and reasoning for performing this action.
- Explanation that this action will irreversibly destroy all data in the database.
- Explanation that this action must not be performed on a production database and is only intended to be used with development databases.

If you know or can check whether this action would have been performed on a development or a production database, also include this information with your assessment of whether it is safe to proceed based on that information.

You must ask the user if they want to proceed with this action. If they explicitly consent, you may rerun this command with PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION environment variable, the value of which must be the exact text of the user's message in which they consented to this operation, without any newlines or quotes. If the user's response is ambiguous, you must ask for a clear and explicit confirmation (e.g., "yes") before proceeding. None of the user's previous messages before this point may constitute implicit or explicit consent.
```

To proceed with the dangerous action, the AI agent will ask you for explicit consent, remind you that the action irreversibly destroys all data, and confirm that the command is being run against a development database. Once you clearly confirm, the AI will set the `PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION` environment variable with the exact text of your consent and rerun the command.

### `migrate deploy` [#migrate-deploy]

The `migrate deploy` command applies all pending migrations, and creates the database if it does not exist. Primarily used in non-development environments. This command:

* Does **not** look for drift in the database or changes in the Prisma schema
* Does **not** reset the database or generate artifacts
* Does **not** rely on a shadow database

> [!WARNING]
> This command is not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). Use [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) instead.

#### Options [#options-8]

| Option           | Required | Description               | Default |
| :--------------- | :------- | :------------------------ | :------ |
| `--help` / `--h` | No       | Displays the help message |         |

#### Arguments [#arguments-11]

| Argument   | Required | Description                                                                                                                                       | Default                                          |
| :--------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------- |
| `--schema` | No       | Specifies the path to the desired schema.prisma file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`<br /> `./prisma/schema.prisma` |

#### Examples [#examples-12]

```bash
prisma migrate deploy
```

### `migrate resolve` [#migrate-resolve]

The `migrate resolve` command allows you to solve migration history issues in production by marking a failed migration as already applied (supports baselining) or rolled back.

Note that this command can only be used with a failed migration. If you try to use it with a successful migration you will receive an error.

> [!WARNING]
> This command is not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). Use [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) instead.

#### Options [#options-9]

| Option           | Required | Description               | Default |
| :--------------- | :------- | :------------------------ | :------ |
| `--help` / `--h` | No       | Displays the help message |         |

#### Arguments [#arguments-12]

| Argument        | Required | Description                                                                                                                                       | Default                                          |
| :-------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------- |
| `--applied`     | No\*     | Record a specific migration as applied - for example `--applied "20201231000000_add_users_table"`                                                 |                                                  |
| `--rolled-back` | No\*     | Record a specific migration as rolled back - for example `--rolled-back "20201231000000_add_users_table"`                                         | `./schema.prisma`<br /> `./prisma/schema.prisma` |
| `--schema`      | No       | Specifies the path to the desired schema.prisma file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`<br /> `./prisma/schema.prisma` |

You must specify either `--rolled-back` *or* `--applied`.

#### Examples [#examples-13]

```bash
prisma migrate resolve --applied 20201231000000_add_users_table
```

```bash
prisma migrate resolve --rolled-back 20201231000000_add_users_table
```

### `migrate status` [#migrate-status]

The `prisma migrate status` command looks up the migrations in `./prisma/migrations/*` folder and the entries in the `_prisma_migrations` table and compiles information about the state of the migrations in your database.

> [!WARNING]
> This command is not supported on [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). Use [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) instead.

For example:

```
Status
3 migrations found in prisma/migrations

Your local migration history and the migrations table from your database are different:

The last common migration is: 20201127134938_new_migration

The migration have not yet been applied:
20201208100950_test_migration

The migrations from the database are not found locally in prisma/migrations:
20201208100950_new_migration
```

In versions 4.3.0 and later, `prisma migrate status` exits with exit code 1 in the following cases:

* a database connection error occurs
* there are migration files in the `migrations` directory that have not been applied to the database
* the migration history in the `migrations` directory has diverged from the state of the database
* no migration table is found
* failed migrations are found

#### Options [#options-10]

| Option           | Required | Description               | Default |
| :--------------- | :------- | :------------------------ | :------ |
| `--help` / `--h` | No       | Displays the help message |         |

#### Arguments [#arguments-13]

| Argument   | Required | Description                                                                                                                                       | Default                                          |
| :--------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------- |
| `--schema` | No       | Specifies the path to the desired schema.prisma file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`<br /> `./prisma/schema.prisma` |

#### Examples [#examples-14]

```bash
prisma migrate status
```

### `migrate diff` [#migrate-diff]

> [!NOTE]
> This command is only partially supported for [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb). See the command options below for details.

This command compares two database schema sources and outputs a description of a migration taking the first to the state of the second.

The output can be given either as a human-readable summary (the default) or an executable script.

> [!WARNING]
> The `migrate diff` command can only compare database features that are [supported by Prisma](https://www.prisma.io/docs/orm/v7/reference/database-features). If two databases differ only in unsupported features, such as views or triggers, then `migrate diff` will not show any difference between them.

The format of the command is:

```bash
prisma migrate diff --from-... <source1> --to-... <source2>
```

where the `--from-...` and `--to-...` options are selected based on the type of database schema source. The supported types of sources are:

* live databases
* migration histories
* Prisma schema data models
* an empty schema

Both schema sources must use the same database provider. For example, a diff comparing a PostgreSQL data source with a SQLite data source is not supported.

See also:

* [Migration troubleshooting in production](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing#fixing-failed-migrations-with-migrate-diff-and-db-execute)

#### Prerequisites [#prerequisites-4]

Before using the `migrate diff` command, if you are using `--from-config-datasource` or `--to-config-datasource`, you must configure your database connection in your `prisma.config.ts` file.

For example:

```prisma title="schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

#### Options [#options-11]

> [!NOTE]
> **Prisma v7 breaking change**: The `--from-url`, `--to-url`, `--from-schema-datasource`, `--to-schema-datasource`, and `--shadow-database-url` options have been removed. Use `--from-config-datasource` and `--to-config-datasource` instead, which read the database URL from `prisma.config.ts`.

One of the following `--from-...` options is required:

| Options                    | Description                                                    | Notes                    |
| :------------------------- | :------------------------------------------------------------- | :----------------------- |
| `--from-empty`             | Assume that the data model you are migrating from is empty     |                          |
| `--from-schema`            | Path to a Prisma schema file, uses the data model for the diff |                          |
| `--from-migrations`        | Path to the Prisma Migrate migrations directory                | Not supported in MongoDB |
| `--from-config-datasource` | Use the datasource from the Prisma config file                 | Prisma v7+               |

One of the following `--to-...` options is required:

| Options                  | Description                                                    | Notes                    |
| :----------------------- | :------------------------------------------------------------- | :----------------------- |
| `--to-empty`             | Assume that the data model you are migrating to is empty       |                          |
| `--to-schema`            | Path to a Prisma schema file, uses the data model for the diff |                          |
| `--to-migrations`        | Path to the Prisma Migrate migrations directory                | Not supported in MongoDB |
| `--to-config-datasource` | Use the datasource from the Prisma config file                 | Prisma v7+               |

Other options:

| Options          | Required | Description                                                                                                                                       | Notes                                                                       |
| :--------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------- |
| `--script`       | No       | Outputs a SQL script instead of the default human-readable summary                                                                                | Not supported in MongoDB                                                    |
| `-o`, `--output` | No       | Writes to a file instead of stdout                                                                                                                | Available since [5.12.1](https://github.com/prisma/orm/releases/tag/5.12.1) |
| `--exit-code`    | No       | Change the exit code behavior to signal if the diff is empty or not (Empty: 0, Error: 1, Not empty: 2). Default behavior is Success: 0, Error: 1. |                                                                             |
| `--config`       | No       | Custom path to your Prisma config file                                                                                                            |                                                                             |
| `--help`         | No       | Displays the help message                                                                                                                         |                                                                             |

#### Examples [#examples-15]

* Compare the configured database to a Prisma schema (e.g., to roll forward after a migration failed):

  ```bash
  prisma migrate diff \
    --from-config-datasource \
    --to-schema=next_datamodel.prisma \
    --script
  ```

* Compare a Prisma schema to the configured database:

  ```bash
  prisma migrate diff \
    --from-schema=schema.prisma \
    --to-config-datasource \
    --script
  ```

* Compare the migrations directory to the configured database (e.g., to generate a migration for a hotfix already applied on production):

  ```bash
  prisma migrate diff \
    --from-migrations ./migrations \
    --to-config-datasource \
    --script
  ```

* Pipe the output to `prisma db execute`:

  ```bash
  prisma migrate diff \
    --from-config-datasource \
    --to-schema=schema.prisma \
    --script | prisma db execute --stdin
  ```

* Detect if both sources are in sync (exits with code 2 if changes are detected):

  ```bash
  prisma migrate diff \
    --exit-code \
    --from-config-datasource \
    --to-schema=schema.prisma
  ```

## Prisma Data Platform [#prisma-data-platform]

### `platform` [#platform-early-access]

The `platform` command is in [Early Access](https://www.prisma.io/docs/console/more/feature-maturity#early-access). It provides access to the Prisma Data Platform through the Prisma CLI starting in version `5.10.0` or later.

* **Authentication**:
  * `platform auth login`: Opens a browser window for login or account creation.
  * `platform auth logout`: Logs out of the platform.
  * `platform auth show`: Displays information about the currently authenticated user.
* **Workspace Management**:
  * `platform workspace show`: Lists all workspaces available to your account.
* **Project Management**:
  * `platform project show`: Lists all projects within the specified workspace.
  * `platform project create`: Creates a new project within the specified workspace.
  * `platform project delete`: Deletes the specified project.
* **Environment Management**:
  * `platform environment show`: Lists all environments for the specified project.
  * `platform environment create`: Creates a new environment within the specified project.
  * `platform environment delete`: Deletes the specified environment.
* **API Key Management**:
  * `platform apikey show`: Lists all API keys for the specified environment.
  * `platform apikey create`: Creates a new API key for the specified environment.
  * `platform apikey delete`: Deletes the specified API key.
* **Prisma Accelerate**:
  * `platform accelerate enable`: Enables Prisma Accelerate for the specified environment.
  * `platform accelerate disable`: Disables Prisma Accelerate for the specified environment.

You can find the complete list of available commands with the arguments in the [`prisma platform` command reference](https://www.prisma.io/docs/cli/v7/console).

## Studio [#studio]

### `studio` [#studio-1]

The `studio` command allows you to interact with and manage your data interactively. It does this by starting a local web server with a web app configured with your project's data schema and records.

Prisma ORM v7 ships a new version of Prisma Studio.

> [!NOTE]
> Supported databases
> 
> Prisma Studio currently supports PostgreSQL, MySQL, and SQLite. Support for CockroachDB and MongoDB is not available yet but may be added in future releases.
> 
> For detailed database support information, including SQLite requirements, see [Databases supported by Prisma Studio](https://www.prisma.io/docs/studio#getting-started).

#### Prerequisites [#prerequisites-5]

Before using the `studio` command, you must configure your database connection in your `prisma.config.ts` file.

For example:

```prisma title="schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

#### Options [#options-12]

The `studio` command recognizes the following options:

| Option            | Required | Description                                                          | Default                  |
| ----------------- | -------- | -------------------------------------------------------------------- | ------------------------ |
| `-b`, `--browser` | No       | The browser to auto-open Studio in.                                  | `<your-default-browser>` |
| `-h`, `--help`    | No       | Show all available options and exit                                  |                          |
| `-p`, `--port`    | No       | The port number to start Studio on.                                  | 5555                     |
| `--config`        | No       | Custom path to your Prisma config file                               |                          |
| `--url`           | No       | Database connection string (overrides the one in your Prisma config) |                          |

#### Arguments [#arguments-14]

| Argument   | Required | Description                                                                                                                                       | Default                                          |
| :--------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------- |
| `--schema` | No       | Specifies the path to the desired schema.prisma file to be processed instead of the default path. Both absolute and relative paths are supported. | `./schema.prisma`<br /> `./prisma/schema.prisma` |

#### Examples [#examples-16]

#### Start Studio on the default port and open a new browser tab to it [#start-studio-on-the-default-port-and-open-a-new-browser-tab-to-it]

```bash
prisma studio
```

#### Start Studio on a different port and open a new browser tab to it [#start-studio-on-a-different-port-and-open-a-new-browser-tab-to-it]

```bash
prisma studio --port 7777
```

#### Start Studio and open a Firefox tab to it [#start-studio-and-open-a-firefox-tab-to-it]

```bash
prisma studio --browser firefox
```

#### Start Studio without opening a new browser tab to it [#start-studio-without-opening-a-new-browser-tab-to-it]

```bash
prisma studio --browser none
```

#### Start Studio with a custom Prisma config file [#start-studio-with-a-custom-prisma-config-file]

```bash
prisma studio --config=./prisma.config.ts
```

#### Start Studio with a direct database connection string [#start-studio-with-a-direct-database-connection-string]

```bash
prisma studio --url="postgresql://user:password@localhost:5432/dbname"
```

## Using a HTTP proxy for the CLI [#using-a-http-proxy-for-the-cli]

Prisma CLI supports [custom HTTP proxies](https://github.com/prisma/orm/issues/506). This is particularly relevant when being behind a corporate firewall.

To activate usage of the proxy, provide either of the following environment variables:

* [`HTTP_PROXY`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference#http_proxy) or `http_proxy`: Proxy URL for http traffic, for example `http://localhost:8080`
* [`HTTPS_PROXY`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference#https_proxy) or `https_proxy`: Proxy URL for https traffic, for example `https://localhost:8080`

## `npx create-db` [#npx-create-db]

The [`create-db`](https://create-db.prisma.io/) command provisions a temporary [Prisma Postgres](https://www.prisma.io/docs/postgres) database with a single command. This is a standalone utility that can be invoked using `npx`. It's ideal for quickly testing, prototyping, or integrating with Prisma Postgres.

You can run the following variants:

| Command                      | Description                                   |
| ---------------------------- | --------------------------------------------- |
| `npx create-db@latest`       | Creates a temporary Prisma Postgres database. |
| `npx create-pg@latest`       | Alias for `npx create-db`.                    |
| `npx create-postgres@latest` | Alias for `npx create-db`.                    |

Each database created with these commands:

* Is available for **24 hours** by default.
* Can be **claimed for free** to make it permanent using the URL displayed in the CLI output.

For full usage details, options (such as `--region` and `--interactive`), and examples, see the [`npx create-db` reference](https://www.prisma.io/docs/postgres/npx-create-db).

## Related pages

- [`Config API`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference): Complete reference for prisma.config.ts configuration options
- [`Connection URLs`](https://www.prisma.io/docs/orm/v7/reference/connection-urls): Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite
- [`Database Features`](https://www.prisma.io/docs/orm/v7/reference/database-features): Database features supported in Prisma ORM
- [`Environment Variables`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference): Reference for Prisma environment variables
- [`Error Reference`](https://www.prisma.io/docs/orm/v7/reference/error-reference): Prisma Client, Migrate, and Introspection error codes

# Prisma Client API (Prisma ORM v7) (/docs/orm/v7/reference/prisma-client-reference)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Complete API reference for Prisma Client queries and operations

Location: ORM > v7 > Reference > Prisma Client API

The Prisma Client API reference documentation is based on the following schema:

```prisma
model User {
  id           Int              @id @default(autoincrement())
  name         String?
  email        String           @unique
  profileViews Int              @default(0)
  role         Role             @default(USER)
  coinflips    Boolean[]
  posts        Post[]
  city         String
  country      String
  profile      ExtendedProfile?
  pets         Json
}

model ExtendedProfile {
  id     Int     @id @default(autoincrement())
  userId Int?    @unique
  bio    String?
  User   User?   @relation(fields: [userId], references: [id])
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  published Boolean @default(true)
  author    User    @relation(fields: [authorId], references: [id])
  authorId  Int
  comments  Json
  views     Int     @default(0)
  likes     Int     @default(0)
}

enum Role {
  USER
  ADMIN
}
```

All example generated types (such as `UserSelect` and `UserWhereUniqueInput`) are based on the `User` model.

## `PrismaClient` [#prismaclient]

This section describes the `PrismaClient` constructor and its parameters.

### `adapter` [#adapter]

Specifies a [driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers#driver-adapters) for database connections. Required unless using [`accelerateUrl`](#accelerateurl).

#### Example [#example]

```ts
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../prisma/generated/client";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
const prisma = new PrismaClient({ adapter });
```

### `accelerateUrl` [#accelerateurl]

Specifies a [Prisma Accelerate](https://www.prisma.io/accelerate) URL for remote query execution. Required unless using [`adapter`](#adapter).

#### Example [#example-1]

```ts
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient({
  accelerateUrl: process.env.ACCELERATE_URL,
});
```

### `log` [#log]

Determines the type and level of logging. See also: [Logging](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/logging)

#### Options [#options]

| Option                   | Example                                                                  |
| ------------------------ | ------------------------------------------------------------------------ |
| Array of log levels      | `[ "info", "query" ]`                                                    |
| Array of log definitions | `[ { level: "info", emit: "event" }, { level: "warn", emit: "stdout" }]` |

##### Log levels [#log-levels]

| Name    | Example                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `query` | Logs all queries run by Prisma. <br /><br /> For relational databases this logs all SQL queries. Example: <br />`prisma:query SELECT "public"."User"."id", "public"."User"."email" FROM "public"."User" WHERE ("public"."User"."id") IN (SELECT "t0"."id" FROM "public"."User" AS "t0" INNER JOIN "public"."Post" AS "j0" ON ("j0"."authorId") = ("t0"."id") WHERE ("j0"."views" > $1 AND "t0"."id" IS NOT NULL)) OFFSET $2` <br /><br /> For MongoDB this logs queries using the [`mongosh` shell](https://www.mongodb.com/docs/mongodb-shell/#mongodb-binary-bin.mongosh) format. Example: <br /> `prisma:query db.User.deleteMany({ _id: ( $in: [ “6221ce49f756b0721fc00542”, ], }, })` |
| `info`  | Example: <br />`prisma:info Started http server on http://127.0.0.1:58471`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `warn`  | Warnings.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `error` | Errors.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |

##### Emit formats [#emit-formats]

| Name     | Description                                                   |
| -------- | ------------------------------------------------------------- |
| `stdout` | See: [stdout](https://en.wikipedia.org/wiki/Standard_streams) |
| `event`  | Raises an event that you can subscribe to.                    |

##### Event types [#event-types]

The `query` event type:

```ts title="index.d.ts"
export type QueryEvent = {
  timestamp: Date;
  query: string; // Query sent to the database
  params: string; // Query parameters
  duration: number; // Time elapsed (in milliseconds) between client issuing query and database responding - not only time taken to run query
  target: string;
};
```

Note that for MongoDB, the `params` and `duration` fields will be undefined.

All other log level event types:

```ts title="index.d.ts"
export type LogEvent = {
  timestamp: Date;
  message: string;
  target: string;
};
```

#### Examples [#examples]

##### Log `query` and `info` to `stdout` [#log-query-and-info-to-stdout]

```ts highlight=3;normal;
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient({ log: ["query", "info"] });

async function main() {
  const countUsers = await prisma.user.count({});
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

```bash
prisma:info  Starting a postgresql pool with 13 connections.
prisma:info  Started http server
prisma:query SELECT COUNT(*) FROM (SELECT "public"."User"."id" FROM "public"."User" WHERE 1=1 ORDER BY "public"."User"."coinflips" ASC OFFSET $1) AS "sub"
```

##### Log a `query` event to console [#log-a-query-event-to-console]

```ts
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient({
  log: [{ level: "query", emit: "event" }],
});

prisma.$on("query", (e) => {
  console.log(e);
});

async function main() {
  const countUsers = await prisma.user.count({});
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

```json
{
  timestamp: 2020-11-17T10:32:10.898Z,
  query: 'SELECT COUNT(*) FROM (SELECT "public"."User"."id" FROM "public"."User" WHERE 1=1 OFFSET $1) AS "sub"',
  params: '[0]',
  duration: 5,
  target: 'quaint::connector::metrics'
}
```

##### Log `info`, `warn`, and `error` events to console [#log-info-warn-and-error-events-to-console]

```ts
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient({
  log: [
    { level: "warn", emit: "event" },
    { level: "info", emit: "event" },
    { level: "error", emit: "event" },
  ],
});

prisma.$on("warn", (e) => {
  console.log(e);
});

prisma.$on("info", (e) => {
  console.log(e);
});

prisma.$on("error", (e) => {
  console.log(e);
});

async function main() {
  const countUsers = await prisma.user.count({});
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

```json
{
  timestamp: 2020-11-17T10:33:24.592Z,
  message: 'Starting a postgresql pool with 13 connections.',
  target: 'quaint::pooled'
}
{
  timestamp: 2020-11-17T10:33:24.637Z,
  message: 'Started http server',
  target: 'query_engine::server'
}
```

### `errorFormat` [#errorformat]

Determines the level and formatting of errors returned by Prisma Client.

#### Error formats [#error-formats]

| Name                  | Description                                    |
| --------------------- | ---------------------------------------------- |
| `undefined`           | If it's not defined, the default is colorless. |
| `pretty`              | Enables pretty error formatting.               |
| `colorless` (default) | Enables colorless error formatting.            |
| `minimal`             | Enables minimal error formatting.              |

#### Examples [#examples-1]

##### No error formatting [#no-error-formatting]

```ts
const prisma = new PrismaClient({
  // Defaults to colorless
});
```

##### `pretty` error formatting [#pretty-error-formatting]

```ts
const prisma = new PrismaClient({
  errorFormat: "pretty",
});
```

##### `colorless` error formatting [#colorless-error-formatting]

```ts
const prisma = new PrismaClient({
  errorFormat: "colorless",
});
```

##### `minimal` error formatting [#minimal-error-formatting]

```ts
const prisma = new PrismaClient({
  errorFormat: "minimal",
});
```

### `comments` [#comments]

Defines an array of [SQL commenter plugins](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/sql-comments) that add metadata to your SQL queries as comments. This is useful for observability, debugging, and correlating queries with application traces.

#### Options [#options-1]

| Option                 | Description                                                                                                 |
| ---------------------- | ----------------------------------------------------------------------------------------------------------- |
| `SqlCommenterPlugin[]` | An array of SQL commenter plugin functions. Each plugin receives query context and returns key-value pairs. |

#### First-party plugins [#first-party-plugins]

| Package                              | Description                                                                      |
| ------------------------------------ | -------------------------------------------------------------------------------- |
| `@prisma/sqlcommenter-query-tags`    | Adds arbitrary tags to queries within an async context using `AsyncLocalStorage` |
| `@prisma/sqlcommenter-trace-context` | Adds W3C Trace Context (`traceparent`) headers for distributed tracing           |

#### Examples [#examples-2]

##### Using first-party plugins [#using-first-party-plugins]

```ts
import { PrismaClient } from "../prisma/generated/client";
import { PrismaPg } from "@prisma/adapter-pg";
import { queryTags } from "@prisma/sqlcommenter-query-tags";
import { traceContext } from "@prisma/sqlcommenter-trace-context";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });

const prisma = new PrismaClient({
  adapter,
  comments: [queryTags(), traceContext()],
});
```

##### Creating a custom plugin [#creating-a-custom-plugin]

```ts
import { PrismaClient } from "../prisma/generated/client";
import { PrismaPg } from "@prisma/adapter-pg";
import type { SqlCommenterPlugin } from "@prisma/sqlcommenter";

const appPlugin: SqlCommenterPlugin = (context) => ({
  application: "my-app",
  environment: process.env.NODE_ENV ?? "development",
  model: context.query.modelName,
  action: context.query.action,
});

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });

const prisma = new PrismaClient({
  adapter,
  comments: [appPlugin],
});
```

This produces SQL queries with comments like:

```sql
SELECT "id", "name" FROM "User" /*action='findMany',application='my-app',environment='production',model='User'*/
```

For more details, see [SQL comments](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/sql-comments).

### `transactionOptions` [#transactionoptions]

Sets default [transaction options](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#transaction-isolation-level) globally.

#### Remarks [#remarks]

* The transaction levels can be overridden on a per-transaction level.

#### Options [#options-2]

| Option           | Description                                                                                                                                                                                                                                                 |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `maxWait`        | The maximum amount of time Prisma Client will wait to acquire a transaction from the database. The default value is 2 seconds.                                                                                                                              |
| `timeout`        | The maximum amount of time the interactive transaction can run before being canceled and rolled back. The default value is 5 seconds.                                                                                                                       |
| `isolationLevel` | Sets the [transaction isolation level](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#transaction-isolation-level). By default this is set to the value currently configured in your database. The available levels can vary depending on the database you use. |

#### Example [#example-2]

```ts
const prisma = new PrismaClient({
  transactionOptions: {
    isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
    maxWait: 5000, // default: 2000
    timeout: 10000, // default: 5000
  },
});
```

## Model queries [#model-queries]

Use model queries to perform CRUD operations on your models. See also: [CRUD](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud)

### `findUnique()` [#findunique]

`findUnique()` query lets you retrieve a single database record:

* By *ID*
* By a *unique* attribute

#### Remarks [#remarks-1]

* Prisma Client's dataloader [automatically batches `findUnique()` queries](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance#using-findunique-with-the-fluent-api) with the same `select` and `where` parameters.
* If you want the query to throw an error if the record is not found, then consider using [`findUniqueOrThrow`](#finduniqueorthrow) instead.
* You cannot use [filter conditions](#filter-conditions-and-operators) (e.g. `equals`, `contains`, `not`) to filter fields of the [JSON](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#json) data type. Using filter conditions will likely result in a `null` response for that field.

#### Options [#options-3]

| Name                   | Example type (`User`)    | Required | Description                                                                                                                                                                                               |
| ---------------------- | ------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `where`                | `UserWhereUniqueInput`   | **Yes**  | Wraps all fields of a model so that a record can be selected (learn more about how to [filter on non-unique fields with `UserWhereUniqueInput`](#filter-on-non-unique-fields-with-userwhereuniqueinput)). |
| `select`               | `XOR<UserSelect, null>`  | No       | [Specifies which properties to include](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields) on the returned object.                                                                                              |
| `include`              | `XOR<UserInclude, null>` | No       | [Specifies which relations should be eagerly loaded](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) on the returned object.                                                                              |
| `omit`                 | `XOR<UserOmit, null>`    | No       | Specifies which properties to exclude on the returned object. Excludes specified fields from the result                                                                                                   |
| `relationLoadStrategy` | `'join'` or `'query'`    | No       | **Default: `join`**. [Load strategy](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview) for relations. Requires `relationJoins` preview feature.                            |

#### Return type [#return-type]

| Return type               | Example                    | Description                                                     |
| ------------------------- | -------------------------- | --------------------------------------------------------------- |
| JavaScript object (typed) | `User`                     |                                                                 |
| JavaScript object (plain) | `{ title: "Hello world" }` | Use `select` and `include` to determine which fields to return. |
| `null`                    | `null`                     | Record not found                                                |

#### Examples [#examples-3]

##### Get the `User` record with an `id` of `42` [#get-the-user-record-with-an-id-of-42]

```ts
const result = await prisma.user.findUnique({
  where: {
    id: 42,
  },
});
```

##### Get the `User` record with an `email` of `alice@prisma.io` [#get-the-user-record-with-an-email-of-aliceprismaio]

```ts
const result = await prisma.user.findUnique({
  where: {
    email: "alice@prisma.io",
  },
});
```

##### Get the `User` record with `firstName` of `Alice` and `lastName` of `Smith` (`@@unique`) [#get-the-user-record-with-firstname-of-alice-and-lastname-of-smith-unique]

**Expand for example User model with a @@unique block**

```prisma
model User {
  firstName String
  lastName  String

  @@unique(fields: [firstName, lastName], name: "fullname")
}
```

```ts
const result = await prisma.user.findUnique({
  where: {
    fullname: {
      // name property of @@unique attribute - default is firstname_lastname
      firstName: "Alice",
      lastName: "Smith",
    },
  },
});
```

##### Get the `User` record with `firstName` of `Alice` and `lastName` of `Smith` (`@@id`) [#get-the-user-record-with-firstname-of-alice-and-lastname-of-smith-id]

**Expand for example User model with an @@id block**

```prisma
model User {
  firstName String
  lastName  String

  @@id([firstName, lastName])
}
```

```ts
const result = await prisma.user.findUnique({
  where: {
    firstName_lastName: {
      firstName: "Alice",
      lastName: "Smith",
    },
  },
});
```

### `findUniqueOrThrow()` [#finduniqueorthrow]

`findUniqueOrThrow()` retrieves a single record in the same way as [`findUnique()`](#findunique). However, if the query does not find the requested record, it throws a `PrismaClientKnownRequestError`.

Here's an example of its usage:

```ts
await prisma.user.findUniqueOrThrow({
  where: { id: 1 },
});
```

`findUniqueOrThrow()` differs from `findUnique()` as follows:

* Its return type is non-nullable. For example, `post.findUnique()` can return `post` or `null`, but `post.findUniqueOrThrow()` always returns `post`.
* It is not compatible with sequential operations in the [`$transaction` API](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#the-transaction-api). If the query throws a `PrismaClientKnownRequestError`, then the API will not roll back any operations in the array of calls. As a workaround, you can use interactive transactions with the `$transaction` API, as follows:

  ```ts
   $transaction(async (prisma) => {
     await prisma.model.create({ data: { ... });
     await prisma.model.findUniqueOrThrow();
   })
  ```

### `findFirst()` [#findfirst]

`findFirst` returns the first record in a list that matches your criteria.

#### Remarks [#remarks-2]

* If you want the query to throw an error if the record is not found, then consider using [`findFirstOrThrow`](#findfirstorthrow) instead.

#### Options [#options-4]

| Name                   | Example type (`User`)                                 | Required | Description                                                                                                                                                                    |
| ---------------------- | ----------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `select`               | `XOR<UserSelect, null>`                               | No       | [Specifies which properties to include](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields) on the returned object.                                                                   |
| `include`              | `XOR<UserInclude, null>`                              | No       | [Specifies which relations should be eagerly loaded](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) on the returned object.                                                   |
| `omit`                 | `XOR<UserOmit, null>`                                 | No       | Specifies which properties to exclude on the returned object. Excludes specified fields from the result.                                                                       |
| `relationLoadStrategy` | `'join'` or `'query'`                                 | No       | **Default: `join`**. [Load strategy](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview) for relations. Requires `relationJoins` preview feature. |
| `where`                | `UserWhereInput`                                      | No       | Wraps *all* model fields in a type so that the list can be filtered by any property.                                                                                           |
| `orderBy`              | `XOR<Enumerable<UserOrderByInput>, UserOrderByInput>` | No       | Lets you order the returned list by any property.                                                                                                                              |

#### Return type [#return-type-1]

| Return type               | Example                    | Description                                                     |
| ------------------------- | -------------------------- | --------------------------------------------------------------- |
| JavaScript object (typed) | `User`                     | Specifies which properties to include on the returned object.   |
| JavaScript object (plain) | `{ title: "Hello world" }` | Use `select` and `include` to determine which fields to return. |
| `null`                    | `null`                     | Record not found                                                |

#### Remarks [#remarks-3]

* `findFirst` calls `findMany` behind the scenes and accepts the same query options.
* Passing in a negative `take` value when you use a `findFirst` query reverses the order of the list.

#### Examples [#examples-4]

See [Filter conditions and operators](#filter-conditions-and-operators) for examples of how to filter results.

##### Get the first `User` record where the `name` is `Alice` [#get-the-first-user-record-where-the-name-is-alice]

```ts
const user = await prisma.user.findFirst({
  where: { name: "Alice" },
});
```

##### Get the first `Post` record where the `title` starts with `A test`, reverse the list with `take` [#get-the-first-post-record-where-the-title-starts-with-a-test-reverse-the-list-with-take]

```ts
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient({});

async function main() {
  const a = await prisma.post.create({
    data: {
      title: "A test 1",
    },
  });

  const b = await prisma.post.create({
    data: {
      title: "A test 2",
    },
  });

  const c = await prisma.post.findFirst({
    where: {
      title: {
        startsWith: "A test",
      },
    },
    orderBy: {
      title: "asc",
    },
    take: -1, // Reverse the list
  });
}

main();
```

### `findFirstOrThrow()` [#findfirstorthrow]

`findFirstOrThrow()` retrieves a single data record in the same way as [`findFirst()`](#findfirst). However, if the query does not find a record, it throws a `PrismaClientKnownRequestError`.

`findFirstOrThrow()` differs from `findFirst()` as follows:

* Its return type is non-nullable. For example, `post.findFirst()` can return `post` or `null`, but `post.findFirstOrThrow` always returns `post`.
* It is not compatible with sequential operations in the [`$transaction` API](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#the-transaction-api). If the query returns `PrismaClientKnownRequestError`, then the API will not roll back any operations in the array of calls. As a workaround, you can use interactive transactions with the `$transaction` API, as follows:

  ```ts
  prisma.$transaction(async (tx) => {
    await tx.model.create({ data: { ... });
    await tx.model.findFirstOrThrow();
  })
  ```

### `findMany()` [#findmany]

`findMany` returns a list of records.

#### Options [#options-5]

| Name                   | Type                                                          | Required | Description                                                                                                                                                                                               |
| ---------------------- | ------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `select`               | `XOR<PostSelect, null>`                                       | No       | [Specifies which properties to include](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields) on the returned object.                                                                                              |
| `include`              | `XOR<PostInclude, null>`                                      | No       | [Specifies which relations should be eagerly loaded](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) on the returned object.                                                                              |
| `omit`                 | `XOR<PostOmit, null>`                                         | No       | Specifies which properties to exclude on the returned object. Excludes specified fields from the result                                                                                                   |
| `relationLoadStrategy` | `'join'` or `'query'`                                         | No       | **Default: `join`**. [Load strategy](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview) for relations. Requires `relationJoins` preview feature.                            |
| `where`                | `UserWhereInput`                                              | No       | Wraps *all* model fields in a type so that the list can be filtered by any property.                                                                                                                      |
| `orderBy`              | `XOR<Enumerable<PostOrder`<br />`ByInput>, PostOrderByInput>` | No       | Lets you order the returned list by any property.                                                                                                                                                         |
| `cursor`               | `UserWhereUniqueInput`                                        | No       | Specifies the position for the list (the value typically specifies an `id` or another unique value).                                                                                                      |
| `take`                 | `number`                                                      | No       | Specifies how many objects should be returned in the list (as seen from the *beginning* (positive value) or *end* (negative value) **either** of the list **or** from the `cursor` position if mentioned) |
| `skip`                 | `number`                                                      | No       | Specifies how many of the returned objects in the list should be skipped.                                                                                                                                 |
| `distinct`             | `Enumerable<UserDistinctFieldEnum>`                           | No       | Lets you filter out duplicate rows by a specific field - for example, return only distinct `Post` titles.                                                                                                 |

#### Return type [#return-type-2]

| Return type                     | Example                      | Description                                                     |
| ------------------------------- | ---------------------------- | --------------------------------------------------------------- |
| JavaScript array object (typed) | `User[]`                     |                                                                 |
| JavaScript array object (plain) | `[{ title: "Hello world" }]` | Use `select` and `include` to determine which fields to return. |
| Empty array                     | `[]`                         | No matching records found.                                      |

#### Examples [#examples-5]

See [Filter conditions and operators](#filter-conditions-and-operators) for examples of how to filter results.

##### Get all `User` records where the `name` is `Alice` [#get-all-user-records-where-the-name-is-alice]

```ts
const user = await prisma.user.findMany({
  where: { name: "Alice" },
});
```

### `create()` [#create]

`create` creates a new database record.

#### Options [#options-6]

| Name                   | Type                                                     | Required | Description                                                                                                                                                                                                                                                                   |
| ---------------------- | -------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`                 | `XOR<UserCreateInput,` <br />`UserUncheckedCreateInput>` | **Yes**  | Wraps all the model fields in a type so that they can be provided when creating new records. It also includes relation fields which lets you perform (transactional) nested inserts. Fields that are marked as optional or have default values in the datamodel are optional. |
| [`select`](#select)    | `XOR<UserSelect, null>`                                  | No       | [Specifies which properties to include](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields) on the returned object.                                                                                                                                                                  |
| [`include`](#include)  | `XOR<UserInclude, null>`                                 | No       | [Specifies which relations should be eagerly loaded](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) on the returned object.                                                                                                                                                  |
| [`omit`](#omit)        | `XOR<UserOmit, null>`                                    | No       | Specifies which properties to exclude on the returned object. Excludes specified fields from the result                                                                                                                                                                       |
| `relationLoadStrategy` | `'join'` or `'query'`                                    | No       | **Default: `join`**. [Load strategy](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview) for relations. Requires `relationJoins` preview feature.                                                                                                |

#### Return type [#return-type-3]

| Return type               | Example                        | Description                                                     |
| ------------------------- | ------------------------------ | --------------------------------------------------------------- |
| JavaScript object (typed) | `User`                         |                                                                 |
| JavaScript object (plain) | `{ name: "Alice Wonderland" }` | Use `select` and `include` to determine which fields to return. |

#### Remarks [#remarks-4]

* You can also perform a nested [`create`](#create) - for example, add a `User` and two `Post` records at the same time.

#### Examples [#examples-6]

##### Create a single new record with the only required field `email` [#create-a-single-new-record-with-the-only-required-field-email]

```ts
const user = await prisma.user.create({
  data: { email: "alice@prisma.io" },
});
```

##### Create multiple new records [#create-multiple-new-records]

In most cases, you can carry out batch inserts with the [`createMany()`](#createmany) or [`createManyAndReturn()`](#createmanyandreturn) queries. However, [there are scenarios where `create()` is the best option to insert multiple records](#remarks-11).

The following example results in **two** `INSERT` statements:

```ts
import { Prisma, PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient({ log: ["query"] });

async function main() {
  let users: Prisma.UserCreateInput[] = [
    {
      email: "ariana@prisma.io",
      name: "Ari",
      profileViews: 20,
      coinflips: [true, false, false],
      role: "ADMIN",
    },
    {
      email: "elsa@prisma.io",
      name: "Elsa",
      profileViews: 20,
      coinflips: [true, false, false],
      role: "ADMIN",
    },
  ];

  await Promise.all(
    users.map(async (user) => {
      await prisma.user.create({
        data: user,
      });
    }),
  );
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

```sql
prisma:query BEGIN
prisma:query INSERT INTO "public"."User" ("name","email","profileViews","role","coinflips") VALUES ($1,$2,$3,$4,$5) RETURNING "public"."User"."id"
prisma:query SELECT "public"."User"."id", "public"."User"."name", "public"."User"."email", "public"."User"."profileViews", "public"."User"."role", "public"."User"."coinflips" FROM "public"."User" WHERE "public"."User"."id" = $1 LIMIT $2 OFFSET $3
prisma:query INSERT INTO "public"."User" ("name","email","profileViews","role","coinflips") VALUES ($1,$2,$3,$4,$5) RETURNING "public"."User"."id"
prisma:query COMMIT
prisma:query SELECT "public"."User"."id", "public"."User"."name", "public"."User"."email", "public"."User"."profileViews", "public"."User"."role", "public"."User"."coinflips" FROM "public"."User" WHERE "public"."User"."id" = $1 LIMIT $2 OFFSET $3
prisma:query COMMIT
```

### `update()` [#update]

`update` updates an existing database record.

#### Options [#options-7]

| Name                   | Type                                                   | Required | Description                                                                                                                                                                                               |
| ---------------------- | ------------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`                 | `XOR<UserUpdateInput`<br />`UserUncheckedUpdateInput>` | **Yes**  | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional.                 |
| `where`                | `UserWhereUniqueInput`                                 | **Yes**  | Wraps all fields of a model so that a record can be selected (learn more about how to [filter on non-unique fields with `UserWhereUniqueInput`](#filter-on-non-unique-fields-with-userwhereuniqueinput)). |
| [`select`](#select)    | `XOR<UserSelect, null>`                                | No       | [Specifies which properties to include](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields) on the returned object.                                                                                              |
| [`include`](#include)  | `XOR<UserInclude, null>`                               | No       | [Specifies which relations should be eagerly loaded](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) on the returned object.                                                                              |
| [`omit`](#omit)        | `XOR<UserOmit, null>`                                  | No       | Specifies which properties to exclude on the returned object. Excludes specified fields from the result.                                                                                                  |
| `relationLoadStrategy` | `'join'` or `'query'`                                  | No       | **Default: `join`**. [Load strategy](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview) for relations. Requires `relationJoins` preview feature.                            |

#### Return type [#return-type-4]

| Return type                                    | Example                        | Description                                                                                                   |
| ---------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| JavaScript object (typed)                      | `User`                         |                                                                                                               |
| JavaScript object (plain)                      | `{ name: "Alice Wonderland" }` | Use `select` and `include` to determine which fields to return.                                               |
| `PrismaClientKnownRequestError` (code `P2025`) |                                | Thrown if the record to update does not exist. See [Error reference](https://www.prisma.io/docs/orm/v7/reference/error-reference#p2025) |

#### Remarks [#remarks-5]

* To perform arithmetic operations on update (add, subtract, multiply, divide), use [atomic updates](#atomic-number-operations) to prevent race conditions.
* You can also perform a nested [`update`](#update-1) - for example, update a user and that user's posts at the same time.

#### Examples [#examples-7]

##### Update the `email` of the `User` record with `id` of `1` to `alice@prisma.io` [#update-the-email-of-the-user-record-with-id-of-1-to-aliceprismaio]

```ts
const user = await prisma.user.update({
  where: { id: 1 },
  data: { email: "alice@prisma.io" },
});
```

### `upsert()` [#upsert]

> [!NOTE]
> This section covers the usage of the `upsert()` operation. To learn about using [nested upsert queries](#upsert-1) within `update()`, reference the linked documentation.

`upsert` does the following:

* If an existing database record satisfies the `where` condition, it updates that record
* If no database record satisfies the `where` condition, it creates a new database record

#### Options [#options-8]

| Name                   | Type                                                    | Required | Description                                                                                                                                                                                                                                                                |
| ---------------------- | ------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `create`               | `XOR<UserCreateInput,`<br />`UserUncheckedCreateInput>` | **Yes**  | Wraps all the fields of the model so that they can be provided when creating new records. It also includes relation fields which lets you perform (transactional) nested inserts. Fields that are marked as optional or have default values in the datamodel are optional. |
| `update`               | `XOR<UserUpdateInput,`<br />`UserUncheckedUpdateInput>` | **Yes**  | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional.                                                                                  |
| `where`                | `UserWhereUniqueInput`                                  | **Yes**  | Wraps all fields of a model so that a record can be selected (learn more about how to [filter on non-unique fields with `UserWhereUniqueInput`](#filter-on-non-unique-fields-with-userwhereuniqueinput)).                                                                  |
| [`select`](#select)    | `XOR<UserSelect, null>`                                 | No       | [Specifies which properties to include](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields) on the returned object.                                                                                                                                                               |
| [`include`](#include)  | `XOR<UserInclude, null>`                                | No       | [Specifies which relations should be eagerly loaded](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) on the returned object.                                                                                                                                               |
| [`omit`](#omit)        | `XOR<UserOmit, null>`                                   | No       | Specifies which properties to exclude on the returned object. Excludes specified fields from the result                                                                                                                                                                    |
| `relationLoadStrategy` | `'join'` or `'query'`                                   | No       | **Default: `join`**. [Load strategy](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview) for relations. Requires `relationJoins` preview feature.                                                                                             |

#### Return type [#return-type-5]

| Return type               | Example                        | Description                                                     |
| ------------------------- | ------------------------------ | --------------------------------------------------------------- |
| JavaScript object (typed) | `User`                         |                                                                 |
| JavaScript object (plain) | `{ name: "Alice Wonderland" }` | Use `select` and `include` to determine which fields to return. |

#### Remarks [#remarks-6]

* To perform arithmetic operations on update (add, subtract, multiply, divide), use [atomic updates](#atomic-number-operations) to prevent race conditions.
* If two or more upsert operations happen at the same time and the record doesn't already exist, then a race condition might happen. As a result, one or more of the upsert operations might throw a unique key constraint error. Your application code can catch this error and retry the operation. Learn more about [unique key constraint errors on upserts](#unique-key-constraint-errors-on-upserts).
* Prisma ORM hands over upsert queries to the database where possible. Learn more about [database upserts](#database-upserts).

#### Examples [#examples-8]

##### Update (if exists) or create a new `User` record with an `email` of `alice@prisma.io` [#update-if-exists-or-create-a-new-user-record-with-an-email-of-aliceprismaio]

```ts
const user = await prisma.user.upsert({
  where: { id: 1 },
  update: { email: "alice@prisma.io" },
  create: { email: "alice@prisma.io" },
});
```

#### Unique key constraint errors on upserts [#unique-key-constraint-errors-on-upserts]

##### Problem [#problem]

If multiple upsert operations happen at the same time and the record doesn't already exist, then one or more of the operations might return a [unique key constraint error](https://www.prisma.io/docs/orm/v7/reference/error-reference#p2002).

##### Cause [#cause]

When Prisma Client does an upsert, it first checks whether that record already exists in the database. To make this check, Prisma Client performs a read operation with the `where` clause from the upsert operation. This has two possible outcomes, as follows:

* If the record does not exist, then Prisma Client creates that record.
* If the record exists, then Prisma Client updates it.

When your application tries to perform two or more concurrent upsert operations, then a race condition might happen where two or more operations do not find the record and therefore try to create that record. In this situation, one of the operations successfully creates the new record but the other operations fail and return a unique key constraint error.

##### Solution [#solution]

Handle the P2002 error in your application code. When it occurs, retry the upsert operation to update the row.

#### Database upserts [#database-upserts]

Where possible, Prisma Client hands over an `upsert` query to the database. This is called a *database upsert*.

Database upserts have the following advantages:

* They are faster than upserts handled by Prisma Client
* [Unique key constraint errors](#unique-key-constraint-errors-on-upserts) cannot happen

Prisma Client uses a database upsert automatically when [specific criteria](#database-upsert-query-criteria) are met. When these criteria are not met, Prisma Client handles the `upsert`.

To use a database upsert, Prisma Client sends the SQL construction [`INSERT ... ON CONFLICT SET .. WHERE`](https://www.prisma.io/dataguide/postgresql/inserting-and-modifying-data/insert-on-conflict) to the database.

##### Database upsert prerequisites [#database-upsert-prerequisites]

Prisma Client uses database upserts with CockroachDB, PostgreSQL, or SQLite data sources.

##### Database upsert query criteria [#database-upsert-query-criteria]

Prisma Client uses a database upsert for an `upsert` query when the query meets the following criteria:

* There are no nested queries in the `upsert`'s `create` and `update` [options](#options-7)
* The query does *not* include a selection that uses a [nested read](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-reads)
* The query modifies only one model
* There is only one unique field in the `upsert`'s `where` option
* The unique field in the `where` option and the unique field in the `create` option have the same value

If your query does not meet these criteria, then Prisma Client handles the upsert itself.

##### Database upsert examples [#database-upsert-examples]

The following examples use this schema:

```prisma
model User {
  id           Int    @id
  profileViews Int
  userName     String @unique
  email        String

  @@unique([id, profileViews])
}
```

The following `upsert` query meets all of the criteria, so Prisma Client uses a database upsert.

```ts
prisma.user.upsert({
  where: {
    userName: "Alice",
  },
  create: {
    id: 1,
    profileViews: 1,
    userName: "Alice",
    email: "alice@prisma.io",
  },
  update: {
    email: "updated@example.com",
  },
});
```

In this situation, Prisma uses the following SQL query:

```sql
INSERT INTO "public"."User" ("id","profileViews","userName","email") VALUES ($1,$2,$3,$4)
ON CONFLICT ("userName") DO UPDATE
SET "email" = $5 WHERE ("public"."User"."userName" = $6 AND 1=1) RETURNING "public"."User"."id", "public"."User"."profileViews", "public"."User"."userName", "public"."User"."email"
```

The following query has multiple unique values in the `where` clause, so Prisma Client does *not* use a database upsert:

```ts
prisma.User.upsert({
  where: {
    userName: "Alice",
    profileViews: 1,
    id: 1,
  },
  create: {
    id: 1,
    profileViews: 1,
    userName: "Alice",
    email: "alice@prisma.io",
  },
  update: {
    email: "updated@example.com",
  },
});
```

In the following query, the values for `userName` in the `where` and `create` options are different, so Prisma Client does *not* use a database upsert.

```ts
prisma.User.upsert({
  where: {
    userName: "Alice",
  },
  create: {
    id: 1,
    profileViews: 1,
    userName: "AliceS",
    email: "alice@prisma.io",
  },
  update: {
    email: "updated@example.com",
  },
});
```

In the following query, the selection on the `title` field in `posts` is a nested read, so Prisma Client does *not* use a database upsert.

```ts
prisma.user.upsert({
  select: {
    email: true,
    id: true,
    posts: {
      select: {
        title: true,
      },
    },
  },
  where: {
    userName: "Alice",
  },

  create: {
    id: 1,
    profileViews: 1,
    userName: "Alice",
    email: "alice@prisma.io",
  },
  update: {
    email: "updated@example.com",
  },
});
```

### `delete()` [#delete]

`delete` deletes an existing database record. You can delete a record:

* By *ID*
* By a *unique* attribute

To delete records that match a certain criteria, use [`deleteMany`](#deletemany) with a filter.

#### Options [#options-9]

| Name                   | Type                     | Required | Description                                                                                                                                                                                               |
| ---------------------- | ------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `where`                | `UserWhereUniqueInput`   | **Yes**  | Wraps all fields of a model so that a record can be selected (learn more about how to [filter on non-unique fields with `UserWhereUniqueInput`](#filter-on-non-unique-fields-with-userwhereuniqueinput)). |
| [`select`](#select)    | `XOR<UserSelect, null>`  | No       | [Specifies which properties to include](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields) on the returned object.                                                                                              |
| [`include`](#include)  | `XOR<UserInclude, null>` | No       | [Specifies which relations should be eagerly loaded](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) on the returned object.                                                                              |
| [`omit`](#omit)        | `XOR<UserOmit, null>`    | No       | Specifies which properties to exclude on the returned object. Excludes specified fields from the result                                                                                                   |
| `relationLoadStrategy` | `'join'` or `'query'`    | No       | **Default: `join`**. [Load strategy](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview) for relations. Requires `relationJoins` preview feature.                            |

#### Return type [#return-type-6]

| Return type                                    | Example                        | Description                                                                                                   |
| ---------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| JavaScript object (typed)                      | `User`                         | The `User` record that was deleted.                                                                           |
| JavaScript object (plain)                      | `{ name: "Alice Wonderland" }` | Data from the `User` record that was deleted. Use `select` and `include` to determine which fields to return. |
| `PrismaClientKnownRequestError` (code `P2025`) |                                | Thrown if the record to delete does not exist. See [Error reference](https://www.prisma.io/docs/orm/v7/reference/error-reference#p2025) |

#### Remarks [#remarks-7]

* To delete multiple records based on some criteria (for example, all `User` records with a `prisma.io` email address, use `deleteMany`)

#### Examples [#examples-9]

##### Delete the `User` record with an `id` of `1` [#delete-the-user-record-with-an-id-of-1]

```ts
const user = await prisma.user.delete({
  where: { id: 1 },
});
```

##### Delete the `User` record where `email` equals `elsa@prisma.io` [#delete-the-user-record-where-email-equals-elsaprismaio]

The following query deletes a specific user record and uses `select` to return the `name` and `email` of the deleted user:

```ts
const deleteUser = await prisma.user.delete({
  where: {
    email: "elsa@prisma.io",
  },
  select: {
    email: true,
    name: true,
  },
});
```

```json
{ "email": "elsa@prisma.io", "name": "Elsa" }
```

### `createMany()` [#createmany]

`createMany` creates multiple records in a transaction.

#### Options [#options-10]

| Name              | Type                              | Required | Description                                                                                                                                                                                                                                             |
| ----------------- | --------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`            | `Enumerable<UserCreateManyInput>` | **Yes**  | Wraps all the model fields in a type so that they can be provided when creating new records. Fields that are marked as optional or have default values in the datamodel are optional.                                                                   |
| `skipDuplicates?` | `boolean`                         | No       | Do not insert records with unique fields or ID fields that already exist. Only supported by databases that support [`ON CONFLICT DO NOTHING`](https://www.postgresql.org/docs/9.5/sql-insert.html#SQL-ON-CONFLICT). This excludes MongoDB and SQLServer |

#### Return type [#return-type-7]

| Return type    | Example        | Description                               |
| -------------- | -------------- | ----------------------------------------- |
| `BatchPayload` | `{ count: 3 }` | A count of the number of records created. |

#### Remarks [#remarks-8]

* `createMany()` is supported by SQLite.
* The `skipDuplicates` option is not supported by MongoDB, SQLServer, or SQLite.
* You **cannot** create or connect relations by using nested `create`, `createMany`, `connect`, `connectOrCreate` queries inside a top-level `createMany()` query. See here for a [workaround](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#using-nested-createmany).
* You can use a nested [`createMany`](#createmany-1) query inside an [`update()`](#update) or [`create()`](#create) query - for example, add a `User` and two `Post` records with a nested `createMany` at the same time.

#### Examples [#examples-10]

##### Create several new users [#create-several-new-users]

```ts
const users = await prisma.user.createMany({
  data: [
    { name: "Sonali", email: "sonali@prisma.io" },
    { name: "Alex", email: "alex@prisma.io" },
  ],
});
```

### `createManyAndReturn()` [#createmanyandreturn]

`createManyAndReturn` creates multiple records and returns the resulting objects. Supported for PostgreSQL, CockroachDB, and SQLite.

#### Options [#options-11]

| Name                  | Type                              | Required | Description                                                                                                                                                                                                                                             |
| --------------------- | --------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`                | `Enumerable<UserCreateManyInput>` | **Yes**  | Wraps all the model fields in a type so that they can be provided when creating new records. Fields that are marked as optional or have default values in the datamodel are optional.                                                                   |
| [`select`](#select)   | `XOR<UserSelect, null>`           | No       | [Specifies which properties to include](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields) on the returned objects.                                                                                                                                           |
| [`omit`](#omit)       | `XOR<UserOmit, null>`             | No       | Specifies which properties to exclude on the returned objects. Excludes specified fields from the result. Mutually exclusive with `select`.                                                                                                             |
| [`include`](#include) | `XOR<UserInclude, null>`          | No       | [Specifies which relations should be eagerly loaded](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) on the returned objects.                                                                                                                           |
| `skipDuplicates?`     | `boolean`                         | No       | Do not insert records with unique fields or ID fields that already exist. Only supported by databases that support [`ON CONFLICT DO NOTHING`](https://www.postgresql.org/docs/9.5/sql-insert.html#SQL-ON-CONFLICT). This excludes MongoDB and SQLServer |

#### Remarks [#remarks-9]

* The `skipDuplicates` option is not supported by SQLite.
* Note that the order of elements returned by `createManyAndReturn` is not guaranteed.
* You **cannot** create or connect relations by using nested `create`, `createMany`, `connect`, `connectOrCreate` queries inside a top-level `createManyAndReturn()` query. See here for a [workaround](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#using-nested-createmany).
* When relations are included via `include`, a separate query is generated per relation.
* `relationLoadStrategy: join` is not supported.

#### Return type [#return-type-8]

| Return type                     | Example                | Description                                                             |
| ------------------------------- | ---------------------- | ----------------------------------------------------------------------- |
| JavaScript array object (typed) | `User[]`               |                                                                         |
| JavaScript array object (plain) | `[{ name: "Sonali" }]` | Use `select`, `omit` and `include` to determine which fields to return. |

#### Examples [#examples-11]

##### Create and return several new users [#create-and-return-several-new-users]

```ts
const users = await prisma.user.createManyAndReturn({
  data: [
    { name: "Sonali", email: "sonali@prisma.io" },
    { name: "Alex", email: "alex@prisma.io" },
  ],
});
```

```json
[
  { "id": 0, "name": "Sonali", "email": "sonali@prisma.io", "profileViews": 0 },
  { "id": 1, "name": "Alex", "email": "alex@prisma.io", "profileViews": 0 }
]
```

### `updateMany()` [#updatemany]

`updateMany` updates a batch of existing database records in bulk and returns the number of updated records.

#### Options [#options-12]

| Name    | Type                                                                    | Required | Description                                                                                                                                                                                         |
| ------- | ----------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`  | `XOR<UserUpdateManyMutationInput,`<br />`UserUncheckedUpdateManyInput>` | **Yes**  | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional on `data`. |
| `where` | `UserWhereInput`                                                        | No       | Wraps *all* fields of a model so that the list can be filtered by any property. If you do not filter the list, all records will be updated.                                                         |
| `limit` | `number`                                                                | No       | Limits the number of records to update.                                                                                                                                                             |

#### Return type [#return-type-9]

| Return type    | Example        | Description                   |
| -------------- | -------------- | ----------------------------- |
| `BatchPayload` | `{ count: 4 }` | The count of updated records. |

```ts
export type BatchPayload = {
  count: number;
};
```

#### Examples [#examples-12]

##### Update all `User` records where the `name` is `Alice` to `ALICE` [#update-all-user-records-where-the-name-is-alice-to-alice]

```ts
const updatedUserCount = await prisma.user.updateMany({
  where: { name: "Alice" },
  data: { name: "ALICE" },
});
```

##### Update all `User` records where the `email` contains `prisma.io` and at least one related `Post` has more than 10 likes [#update-all-user-records-where-the-email-contains-prismaio-and-at-least-one-related-post-has-more-than-10-likes]

```ts
const updatedUserCount = await prisma.user.updateMany({
  where: {
    email: {
      contains: "prisma.io",
    },
    posts: {
      some: {
        likes: {
          gt: 10,
        },
      },
    },
  },
  data: {
    role: "USER",
  },
});
```

##### Update `User` records where the `email` contains `prisma.io`, but limit to 5 records updated. [#update-user-records-where-the-email-contains-prismaio-but-limit-to-5-records-updated]

```ts
const updatedUserCount = await prisma.user.updateMany({
  where: {
    email: {
      contains: "prisma.io",
    },
  },
  data: {
    role: "USER",
  },
  limit: 5,
});
```

### `updateManyAndReturn()` [#updatemanyandreturn]

`updateManyAndReturn` updates multiple records and returns the resulting objects. Supported for PostgreSQL, CockroachDB, and SQLite.

#### Options [#options-13]

| Name    | Type                                                                    | Required | Description                                                                                                                                                                                         |
| ------- | ----------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`  | `XOR<UserUpdateManyMutationInput,`<br />`UserUncheckedUpdateManyInput>` | **Yes**  | Wraps all the fields of the model so that they can be provided when updating an existing record. Fields that are marked as optional or have default values in the datamodel are optional on `data`. |
| `where` | `UserWhereInput`                                                        | No       | Wraps *all* fields of a model so that the list can be filtered by any property. If you do not filter the list, all records will be updated.                                                         |

#### Return type [#return-type-10]

| Return type                     | Example                | Description                                                             |
| ------------------------------- | ---------------------- | ----------------------------------------------------------------------- |
| JavaScript array object (typed) | `User[]`               |                                                                         |
| JavaScript array object (plain) | `[{ name: "Sonali" }]` | Use `select`, `omit` and `include` to determine which fields to return. |

#### Examples [#examples-13]

##### Update and return multiple users [#update-and-return-multiple-users]

```ts
const users = await prisma.user.updateManyAndReturn({
  where: {
    email: {
      contains: "prisma.io",
    },
  },
  data: {
    role: "ADMIN",
  },
});
```

```json
[
  { "id": 0, "name": "Sonali", "email": "sonali@prisma.io", "role": "ADMIN", "profileViews": 0 },
  { "id": 1, "name": "Alex", "email": "alex@prisma.io", "role": "ADMIN", "profileViews": 0 }
]
```

### `deleteMany()` [#deletemany]

`deleteMany` deletes multiple records in a transaction.

#### Options [#options-14]

| Name    | Type             | Required | Description                                                                  |
| ------- | ---------------- | -------- | ---------------------------------------------------------------------------- |
| `where` | `UserWhereInput` | No       | Wraps *all* fields of a model so that the list can be filtered by any field. |
| `limit` | `Int`            | No       | Limits the number of records deleted.                                        |

#### Return type [#return-type-11]

| Return type    | Example        | Description                   |
| -------------- | -------------- | ----------------------------- |
| `BatchPayload` | `{ count: 4 }` | The count of deleted records. |

```ts
export type BatchPayload = {
  count: number;
};
```

#### Examples [#examples-14]

##### Delete all `User` records [#delete-all-user-records]

```ts
const deletedUserCount = await prisma.user.deleteMany({});
```

##### Delete all `User` records where the `name` is `Alice` [#delete-all-user-records-where-the-name-is-alice]

```ts
const deletedUserCount = await prisma.user.deleteMany({
  where: { name: "Alice" },
});
```

##### Delete all `User` records where the `email` contains `prisma.io`, but limit to 5 records deleted. [#delete-all-user-records-where-the-email-contains-prismaio-but-limit-to-5-records-deleted]

```ts
const deletedUserCount = await prisma.user.deleteMany({
  where: {
    email: {
      contains: "prisma.io",
    },
  },
  limit: 5,
});
```

See [Filter conditions and operators](#filter-conditions-and-operators) for examples of how to filter the records to delete.

### `count()` [#count]

#### Options [#options-15]

| Name      | Type                                                          | Required | Description                                                                                                                                                                                               |
| --------- | ------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `where`   | `UserWhereInput`                                              | No       | Wraps *all* model fields in a type so that the list can be filtered by any property.                                                                                                                      |
| `orderBy` | `XOR<Enumerable<PostOrder`<br />`ByInput>, PostOrderByInput>` | No       | Lets you order the returned list by any property.                                                                                                                                                         |
| `cursor`  | `UserWhereUniqueInput`                                        | No       | Specifies the position for the list (the value typically specifies an `id` or another unique value).                                                                                                      |
| `take`    | `number`                                                      | No       | Specifies how many objects should be returned in the list (as seen from the *beginning* (positive value) or *end* (negative value) **either** of the list **or** from the `cursor` position if mentioned) |
| `skip`    | `number`                                                      | No       | Specifies how many of the returned objects in the list should be skipped.                                                                                                                                 |

#### Return type [#return-type-12]

| Return type                    | Example                  | Description                   |
| ------------------------------ | ------------------------ | ----------------------------- |
| `number`                       | `29`                     | The count of records.         |
| `UserCountAggregateOutputType` | `{ _all: 27, name: 10 }` | Returned if `select` is used. |

#### Examples [#examples-15]

##### Count all `User` records [#count-all-user-records]

```ts
const result = await prisma.user.count();
```

##### Count all `User` records with at least one published `Post` [#count-all-user-records-with-at-least-one-published-post]

```ts
const result = await prisma.user.count({
  where: {
    post: {
      some: {
        published: true,
      },
    },
  },
});
```

##### Use `select` to perform three separate counts [#use-select-to-perform-three-separate-counts]

The following query returns:

* A count of all records (`_all`)
* A count of all records with non-`null` `name` fields
* A count of all records with non-`null` `city` fields

```ts
const c = await prisma.user.count({
  select: {
    _all: true,
    city: true,
    name: true,
  },
});
```

### `aggregate()` [#aggregate]

See also: [Aggregation, grouping, and summarizing](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#aggregate)

#### Options [#options-16]

| Name      | Type                                                         | Required | Description                                                                                                                                                                                               |
| --------- | ------------------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `where`   | `UserWhereInput`                                             | No       | Wraps *all* model fields in a type so that the list can be filtered by any property.                                                                                                                      |
| `orderBy` | `XOR<Enumerable<UserOrderByInput>,`<br />`UserOrderByInput>` | No       | Lets you order the returned list by any property.                                                                                                                                                         |
| `cursor`  | `UserWhereUniqueInput`                                       | No       | Specifies the position for the list (the value typically specifies an `id` or another unique value).                                                                                                      |
| `take`    | `number`                                                     | No       | Specifies how many objects should be returned in the list (as seen from the *beginning* (positive value) or *end* (negative value) **either** of the list **or** from the `cursor` position if mentioned) |
| `skip`    | `number`                                                     | No       | Specifies how many of the returned objects in the list should be skipped.                                                                                                                                 |
| `_count`  | `true`                                                       | No       | Returns a count of matching records or non-`null` fields.                                                                                                                                                 |
| `_avg`    | `UserAvgAggregateInputType`                                  | No       | Returns an average of all values of the specified field.                                                                                                                                                  |
| `_sum`    | `UserSumAggregateInputType`                                  | No       | Returns the sum of all values of the specified field.                                                                                                                                                     |
| `_min`    | `UserMinAggregateInputType`                                  | No       | Returns the smallest available value of the specified field.                                                                                                                                              |
| `_max`    | `UserMaxAggregateInputType`                                  | No       | Returns the largest available value of the specified field.                                                                                                                                               |

#### Examples [#examples-16]

##### Return `_min`, `_max`, and `_count` of `profileViews` of all `User` records [#return-_min-_max-and-_count-of-profileviews-of-all-user-records]

```ts
const minMaxAge = await prisma.user.aggregate({
  _count: {
    _all: true,
  },
  _max: {
    profileViews: true,
  },
  _min: {
    profileViews: true,
  },
});
```

```json
{
  _count: { _all: 29 },
  _max: { profileViews: 90 },
  _min: { profileViews: 0 }
}
```

##### Return `_sum` of all `profileViews` for all `User` records [#return-_sum-of-all-profileviews-for-all-user-records]

```ts
const setValue = await prisma.user.aggregate({
  _sum: {
    profileViews: true,
  },
});
```

```json
{
  "_sum": {
    "profileViews": 9493
  }
}
```

### `groupBy()` [#groupby]

See also: [Aggregation, grouping, and summarizing](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#group-by)

#### Options [#options-17]

| Name      | Type                                                         | Required | Description                                                                                                                                                                                               |
| --------- | ------------------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `where`   | `UserWhereInput`                                             | No       | Wraps *all* model fields in a type so that the list can be filtered by any property.                                                                                                                      |
| `orderBy` | `XOR<Enumerable<UserOrderByInput>,`<br />`UserOrderByInput>` | No       | Lets you order the returned list by any property that is also present in `by`.                                                                                                                            |
| `by`      | `Array<UserScalarFieldEnum>` \| `string`                     | No       | Specifies the field or combination of fields to group records by.                                                                                                                                         |
| `having`  | `UserScalarWhereWithAggregatesInput`                         | No       | Allows you to filter groups by an aggregate value - for example, only return groups *having* an average age less than 50.                                                                                 |
| `take`    | `number`                                                     | No       | Specifies how many objects should be returned in the list (as seen from the *beginning* (positive value) or *end* (negative value) **either** of the list **or** from the `cursor` position if mentioned) |
| `skip`    | `number`                                                     | No       | Specifies how many of the returned objects in the list should be skipped.                                                                                                                                 |
| `_count`  | `true` \| `UserCountAggregateInputType`                      | No       | Returns a count of matching records or non-`null` fields.                                                                                                                                                 |
| `_avg`    | `UserAvgAggregateInputType`                                  | No       | Returns an average of all values of the specified field.                                                                                                                                                  |
| `_sum`    | `UserSumAggregateInputType`                                  | No       | Returns the sum of all values of the specified field.                                                                                                                                                     |
| `_min`    | `UserMinAggregateInputType`                                  | No       | Returns the smallest available value of the specified field.                                                                                                                                              |
| `_max`    | `UserMaxAggregateInputType`                                  | No       | Returns the largest available value of the specified field.                                                                                                                                               |

#### Examples [#examples-17]

##### Group by `country`/`city` where the average `profileViews` is greater than `200`, and return the `_sum` of `profileViews` for each group [#group-by-countrycity-where-the-average-profileviews-is-greater-than-200-and-return-the-_sum-of-profileviews-for-each-group]

The query also returns a count of `_all` records in each group, and all records with non-`null` `city` field values in each group.

```ts
const groupUsers = await prisma.user.groupBy({
  by: ["country", "city"],
  _count: {
    _all: true,
    city: true,
  },
  _sum: {
    profileViews: true,
  },
  orderBy: {
    country: "desc",
  },
  having: {
    profileViews: {
      _avg: {
        gt: 200,
      },
    },
  },
});
```

```json
[
  {
    country: "Denmark",
    city: "Copenhagen",
    _sum: { profileViews: 490 },
    _count: {
      _all: 70,
      city: 8,
    },
  },
  {
    country: "Sweden",
    city: "Stockholm",
    _sum: { profileViews: 500 },
    _count: {
      _all: 50,
      city: 3,
    },
  },
];
```

### `findRaw()` [#findraw]

See: [Using Raw SQL (`findRaw()`)](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#findraw).

### `aggregateRaw()` [#aggregateraw]

See: [Using Raw SQL (`aggregateRaw()`)](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#aggregateraw).

## Model query options [#model-query-options]

### `select` [#select]

`select` defines which fields are included in the object that Prisma Client returns. See: [Select fields and include relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields).

#### Remarks [#remarks-10]

* You cannot combine `select` and `include` on the same level.
* You can [select a `_count` of relations](#select-a-_count-of-relations).

#### Examples [#examples-18]

##### Select the `name` and `profileViews` fields of a single `User` record [#select-the-name-and-profileviews-fields-of-a-single-user-record]

```ts
const result = await prisma.user.findUnique({
  where: { id: 1 },
  select: {
    name: true,
    profileViews: true,
  },
});
```

```json
{
  name: "Alice",
  profileViews: 0
}
```

##### Select the `email` and `role` fields of a multiple `User` records [#select-the-email-and-role-fields-of-a-multiple-user-records]

```ts
const result = await prisma.user.findMany({
  select: {
    email: true,
    role: true,
  },
});
```

```json
[
  {
    email: "alice@prisma.io",
    role: "ADMIN",
  },
  {
    email: "bob@prisma.io",
    role: "USER",
  },
];
```

##### Select a `_count` of relations [#select-a-_count-of-relations]

```ts
const usersWithCount = await prisma.user.findMany({
  select: {
    _count: {
      select: { posts: true },
    },
  },
});
```

```json
{
  _count: {
    posts: 3;
  }
}
```

##### Select the 'id' and 'title' fields of related `Post` records [#select-the-id-and-title-fields-of-related-post-records]

```ts
const result = await prisma.user.findMany({
  select: {
    id: true,
    name: true,
    posts: {
      select: {
        id: true,
        title: true,
      },
    },
  },
});
```

```ts
[
  {
    id: 1,
    name: "Alice",
    posts: [
      { id: 1, title: "Hello World" },
      { id: 2, title: "Bye bye" },
    ],
  },
  {
    id: 2,
    name: "Bob",
    posts: [],
  },
];
```

##### `include` inside `select` [#include-inside-select]

```ts
const result = await prisma.user.findMany({
  select: {
    id: true,
    name: true,
    posts: {
      include: {
        author: true,
      },
    },
  },
});
```

```json
[
  {
    id: 1,
    name: "Alice",
    posts: [
      {
        id: 1,
        title: "Hello World",
        published: true,
        author: {
          id: 1,
          name: "Alice",
          email: "alice@prisma.io",
          role: "ADMIN",
          coinflips: [true, false],
          profileViews: 0,
        },
      },
      {
        id: 2,
        title: "Bye bye",
        published: false,
        author: {
          id: 1,
          name: "Alice",
          email: "alice@prisma.io",
          role: "USER",
          coinflips: [],
          profileViews: 0,
        },
      },
    ],
  },
];
```

### `include` [#include]

`include` defines which relations are included in the result that Prisma Client returns. See: [Select fields and include relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields).

#### Remarks [#remarks-11]

* You can [`include` a `_count` of relations](#include-a-_count-of-relations).

#### Examples [#examples-19]

##### Include the `posts` and `profile` relation when loading `User` records [#include-the-posts-and-profile-relation-when-loading-user-records]

```ts
const users = await prisma.user.findMany({
  include: {
    posts: true, // Returns all fields for all posts
    profile: true, // Returns all Profile fields
  },
});
```

##### Include the `posts` relation on the returned objects when creating a new `User` record with two `Post` records [#include-the-posts-relation-on-the-returned-objects-when-creating-a-new-user-record-with-two-post-records]

```ts
const user = await prisma.user.create({
  data: {
    email: "alice@prisma.io",
    posts: {
      create: [{ title: "This is my first post" }, { title: "Here comes a second post" }],
    },
  },
  include: { posts: true }, // Returns all fields for all posts
});
```

#### Generated types for `include` [#generated-types-for-include]

The following example demonstrates how to use TypeScript's `satisfies` operator with `include`:

```ts
const includePosts = { posts: true } satisfies Prisma.UserInclude;
```

##### Include a `_count` of relations [#include-a-_count-of-relations]

```ts
const usersWithCount = await prisma.user.findMany({
  include: {
    _count: {
      select: { posts: true },
    },
  },
});
```

```json
{ id: 1, name: "Bob", email: "bob@prisma.io", _count: { posts: 3 } },
{ id: 2,  name: "Enya", email: "enya@prisma.io", _count: { posts: 2 } }
```

### `omit` [#omit]

`omit` defines which fields are excluded in the object that Prisma Client returns.

#### Remarks [#remarks-12]

* You cannot combine `omit` and `select` since they serve opposite purposes.

#### Examples [#examples-20]

##### Omit the `password` field from all `User` records [#omit-the-password-field-from-all-user-records]

```ts
const result = await prisma.user.findMany({
  omit: {
    password: true,
  },
});
```

```json
[
  {
    id: 1,
    email: "jenny@prisma.io",
    name: "Jenny",
  },
  {
    id: 2,
    email: "rose@prisma.io",
    name: "Rose",
  },
];
```

##### Omit the `title` fields from all `User`'s `posts` relation [#omit-the-title-fields-from-all-users-posts-relation]

```ts
const results = await prisma.user.findMany({
  omit: {
    password: true,
  },
  include: {
    posts: {
      omit: {
        title: true,
      },
    },
  },
});
```

```json
[
  {
    id: 1,
    email: "jenny@prisma.io",
    name: "Jenny",
    posts: [
      {
        id: 1,
        author: {
          id: 1,
          email: "jenny@prisma.io",
          name: "Jenny",
        },
        authorId: 1,
      },
    ],
  },
  {
    id: 2,
    email: "rose@prisma.io",
    name: "Rose",
    posts: [
      {
        id: 2,
        author: {
          id: 2,
          email: "rose@prisma.io",
          name: "Rose",
        },
        authorId: 2,
      },
    ],
  },
];
```

#### Generated types for `omit` [#generated-types-for-omit]

The following example demonstrates how to use TypeScript's `satisfies` operator with `omit`:

```ts
const omitPassword = { password: true } satisfies Prisma.UserOmit;
```

### `relationLoadStrategy` (Preview) [#relationloadstrategy-preview]

`relationLoadStrategy` specifies how a relation should be loaded from the database. It has two possible values:

* `join` (default): Uses a database-level `LATERAL JOIN` (PostgreSQL) or correlated subqueries (MySQL) and fetches all data with a single query to the database.
* `query`: Sends multiple queries to the database (one per table) and joins them on the application level.

> **Note**: Once `relationLoadStrategy` moves from [Preview](https://www.prisma.io/docs/orm/v7/more/releases#preview) into [General Availability](https://www.prisma.io/docs/orm/v7/more/releases#generally-available-ga), `join` will universally become the default for all relation queries.

You can learn more about join strategies in [Relation load strategies (Preview)](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview).

Because the `relationLoadStrategy` option is currently in Preview, you need to enable it via the `relationJoins` preview feature flag in your Prisma schema file:

```prisma
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["relationJoins"]
}
```

After adding this flag, you need to run `prisma generate` again to re-generate Prisma Client. The `relationJoins` feature is currently available on PostgreSQL, CockroachDB and MySQL.

#### Remarks [#remarks-13]

* In most situations, the default `join` strategy will be more effective. Use `query` if you want to save resources on your database server or if you profiling shows that the application-level join is more performant.
* You can only specify the `relationLoadStrategy` on the top-level in your query. The top-level choice will affect all nested sub-queries.

#### Examples [#examples-21]

##### Load the `posts` relation via a database-level JOIN when using `include` [#load-the-posts-relation-via-a-database-level-join-when-using-include]

```ts
const users = await prisma.user.findMany({
  relationLoadStrategy: "join",
  include: {
    posts: true,
  },
});
```

##### Load the `posts` relation via a database-level JOIN when using `select` [#load-the-posts-relation-via-a-database-level-join-when-using-select]

```ts
const users = await prisma.user.findMany({
  relationLoadStrategy: "join",
  select: {
    posts: true,
  },
});
```

### `where` [#where]

`where` defines one or more [filters](#filter-conditions-and-operators), and can be used to filter on record properties (like a user's email address) or related record properties (like a user's top 10 most recent post titles).

#### Examples [#examples-22]

```ts
const results = await prisma.user.findMany({
  where: {
    email: {
      endsWith: "prisma.io",
    },
  },
});
```

#### Generated types for `where` [#generated-types-for-where]

The following examples demonstrate how to use TypeScript's `satisfies` operator with `where`:

* `UserWhereInput`

  ```ts
  // UserWhereInput
  const whereNameIs = { name: "Rich" } satisfies Prisma.UserWhereInput;

  // It can be combined with conditional operators too
  const whereNameIsWithAnd = {
    name: "Rich",
    AND: [
      {
        email: {
          contains: "rich@boop.com",
        },
      },
    ],
  } satisfies Prisma.UserWhereInput;
  ```

* `UserWhereUniqueInput` This type works by exposing any unique fields on the model. A field assigned `@id` is considered unique,
  as is one assigned `@unique`.

  This type exposes all fields on the model. This means that when you filter for a single record based on a unique field, you can check additional non-unique and unique fields at the same time. Learn more about how to [filter on non-unique fields with `UserWhereUniqueInput`](#filter-on-non-unique-fields-with-userwhereuniqueinput).

  ```ts
  // UserWhereUniqueInput
  const whereEmailIsUnique = { email: "rich@boop.com" } satisfies Prisma.UserWhereUniqueInput;
  ```

* `PostScalarWhereInput`

  ```ts
  const whereScalarTitleIs = { title: "boop" } satisfies Prisma.PostScalarWhereInput;
  ```

* `PostUpdateWithWhereUniqueWithoutAuthorInput` - This type accepts a unique `where` field (an `@id` or another assigned `@unique`)
  and updates any field on the `Post` model except the `Author`. The `Author` is the scalar field on the `Post` model.

  ```ts
  const updatePostByIdWithoutAuthor = {
    where: { id: 1 },
    data: {
      content: "This is some updated content",
      published: true,
      title: "This is a new title",
    },
  } satisfies Prisma.PostUpdateWithWhereUniqueWithoutAuthorInput;
  ```

* `PostUpsertWithWhereUniqueWithoutAuthorInput` - This type will update the `Post` records title field where the id matches, if it doesn't exist it will create it instead.

  ```ts
  const updatePostTitleOrCreateIfNotExist = {
    where: { id: 1 },
    update: { title: "This is a new title" },
    create: {
      id: 1,
      title: "If the title doesn't exist, then create one with this text",
    },
  } satisfies Prisma.PostUpsertWithWhereUniqueWithoutAuthorInput;
  ```

* `PostUpdateManyWithWhereWithoutAuthorInput` - This type will update all `Post` records where published is set to false.

  ```ts
  const publishAllPosts = {
    where: { published: { equals: false } },
    data: { published: true },
  } satisfies Prisma.PostUpdateManyWithWhereWithoutAuthorInput;
  ```

### `orderBy` [#orderby]

Sorts a list of records. See also: [Sorting](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting)

#### Remarks [#remarks-14]

* You can [order by relation fields](#sort-post-by-the-related-user-records-name) - for example, order posts by the author's name.
* In PostgreSQL you can [order by relevance](#sort-post-by-relevance-of-the-title). For details, see [Sort by relevance](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting#sort-by-relevance-postgresql-and-mysql).
* You can [sort `null` records first or last](#sort-post-by-the-related-user-records-name-with-null-records-first). For details, see [Sort with nulls first or last](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting#sort-with-null-records-first-or-last).

#### Inputs for `sort` argument [#inputs-for-sort-argument]

| Name   | Description             |
| ------ | ----------------------- |
| `asc`  | Sort ascending (A → Z)  |
| `desc` | Sort descending (Z → A) |

#### Inputs for `nulls` argument [#inputs-for-nulls-argument]

Note:

* This argument is optional.
* For use on optional [scalar](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#scalar-fields) fields only. If you try to sort by nulls on a required or [relation](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#relation-fields) field, Prisma Client throws a [P2009 error](https://www.prisma.io/docs/orm/v7/reference/error-reference#p2009).

| Name    | Description                    |
| ------- | ------------------------------ |
| `first` | Sort with `null` values first. |
| `last`  | Sort with `null` values last.  |

#### Examples [#examples-23]

##### Sort `User` by `email` field [#sort-user-by-email-field]

The following example returns all `User` records sorted by `email` ascending:

```ts
const users = await prisma.user.findMany({
  orderBy: {
    email: "asc",
  },
});
```

The following example returns all `User` records sorted by `email` descending:

```ts
const users = await prisma.user.findMany({
  orderBy: {
    email: "desc",
  },
});
```

#### Sort `Post` by the related `User` record's `name` [#sort-post-by-the-related-user-records-name]

The following query orders posts by user name:

```ts
const posts = await prisma.post.findMany({
  orderBy: {
    author: {
      name: "asc",
    },
  },
});
```

#### Sort `Post` by the related `User` record's `name`, with `null` records first [#sort-post-by-the-related-user-records-name-with-null-records-first]

The following query orders posts by user name, with `null` records first:

```ts
const posts = await prisma.post.findMany({
  orderBy: {
    author: {
      name: { sort: "asc", nulls: "first" },
    },
  },
});
```

#### Sort `Post` by relevance of the title [#sort-post-by-relevance-of-the-title]

> [!NOTE]
> For PostgreSQL, this feature is still in Preview. [Enable the `fullTextSearchPostgres` feature flag](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search#enabling-full-text-search-for-postgresql) in order to use it.

The following query orders posts by relevance of the search term `'database'` to the title:

```ts
const posts = await prisma.post.findMany({
  orderBy: {
    _relevance: {
      fields: ['title'],
      search: 'database',
      sort: 'asc'
    },
})
```

#### Sort `User` by the `posts` count [#sort-user-by-the-posts-count]

The following query orders users by post count:

```ts
const getActiveusers = await prisma.user.findMany({
  orderBy: {
    posts: {
      count: "desc",
    },
  },
});
```

##### Sort `User` by multiple fields - `email` *and* `role` [#sort-user-by-multiple-fields---email-and-role]

The following example sorts users by two fields - first `email`, then `role`:

```ts
const users = await prisma.user.findMany({
  select: {
    email: true,
    role: true,
  },
  orderBy: [
    {
      email: "desc",
    },
    {
      role: "desc",
    },
  ],
});
```

```json
[
  {
    "email": "yuki@prisma.io",
    "role": "USER"
  },
  {
    "email": "nora@prisma.io",
    "role": "USER"
  },
  {
    "email": "mary@prisma.io",
    "role": "MODERATOR"
  },
  {
    "email": "elsa@prisma.io",
    "role": "MODERATOR"
  },
  {
    "email": "eloise@prisma.io",
    "role": "USER"
  },
  {
    "email": "coco@prisma.io",
    "role": "ADMIN"
  },
  {
    "email": "anna@prisma.io",
    "role": "USER"
  },
  {
    "email": "alice@prisma.io",
    "role": "USER"
  }
]
```

The order of sorting parameters matters - the following query sorts by `role`, then `email`. Note the difference in the results:

```ts
const users = await prisma.user.findMany({
  select: {
    email: true,
    role: true,
  },
  orderBy: [
    {
      role: "desc",
    },
    {
      email: "desc",
    },
  ],
});
```

```json
[
  {
    "email": "mary@prisma.io",
    "role": "MODERATOR"
  },
  {
    "email": "elsa@prisma.io",
    "role": "MODERATOR"
  },
  {
    "email": "yuki@prisma.io",
    "role": "USER"
  },
  {
    "email": "nora@prisma.io",
    "role": "USER"
  },
  {
    "email": "eloise@prisma.io",
    "role": "USER"
  },
  {
    "email": "anna@prisma.io",
    "role": "USER"
  },
  {
    "email": "alice@prisma.io",
    "role": "USER"
  },
  {
    "email": "coco@prisma.io",
    "role": "ADMIN"
  }
]
```

##### Sort `User` by `email`, select `name` and `email` [#sort-user-by-email-select-name-and-email]

The following example returns all the `name` and `email` fields of all `User` records, sorted by `email`:

```ts
const users3 = await prisma.user.findMany({
  orderBy: {
    email: "asc",
  },
  select: {
    name: true,
    email: true,
  },
});
```

```json
[
  {
    name: "Alice",
    email: "alice@prisma.io",
  },
  {
    name: "Ariadne",
    email: "ariadne@prisma.io",
  },
  {
    name: "Bob",
    email: "bob@prisma.io",
  },
];
```

##### Sort `User` records by `email` and sort nested `Post` records by `title` [#sort-user-records-by-email-and-sort-nested-post-records-by-title]

The following example:

* Returns all `User` records sorted by `email`
* For each `User` record, returns the `title` field of all nested `Post` records sorted by `title`

```ts
const usersWithPosts = await prisma.user.findMany({
  orderBy: {
    email: "asc",
  },
  include: {
    posts: {
      select: {
        title: true,
      },
      orderBy: {
        title: "asc",
      },
    },
  },
});
```

```json
[
  {
    "id": 2,
    "email": "alice@prisma.io",
    "name": "Alice",
    "posts": [
      {
        "title": "Watch the talks from Prisma Day 2019"
      }
    ]
  },
  {
    "id": 3,
    "email": "ariadne@prisma.io",
    "name": "Ariadne",
    "posts": [
      {
        "title": "How to connect to a SQLite database"
      },
      {
        "title": "My first day at Prisma"
      }
    ]
  },
  {
    "id": 1,
    "email": "bob@prisma.io",
    "name": "Bob",
    "posts": [
      {
        "title": "Follow Prisma on Twitter"
      },
      {
        "title": "Subscribe to GraphQL Weekly for community news "
      }
    ]
  }
]
```

##### Sort one user's nested list of `Post` records [#sort-one-users-nested-list-of-post-records]

The following example retrieves a single `User` record by ID, as well as a list of nested `Post` records sorted by `title`:

```ts
const userWithPosts = await prisma.user.findUnique({
  where: {
    id: 1,
  },
  include: {
    posts: {
      orderBy: {
        title: "desc",
      },
      select: {
        title: true,
        published: true,
      },
    },
  },
});
```

```json
{
  "email": "sarah@prisma.io",
  "id": 1,
  "name": "Sarah",
  "extendedProfile": null,
  "role": "USER",
  "posts": [
    {
      "title": "Prisma Day 2020",
      "published": false
    },
    {
      "title": "My first post",
      "published": false
    },
    {
      "title": "All about databases",
      "published": true
    }
  ]
}
```

##### Sort by `enum` [#sort-by-enum]

The following sorts all `User` records by `role` (an `enum`):

```ts
const sort = await prisma.user.findMany({
  orderBy: {
    role: "desc",
  },
  select: {
    email: true,
    role: true,
  },
});
```

```json
[
  {
    "email": "emma@prisma.io",

    "role": "USER"
  },
  {
    "email": "suma@prisma.io",
    "role": "ADMIN"
  },
  {
    "email": "kwame@prisma.io",
    "role": "ADMIN"
  },
  {
    "email": "pearl@prisma.io",
    "role": "ADMIN"
  }
]
```

#### Generated types for `orderBy` [#generated-types-for-orderby]

The following examples demonstrate how to use TypeScript's `satisfies` operator with `orderBy`:

* `UserOrderByInput`
  ```ts
  const orderEmailsByDescending = { email: "desc" } satisfies Prisma.UserOrderByInput;
  ```

### `distinct` [#distinct]

Deduplicate a list of records from [`findMany`](#findmany) or [`findFirst`](#findfirst). See also: [Aggregation, grouping, and summarizing](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#select-distinct)

#### Examples [#examples-24]

##### Select distinct on a single field [#select-distinct-on-a-single-field]

The following example returns all distinct `city` fields, and selects only the `city` and `country` fields:

```ts
const distinctCities = await prisma.user.findMany({
  select: {
    city: true,
    country: true,
  },
  distinct: ["city"],
});
```

```json
[
  { city: "Paris", country: "France" },
  { city: "Lyon", country: "France" },
];
```

##### Select distinct on multiple fields [#select-distinct-on-multiple-fields]

The following example returns all distinct `city` *and* `country` field combinations, and selects only the `city` and `country` fields:

```ts
const distinctCitiesAndCountries = await prisma.user.findMany({
  select: {
    city: true,
    country: true,
  },
  distinct: ["city", "country"],
});
```

```json
[
  { city: "Paris", country: "France" },
  { city: "Paris", country: "Denmark" },
  { city: "Lyon", country: "France" },
];
```

Note that there is now a "Paris, Denmark" in addition to "Paris, France":

##### Select distinct in combination with a filter [#select-distinct-in-combination-with-a-filter]

The following example returns all distinct `city` *and* `country` field combinations where the user's email contains `"prisma.io"`, and selects only the `city` and `country` fields:

```ts
const distinctCitiesAndCountries = await prisma.user.findMany({
  where: {
    email: {
      contains: "prisma.io",
    },
  },
  select: {
    city: true,
    country: true,
  },
  distinct: ["city", "country"],
});
```

```json
[
  { city: "Paris", country: "Denmark" },
  { city: "Lyon", country: "France" },
];
```

## `nativeDistinct` [#nativedistinct]

Enabling `nativeDistinct` in your Prisma schema pushes the `distinct` operation to the database layer
(where supported). This can significantly improve performance. However, note that:

* Some databases may not fully support DISTINCT on certain field combinations.
* Behavior can differ among providers.

To enable `nativeDistinct`:

```prisma
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["nativeDistinct"]
}
```

See [Preview Features](https://www.prisma.io/docs/orm/v7/reference/preview-features/client-preview-features#preview-features-promoted-to-general-availability) for more details.

## Nested queries [#nested-queries]

### `create` [#create-1]

A nested `create` query adds a new related record or set of records to a parent record. See: [Working with relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries)

#### Remarks [#remarks-15]

* `create` is available as a nested query when you `create()` (`prisma.user.create(...)`) a new parent record or `update()` (`prisma.user.update(...)`) an existing parent record.
* You can use a nested `create` *or* a nested [`createMany`](#createmany-1) to create multiple related records. If you require the [`skipDuplicates` query option](#nested-createmany-options) you should use `createMany`.

#### Examples [#examples-25]

##### Create a new `User` record with a new `Profile` record [#create-a-new-user-record-with-a-new-profile-record]

```ts highlight=5;normal
const user = await prisma.user.create({
  data: {
    email: 'alice@prisma.io',
    profile: {
      create: { bio: 'Hello World' },
    },
  },
});
```

##### Create a new `Profile` record with a new `User` record [#create-a-new-profile-record-with-a-new-user-record]

```ts
const user = await prisma.profile.create({
  data: {
    bio: "Hello World",
    user: {
      create: { email: "alice@prisma.io" }, // [!code highlight]
    },
  },
});
```

##### Create a new `User` record with a new `Post` record [#create-a-new-user-record-with-a-new-post-record]

```ts highlight=5;normal
const user = await prisma.user.create({
  data: {
    email: "alice@prisma.io",
    posts: {
      create: { title: "Hello World" },
    },
  },
});
```

##### Create a new `User` record with two new `Post` records [#create-a-new-user-record-with-two-new-post-records]

Because it's a one-to-many relation, you can also create multiple `Post` records at once by passing an array to `create`:

```ts highlight=5-12;normal
const user = await prisma.user.create({
  data: {
    email: "alice@prisma.io",
    posts: {
      create: [
        {
          title: "This is my first post",
        },
        {
          title: "Here comes a second post",
        },
      ],
    },
  },
});
```

Note: You can also use a nested [`createMany`](#createmany-1) to achieve the same result.

##### Update an existing `User` record by creating a new `Profile` record [#update-an-existing-user-record-by-creating-a-new-profile-record]

```ts highlight=5;normal;
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    profile: {
      create: { bio: "Hello World" },
    },
  },
});
```

##### Update an existing `User` record by creating a new `Post` record [#update-an-existing-user-record-by-creating-a-new-post-record]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    posts: {
      create: { title: "Hello World" }, // [!code highlight]
    },
  },
});
```

### `createMany` [#createmany-1]

A nested `createMany` query adds a new set of records to a parent record. See: [Working with relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries)

#### Remarks [#remarks-16]

* `createMany` is available as a nested query when you `create()` (`prisma.user.create(...)`) a new parent record or `update()` (`prisma.user.update(...)`) an existing parent record.
  * Available in the context of a one-to-many relation — for example, you can `prisma.user.create(...)` a user and use a nested `createMany` to create multiple posts (posts have one user).
  * **Not** available in the context of a many-to-many relation — for example, you **cannot** `prisma.post.create(...)` a post and use a nested `createMany` to create categories (many posts have many categories).
* You cannot nest an additional `create` or `createMany`.
* Allows setting foreign keys directly — for example, setting the `categoryId` on a post.
* Nested `createMany` is supported by SQLite.
* You can use a nested `create` *or* a nested `createMany` to create multiple related records - [if you do not need the `skipDuplicates` query option, you should probably use `create`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#create-a-single-record-and-multiple-related-records).

#### Options [#nested-createmany-options]

| Name              | Type                              | Required | Description                                                                                                                                                                                                                                             |
| ----------------- | --------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`            | `Enumerable<UserCreateManyInput>` | **Yes**  | Wraps all the model fields in a type so that they can be provided when creating new records. Fields that are marked as optional or have default values in the datamodel are optional.                                                                   |
| `skipDuplicates?` | `boolean`                         | No       | Do not insert records with unique fields or ID fields that already exist. Only supported by databases that support [`ON CONFLICT DO NOTHING`](https://www.postgresql.org/docs/9.5/sql-insert.html#SQL-ON-CONFLICT). This excludes MongoDB and SQLServer |

#### Examples [#examples-26]

##### Update a `User` and multiple new related `Post` records [#update-a-user-and-multiple-new-related-post-records]

```ts
const user = await prisma.user.update({
  where: {
    id: 9,
  },
  data: {
    name: "Elliott",
    posts: {
      createMany: {
        data: [{ title: "My first post" }, { title: "My second post" }],
      },
    },
  },
});
```

### `set` [#set]

`set` overwrites the value of a relation - for example, replacing a list of `Post` records with a different list. See: [Working with relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries)

#### Examples [#examples-27]

##### Update an existing `User` record by disconnecting any previous `Post` records and connecting two other existing ones [#update-an-existing-user-record-by-disconnecting-any-previous-post-records-and-connecting-two-other-existing-ones]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    posts: {
      set: [{ id: 32 }, { id: 42 }],
    },
  },
});
```

### `connect` [#connect]

A nested `connect` query connects a record to an existing related record by specifying an ID or unique identifier. See: [Working with relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries)

#### Remarks [#remarks-17]

* `connect` is available as a nested query when you create a new parent record or update an existing parent record.

* If the related record does not exist, Prisma Client throws an exception:

  ```
  The required connected records were not found. Expected 1 records to be connected, found 0.
  ```

* When using `set` and `connect` together, the order in which they are applied significantly impacts the result. If `set` is used before `connect`, the connected records will only reflect the final state established by the `connect` operation, as `set` clears all existing connections before `connect` establishes new ones. Conversely, if `connect` is applied before `set`, the `set` operation will override the `connect` action by clearing all connected records and replacing them with its own specified state.

#### Examples [#examples-28]

##### Create a new `Profile` record and connect it to an existing `User` record via unique field [#create-a-new-profile-record-and-connect-it-to-an-existing-user-record-via-unique-field]

```ts
const user = await prisma.profile.create({
  data: {
    bio: "Hello World",
    user: {
      connect: { email: "alice@prisma.io" },
    },
  },
});
```

##### Create a new `Profile` record and connect it to an existing `User` record via an ID field [#create-a-new-profile-record-and-connect-it-to-an-existing-user-record-via-an-id-field]

```ts
const user = await prisma.profile.create({
  data: {
    bio: "Hello World",
    user: {
      connect: { id: 42 }, // sets userId of Profile record
    },
  },
});
```

You can also set the foreign key directly:

```ts
const user = await prisma.profile.create({
  data: {
    bio: "Hello World",
    userId: 42,
  },
});
```

However, you can't use both the direct approach and the `connect` approach in the same query. See [this issue comment](https://github.com/prisma/orm/issues/4322#issuecomment-737976117) for details.

##### Create a new `Post` record and connect it to an existing `User` record [#create-a-new-post-record-and-connect-it-to-an-existing-user-record]

```ts
const user = await prisma.post.create({
  data: {
    title: "Hello World",
    author: {
      connect: { email: "alice@prisma.io" },
    },
  },
});
```

##### Update an existing `User` record by connecting it to an existing `Profile` record [#update-an-existing-user-record-by-connecting-it-to-an-existing-profile-record]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    profile: {
      connect: { id: 24 },
    },
  },
});
```

##### Update an existing `User` record by connecting it to two existing `Post` records [#update-an-existing-user-record-by-connecting-it-to-two-existing-post-records]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    posts: {
      connect: [{ id: 24 }, { id: 42 }],
    },
  },
});
```

### `connectOrCreate` [#connectorcreate]

`connectOrCreate` *either* connects a record to an existing related record by ID or unique identifier *or* creates a new related record if the record does not exist. See: [Working with relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries)

#### Remarks [#remarks-18]

Multiple `connectOrCreate` queries that run as concurrent transactions can result in a **race condition**. Consider the following example, where two queries attempt to `connectOrCreate` a blog post tag named `computing` at the same time (tag names must be unique):

  

#### Query A

```ts
const createPost = await prisma.post.create({
  data: {
    title: "How to create a compiler",
    content: "...",
    author: {
      connect: {
        id: 9,
      },
    },
    tags: {
      connectOrCreate: {
        create: {
          name: "computing",
        },
        where: {
          name: "computing",
        },
      },
    },
  },
});
```

#### Query B

```ts
const createPost = await prisma.post.create({
  data: {
    title: "How to handle schema drift in production",
    content: "...",
    author: {
      connect: {
        id: 15,
      },
    },
    tags: {
      connectOrCreate: {
        create: {
          name: "computing",
        },
        where: {
          name: "computing",
        },
      },
    },
  },
});
```

If query A and query B overlap in the following way, query A results in an exception:

| Query A (Fail ❌)                                                 | Query B (Success ✅)                                              |
| :--------------------------------------------------------------- | :--------------------------------------------------------------- |
| Query hits server, starts transaction A                          | Query hits server, starts transaction B                          |
|                                                                  | Find record where `tagName` equals `computing`, record not found |
| Find record where `tagName` equals `computing`, record not found |                                                                  |
|                                                                  | Create record where `tagName` equals `computing` and connect     |
| Create record where `tagName` equals `computing`                 |                                                                  |
| Unique violation, record already created by transaction B        |                                                                  |

To work around this scenario, we recommend catching the unique violation exception (`PrismaClientKnownRequestError`, error `P2002`) and retrying failed queries.

#### Examples [#examples-29]

##### Create a new `Profile` record, then connect it to an existing `User` record *or* create a new `User` [#create-a-new-profile-record-then-connect-it-to-an-existing-user-record-or-create-a-new-user]

The following example:

1. Creates a `Profile`
2. Attempts to connect the profile to a `User` where the email address is `alice@prisma.io`
3. Creates a new user if a matching user does not exist

```ts
const user = await prisma.profile.create({
  data: {
    bio: 'The coolest Alice on the planet',
    user: {
      connectOrCreate: {
        where:  { email: 'alice@prisma.io' },
        create: { email: 'alice@prisma.io'}
    },
  },
})
```

##### Create a new `Post` record and connect it to an existing `User` record, *or* create a new `User` [#create-a-new-post-record-and-connect-it-to-an-existing-user-record-or-create-a-new-user]

```ts
const user = await prisma.post.create({
  data: {
    title: "Hello World",
    author: {
      connectOrCreate: {
        where: { email: "alice@prisma.io" },
        create: { email: "alice@prisma.io" },
      },
    },
  },
});
```

##### Update an existing `User` record by connecting it to an existing `Profile` record, *or* creating a new `Profile` record [#update-an-existing-user-record-by-connecting-it-to-an-existing-profile-record-or-creating-a-new-profile-record]

The following example:

1. Attempts to connect the user to a `Profile` with an `id` of `20`
2. Creates a new profile if a matching profile does not exist

```ts
const updateUser = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    profile: {
      connectOrCreate: {
        where: { id: 20 },
        create: {
          bio: "The coolest Alice in town",
        },
      },
    },
  },
});
```

##### Update an existing `User` record by connect it to two existing `Post` records, or creating two new `Post` records [#update-an-existing-user-record-by-connect-it-to-two-existing-post-records-or-creating-two-new-post-records]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    posts: {
      connectOrCreate: [
        {
          where: { id: 32 },
          create: { title: "This is my first post" },
        },
        {
          where: { id: 19 },
          create: { title: "This is my second post" },
        },
      ],
    },
  },
});
```

### `disconnect` [#disconnect]

A nested `disconnect` query breaks the connection between a parent record and a related record, but does not delete either record. See: [Working with relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries)

#### Remarks [#remarks-19]

* `disconnect` is only available if the relation is optional.
* If the relationship you are attempting to disconnect does not exist, the operation does nothing.

#### Examples [#examples-30]

##### Update an existing `User` record by disconnecting the `Profile` record it's connected to [#update-an-existing-user-record-by-disconnecting-the-profile-record-its-connected-to]

```ts
const user = await prisma.user.update({
  where: { email: "bob@prisma.io" },
  data: {
    profile: {
      disconnect: true,
    },
  },
});
```

##### Update an existing `User` record by disconnecting two `Post` records it's connected to [#update-an-existing-user-record-by-disconnecting-two-post-records-its-connected-to]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    posts: {
      disconnect: [{ id: 44 }, { id: 46 }],
    },
  },
});
```

### `update` [#update-1]

A nested `update` query updates one or more related records where the parent record's ID is `n`. See: [Working with relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#update-a-specific-related-record)

#### Remarks [#remarks-20]

* Nested `update` queries are only available in the context of a top-level `update` query (for example, `prisma.user.update(...)`).

* If the parent record does not exist, Prisma Client throws an exception:

  ```
  AssertionError("Expected a valid parent ID to be present for nested update to-one case.")
  ```

* If the related record that you want to update does not exist, Prisma Client throws an exception:

  ```
  AssertionError("Expected a valid parent ID to be present for nested update to-one case.")
  ```

#### Examples [#examples-31]

##### Update an existing `User` record by updating the `Profile` record it's connected to [#update-an-existing-user-record-by-updating-the-profile-record-its-connected-to]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    profile: {
      update: { bio: "Hello World" },
    },
  },
});
```

##### Update an existing `User` record by updating two `Post` records it's connected to [#update-an-existing-user-record-by-updating-two-post-records-its-connected-to]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    posts: {
      update: [
        {
          data: { published: true },
          where: { id: 32 },
        },
        {
          data: { published: true },
          where: { id: 23 },
        },
      ],
    },
  },
});
```

### `upsert` [#upsert-1]

> [!NOTE]
> This section covers the usage of nested upsert within `update()`. To learn about the [`upsert()`](#upsert) operation, reference the linked documentation.

A nested `upsert` query updates a related record if it exists, or creates a new related record.

#### Examples [#examples-32]

##### Update an existing `User` record by updating the `Profile` record it's connected to or creating a new one (*upsert*) [#update-an-existing-user-record-by-updating-the-profile-record-its-connected-to-or-creating-a-new-one-upsert]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    profile: {
      upsert: {
        create: { bio: "Hello World" },
        update: { bio: "Hello World" },
      },
    },
  },
});
```

##### Update an existing `User` record by updating two `Post` record it's connected to or creating new ones (*upsert*) [#update-an-existing-user-record-by-updating-two-post-record-its-connected-to-or-creating-new-ones-upsert]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    posts: {
      upsert: [
        {
          create: { title: "This is my first post" },
          update: { title: "This is my first post" },
          where: { id: 32 },
        },
        {
          create: { title: "This is my second post" },
          update: { title: "This is my second post" },
          where: { id: 23 },
        },
      ],
    },
  },
});
```

### `delete` [#delete-1]

A nested `delete` query deletes a related record. The parent record is not deleted.

#### Remarks [#remarks-21]

* `delete` is only available if the relation is optional.

#### Examples [#examples-33]

##### Update an existing `User` record by deleting the `Profile` record it's connected to [#update-an-existing-user-record-by-deleting-the-profile-record-its-connected-to]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    profile: {
      delete: true,
    },
  },
});
```

##### Update an existing `User` record by deleting two `Post` records it's connected to [#update-an-existing-user-record-by-deleting-two-post-records-its-connected-to]

```ts
const user = await prisma.user.update({
  where: { email: "alice@prisma.io" },
  data: {
    posts: {
      delete: [{ id: 34 }, { id: 36 }],
    },
  },
});
```

### `updateMany` [#updatemany-1]

A nested `updateMany` updates a list of related records and supports filtering - for example, you can update a user's unpublished posts.

#### Examples [#examples-34]

##### Update all unpublished posts belonging to a specific user [#update-all-unpublished-posts-belonging-to-a-specific-user]

```ts
const result = await prisma.user.update({
  where: {
    id: 2,
  },
  data: {
    posts: {
      updateMany: {
        where: {
          published: false,
        },
        data: {
          likes: 0,
        },
      },
    },
  },
});
```

### `deleteMany` [#deletemany-1]

A nested `deleteMany` deletes related records and supports filtering. For example, you can delete a user's posts while updating other properties of that user.

#### Examples [#examples-35]

##### Delete all posts belonging to a specific user as part of an update [#delete-all-posts-belonging-to-a-specific-user-as-part-of-an-update]

```ts
const result = await prisma.user.update({
  where: {
    id: 2,
  },
  data: {
    name: "Updated name",
    posts: {
      deleteMany: {},
    },
  },
});
```

## Filter conditions and operators [#filter-conditions-and-operators]

### `equals` [#equals]

Value equals `n`.

#### Examples [#examples-36]

**Return all users where `name` equals `"Eleanor"`**

```ts
const result = await prisma.user.findMany({
  where: {
    name: {
      equals: "Eleanor",
    },
  },
});
```

You can also exclude the `equals`:

```ts
const result = await prisma.user.findMany({
  where: {
    name: "Eleanor",
  },
});
```

**Return all products with a quantity lower than the "warn quantity" threshold**

This example compares fields of the same model.

```ts
const productsWithLowQuantity = await prisma.product.findMany({
  where: {
    quantity: {
      lte: prisma.product.fields.warnQuantity,
    },
  },
});
```

**Return all users that have blue and green as their favorite colors**

This example finds users that have set their `favoriteColors` field to `['blue', 'green']`.

Note that when using `equals`, order of elements matters. That is to say `['blue', 'green']` is **not** equal to `['green', 'blue']`

```ts
const favoriteColorFriends = await prisma.user.findMany({
  where: {
    favoriteColors: {
      equals: ["blue", "green"],
    },
  },
});
```

### `not` [#not]

Value does not equal `n`.

#### Examples [#examples-37]

##### Return all users where `name` does **not** equal `"Eleanor"` [#return-all-users-where-name-does-not-equal-eleanor]

```ts
const result = await prisma.user.findMany({
  where: {
    name: {
      not: "Eleanor",
    },
  },
});
```

> [!WARNING]
> `not` will return all items that do not match a given value. However, if the column is nullable, `NULL` values will not be returned. If you require null values to be returned, use an [`OR`](#or) operator to include `NULL` values.

##### Return all users where `name` does **not** equal `"Eleanor"` **including** users where `name` is `NULL` [#return-all-users-where-name-does-not-equal-eleanor-including-users-where-name-is-null]

```ts
await prisma.user.findMany({
  where: {
    OR: [{ name: { not: "Eleanor" } }, { name: null }],
  },
});
```

### `in` [#in]

Value `n` exists in list.

> [!NOTE]
> `null` values are not returned. For example, if you combine `in` and `NOT` to return a user whose name is *not* in the list, users with `null` value names are not returned.

#### Examples [#examples-38]

##### Get `User` records where the `id` can be found in the following list: `[22, 91, 14, 2, 5]` [#get-user-records-where-the-id-can-be-found-in-the-following-list-22-91-14-2-5]

```ts
const getUser = await prisma.user.findMany({
  where: {
    id: { in: [22, 91, 14, 2, 5] },
  },
});
```

##### Get `User` records where the `name` can be found in the following list: `['Saqui', 'Clementine', 'Bob']` [#get-user-records-where-the-name-can-be-found-in-the-following-list-saqui-clementine-bob]

```ts
const getUser = await prisma.user.findMany({
  where: {
    name: { in: ["Saqui", "Clementine", "Bob"] },
  },
});
```

##### Get `User` records where `name` is **not** present in the list [#get-user-records-where-name-is-not-present-in-the-list]

The following example combines `in` and [`NOT`](#not). You can also use [`notIn`](#notin).

```ts
const getUser = await prisma.user.findMany({
  where: {
    NOT: {
      name: { in: ["Saqui", "Clementine", "Bob"] },
    },
  },
});
```

##### Get a `User` record where at least one `Post` has at least one specified `Category` [#get-a-user-record-where-at-least-one-post-has-at-least-one-specified-category]

```ts
const getUser = await prisma.user.findMany({
  where: {
    // Find users where..
    posts: {
      some: {
        // ..at least one (some) posts..
        categories: {
          some: {
            // .. have at least one category ..
            name: {
              in: ["Food", "Introductions"], // .. with a name that matches one of the following.
            },
          },
        },
      },
    },
  },
});
```

### `notIn` [#notin]

Value `n` does not exist in list.

#### Remarks [#remarks-22]

* `null` values are not returned.

#### Examples [#examples-39]

##### Get `User` records where the `id` can **not** be found in the following list: `[22, 91, 14, 2, 5]` [#get-user-records-where-the-id-can-not-be-found-in-the-following-list-22-91-14-2-5]

```ts
const getUser = await prisma.user.findMany({
  where: {
    id: { notIn: [22, 91, 14, 2, 5] },
  },
});
```

### `lt` [#lt]

Value `n` is less than `x`.

#### Examples [#examples-40]

##### Get all `Post` records where `likes` is less than `9` [#get-all-post-records-where-likes-is-less-than-9]

```ts
const getPosts = await prisma.post.findMany({
  where: {
    likes: {
      lt: 9,
    },
  },
});
```

### `lte` [#lte]

Value `n` is less than *or* equal to `x`.

#### Examples [#examples-41]

##### Get all `Post` records where `likes` is less or equal to `9` [#get-all-post-records-where-likes-is-less-or-equal-to-9]

```ts
const getPosts = await prisma.post.findMany({
  where: {
    likes: {
      lte: 9,
    },
  },
});
```

### `gt` [#gt]

Value `n` is greater than `x`.

#### Examples [#examples-42]

##### Get all `Post` records where `likes` is greater than `9` [#get-all-post-records-where-likes-is-greater-than-9]

```ts
const getPosts = await prisma.post.findMany({
  where: {
    likes: {
      gt: 9,
    },
  },
});
```

### `gte` [#gte]

Value `n` is greater than *or* equal to `x`.

#### Examples [#examples-43]

##### Get all `Post` records where `likes` is greater than or equal to `9` [#get-all-post-records-where-likes-is-greater-than-or-equal-to-9]

```ts
const getPosts = await prisma.post.findMany({
  where: {
    likes: {
      gte: 9,
    },
  },
});
```

#### Examples [#examples-44]

##### Get all `Post` records where `date_created` is greater than March 19th, 2020 [#get-all-post-records-where-date_created-is-greater-than-march-19th-2020]

```js
const result = await prisma.post.findMany({
  where: {
    date_created: {
      gte: new Date("2020-03-19T14:21:00+0200") /* Includes time offset for UTC */,
    },
  },
});
```

### `contains` [#contains]

Value `n` contains `x`.

#### Examples [#examples-45]

##### Count all `Post` records where `content` contains `databases` [#count-all-post-records-where-content-contains-databases]

```js
const result = await prisma.post.count({
  where: {
    content: {
      contains: "databases",
    },
  },
});
```

##### Count all `Post` records where `content` **does not** contain `databases` [#count-all-post-records-where-content-does-not-contain-databases]

```js
const result = await prisma.post.count({
  where: {
    NOT: {
      content: {
        contains: "databases",
      },
    },
  },
});
```

### `search` [#search]

Use [Full-Text Search](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search) to search within a `String` field.

> [!NOTE]
> For PostgreSQL, this feature is still in Preview. [Enable the `fullTextSearchPostgres` feature flag](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search#enabling-full-text-search-for-postgresql) in order to use it.

#### Examples [#examples-46]

##### Find all posts with a title that contains `cat` or `dog`. [#find-all-posts-with-a-title-that-contains-cat-or-dog]

```js
const result = await prisma.post.findMany({
  where: {
    title: {
      search: "cat | dog",
    },
  },
});
```

##### Find all posts with a title that contains `cat` and `dog`. [#find-all-posts-with-a-title-that-contains-cat-and-dog]

```js
const result = await prisma.post.findMany({
  where: {
    title: {
      search: "cat & dog",
    },
  },
});
```

##### Find all posts with a title that doesn't contain `cat`. [#find-all-posts-with-a-title-that-doesnt-contain-cat]

```js
const result = await prisma.post.findMany({
  where: {
    title: {
      search: "!cat",
    },
  },
});
```

### `mode` [#mode]

#### Remarks [#remarks-23]

* Supported by the PostgreSQL and MongoDB connectors only

#### Examples [#examples-47]

##### Get all `Post` records where `title` contains `prisma`, in a case insensitive way [#get-all-post-records-where-title-contains-prisma-in-a-case-insensitive-way]

```js
const result = await prisma.post.findMany({
  where: {
    title: {
      contains: "prisma",
      mode: "insensitive",
    },
  },
});
```

### `startsWith` [#startswith]

#### Examples [#examples-48]

##### Get all `Post` records where `title` starts with `Pr` (such as `Prisma`) [#get-all-post-records-where-title-starts-with-pr-such-as-prisma]

```js
const result = await prisma.post.findMany({
  where: {
    title: {
      startsWith: "Pr",
    },
  },
});
```

### `endsWith` [#endswith]

#### Get all `User` records where `email` ends with `prisma.io` [#get-all-user-records-where-email-ends-with-prismaio]

```js
const result = await prisma.user.findMany({
  where: {
    email: {
      endsWith: "prisma.io",
    },
  },
});
```

### `AND` [#and]

All conditions must return `true`. Alternatively, pass a list of objects into the `where` clause - the [`AND` operator is not required](#get-all-post-records-where-the-content-field-contains-prisma-and-published-is-false-no-and).

#### Examples [#examples-49]

##### Get all `Post` records where the `content` field contains `Prisma` and `published` is `false` [#get-all-post-records-where-the-content-field-contains-prisma-and-published-is-false]

```js
const result = await prisma.post.findMany({
  where: {
    AND: [
      {
        content: {
          contains: "Prisma",
        },
      },
      {
        published: {
          equals: false,
        },
      },
    ],
  },
});
```

##### Get all `Post` records where the `content` field contains `Prisma` and `published` is `false` (no `AND`) [#get-all-post-records-where-the-content-field-contains-prisma-and-published-is-false-no-and]

The following format returns the same results as the previous example **without** the `AND` operator:

```js
const result = await prisma.post.findMany({
  where: {
    content: {
      contains: "Prisma",
    },
    published: {
      equals: false,
    },
  },
});
```

##### Get all `Post` records where the `title` field contains `Prisma` or `databases`, and `published` is `false` [#get-all-post-records-where-the-title-field-contains-prisma-or-databases-and-published-is-false]

The following example combines `OR` and `AND`:

```js
const result = await prisma.post.findMany({
  where: {
    OR: [
      {
        title: {
          contains: "Prisma",
        },
      },
      {
        title: {
          contains: "databases",
        },
      },
    ],
    AND: {
      published: false,
    },
  },
});
```

### `OR` [#or]

One or more conditions must return `true`.

#### Examples [#examples-50]

##### Get all `Post` records where the `title` field contains `Prisma` or `databases` [#get-all-post-records-where-the-title-field-contains-prisma-or-databases]

```js
const result = await prisma.post.findMany({
  where: {
    OR: [
      {
        title: {
          contains: "Prisma",
        },
      },
      {
        title: {
          contains: "databases",
        },
      },
    ],
  },
});
```

##### Get all `Post` records where the `title` field contains `Prisma` or `databases`, but not `SQL` [#get-all-post-records-where-the-title-field-contains-prisma-or-databases-but-not-sql]

The following example combines `OR` and `NOT`:

```js
const result = await prisma.post.findMany({
  where: {
    OR: [
      {
        title: {
          contains: "Prisma",
        },
      },
      {
        title: {
          contains: "databases",
        },
      },
    ],
    NOT: {
      title: {
        contains: "SQL",
      },
    },
  },
});
```

##### Get all `Post` records where the `title` field contains `Prisma` or `databases`, and `published` is `false` [#get-all-post-records-where-the-title-field-contains-prisma-or-databases-and-published-is-false-1]

The following example combines `OR` and `AND`:

```js
const result = await prisma.post.findMany({
  where: {
    OR: [
      {
        title: {
          contains: "Prisma",
        },
      },
      {
        title: {
          contains: "databases",
        },
      },
    ],
    AND: {
      published: false,
    },
  },
});
```

### `NOT` [#not-1]

All conditions must return `false`.

#### Examples [#examples-51]

##### Get all `Post` records where the `title` does not contain `SQL` [#get-all-post-records-where-the-title-does-not-contain-sql]

```js
const result = await prisma.post.findMany({
  where: {
    NOT: {
      title: {
        contains: "SQL",
      },
    },
  },
});
```

##### Get all `Post` records where the `title` field contains `Prisma` or `databases`, but not `SQL`, and the related `User` record' email address does not contain `sarah` [#get-all-post-records-where-the-title-field-contains-prisma-or-databases-but-not-sql-and-the-related-user-record-email-address-does-not-contain-sarah]

```js
const result = await prisma.post.findMany({
  where: {
    OR: [
      {
        title: {
          contains: "Prisma",
        },
      },
      {
        title: {
          contains: "databases",
        },
      },
    ],
    NOT: {
      title: {
        contains: "SQL",
      },
    },
    user: {
      NOT: {
        email: {
          contains: "sarah",
        },
      },
    },
  },
  include: {
    user: true,
  },
});
```

## Relation filters [#relation-filters]

### `some` [#some]

Returns all records where **one or more** ("some") *related* records match filtering criteria.

#### Remarks [#remarks-24]

* You can use `some` without parameters to return all records with at least one relation

#### Examples [#examples-52]

##### Get all `User` records where *some* posts mention `Prisma` [#get-all-user-records-where-some-posts-mention-prisma]

```ts
const result = await prisma.user.findMany({
  where: {
    post: {
      some: {
        content: {
          contains: "Prisma"
        }
      }
    }
  }
}
```

### `every` [#every]

Returns all records where **all** ("every") *related* records match filtering criteria.

#### Examples [#examples-53]

##### Get all `User` records where *all* posts are published [#get-all-user-records-where-all-posts-are-published]

```ts
const result = await prisma.user.findMany({
  where: {
    post: {
      every: {
        published: true
      },
    }
  }
}
```

### `none` [#none]

Returns all records where **zero** *related* records match filtering criteria.

#### Remarks [#remarks-25]

* You can use `none` without parameters to [return all records with no relations](#get-all-user-records-with-zero-posts)

#### Examples [#examples-54]

##### Get all `User` records with zero posts [#get-all-user-records-with-zero-posts]

```ts
const result = await prisma.user.findMany({
  where: {
    post: {
        none: {} // User has no posts
    }
  }
}
```

##### Get all `User` records with zero published posts [#get-all-user-records-with-zero-published-posts]

```ts
const result = await prisma.user.findMany({
  where: {
    post: {
        none: {
          published: true
        }
    }
  }
}
```

### `is` [#is]

Returns all records where related record matches filtering criteria (for example, user's name `is` Bob).

#### Examples [#examples-55]

##### Get all `Post` records where user's name is `"Bob"` [#get-all-post-records-where-users-name-is-bob]

```ts
const result = await prisma.post.findMany({
  where: {
    user: {
        is: {
          name: "Bob"
        },
    }
  }
}
```

### `isNot` [#isnot]

Returns all records where the related record does not match the filtering criteria (for example, user's name `isNot` Bob).

#### Examples [#examples-56]

##### Get all `Post` records where user's name is NOT `"Bob"` [#get-all-post-records-where-users-name-is-not-bob]

```ts
const result = await prisma.post.findMany({
  where: {
    user: {
        isNot: {
          name: "Bob"
        },
    }
  }
}
```

## Scalar list methods [#scalar-list-methods]

### `set` [#set-1]

Use `set` to overwrite the value of a scalar list field.

#### Remarks [#remarks-26]

* `set` is optional - you can set the value directly:

  ```ts
  tags: ["computers", "books"];
  ```

#### Examples [#examples-57]

##### Set the value of `tags` to a list of string values [#set-the-value-of-tags-to-a-list-of-string-values]

```ts
const setTags = await prisma.post.update({
  where: {
    id: 9,
  },
  data: {
    tags: {
      set: ["computing", "books"],
    },
  },
});
```

##### Set `tags` to a list of values *without* using the `set` keyword [#set-tags-to-a-list-of-values-without-using-the-set-keyword]

```ts
const setTags = await prisma.post.update({
  where: {
    id: 9,
  },
  data: {
    tags: ["computing", "books"],
  },
});
```

#### Set the value of `tags` to a single string value [#set-the-value-of-tags-to-a-single-string-value]

```ts
const setTags = await prisma.post.update({
  where: {
    id: 9,
  },
  data: {
    tags: {
      set: "computing",
    },
  },
});
```

### `push` [#push]

Use `push` to add *one* value or *multiple* values to a scalar list field.

#### Remarks [#remarks-27]

* Available for PostgreSQL and MongoDB only.
* You can push a list of values or only a single value.

#### Examples [#examples-58]

##### Add a `computing` item to the `tags` list [#add-a-computing-item-to-the-tags-list]

```ts
const addTag = await prisma.post.update({
  where: {
    id: 9,
  },
  data: {
    tags: {
      push: "computing",
    },
  },
});
```

```ts
const addTag = await prisma.post.update({
  where: {
    id: 9,
  },
  data: {
    tags: {
      push: ["computing", "genetics"],
    },
  },
});
```

### `unset` [#unset]

Use `unset` to unset the value of a scalar list (MongoDB only). Unlike `set: null`, `unset` removes the list entirely.

#### Examples [#examples-59]

##### Unset the value of `tags` [#unset-the-value-of-tags]

```ts
const setTags = await prisma.post.update({
  where: {
    id: 9,
  },
  data: {
    tags: {
      unset: true,
    },
  },
});
```

## Scalar list filters [#scalar-list-filters]

Scalar list filters allow you to filter by the contents of a list / array field.

> [!WARNING]
> Available for PostgreSQL, CockroachDB, and MongoDB.

### Remarks [#remarks-28]

* Scalar list / array filters [ignore `NULL` values](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-scalar-lists-arrays#null-values-in-arrays) . Using `isEmpty` or `NOT` does not return records with `NULL` value lists / arrays, and `{ equals: null }` results in an error.

### `has` [#has]

The given value exists in the list.

#### Examples [#examples-60]

The following query returns all `Post` records where the `tags` list includes `"databases"`:

```ts
const posts = await client.post.findMany({
  where: {
    tags: {
      has: "databases",
    },
  },
});
```

The following query returns all `Post` records where the `tags` list **does not** include `"databases"`:

```ts
const posts = await client.post.findMany({
  where: {
    NOT: {
      tags: {
        has: "databases",
      },
    },
  },
});
```

### `hasEvery` [#hasevery]

Every value exists in the list.

#### Examples [#examples-61]

The following query returns all `Post` records where the `tags` list includes *at least* `"databases"` *and* `"typescript"`:

```ts
const posts = await prisma.post.findMany({
  where: {
    tags: {
      hasEvery: ["databases", "typescript"],
    },
  },
});
```

### `hasSome` [#hassome]

At least one value exists in the list.

#### Examples [#examples-62]

The following query returns all `Post` records where the `tags` list includes `"databases"` *or* `"typescript"`:

```ts
const posts = await prisma.post.findMany({
  where: {
    tags: {
      hasSome: ["databases", "typescript"],
    },
  },
});
```

### `isEmpty` [#isempty]

The list is empty.

#### Examples [#examples-63]

The following query returns all `Post` records that have no tags:

```ts
const posts = await prisma.post.findMany({
  where: {
    tags: {
      isEmpty: true,
    },
  },
});
```

### `isSet` [#isset]

Filter lists to include only results that have been set (MongoDB only) (either set to a value, or explicitly set to `null`). Setting this filter to `true` will exclude undefined results that are not set at all.

#### Examples [#examples-64]

The following query returns all `Post` records where the `tags` have been set to either `null` or a value:

```ts
const posts = await prisma.post.findMany({
  where: {
    tags: {
      isSet: true,
    },
  },
});
```

### `equals` [#equals-1]

The list matches the given value exactly.

#### Examples [#examples-65]

The following query returns all `Post` records where the `tags` list includes `"databases"` and `"typescript"` only:

```ts
const posts = await prisma.post.findMany({
  where: {
    tags: {
      equals: ["databases", "typescript"],
    },
  },
});
```

## Composite type methods [#composite-type-methods]

Composite type methods allow you to create, update and delete [composite types](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/composite-types) (MongoDB only).

### `set` [#set-2]

Use `set` to overwrite the value of a composite type.

#### Remarks [#remarks-29]

* The `set` keyword is optional - you can set the value directly:
  ```ts
  photos: [
    { height: 100, width: 200, url: "1.jpg" },
    { height: 100, width: 200, url: "2.jpg" },
  ];
  ```

#### Examples [#examples-66]

##### Set the `shippingAddress` composite type within a new `order` [#set-the-shippingaddress-composite-type-within-a-new-order]

```ts
const order = await prisma.order.create({
  data: {
    // Normal relation
    product: { connect: { id: "some-object-id" } },
    color: "Red",
    size: "Large",
    // Composite type
    shippingAddress: {
      set: {
        street: "1084 Candycane Lane",
        city: "Silverlake",
        zip: "84323",
      },
    },
  },
});
```

##### Set an optional composite type to `null` [#set-an-optional-composite-type-to-null]

```ts
const order = await prisma.order.create({
  data: {
    // Embedded optional type, set to null
    billingAddress: {
      set: null,
    },
  },
});
```

### `unset` [#unset-1]

Use `unset` to unset the value of a composite type. Unlike `set: null`, this removes the field entirely from the MongoDB document.

#### Examples [#examples-67]

##### Remove the `billingAddress` from an `order` [#remove-the-billingaddress-from-an-order]

```ts
const order = await prisma.order.update({
  where: {
    id: "some-object-id",
  },
  data: {
    billingAddress: {
      // Unset the billing address
      // Removes "billingAddress" field from order
      unset: true,
    },
  },
});
```

### `update` [#update-2]

Use `update` to update fields within a required composite type.

#### Remarks [#remarks-30]

The `update` method cannot be used on optional types. Instead, use [upsert](#upsert-2)

#### Examples [#examples-68]

##### Update the zip field of a `shippingAddress` composite type [#update-the-zip-field-of-a-shippingaddress-composite-type]

```ts
const order = await prisma.order.update({
  where: {
    id: "some-object-id",
  },
  data: {
    shippingAddress: {
      // Update just the zip field
      update: {
        zip: "41232",
      },
    },
  },
});
```

### `upsert` [#upsert-2]

Use `upsert` to update an existing optional composite type if it exists, and otherwise set the composite type.

#### Remarks [#remarks-31]

The `upsert` method cannot be used on required types. Instead, use [update](#update-2)

#### Examples [#examples-69]

##### Create a new `billingAddress` if it doesn't exist, and otherwise update it [#create-a-new-billingaddress-if-it-doesnt-exist-and-otherwise-update-it]

```ts
const order = await prisma.order.update({
  where: {
    id: "some-object-id",
  },
  data: {
    billingAddress: {
      // Create the address if it doesn't exist,
      // otherwise update it
      upsert: {
        set: {
          street: "1084 Candycane Lane",
          city: "Silverlake",
          zip: "84323",
        },
        update: {
          zip: "84323",
        },
      },
    },
  },
});
```

### `push` [#push-1]

Use `push` to push values to the end of a list of composite types.

#### Examples [#examples-70]

##### Add a new photo to the `photos` list [#add-a-new-photo-to-the-photos-list]

```ts
const product = prisma.product.update({
  where: {
    id: 10,
  },
  data: {
    photos: {
      // Push a photo to the end of the photos list
      push: [{ height: 100, width: 200, url: "1.jpg" }],
    },
  },
});
```

## Composite type filters [#composite-type-filters]

Composite type filters allow you to filter the contents of [composite types](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/composite-types) (MongoDB only).

### `equals` [#equals-2]

Use `equals` to filter results by matching a composite type or a list of composite types. Requires all required fields of the composite type to match.

#### Remarks [#remarks-32]

When matching optional fields, you need to distinguish between undefined (missing) fields of the document, and fields that have been explicitly set to `null`:

* If you omit an optional field, it will match undefined fields, but not fields that have been set to `null`
* If you filter for `null` values of an optional field with `equals: { ... exampleField: null ... }`, then it will match only documents where the field has been set to `null`, and not undefined fields

The ordering of fields and lists matters when using `equals`:

* For fields, `{ "a": "1", "b": "2" }` and `{ "b": "2", "a": "1" }` are not considered equal
* For lists, `[ { "a": 1 }, { "a": 2 } ]` and `[ { "a": 2 }, { "a": 1 } ]` are not considered equal

#### Examples [#examples-71]

##### Find orders that exactly match the given `shippingAddress` [#find-orders-that-exactly-match-the-given-shippingaddress]

```ts
const orders = await prisma.order.findMany({
  where: {
    shippingAddress: {
      equals: {
        street: "555 Candy Cane Lane",
        city: "Wonderland",
        zip: "52337",
      },
    },
  },
});
```

##### Find products with photos that match all of a list of `url`s [#find-products-with-photos-that-match-all-of-a-list-of-urls]

```ts
const product = prisma.product.findMany({
  where: {
    equals: {
      photos: [{ url: "1.jpg" }, { url: "2.jpg" }],
    },
  },
});
```

### `is` [#is-1]

Use `is` to filter results by matching specific fields within composite types.

#### Examples [#examples-72]

##### Find orders with a `shippingAddress` that matches the given street name [#find-orders-with-a-shippingaddress-that-matches-the-given-street-name]

```ts
const orders = await prisma.order.findMany({
  where: {
    shippingAddress: {
      is: {
        street: "555 Candy Cane Lane",
      },
    },
  },
});
```

### `isNot` [#isnot-1]

Use `isNot` to filter results for composite type fields that do not match.

#### Examples [#examples-73]

##### Find orders with a `shippingAddress` that does not match the given zip code [#find-orders-with-a-shippingaddress-that-does-not-match-the-given-zip-code]

```ts
const orders = await prisma.order.findMany({
  where: {
    shippingAddress: {
      isNot: {
        zip: "52337",
      },
    },
  },
});
```

### `isEmpty` [#isempty-1]

Use `isEmpty` to filter results for an empty list of composite types.

#### Examples [#examples-74]

##### Find products with no photos [#find-products-with-no-photos]

```ts
const product = prisma.product.findMany({
  where: {
    photos: {
      isEmpty: true,
    },
  },
});
```

### `every` [#every-1]

Use `every` to filter for lists of composite types where every item in the list matches the condition

#### Examples [#examples-75]

##### Find the first product where every photo has a `height` of `200` [#find-the-first-product-where-every-photo-has-a-height-of-200]

```ts
const product = await prisma.product.findFirst({
  where: {
    photos: {
      every: {
        height: 200,
      },
    },
  },
});
```

### `some` [#some-1]

Use `some` to filter for lists of composite types where one or more items in the list match the condition.

#### Examples [#examples-76]

##### Find the first product where one or more photos have a `url` of `2.jpg` [#find-the-first-product-where-one-or-more-photos-have-a-url-of-2jpg]

```ts
const product = await prisma.product.findFirst({
  where: {
    photos: {
      some: {
        url: "2.jpg",
      },
    },
  },
});
```

### `none` [#none-1]

Use `none` to filter for lists of composite types where no items in the list match the condition.

#### Examples [#examples-77]

##### Find the first product where no photos have a `url` of `2.jpg` [#find-the-first-product-where-no-photos-have-a-url-of-2jpg]

```ts
const product = await prisma.product.findFirst({
  where: {
    photos: {
      none: {
        url: "2.jpg",
      },
    },
  },
});
```

## Atomic number operations [#atomic-number-operations]

Atomic operations on update is available for number field types (`Float` and `Int`). This feature allows you to update a field based on its **current** value (such as *subtracting* or *dividing*) without risking a race condition.

**Overview: Race conditions**

A race conditions occurs when two or more operations must be done in sequence in order to complete a task. In the following example, two clients try to increase the same field (`postCount`) by one:

| Client   | Operation           | Value  |
| :------- | :------------------ | :----- |
| Client 1 | **Get** field value | `21`   |
| Client 2 | **Get** field value | `21`   |
| Client 2 | **Set** field value | `22`   |
| Client 1 | **Set** field value | `22` ✘ |

The value *should* be `23`, but the two clients did not read and write to the `postCount` field in sequence. Atomic operations on update combine read and write into a single operation, which prevents a race condition:

| Client   | Operation                   | Value         |
| :------- | :-------------------------- | :------------ |
| Client 1 | **Get and set** field value | `21` → `22`   |
| Client 2 | **Get and set** field value | `22` → `23` ✔ |

### Operators [#operators]

| Option      | Description                                                   |
| :---------- | :------------------------------------------------------------ |
| `increment` | Adds `n` to the current value.                                |
| `decrement` | Subtracts `n` from the current value.                         |
| `multiply`  | Multiplies the current value by `n`.                          |
| `divide`    | Divides the current value by `n`.                             |
| `set`       | Sets the current field value. Identical to `{ myField : n }`. |

### Remarks [#remarks-33]

* You can only perform **one** atomic update per field, per query.
* If a field is `null`, it will not be updated by `increment`, `decrement`, `multiply`, or `divide`.

### Examples [#examples-78]

#### Increment all `view` and `likes` fields of all `Post` records by `1` [#increment-all-view-and-likes-fields-of-all-post-records-by-1]

```ts
const updatePosts = await prisma.post.updateMany({
  data: {
    views: {
      increment: 1,
    },
    likes: {
      increment: 1,
    },
  },
});
```

#### Set all `views` fields of all `Post` records to `0` [#set-all-views-fields-of-all-post-records-to-0]

```ts
const updatePosts = await prisma.post.updateMany({
  data: {
    views: {
      set: 0,
    },
  },
});
```

Can also be written as:

```ts
const updatePosts = await prisma.post.updateMany({
  data: {
    views: 0,
  },
});
```

## `Json` filters [#json-filters]

For use cases and advanced examples, see: [Working with `Json` fields](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-json-fields).

> [!WARNING]
> Supported by [PostgreSQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql) and [MySQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql) with different syntaxes for the `path` option. PostgreSQL does not support filtering on object key values in arrays.

The examples in this section assumes that the value of the `pet` field is:

```json
{
  "favorites": {
    "catBreed": "Turkish van",
    "dogBreed": "Rottweiler",
    "sanctuaries": ["RSPCA", "Alley Cat Allies"],
    "treats": [
      { "name": "Dreamies", "manufacturer": "Mars Inc" },
      { "name": "Treatos", "manufacturer": "The Dog People" }
    ]
  },
  "fostered": {
    "cats": ["Bob", "Alice", "Svetlana the Magnificent", "Queenie"]
  },
  "owned": {
    "cats": ["Elliott"]
  }
}
```

### Remarks [#remarks-34]

* The implementation of `Json` filtering [differs between database connectors](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-json-fields)
* Filtering is case sensitive in PostgreSQL and does not yet support `mode`

### `path` [#path]

`path` represents the location of a specific key. The following query returns all users where the nested `favorites` > `dogBreed` key equals `"Rottweiler"`.

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: ["favorites", "dogBreed"],
      equals: "Rottweiler",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.favorites.dogBreed",
      equals: "Rottweiler",
    },
  },
});
```

The following query returns all users where the nested `owned` > `cats` array contains `"Elliott"`.

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: ["owned", "cats"],
      array_contains: ["Elliott"],
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.owned.cats",
      array_contains: "Elliott",
    },
  },
});
```

> [!WARNING]
> Filtering by the key values of objects inside an array (below) is only supported by the MySQL connector.

The following query returns all users where the nested `favorites` > `treats` array contains an object where the `name` value is `"Dreamies"`:

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.favorites.treats[*].name",
      array_contains: "Dreamies",
    },
  },
});
```

### `string_contains` [#string_contains]

The following query returns all users where the nested `favorites` > `catBreed` key value contains `"Van"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: ["favorites", "catBreed"],
      string_contains: "Van",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.favorites.catBreed",
      string_contains: "Van",
    },
  },
});
```

### `string_starts_with` [#string_starts_with]

The following query returns all users where the nested `favorites` > `catBreed` key value starts with `"Turkish"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: ["favorites", "catBreed"],
      string_starts_with: "Turkish",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.favorites.catBreed",
      string_starts_with: "Turkish",
    },
  },
});
```

### `string_ends_with` [#string_ends_with]

The following query returns all users where the nested `favorites` > `catBreed` key value ends with `"Van"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: ["favorites", "catBreed"],
      string_ends_with: "Van",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.favorites.catBreed",
      string_ends_with: "Van",
    },
  },
});
```

### `mode` [#mode-1]

Specify whether the string filtering should be case sensitive (default) or case insensitive.

The following query returns all users where the nested `favorites` > `catBreed` key value contains `"Van"` or `"van"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: ["favorites", "catBreed"],
      string_contains: "Van",
      mode: "insensitive",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.favorites.catBreed",
      string_contains: "Van",
      mode: "insensitive",
    },
  },
});
```

### `array_contains` [#array_contains]

The following query returns all users where the `sanctuaries` array contains the value `"RSPCA"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: ["sanctuaries"],
      array_contains: ["RSPCA"],
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.sanctuaries",
      array_contains: "RSPCA",
    },
  },
});
```

> [!NOTE]
> In PostgreSQL, the value of `array_contains` must be an array and not a string, even if the array only contains a single value.

The following query returns all users where the `sanctuaries` array contains *all* the values in the given array:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: ["sanctuaries"],
      array_contains: ["RSPCA", "Alley Cat Allies"],
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.sanctuaries",
      array_contains: ["RSPCA", "Alley Cat Allies"],
    },
  },
});
```

### `array_starts_with` [#array_starts_with]

The following query returns all users where the `sanctuaries` array starts with the value `"RSPCA"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: ["sanctuaries"],
      array_starts_with: "RSPCA",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.sanctuaries",
      array_starts_with: "RSPCA",
    },
  },
});
```

### `array_ends_with` [#array_ends_with]

The following query returns all users where the `sanctuaries` array ends with the value `"Alley Cat Allies"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: ["sanctuaries"],
      array_ends_with: "Alley Cat Allies",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    pets: {
      path: "$.sanctuaries",
      array_ends_with: "Alley Cat Allies",
    },
  },
});
```

## Client methods [#client-methods]

**Note:** Client-level methods are prefixed by `$`.

### Remarks [#remarks-35]

* `$on` and `$use` client methods do not exist on extended client instances which are extended using [`$extends`](#extends)

> [!WARNING]
> In [extended clients](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions), Client methods do not necessarily exist. If you are extending your client, make sure to check for existence before using Client methods like `$transaction` or `$connect`.
> 
> In addition, if you are using `$on` or `$use`, you will need to use these client methods before extending your client as these methods do not exist on extended clients. For `$use` specifically we recommend transitioning [to use query extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query).

### `$disconnect()` [#disconnect-1]

The `$disconnect()` method closes the database connections that were established when `$connect` was called and stops the process that was running Prisma ORM's query engine. See [Connection management](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-management) for an overview of `$connect()` and `$disconnect()`.

#### Remarks [#remarks-36]

* `$disconnect()` returns a `Promise`, so you should call it inside an `async` function with the `await` keyword.

### `$connect()` [#connect-1]

The `$connect()` method establishes a physical connection to the database via Prisma ORM's query engine. See [Connection management](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-management) for an overview of `$connect()` and `$disconnect()`.

#### Remarks [#remarks-37]

* `$connect()` returns a `Promise`, so you should call it inside an `async` function with the `await` keyword.

### `$on()` [#on]

> [!WARNING]
> `$on` is not available in [extended clients](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions). Please either migrate to client extensions or use the `$on` method prior to extending your client.

The `$on()` method allows you to subscribe to [logging events](#log) or the [exit hook](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-management#exit-hooks).

### `$queryRawTyped` [#queryrawtyped]

See: [Using Raw SQL (`$queryRawTyped`)](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql).

### `$queryRaw` [#queryraw]

See: [Using Raw SQL (`$queryRaw`)](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#queryraw).

### `$queryRawUnsafe()` [#queryrawunsafe]

See: [Using Raw SQL (`$queryRawUnsafe()`)](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#queryrawunsafe).

### `$executeRaw` [#executeraw]

See: [Using Raw SQL (`$executeRaw`)](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#executeraw).

### `$executeRawUnsafe()` [#executerawunsafe]

See: [Using Raw SQL (`$executeRawUnsafe()`)](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#executerawunsafe).

### `$runCommandRaw()` [#runcommandraw]

See: [Using Raw SQL (`$runCommandRaw()`)](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#runcommandraw).

### `$transaction()` [#transaction]

See: [Transactions](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions).

### `$extends` [#extends]

With `$extends`, you can create and use Prisma Client extensions to add functionality to Prisma Client in the following ways:

* `model`: add custom methods to your models
* `client`: add custom methods to your client
* `query`: create custom Prisma Client queries
* `result`: add custom fields to your query results

Learn more: [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions).

## Utility types [#utility-types]

Utility types are helper functions and types that live on the `Prisma` namespace. They are useful for keeping your application type safe.

### Type-checking with `satisfies` [#type-checking-with-satisfies]

You can use TypeScript's `satisfies` operator to create re-usable query parameters based on your schema models while ensuring that the objects you create are type-compatible with the generated Prisma Client types. See also: [Type safety with Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety).

Use the generated Prisma Client types with `satisfies` to get type checking and inference:

```ts
const args = { ... } satisfies Prisma.GeneratedType;
```

#### Example [#example-3]

The following example shows how you can create type-checked input for the `create` operation that you can reuse within your app:

```ts
import { Prisma } from "../prisma/generated/client";

const createUserAndPostInput = (
  name: string,
  email: string,
  postTitle: string,
) =>
  ({
    name,
    email,
    posts: {
      create: {
        title: postTitle,
      },
    },
  }) satisfies Prisma.UserCreateInput;
```

## Compare columns in the same table [#compare-columns-in-the-same-table]

You can compare columns in the same table directly, for non-unique filters.

> [!NOTE]
> In the following situations, you must [use raw queries to compare columns in the same table](https://www.prisma.io/docs/orm/v7/more/troubleshooting/raw-sql-comparisons):
> 
> * If you want to use a unique filter, such as [`findUnique`](#findunique) or [`findUniqueOrThrow`](#finduniqueorthrow)
> * If you want to compare a field with a [unique constraint](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-a-unique-field)
> * If you want to use one of the following operators to compare a [JSON field](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-json-fields) in MySQL or MariaDB with another field: [`gt`](#gt), [`gte`](#gte), [`lt`](#lt), or [`lte`](#lte). Note that you can use these operators to compare the JSON field with a scalar value. This limitation applies only if you try to compare a JSON field with another field.

To compare columns in the same table, use the `<model>.fields` property. In the following example, the query returns all records where the value in the `prisma.product.quantity` field is less than or equal to the value in the `prisma.product.warnQuantity` field.

```ts
prisma.product.findMany({
  where: { quantity: { lte: prisma.product.fields.warnQuantity } },
});
```

> [!NOTE]
> `fields` is a special property of every model. It contains the list of fields for that model.

### Considerations [#considerations]

#### Fields must be of the same type [#fields-must-be-of-the-same-type]

You can only make comparisons on fields of the same type. For example, the following causes an error:

```ts
await prisma.order.findMany({
  where: {
    id: { equals: prisma.order.fields.due },
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // Type error: id is a string, while amountDue is an integer
  },
});
```

#### Fields must be in the same model [#fields-must-be-in-the-same-model]

You can only make comparisons with the `fields` property on fields in the same model. The following example does not work:

```ts
await prisma.order.findMany({
  where: {
    id: { equals: prisma.user.fields.name },
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // Type error: name is a field on the User model, not Order
  },
});
```

However, you can compare fields in separate models with [standard queries](#model-queries).

#### In `groupBy` model queries, put your referenced fields in the `by` argument [#in-groupby-model-queries-put-your-referenced-fields-in-the-by-argument]

If you use the [groupBy](#groupby) model query with the `having` option, then you must put your referenced fields in the `by` argument.

The following example works:

```ts
prisma.user.groupBy({
  by: ["id", "name"],
  having: { id: { equals: prisma.user.fields.name } },
});
```

The following example does not work, because `name` is not in the `by` argument:

```ts
prisma.user.groupBy({
  by: ["id"],
  having: { id: { equals: prisma.user.fields.name } },
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // name is not in the 'by' argument
});
```

#### Search for fields in scalar lists [#search-for-fields-in-scalar-lists]

If your data source supports scalar lists (for example in PostgreSQL), then you can search for all records where a specific field is in a list of fields. To do so, reference the scalar list with the [`in`](#in) and [`notIn`](#notin) filters. For example:

```ts
await prisma.user.findMany({
  where: {
    // find all users where 'name' is in a list of tags
    name: { in: prisma.user.fields.tags },
  },
});
```

## Filter on non-unique fields with `UserWhereUniqueInput` [#filter-on-non-unique-fields-with-userwhereuniqueinput]

The generated type `UserWhereUniqueInput` on [`where`](#where) exposes all fields on the model, not just unique fields.

You must specify at least one unique field in your `where` statement [outside of boolean operators](#boolean-operators-with-userwhereuniqueinput), and you can specify any number of additional unique and non-unique fields. You can use this to add filters to any operation that returns a single record. For example, you can use this feature for the following:

* [Optimistic concurrency control on updates](#optimistic-concurrency-control-on-updates)
* [Permission checks](#permission-checks)
* [Soft deletes](#soft-deletes)
* Filter on optional [one-to-one nested reads](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-reads)

### Optimistic concurrency control on updates [#optimistic-concurrency-control-on-updates]

You can filter on non-unique fields to perform [optimistic concurrency control](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#optimistic-concurrency-control) on `update` operations.

To perform optimistic concurrency control, use a `version` field to check whether the data in a record or related record has changed while your code executes.

In the following example, `updateOne` and `updateTwo` first read the same record and then attempt to update it. The database only executes these updates if the value in `version` is the same as the value when it did the initial read. When the database executes the first of these updates (which might be `updateOne` or `updateTwo`, depending on timing), it increments the value in `version`. This means that the database does not execute the second update because the value in `version` has changed.

```prisma
model User {
  id      Int    @id @default(autoincrement())
  email   String @unique
  city    String
  version Int
}
```

```ts
function updateOne() {
  const user = await prisma.user.findUnique({ id: 1 });

  await prisma.user.update({
    where: { id: user.id, version: user.version },
    data: { city: "Berlin", version: { increment: 1 } },
  });
}

function updateTwo() {
  const user = await prisma.user.findUnique({ id: 1 });

  await prisma.user.update({
    where: { id: user.id, version: user.version },
    data: { city: "New York", version: { increment: 1 } },
  });
}

function main() {
  await Promise.allSettled([updateOne(), updateTwo()]);
}
```

### Permission checks [#permission-checks]

You can filter on non-unique fields to check permissions during an update.

In the following example, a user wants to update a post title. The `where` statement checks the value in `authorId` to confirm that the user is the author of the post. The application only updates the post title if the user is the post author.

```ts
await prisma.post.update({
  where: { id: 1, authorId: 1 },
  data: { title: "Updated post title" },
});
```

### Soft deletes [#soft-deletes]

You can filter on non-unique fields to handle soft deletes.

In the following example, we do not want to return a post if it is soft-deleted. The operation only returns the post if the value in `isDeleted` is `false`.

```ts
prisma.Post.findUnique({ where: { id: postId, isDeleted: false } });
```

### `UserWhereUniqueInput` considerations [#userwhereuniqueinput-considerations]

#### Boolean operators with `UserWhereUniqueInput` [#boolean-operators-with-userwhereuniqueinput]

With `UserWhereUniqueInput`, you must specify at least one unique field outside of the boolean operators `AND`, `OR`, `NOT`. You can still use these boolean operators in conjunction with any other unique fields or non-unique fields in your filter.

In the following example, we test `id`, a unique field, in conjunction with `email`. This is valid.

```ts
await prisma.user.update({
  where: { id: 1, OR: [{ email: "bob@prisma.io" }, { email: "alice@prisma.io" }] },
        // ^^^ Valid: the expression specifies a unique field (`id`) outside of any boolean operators
  data: { ... }
})

// SQL equivalent:
// WHERE id = 1 AND (email = "bob@prisma.io" OR email = "alice@prisma.io")
```

The following example is not valid, because there is no unique field outside of any boolean operators:

```ts
await prisma.user.update({
  where: { OR: [{ email: "bob@prisma.io" }, { email: "alice@prisma.io" }] },
        // ^^^ Invalid: the expressions does not contain a unique field outside of boolean operators
  data: { ... }
})
```

#### One-to-one relations [#one-to-one-relations]

You can filter on non-unique fields in the following operations on [one-to-one relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-one-relations):

* Nested update
* Nested upsert
* Nested disconnect
* Nested delete

Prisma Client automatically uses a unique filter to select the appropriate related record. As a result, you do not need to specify a unique filter in your `where` statement with a `WhereUniqueInput` [generated type](#generated-types-for-where). Instead, the `where` statement has a `WhereInput` generated type. You can use this to filter without the restrictions of `WhereUniqueInput`.

##### Nested update example [#nested-update-example]

```ts
await prisma.user.update({
  where: { id: 1 },
  data: {
    to_one: {
      update: { where: { /* WhereInput */ }, data: { field: "updated" } }
    }
  }
})
```

##### Nested upsert example [#nested-upsert-example]

```ts
await prisma.user.update({
  where: { id: 1 },
  data: {
    to_one: {
      upsert: {
        where: { /* WhereInput */ },
        create: { /* CreateInput */ },
        update: { /* UpdateInput */ },
      }
    }
  }
})
```

##### Nested disconnect example [#nested-disconnect-example]

```ts
await prisma.user.update({
  where: { id: 1 },
  data: {
    to_one: {
      disconnect: { /* WhereInput */ }
    }
  }
})
```

##### Nested delete example [#nested-delete-example]

```ts
await prisma.user.update({
  where: { id: 1 },
  data: {
    to_one: {
      delete: { /* WhereInput */ }
    }
  }
})
```

## `PrismaPromise` behavior [#prismapromise-behavior]

All Prisma Client queries return an instance of `PrismaPromise`. This is a ["thenable"](https://masteringjs.io/tutorials/fundamentals/thenable), meaning a `PrismaPromise` only executes when you call `await` or `.then()` or `.catch()`. This behavior is different from a regular JavaScript [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise), which starts executing immediately.

For example:

```ts
const findPostOperation = prisma.post.findMany({}); // Query not yet executed

findPostOperation.then(); // Prisma Client now executes the query
// or
await findPostOperation; // Prisma Client now executes the query
```

When using the [`$transaction` API](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#the-transaction-api), this behavior makes it possible for Prisma Client to pass all the queries on to the query engine as a single transaction.

## Where to go next [#where-to-go-next]

* [Prisma Client overview](https://www.prisma.io/docs/orm/v7/prisma-client) for a more guided introduction before diving back into the reference
* [CRUD guide](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud) if you want practical examples for the most common query patterns
* [Generating Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client) if you're adjusting client output, runtime setup, or generation workflow
* [Prisma Studio getting started](https://www.prisma.io/docs/studio/getting-started) if you want a visual way to inspect the data you're querying

## Related pages

- [`Config API`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference): Complete reference for prisma.config.ts configuration options
- [`Connection URLs`](https://www.prisma.io/docs/orm/v7/reference/connection-urls): Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite
- [`Database Features`](https://www.prisma.io/docs/orm/v7/reference/database-features): Database features supported in Prisma ORM
- [`Environment Variables`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference): Reference for Prisma environment variables
- [`Error Reference`](https://www.prisma.io/docs/orm/v7/reference/error-reference): Prisma Client, Migrate, and Introspection error codes

# Config API (Prisma ORM v7) (/docs/orm/v7/reference/prisma-config-reference)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Complete reference for prisma.config.ts configuration options

Location: ORM > v7 > Reference > Config API

The Prisma Config file (`prisma.config.ts`) configures the Prisma CLI using TypeScript. It's automatically created when you run `prisma init`.

You can define your config using either the `defineConfig` helper or TypeScript's `satisfies` operator:

* Using the `defineConfig` helper:

  ```ts
  import "dotenv/config";
  import { defineConfig, env } from "prisma/config";

  export default defineConfig({
    schema: "prisma/schema.prisma",
    migrations: {
      path: "prisma/migrations",
      seed: "tsx prisma/seed.ts",
    },
    datasource: {
      url: env("DATABASE_URL"),
    },
  });
  ```

* Using TypeScript's `satisfies` operator with the `PrismaConfig` type:

  ```ts
  import "dotenv/config";
  import type { PrismaConfig } from "prisma";
  import { env } from "prisma/config";

  export default {
    schema: "prisma/schema.prisma",
    migrations: {
      path: "prisma/migrations",
      seed: "tsx prisma/seed.ts",
    },
    datasource: {
      url: env("DATABASE_URL"),
    },
  } satisfies PrismaConfig;
  ```

## Configuration interface [#configuration-interface]

Here is a simplified version of the `PrismaConfig` type:

```ts
export declare type PrismaConfig = {
  // Whether features with an unstable API are enabled.
  experimental: {
    externalTables: boolean;
  };

  // The path to the schema file, or path to a folder that shall be recursively searched for *.prisma files.
  schema?: string;

  // Configuration for Prisma migrations.
  migrations?: {
    path: string;
    seed: string;
    initShadowDb: string;
  };

  // Configuration for the database view entities.
  views?: {
    path: string;
  };

  // Configuration for the `typedSql` preview feature.
  typedSql?: {
    path: string;
  };

  // Database connection configuration
  datasource?: {
    url: string;
    shadowDatabaseUrl?: string;
  };
};
```

## Supported file extensions [#supported-file-extensions]

Prisma Config files can be named as `prisma.config.*` or `.config/prisma.*` with the extensions `js`, `ts`, `mjs`, `cjs`, `mts`, or `cts`. Other extensions are supported to ensure compatibility with different TypeScript compiler settings.

> [!NOTE]
> Recommendation
> 
> * Use &#x2A;*`prisma.config.ts`** for small TypeScript projects.
> * Use &#x2A;*`.config/prisma.ts`** for larger TypeScript projects with multiple configuration files (following the [`.config` directory proposal](https://github.com/pi0/config-dir)).

## Options reference [#options-reference]

### `schema` [#schema]

Configures how Prisma ORM locates and loads your schema file(s). Can be a file or folder path. Relative paths are resolved relative to the `prisma.config.ts` file location. See [Multi-file Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/location#multi-file-prisma-schema) for more info about schema location options.

| Property | Type     | Required | Default                                        |
| -------- | -------- | -------- | ---------------------------------------------- |
| `schema` | `string` | No       | `./prisma/schema.prisma` and `./schema.prisma` |

### `tables.external` and `enums.external` [#tablesexternal-and-enumsexternal]

These options declare tables and enums in your database that are **managed externally** (not by Prisma Migrate). You can still query them with Prisma Client, but they will be ignored by migrations.

| Property          | Type       | Required | Default |
| ----------------- | ---------- | -------- | ------- |
| `tables.external` | `string[]` | No       | `[]`    |
| `enums.external`  | `string[]` | No       | `[]`    |

**Example:**

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
  experimental: {
    externalTables: true,
  },
  tables: {
    external: ["public.users"],
  },
  enums: {
    external: ["public.role"],
  },
});
```

Learn more about the [`externalTables` feature here](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables).

### `migrations.path` [#migrationspath]

The path to the directory where Prisma should store migration files, and look for them.

| Property          | Type     | Required | Default |
| ----------------- | -------- | -------- | ------- |
| `migrations.path` | `string` | No       | none    |

### `migrations.seed` [#migrationsseed]

Defines the command to run when executing `npx prisma db seed`. Seeding is only triggered explicitly via this command.

| Property          | Type     | Required | Default |
| ----------------- | -------- | -------- | ------- |
| `migrations.seed` | `string` | No       | none    |

**Example:**

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "tsx db/seed.ts",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### `migrations.initShadowDb` [#migrationsinitshadowdb]

This option allows you to define SQL statements that Prisma runs on the **shadow database** before creating migrations. It is useful when working with [external managed tables](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables), as Prisma needs to know about the structure of these tables to correctly generate migrations.

| Property                  | Type     | Required | Default |
| ------------------------- | -------- | -------- | ------- |
| `migrations.initShadowDb` | `string` | No       | none    |

**Example:**

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    initShadowDb: `
      CREATE TABLE public.users (id SERIAL PRIMARY KEY);
    `,
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
  experimental: {
    externalTables: true,
  },
  tables: {
    external: ["public.users"],
  },
});
```

Learn more about the [`externalTables` feature here](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables).

### `views.path` [#viewspath]

The path to the directory where Prisma should look for the SQL view definitions.

| Property     | Type     | Required | Default |
| ------------ | -------- | -------- | ------- |
| `views.path` | `string` | No       | none    |

### `typedSql.path` [#typedsqlpath]

The path to the directory where Prisma should look for the SQL files used for generating typings via [`typedSql`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql).

| Property        | Type     | Required | Default |
| --------------- | -------- | -------- | ------- |
| `typedSql.path` | `string` | No       | none    |

### `experimental` [#experimental]

Enables specific experimental features in the Prisma CLI.

| Property         | Type      | Required | Default |
| ---------------- | --------- | -------- | ------- |
| `externalTables` | `boolean` | No       | `false` |

Example:

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
  experimental: {
    externalTables: true,
  },
});
```

> [!NOTE]
> If you use the `externalTables` feature without enabling the experimental flag, Prisma will throw an error:
> 
> ```bash
> Failed to load config file "~" as a TypeScript/JavaScript module. Error: Error: The `externalTables` configuration requires `experimental.externalTables` to be set to `true`.
> ```

### `datasource.url` [#datasourceurl]

Connection URL including authentication info. Uses [the syntax provided by the database](https://www.prisma.io/docs/orm/v7/reference/connection-urls#format).

| Property         | Type     | Required | Default |
| ---------------- | -------- | -------- | ------- |
| `datasource.url` | `string` | Yes      | `''`    |

**Example:**

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

### `datasource.shadowDatabaseUrl` [#datasourceshadowdatabaseurl]

Connection URL to the shadow database used by Prisma Migrate. Allows you to use a cloud-hosted database as the shadow database.

| Property                       | Type     | Required | Default |
| ------------------------------ | -------- | -------- | ------- |
| `datasource.shadowDatabaseUrl` | `string` | No       | `''`    |

### `datasource.directUrl` (Removed) [#datasourcedirecturl-removed]

> [!WARNING]
> Removed in Prisma ORM v7
> 
> The `datasource.directUrl` property has been removed in Prisma ORM v7 in favor of the [`url` property](#datasourceurl).

**For Prisma ORM v6.19 and earlier**

Connection URL for direct connection to the database.

If you use a connection pooler URL in the `url` argument (for example, pgBouncer), Prisma CLI commands that require a direct connection to the database use the URL in the `directUrl` argument.

The `directUrl` property is supported by Prisma Studio from version 5.1.0 upwards. The `directUrl` property is not needed when using [Prisma Postgres](https://www.prisma.io/docs/postgres) database.

| Property               | Type     | Required | Default |
| ---------------------- | -------- | -------- | ------- |
| `datasource.directUrl` | `string` | No       | `''`    |

### `adapter` (Removed) [#adapter-removed]

> [!WARNING]
> Removed in Prisma ORM v7
> 
> The `adapter` property has been removed in Prisma ORM v7. Migrations for driver adapters work automatically without additional configuration in `prisma.config.ts` as of Prisma ORM v7.

**For Prisma ORM v6.19 and earlier**

A function that returns a Prisma driver adapter instance which is used by the Prisma CLI to run migrations. The function should return a `Promise` that resolves to a valid Prisma driver adapter.

  | Property  | Type                                                   | Required | Default |
  | --------- | ------------------------------------------------------ | -------- | ------- |
  | `adapter` | `() => Promise<SqlMigrationAwareDriverAdapterFactory>` | No       | none    |

  Example using the Prisma ORM D1 driver adapter:

  ```ts
  import path from "node:path";
  import type { PrismaConfig } from "prisma";
  import { PrismaD1 } from "@prisma/adapter-d1";

  export default {
    experimental: {
      adapter: true,
    },
    engine: "js",
    schema: path.join("prisma", "schema.prisma"),
    async adapter() {
      return new PrismaD1({
        CLOUDFLARE_D1_TOKEN: process.env.CLOUDFLARE_D1_TOKEN,
        CLOUDFLARE_ACCOUNT_ID: process.env.CLOUDFLARE_ACCOUNT_ID,
        CLOUDFLARE_DATABASE_ID: process.env.CLOUDFLARE_DATABASE_ID,
      });
    },
  } satisfies PrismaConfig;
  ```

  > [!NOTE]
> As of [Prisma ORM v6.11.0](https://github.com/prisma/orm/releases/tag/6.11.0), the D1 adapter has been renamed from `PrismaD1HTTP` to `PrismaD1`.

### `engine` (Removed) [#engine-removed]

> [!WARNING]
> Removed in Prisma ORM v7
> 
> The `engine` property has been removed in Prisma ORM v7.

**For Prisma ORM v6.19 and earlier**

Configure the schema engine your project should use.

| Property | Type              | Required | Default   |
| -------- | ----------------- | -------- | --------- |
| `engine` | `classic` or `js` | No       | `classic` |

By default it is set to use the classic engine, which requires that `datasource` be set in your `prisma.config.ts`.

```ts
import "dotenv/config";
import path from "node:path";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  engine: "classic",
  datasource: {
    url: env("DATABASE_URL"),
  },
  schema: path.join("prisma", "schema.prisma"),
});
```

### `studio` (Removed) [#studio-removed]

> [!WARNING]
> Removed in Prisma ORM v7
> 
> The `studio` property has been removed in Prisma ORM v7. To run Prisma Studio, use:
> 
> 
>   
> 
>   #### bun

>     ```bash
>     bunx prisma studio --config ./prisma.config.ts
>     ```
>
> 
>   #### pnpm

>     ```bash
>     pnpm prisma studio --config ./prisma.config.ts
>     ```
>
> 
>   #### yarn

>     ```bash
>     yarn prisma studio --config ./prisma.config.ts
>     ```
>
> 
>   #### npm

>     ```bash
>     npx prisma studio --config ./prisma.config.ts
>     ```
>
> 
> 
> Prisma Studio now uses the connection configuration from the `datasource` property automatically. See the [Prisma Studio documentation](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#studio) for more details.

**For Prisma ORM v6.19 and earlier**

Configures how Prisma Studio connects to your database. See sub-options below for details.

| Property | Type     | Required | Default |
| -------- | -------- | -------- | ------- |
| `studio` | `object` | No       | none    |

#### `studio.adapter` (Removed) [#studioadapter-removed]

A function that returns a Prisma driver adapter instance. The function receives an `env` parameter containing environment variables and should return a `Promise` that resolves to a valid Prisma driver adapter.

| Property          | Type                                                           | Required | Default |
| ----------------- | -------------------------------------------------------------- | -------- | ------- |
| `studio.adapter ` | `(env: Env) => Promise<SqlMigrationAwareDriverAdapterFactory>` | No       | none    |

Example using the Prisma ORM LibSQL driver adapter:

```ts
import type { PrismaConfig } from "prisma";

export default {
  experimental: {
    studio: true,
  },
  engine: "js",
  studio: {
    adapter: async (env: Env) => {
      const { PrismaLibSQL } = await import("@prisma/adapter-libsql");
      const { createClient } = await import("@libsql/client");

      const libsql = createClient({
        url: env.DOTENV_PRISMA_STUDIO_LIBSQL_DATABASE_URL,
      });
      return new PrismaLibSQL(libsql);
    },
  },
} satisfies PrismaConfig;
```

## Common patterns [#common-patterns]

### Setting up your project [#setting-up-your-project]

To get started with Prisma Config, create a `prisma.config.ts` file in your project root. You can use either of these approaches:

Using `defineConfig`:

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Using TypeScript types:

```ts
import "dotenv/config";
import type { PrismaConfig } from "prisma";
import { env } from "prisma/config";

export default {
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
} satisfies PrismaConfig;
```

### Using environment variables [#using-environment-variables]

Environment variables from `.env` files need to be loaded explicitly. The `prisma init` command generates a config that includes `import 'dotenv/config'` by default.

#### Using dotenv (Recommended for Prisma ORM v7) [#using-dotenv-recommended-for-prisma-orm-v7]

1. Install the `dotenv` package:

  

#### bun

```bash
bun add dotenv
```

#### pnpm

```bash
pnpm add dotenv
```

#### yarn

```bash
yarn add dotenv
```

#### npm

```bash
npm install dotenv
```

2. Import `dotenv/config` at the top of your `prisma.config.ts` file:

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "tsx prisma/seed.ts",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

#### Using Node.js v20+ or tsx with --env-file flag [#using-nodejs-v20-or-tsx-with---env-file-flag]

If using Node.js v20+ or `tsx`, you can pass a `--env-file` flag to automatically load environment variables:

```bash
tsx --env-title=".env" src/index.ts
tsx watch --env-title=".env" --env-title=".local.env" src/index.ts
tsx --env-title=".env" ./prisma/seed.ts
```

#### Using Bun [#using-bun]

For Bun, `.env` files are automatically loaded without additional configuration. The `import 'dotenv/config'` line that `prisma init` generates is not needed when using Bun and can be safely removed from your `prisma.config.ts` file.

> [!NOTE]
> When running `prisma init` with Bun, use the `--bun` flag (for example, `bunx --bun prisma init`) to ensure Prisma uses the Bun runtime instead of falling back to Node.js.

#### Type-safe environment variables [#type-safe-environment-variables]

Use the `env()` helper function to provide type-safe access to environment variables:

```ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

type Env = {
  DATABASE_URL: string;
};

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env<Env>("DATABASE_URL"),
  },
});
```

#### Handling optional environment variables [#handling-optional-environment-variables]

The `env()` helper function from `prisma/config` **throws an error** if the specified environment variable is not defined. This is important to understand because:

* Every Prisma CLI command loads the `prisma.config.ts` file
* Only **some** commands actually need the `datasource.url` value (e.g., `prisma db *`, `prisma migrate *`, `prisma generate --sql`)
* Commands like `prisma generate` don't need a database URL, but will still fail if `env()` throws an error when loading the config file

For example, if you run `prisma generate` without `DATABASE_URL` set, and your config uses `env('DATABASE_URL')`, you'll see:

```bash
Error: PrismaConfigEnvError: Missing required environment variable: DATABASE_URL
```

**Solution:** If your environment variable isn't guaranteed to exist (e.g., in CI/CD pipelines where you only run `prisma generate` for type-checking), don't use the `env()` helper. Instead, access the environment variable directly:

```ts
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env.DATABASE_URL!, // Or use: process.env.DATABASE_URL ?? '' to provide a fallback value
  },
});
```

> [!NOTE]
> Use the `env()` helper when you want to **enforce** that an environment variable exists. Use `process.env` directly when the variable may be optional depending on the command being run.

### Using multi-file schemas [#using-multi-file-schemas]

If you want to split your Prisma schema into multiple files, you need to specify the path to your Prisma schema folder via the `schema` property:

```ts
import path from "node:path";
import type { PrismaConfig } from "prisma";

export default {
  schema: path.join("prisma", "schema"),
} satisfies PrismaConfig;
```

In that case, your `migrations` directory must be located next to the `.prisma` file that defines the `datasource` block.

For example, assuming `schema.prisma` defines the `datasource`, here's how how need to place the migrations folder:

```
# `migrations` and `schema.prisma` are on the same level
.
├── migrations
├── models
│   ├── posts.prisma
│   └── users.prisma
└── schema.prisma
```

## Path resolution [#path-resolution]

Prisma CLI commands such as `prisma validate` or `prisma migrate` use `prisma.config.ts` (or `.config/prisma.ts`) to locate your Prisma schema and other resources.

**Key rules:**

* Paths defined in the config file (e.g., `schema`, `migrations`) are always resolved **relative to the location of the config file**, not where you run the CLI command from.
* The CLI must first **find the config file** itself, which depends on how Prisma is installed and the package manager used.

### Behavior with `pnpm prisma` [#behavior-with-pnpm-prisma]

When Prisma is installed locally and run via `pnpm prisma`, the config file is detected automatically whether you run the command from the project root or a subdirectory.

Example project tree:

```
.
├── node_modules
├── package.json
├── prisma-custom
│   └── schema.prisma
├── prisma.config.ts
└── src
```

Example run from the project root:

```bash
pnpm prisma validate
# → Loaded Prisma config from ./prisma.config.ts
# → Prisma schema loaded from prisma-custom/schema.prisma
```

Example run from a subdirectory:

```bash
cd src
pnpm prisma validate
# → Still finds prisma.config.ts and resolves schema correctly
```

### Behavior with `npx prisma` or `bunx prisma` [#behavior-with-npx-prisma-or-bunx-prisma]

When running via `npx prisma` or `bunx prisma`, the CLI only detects the config file if the command is run from the **project root** (where `package.json` declares Prisma).

> [!NOTE]
> When running `prisma init` with Bun, use `bunx --bun prisma init` to ensure Prisma runs with the Bun runtime.

Example run from the project root:

  

#### bun

```bash
bunx prisma validate
# → Works as expected
```

#### pnpm

```bash
pnpm prisma validate
# → Works as expected
```

#### yarn

```bash
yarn prisma validate
# → Works as expected
```

#### npm

```bash
npx prisma validate
# → Works as expected
```

Run from a subdirectory (fails):

  

#### bun

```bash
cd src
bunx prisma validate
# → Error: Could not find Prisma Schema...
```

#### pnpm

```bash
cd src
pnpm prisma validate
# → Error: Could not find Prisma Schema...
```

#### yarn

```bash
cd src
yarn prisma validate
# → Error: Could not find Prisma Schema...
```

#### npm

```bash
cd src
npx prisma validate
# → Error: Could not find Prisma Schema...
```

To fix this, you can use the `--config` flag:

  

#### bun

```bash
bunx prisma validate --config ../prisma.config.ts
```

#### pnpm

```bash
pnpm prisma validate --config ../prisma.config.ts
```

#### yarn

```bash
yarn prisma validate --config ../prisma.config.ts
```

#### npm

```bash
npx prisma validate --config ../prisma.config.ts
```

### Global Prisma installations [#global-prisma-installations]

If Prisma is installed globally (`npm i -g prisma`), it may not find your `prisma.config.ts` or `prisma/config` module by default.
To avoid issues:

* Prefer local Prisma installations in your project.
* Or use `prisma/config` locally and pass `--config` to point to your config file.

### Monorepos [#monorepos]

* If Prisma is installed in the **workspace root**, `pnpm prisma` will detect the config file from subdirectories.
* If Prisma is installed in a **subpackage** (e.g., `./packages/db`), run commands from that package directory or deeper.

### Custom config location [#custom-config-location]

You can specify a custom location for your config file when running Prisma CLI commands:

```bash
prisma validate --config ./path/to/myconfig.ts
```

## Loading environment variables [#loading-environment-variables]

To load environment variables, install the `dotenv` package and add `import 'dotenv/config'` at the top of your `prisma.config.ts` file.

To load environment variables in your Prisma application, use the `prisma.config.ts` file along with the `env` helper from `prisma/config`.

1. Install the `dotenv` package:

   
     

#### bun

```bash
bun add dotenv
```

#### pnpm

```bash
pnpm add dotenv
```

#### yarn

```bash
yarn add dotenv
```

#### npm

```bash
npm install dotenv
```
   

2. Create a `.env` file in your project root (if it doesn't exist) and add your database connection string:

   ```bash
   DATABASE_URL="your_database_connection_string_here"
   ```

3. Ensure your `prisma.config.ts` file imports `dotenv/config` at the top:

   ```ts title="prisma.config.ts"
   import "dotenv/config"; // [!code ++]
   import { defineConfig, env } from "prisma/config";

   export default defineConfig({
     schema: "prisma/schema.prisma",
     migrations: {
       path: "prisma/migrations",
       seed: "tsx prisma/seed.ts",
     },
     datasource: {
       url: env("DATABASE_URL"),
     },
   });
   ```

## Related pages

- [`Connection URLs`](https://www.prisma.io/docs/orm/v7/reference/connection-urls): Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite
- [`Database Features`](https://www.prisma.io/docs/orm/v7/reference/database-features): Database features supported in Prisma ORM
- [`Environment Variables`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference): Reference for Prisma environment variables
- [`Error Reference`](https://www.prisma.io/docs/orm/v7/reference/error-reference): Prisma Client, Migrate, and Introspection error codes
- [`Prisma CLI reference`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference): This page gives an overview of all available Prisma CLI commands, explains their options and shows numerous usage examples

# Schema API (Prisma ORM v7) (/docs/orm/v7/reference/prisma-schema-reference)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Reference for Prisma Schema Language (PSL)

Location: ORM > v7 > Reference > Schema API

## `datasource` [#datasource]

Defines a [data source](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/data-sources) in the Prisma schema.

### Fields [#fields]

A `datasource` block accepts the following fields:

| Name           | Required | Type                                                                            | Description                                                                                                                              |
| -------------- | -------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `provider`     | **Yes**  | String (`postgresql`, `mysql`, `sqlite`, `sqlserver`, `mongodb`, `cockroachdb`) | Specifies the database connector to use.                                                                                                 |
| `relationMode` | No       | String (`foreignKeys`, `prisma`)                                                | Sets whether [referential integrity](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode) is enforced by foreign keys or by Prisma. |
| `schemas`      | No       | Array of strings                                                                | List of database schemas to include ([multi-schema](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema) support, PostgreSQL and SQL Server).  |
| `extensions`   | No       | Array of extension names                                                        | [PostgreSQL extensions](https://www.prisma.io/docs/orm/v7/prisma-schema/postgresql-extensions) to enable.                                                          |

Connection URLs (`url`, `directUrl`, `shadowDatabaseUrl`) are configured in [`prisma.config.ts`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference#datasourceurl), not in the schema file.

The following providers are available:

* [`sqlite`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite)
* [`postgresql`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql)
* [`mysql`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql)
* [`sqlserver`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server)
* [`mongodb`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb)
* [`cockroachdb`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#cockroachdb)

### Remarks [#remarks]

* You can only have **one** `datasource` block in a schema.
* `datasource db` is convention - however, you can give your data source any name - for example, `datasource mysql` or `datasource data`.

### Examples [#examples]

#### PostgreSQL datasource [#postgresql-datasource]

```prisma
datasource db {
  provider = "postgresql"
}
```

Configure the connection URL in `prisma.config.ts`:

```ts
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Learn more about PostgreSQL connection strings in the [PostgreSQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql) documentation.

#### Specify a PostgreSQL data source via an environment variable [#specify-a-postgresql-data-source-via-an-environment-variable]

In this example, the target database is available with the following credentials:

* User: `johndoe`
* Password: `mypassword`
* Host: `localhost`
* Port: `5432`
* Database name: `mydb`
* Schema name: `public`

```prisma
datasource db {
  provider = "postgresql"
}
```

When running a Prisma CLI command that needs the database connection URL (e.g. `prisma generate`), you need to make sure that the `DATABASE_URL` environment variable is set.

One way to do so is by creating a [`.env`](https://github.com/motdotla/dotenv) file with the following contents. Note that the file must be in the same directory as your `schema.prisma` file to automatically picked up the Prisma CLI.

```
DATABASE_URL=postgresql://johndoe:mypassword@localhost:5432/mydb?schema=public
```

#### MySQL datasource [#mysql-datasource]

```prisma
datasource db {
  provider = "mysql"
}
```

Learn more about [MySQL connection URLs](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql).

#### MongoDB datasource [#mongodb-datasource]

```prisma
datasource db {
  provider = "mongodb"
}
```

Learn more about [MongoDB connection URLs](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

#### SQLite datasource [#sqlite-datasource]

```prisma
datasource db {
  provider = "sqlite"
}
```

Learn more about [SQLite connection URLs](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite).

#### CockroachDB datasource [#cockroachdb-datasource]

```prisma
datasource db {
  provider = "cockroachdb"
}
```

CockroachDB uses the same connection URL format as PostgreSQL. Learn more about [PostgreSQL connection URLs](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql).

#### Multi-schema datasource (PostgreSQL) [#multi-schema-datasource-postgresql]

```prisma
datasource db {
  provider = "postgresql"
  schemas  = ["public", "analytics"]
}
```

## `generator` [#generator]

Defines a [generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators) in the Prisma schema.

### Fields for `prisma-client-js` provider [#fields-for-prisma-client-js-provider]

This is the default generator for Prisma ORM 6.x and earlier versions. Learn more about [generators](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client-js-deprecated).

A `generator` block accepts the following fields:

| Name              | Required | Type                         | Description                                                                                                                                                                                                                       |
| :---------------- | :------- | :--------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider`        | **Yes**  | `prisma-client-js`           | Describes which [generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators) to use. This can point to a file that implements a generator or specify a built-in generator directly.                                                     |
| `output`          | No       | String (file path)           | Determines the location for the generated client, learn more about [fields for `prisma-client` provider](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider). **Default**: `node_modules/.prisma/client` |
| `previewFeatures` | No       | List of Enums                | Use intellisense to see list of currently available Preview features (`Ctrl+Space` in Visual Studio Code) **Default**: none                                                                                                       |
| `engineType`      | No       | Enum (`library` or `binary`) | Defines the query engine type to download and use. **Default**: `library`                                                                                                                                                         |
| `binaryTargets`   | No       | List of Enums (see below)    | Specify the OS on which the Prisma Client will run to ensure compatibility of the query engine. **Default**: `native`                                                                                                             |
| `moduleFormat`    | No       | Enum (`cjs` or `esm`)        | Defines the module format of the generated Prisma Client. This field is available only with `prisma-client` generator.                                                                                                            |

> [!NOTE]
> important
> 
> We recommend defining a custom output path, adding the path to `.gitignore`, and then making sure to run `prisma generate` via a custom build script or postinstall hook.

### Fields for `prisma-client` provider [#fields-for-prisma-client-provider]

The ESM-first client generator. It generates plain TypeScript code into a directory you specify, so the generated code lives alongside your application code. Learn more about the new [`prisma-client`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) generator.

> [!NOTE]
> The `prisma-client` generator is the default generator in Prisma ORM 7.

A `generator` block accepts the following fields:

| Name                     | Required | Type                                                                                                               | Description                                                                                                                                                                                                                               |
| :----------------------- | :------- | :----------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider`               | **Yes**  | `prisma-client`                                                                                                    | Describes which [generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators) to use. This can point to a file that implements a generator or specify a built-in generator directly.                                                             |
| `output`                 | **Yes**  | String (file path)                                                                                                 | Determines the location for the generated client, learn more about [fields for `prisma-client` provider](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider).                                                    |
| `previewFeatures`        | No       | List of Enums                                                                                                      | Use intellisense to see list of currently available Preview features (`Ctrl+Space` in Visual Studio Code) **Default**: none                                                                                                               |
| `runtime`                | No       | Enum (`nodejs`, `deno`, `bun`, `workerd` (alias `cloudflare`), `vercel-edge` (alias `edge-light`), `react-native`) | Target runtime environment. **Default**: `nodejs`                                                                                                                                                                                         |
| `moduleFormat`           | No       | Enum (`esm` or `cjs`)                                                                                              | Determines whether the generated code supports ESM (uses `import`) or CommonJS (uses `require(...)`) modules. We always recommend `esm` unless you have a good reason to use `cjs`. **Default**: Inferred from environment.               |
| `generatedFileExtension` | No       | Enum (`ts` or `mts` or `cts`)                                                                                      | File extension for generated TypeScript files. **Default**: `ts`                                                                                                                                                                          |
| `importFileExtension`    | No       | Enum (`ts`,`mts`,`cts`,`js`,`mjs`,`cjs`, empty (for bare imports))                                                 | File extension used in import statements **Default**: Inferred from environment.                                                                                                                                                          |
| `compilerBuild`          | No       | String (`fast`, `small`)                                                                                           | Defines what build of the query compiler to use for the generated client. `fast`, the default, gives you fast query compilation, but with an increase in size. `small` gives you the smallest size, but with a slightly slower execution. |

#### `binaryTargets` options [#binarytargets-options]

The following tables list all supported operating systems with the name of platform to specify in `binaryTargets`.

Unless specified otherwise, the default supported CPU architecture is x86_64.

##### macOS [#macos]

| Build OS            | Prisma engine build name |
| :------------------ | :----------------------- |
| macOS Intel x86_64 | `darwin`                 |
| macOS ARM64         | `darwin-arm64`           |

##### Windows [#windows]

| Build OS | Prisma engine build name |
| :------- | :----------------------- |
| Windows  | `windows`                |

##### Linux (Alpine on x86_64 architectures) [#linux-alpine-on-x86_64-architectures]

| Build OS                | Prisma engine build name   | OpenSSL |
| :---------------------- | :------------------------- | :-----: |
| Alpine (3.17 and newer) | `linux-musl-openssl-3.0.x` |  3.0.x  |
| Alpine (3.16 and older) | `linux-musl`               |  1.1.x  |

##### Linux (Alpine on ARM64 architectures) [#linux-alpine-on-arm64-architectures]

| Build OS                | Prisma engine build name         | OpenSSL |
| :---------------------- | :------------------------------- | :-----: |
| Alpine (3.17 and newer) | `linux-musl-arm64-openssl-3.0.x` |  3.0.x  |
| Alpine (3.16 and older) | `linux-musl-arm64-openssl-1.1.x` |  1.1.x  |

##### Linux (Debian), x86_64 [#linux-debian-x86_64]

| Build OS             | Prisma engine build name | OpenSSL |
| :------------------- | :----------------------- | :-----: |
| Debian 8 (Jessie)    | `debian-openssl-1.0.x`   |  1.0.x  |
| Debian 9 (Stretch)   | `debian-openssl-1.1.x`   |  1.1.x  |
| Debian 10 (Buster)   | `debian-openssl-1.1.x`   |  1.1.x  |
| Debian 11 (Bullseye) | `debian-openssl-1.1.x`   |  1.1.x  |
| Debian 12 (Bookworm) | `debian-openssl-3.0.x`   |  3.0.x  |

##### Linux (Ubuntu), x86_64 [#linux-ubuntu-x86_64]

| Build OS               | Prisma engine build name | OpenSSL |
| :--------------------- | :----------------------- | :-----: |
| Ubuntu 14.04 (trusty)  | `debian-openssl-1.0.x`   |  1.0.x  |
| Ubuntu 16.04 (xenial)  | `debian-openssl-1.0.x`   |  1.0.x  |
| Ubuntu 18.04 (bionic)  | `debian-openssl-1.1.x`   |  1.1.x  |
| Ubuntu 19.04 (disco)   | `debian-openssl-1.1.x`   |  1.1.x  |
| Ubuntu 20.04 (focal)   | `debian-openssl-1.1.x`   |  1.1.x  |
| Ubuntu 21.04 (hirsute) | `debian-openssl-1.1.x`   |  1.1.x  |
| Ubuntu 22.04 (jammy)   | `debian-openssl-3.0.x`   |  3.0.x  |
| Ubuntu 23.04 (lunar)   | `debian-openssl-3.0.x`   |  3.0.x  |

##### Linux (CentOS), x86_64 [#linux-centos-x86_64]

| Build OS | Prisma engine build name | OpenSSL |
| :------- | :----------------------- | :-----: |
| CentOS 7 | `rhel-openssl-1.0.x`     |  1.0.x  |
| CentOS 8 | `rhel-openssl-1.1.x`     |  1.1.x  |

##### Linux (Fedora), x86_64 [#linux-fedora-x86_64]

| Build OS  | Prisma engine build name | OpenSSL |
| :-------- | :----------------------- | :-----: |
| Fedora 28 | `rhel-openssl-1.1.x`     |  1.1.x  |
| Fedora 29 | `rhel-openssl-1.1.x`     |  1.1.x  |
| Fedora 30 | `rhel-openssl-1.1.x`     |  1.1.x  |
| Fedora 36 | `rhel-openssl-3.0.x`     |  3.0.x  |
| Fedora 37 | `rhel-openssl-3.0.x`     |  3.0.x  |
| Fedora 38 | `rhel-openssl-3.0.x`     |  3.0.x  |

##### Linux (Linux Mint), x86_64 [#linux-linux-mint-x86_64]

| Build OS      | Prisma engine build name | OpenSSL |
| :------------ | :----------------------- | :-----: |
| Linux Mint 18 | `debian-openssl-1.0.x`   |  1.0.x  |
| Linux Mint 19 | `debian-openssl-1.1.x`   |  1.1.x  |
| Linux Mint 20 | `debian-openssl-1.1.x`   |  1.1.x  |
| Linux Mint 21 | `debian-openssl-3.0.x`   |  3.0.x  |

##### Linux (Arch Linux), x86_64 [#linux-arch-linux-x86_64]

| Build OS              | Prisma engine build name | OpenSSL |
| :-------------------- | :----------------------- | :-----: |
| Arch Linux 2019.09.01 | `debian-openssl-1.1.x`   |  1.1.x  |
| Arch Linux 2023.04.23 | `debian-openssl-3.0.x`   |  3.0.x  |

##### Linux ARM64 (all major distros but Alpine) [#linux-arm64-all-major-distros-but-alpine]

| Build OS                       | Prisma engine build name    | OpenSSL |
| :----------------------------- | :-------------------------- | :-----: |
| Linux ARM64 glibc-based distro | `linux-arm64-openssl-1.0.x` |  1.0.x  |
| Linux ARM64 glibc-based distro | `linux-arm64-openssl-1.1.x` |  1.1.x  |
| Linux ARM64 glibc-based distro | `linux-arm64-openssl-3.0.x` |  3.0.x  |

### Examples [#examples-1]

#### Specify the `prisma-client-js` generator with the default `output`, `previewFeatures`, `engineType` and `binaryTargets` [#specify-the-prisma-client-js-generator-with-the-default-output-previewfeatures-enginetype-and-binarytargets]

```prisma
generator client {
  provider = "prisma-client-js"
}
```

Note that the above `generator` definition is **equivalent** to the following because it uses the default values for `output`, `engineType` and `binaryTargets` (and implicitly `previewFeatures`):

```prisma
generator client {
  provider      = "prisma-client-js"
  output        = "node_modules/.prisma/client"
  engineType    = "library"
  binaryTargets = ["native"]
}
```

#### Specify a custom `output` location for Prisma Client [#specify-a-custom-output-location-for-prisma-client]

This example shows how to define a custom `output` location of the generated asset to override the default one.

```prisma
generator client {
  provider = "prisma-client-js"
  output   = "../src/generated/client"
}
```

#### Specify custom `binaryTargets` to ensure compatibility with the OS [#specify-custom-binarytargets-to-ensure-compatibility-with-the-os]

This example shows how to configure Prisma Client to run on `Ubuntu 19.04 (disco)` based on the table [above](#linux-ubuntu-x86_64).

```prisma
generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["debian-openssl-1.1.x"]
}
```

#### Specify a `provider` pointing to some custom generator implementation [#specify-a-provider-pointing-to-some-custom-generator-implementation]

This example shows how to use a custom generator that's located in a directory called `my-generator`.

```prisma
generator client {
  provider = "./my-generator"
}
```

## `model` [#model]

Defines a Prisma [model](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-models) .

### Remarks [#remarks-1]

* Every record of a model must be *uniquely* identifiable. You must define *at least* one of the following attributes per model:
  * [`@unique`](#unique)
  * [`@@unique`](#unique-1)
  * [`@id`](#id)
  * [`@@id`](#id-1)

#### Naming conventions [#naming-conventions]

* Model names must adhere to the following regular expression: `[A-Za-z][A-Za-z0-9_]*`
* Model names must start with a letter and are typically spelled in [PascalCase](https://wiki.c2.com/?PascalCase)
* Model names should use the singular form (for example, `User` instead of `user`, `users` or `Users`)
* Prisma ORM has a number of **reserved words** that are being used by Prisma ORM internally and therefore cannot be used as a model name. You can find the reserved words in [the Prisma Client generator source](https://github.com/prisma/orm/blob/6.5.0/packages/client/src/generation/generateClient.ts#L556-L605) and in [the Prisma engines source](https://github.com/prisma/prisma-engines/blob/main/psl/parser-database/src/names/reserved_model_names.rs#L44).

> **Note**: You can use the [`@@map` attribute](#map-1) to map a model (for example, `User`) to a table with a different name that does not match model naming conventions (for example, `users`).

#### Order of fields [#order-of-fields]

* Introspection lists model fields in the same order as the corresponding columns in the database. Relation fields are listed after scalar fields.

### Examples [#examples-2]

#### A model named `User` with two scalar fields [#a-model-named-user-with-two-scalar-fields]

  

#### Relational databases

```prisma
model User {
  email String  @unique // `email` can not be optional because it's the only unique field on the model
  name  String?
}
```

#### MongoDB

```prisma
model User {
  id    String  @default(auto()) @map("_id") @db.ObjectId
  email String  @unique
  name  String?
}
```

## `model` fields [#model-fields]

[Fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-fields) are properties of models.

### Remarks [#remarks-2]

#### Naming conventions [#naming-conventions-1]

* Must start with a letter
* Typically spelled in camelCase
* Must adhere to the following regular expression: `[A-Za-z][A-Za-z0-9_]*`

> **Note**: You can use the [`@map` attribute](#map) to [map a field name to a column](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names) with a different name that does not match field naming conventions: e.g. `myField @map("my_field")`.

## `model` field scalar types [#model-field-scalar-types]

The *data source connector* determines what *native database type* each of Prisma ORM scalar type maps to. Similarly, the *generator* determines what *type in the target programming language* each of these types map to.

Prisma models also have [model field types](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations) that define relations between models.

### `String` [#string]

Variable length text.

#### Default type mappings [#default-type-mappings]

| Connector   | Default mapping  |
| ----------- | ---------------- |
| PostgreSQL  | `text`           |
| SQL Server  | `nvarchar(1000)` |
| MySQL       | `varchar(191)`   |
| MongoDB     | `String`         |
| SQLite      | `TEXT`           |
| CockroachDB | `STRING`         |

#### PostgreSQL [#postgresql]

| Native database type | Native database type attribute | Notes                                                                                                                                                                       |
| :------------------- | :----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text`               | `@db.Text`                     |                                                                                                                                                                             |
| `char(x)`            | `@db.Char(x)`                  |                                                                                                                                                                             |
| `varchar(x)`         | `@db.VarChar(x)`               |                                                                                                                                                                             |
| `bit(x)`             | `@db.Bit(x)`                   |                                                                                                                                                                             |
| `varbit`             | `@db.VarBit`                   |                                                                                                                                                                             |
| `uuid`               | `@db.Uuid`                     |                                                                                                                                                                             |
| `xml`                | `@db.Xml`                      |                                                                                                                                                                             |
| `inet`               | `@db.Inet`                     |                                                                                                                                                                             |
| `citext`             | `@db.Citext`                   | Only available if [Citext extension is enabled](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/unsupported-database-features#enable-postgresql-extensions-for-native-database-functions). |

#### MySQL [#mysql]

| Native database type | Native database type attribute |
| :------------------- | :----------------------------- |
| `VARCHAR(x)`         | `@db.VarChar(x)`               |
| `TEXT`               | `@db.Text`                     |
| `CHAR(x)`            | `@db.Char(x)`                  |
| `TINYTEXT`           | `@db.TinyText`                 |
| `MEDIUMTEXT`         | `@db.MediumText`               |
| `LONGTEXT`           | `@db.LongText`                 |

You can use Prisma Migrate to map `@db.Bit(1)` to `String`:

```prisma
model Model {
  /* ... */
  myField String @db.Bit(1)
}
```

#### MongoDB [#mongodb]

`String`

| Native database type attribute | Notes                                                                             |
| :----------------------------- | :-------------------------------------------------------------------------------- |
| `@db.String`                   |                                                                                   |
| `@db.ObjectId`                 | Required if the underlying BSON type is `OBJECT_ID` (ID fields, relation scalars) |

#### Microsoft SQL Server [#microsoft-sql-server]

| Native database type | Native database type attribute |
| :------------------- | :----------------------------- |
| `char(x)`            | `@db.Char(x)`                  |
| `nchar(x)`           | `@db.NChar(x)`                 |
| `varchar(x)`         | `@db.VarChar(x)`               |
| `nvarchar(x)`        | `@db.NVarChar(x)`              |
| `text`               | `@db.Text`                     |
| `ntext`              | `@db.NText`                    |
| `xml`                | `@db.Xml`                      |
| `uniqueidentifier`   | `@db.UniqueIdentifier`         |

#### SQLite [#sqlite]

`TEXT`

#### CockroachDB [#cockroachdb]

| Native database type                     | Native database type attribute | Notes |
| :--------------------------------------- | :----------------------------- | ----- |
| `STRING(x)` \| `TEXT(x)` \| `VARCHAR(x)` | `@db.String(x)`                |       |
| `CHAR(x)`                                | `@db.Char(x)`                  |       |
| `"char"`                                 | `@db.CatalogSingleChar`        |       |
| `BIT(x)`                                 | `@db.Bit(x)`                   |       |
| `VARBIT`                                 | `@db.VarBit`                   |       |
| `UUID`                                   | `@db.Uuid`                     |       |
| `INET`                                   | `@db.Inet`                     |       |

Note that the `xml` and `citext` types supported in PostgreSQL are not currently supported in CockroachDB.

#### Clients [#clients]

| Prisma Client JS |
| ---------------- |
| `string`         |

### `Boolean` [#boolean]

True or false value.

#### Default type mappings [#default-type-mappings-1]

| Connector   | Default mapping |
| ----------- | --------------- |
| PostgreSQL  | `boolean`       |
| SQL Server  | `bit`           |
| MySQL       | `TINYINT(1)`    |
| MongoDB     | `Bool`          |
| SQLite      | `INTEGER`       |
| CockroachDB | `BOOL`          |

#### PostgreSQL [#postgresql-1]

| Native database types | Native database type attribute | Notes |
| :-------------------- | :----------------------------- | ----- |
| `boolean`             | `@db.Boolean`                  |       |

#### MySQL [#mysql-1]

| Native database types | Native database type attribute | Notes                                                                                                                                                     |
| --------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TINYINT(1)`          | `@db.TinyInt(1)`               | `TINYINT` maps to `Int` if the max length is greater than 1 (for example, `TINYINT(2)`) *or* the default value is anything other than `1`, `0`, or `NULL` |
| `BIT(1)`              | `@db.Bit`                      |                                                                                                                                                           |

#### MongoDB [#mongodb-1]

`Bool`

#### Microsoft SQL Server [#microsoft-sql-server-1]

| Native database types | Native database type attribute | Notes |
| :-------------------- | :----------------------------- | ----- |
| `bit`                 | `@db.Bit`                      |       |

#### SQLite [#sqlite-1]

`INTEGER`

#### CockroachDB [#cockroachdb-1]

| Native database types | Native database type attribute | Notes |
| :-------------------- | :----------------------------- | ----- |
| `BOOL`                | `@db.Bool`                     |       |

#### Clients [#clients-1]

| Prisma Client JS |
| ---------------- |
| `boolean`        |

### `Int` [#int]

#### Default type mappings [#default-type-mappings-2]

| Connector   | Default mapping |
| ----------- | --------------- |
| PostgreSQL  | `integer`       |
| SQL Server  | `int`           |
| MySQL       | `INT`           |
| MongoDB     | `Int`           |
| SQLite      | `INTEGER`       |
| CockroachDB | `INT`           |

#### PostgreSQL [#postgresql-2]

| Native database types      | Native database type attribute           | Notes |
| -------------------------- | ---------------------------------------- | ----- |
| `integer` \| `int`, `int4` | `@db.Integer`                            |       |
| `smallint` \| `int2`       | `@db.SmallInt`                           |       |
| `smallserial` \| `serial2` | `@db.SmallInt @default(autoincrement())` |       |
| `serial` \| `serial4`      | `@db.Int @default(autoincrement())`      |       |
| `oid`                      | `@db.Oid`                                |       |

#### MySQL [#mysql-2]

| Native database types | Native database type attribute | Notes                                                                                                                                                                                      |
| :-------------------- | :----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `INT`                 | `@db.Int`                      |                                                                                                                                                                                            |
| `INT UNSIGNED`        | `@db.UnsignedInt`              |                                                                                                                                                                                            |
| `SMALLINT`            | `@db.SmallInt`                 |                                                                                                                                                                                            |
| `SMALLINT UNSIGNED`   | `@db.UnsignedSmallInt`         |                                                                                                                                                                                            |
| `MEDIUMINT`           | `@db.MediumInt`                |                                                                                                                                                                                            |
| `MEDIUMINT UNSIGNED`  | `@db.UnsignedMediumInt`        |                                                                                                                                                                                            |
| `TINYINT`             | `@db.TinyInt`                  | `TINYINT` maps to `Int` if the max length is greater than 1 (for example, `TINYINT(2)`) *or* the default value is anything other than `1`, `0`, or `NULL`. `TINYINT(1)` maps to `Boolean`. |
| `TINYINT UNSIGNED`    | `@db.UnsignedTinyInt`          | `TINYINT(1) UNSIGNED` maps to `Int`, not `Boolean`                                                                                                                                         |
| `YEAR`                | `@db.Year`                     |                                                                                                                                                                                            |

#### MongoDB [#mongodb-2]

`Int`

| Native database type attribute | Notes |
| :----------------------------- | :---- |
| `@db.Int`                      |       |
| `@db.Long`                     |       |

#### Microsoft SQL Server [#microsoft-sql-server-2]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `int`                 | `@db.Int`                      |       |
| `smallint`            | `@db.SmallInt`                 |       |
| `tinyint`             | `@db.TinyInt`                  |       |
| `bit`                 | `@db.Bit`                      |       |

#### SQLite [#sqlite-2]

`INTEGER`

#### CockroachDB [#cockroachdb-2]

| Native database types        | Native database type attribute       | Notes                                                                                                             |
| ---------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `INTEGER` \| `INT` \| `INT8` | `@db.Int8`                           | Note that this differs from PostgreSQL, where `integer` and `int` are aliases for `int4` and map to `@db.Integer` |
| `INT4`                       | `@db.Int4`                           |                                                                                                                   |
| `INT2` \| `SMALLINT`         | `@db.Int2`                           |                                                                                                                   |
| `SMALLSERIAL` \| `SERIAL2`   | `@db.Int2 @default(autoincrement())` |                                                                                                                   |
| `SERIAL` \| `SERIAL4`        | `@db.Int4 @default(autoincrement())` |                                                                                                                   |
| `SERIAL8` \| `BIGSERIAL`     | `@db.Int8 @default(autoincrement())` |                                                                                                                   |

#### Clients [#clients-2]

| Prisma Client JS |
| ---------------- |
| `number`         |

### `BigInt` [#bigint]

#### Default type mappings [#default-type-mappings-3]

| Connector   | Default mapping |
| ----------- | --------------- |
| PostgreSQL  | `bigint`        |
| SQL Server  | `int`           |
| MySQL       | `BIGINT`        |
| MongoDB     | `Long`          |
| SQLite      | `INTEGER`       |
| CockroachDB | `INTEGER`       |

#### PostgreSQL [#postgresql-3]

| Native database types    | Native database type attribute         | Notes |
| ------------------------ | -------------------------------------- | ----- |
| `bigint` \| `int8`       | `@db.BigInt`                           |       |
| `bigserial` \| `serial8` | `@db.BigInt @default(autoincrement())` |       |

#### MySQL [#mysql-3]

| Native database types | Native database type attribute                 | Notes |
| --------------------- | ---------------------------------------------- | ----- |
| `BIGINT`              | `@db.BigInt`                                   |       |
| `SERIAL`              | `@db.UnsignedBigInt @default(autoincrement())` |       |

#### MongoDB [#mongodb-3]

`Long`

#### Microsoft SQL Server [#microsoft-sql-server-3]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `bigint`              | `@db.BigInt`                   |       |

#### SQLite [#sqlite-3]

`INTEGER`

#### CockroachDB [#cockroachdb-3]

| Native database types       | Native database type attribute       | Notes                                                                      |
| --------------------------- | ------------------------------------ | -------------------------------------------------------------------------- |
| `BIGINT` \| `INT` \| `INT8` | `@db.Int8`                           | Note that this differs from PostgreSQL, where `int` is an alias for `int4` |
| `bigserial` \| `serial8`    | `@db.Int8 @default(autoincrement())` |                                                                            |

#### Clients [#clients-3]

| Client           | Type                                                                                                | Description                                                                                                 |
| :--------------- | :-------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------- |
| Prisma Client JS | [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) | See [examples of working with `BigInt`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types#working-with-bigint) |

### `Float` [#float]

Floating point number.

#### Default type mappings [#default-type-mappings-4]

| Connector   | Default mapping    |
| ----------- | ------------------ |
| PostgreSQL  | `double precision` |
| SQL Server  | `float(53)`        |
| MySQL       | `DOUBLE`           |
| MongoDB     | `Double`           |
| SQLite      | `REAL`             |
| CockroachDB | `DOUBLE PRECISION` |

#### PostgreSQL [#postgresql-4]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `double precision`    | `@db.DoublePrecision`          |       |
| `real`                | `@db.Real`                     |       |

#### MySQL [#mysql-4]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `FLOAT`               | `@db.Float`                    |       |
| `DOUBLE`              | `@db.Double`                   |       |

#### MongoDB [#mongodb-4]

`Double`

#### Microsoft SQL Server [#microsoft-sql-server-4]

| Native database types | Native database type attribute |
| --------------------- | ------------------------------ |
| `float`               | `@db.Float`                    |
| `money`               | `@db.Money`                    |
| `smallmoney`          | `@db.SmallMoney`               |
| `real`                | `@db.Real`                     |

#### SQLite connector [#sqlite-connector]

`REAL`

#### CockroachDB [#cockroachdb-4]

| Native database types          | Native database type attribute | Notes |
| ------------------------------ | ------------------------------ | ----- |
| `DOUBLE PRECISION` \| `FLOAT8` | `@db.Float8`                   |       |
| `REAL` \| `FLOAT4` \| `FLOAT`  | `@db.Float4`                   |       |

#### Clients [#clients-4]

| Prisma Client JS |
| ---------------- |
| `number`         |

### `Decimal` [#decimal]

#### Default type mappings [#default-type-mappings-5]

| Connector   | Default mapping                                             |
| ----------- | ----------------------------------------------------------- |
| PostgreSQL  | `decimal(65,30)`                                            |
| SQL Server  | `decimal(32,16)`                                            |
| MySQL       | `DECIMAL(65,30)`                                            |
| MongoDB     | [Not supported](https://github.com/prisma/orm/issues/12637) |
| SQLite      | `DECIMAL`                                                   |
| CockroachDB | `DECIMAL`                                                   |

#### PostgreSQL [#postgresql-5]

| Native database types  | Native database type attribute | Notes |
| ---------------------- | ------------------------------ | ----- |
| `decimal` \| `numeric` | `@db.Decimal(p, s)`†           |       |
| `money`                | `@db.Money`                    |       |

* † `p` (precision), the maximum total number of decimal digits to be stored. `s` (scale), the number of decimal digits that are stored to the right of the decimal point.

#### MySQL [#mysql-5]

| Native database types  | Native database type attribute | Notes |
| ---------------------- | ------------------------------ | ----- |
| `DECIMAL` \| `NUMERIC` | `@db.Decimal(p, s)`†           |       |

* † `p` (precision), the maximum total number of decimal digits to be stored. `s` (scale), the number of decimal digits that are stored to the right of the decimal point.

#### MongoDB [#mongodb-5]

[Not supported](https://github.com/prisma/orm/issues/12637).

#### Microsoft SQL Server [#microsoft-sql-server-5]

| Native database types  | Native database type attribute | Notes |
| ---------------------- | ------------------------------ | ----- |
| `decimal` \| `numeric` | `@db.Decimal(p, s)`†           |       |

* † `p` (precision), the maximum total number of decimal digits to be stored. `s` (scale), the number of decimal digits that are stored to the right of the decimal point.

#### SQLite [#sqlite-4]

`DECIMAL` (changed from `REAL` in 2.17.0)

#### CockroachDB [#cockroachdb-5]

| Native database types           | Native database type attribute | Notes                                                         |
| ------------------------------- | ------------------------------ | ------------------------------------------------------------- |
| `DECIMAL` \| `DEC` \| `NUMERIC` | `@db.Decimal(p, s)`†           |                                                               |
| `money`                         | Not yet                        | PostgreSQL's `money` type is not yet supported by CockroachDB |

* † `p` (precision), the maximum total number of decimal digits to be stored. `s` (scale), the number of decimal digits that are stored to the right of the decimal point.

#### Clients [#clients-5]

| Client           | Type                                               | Description                                                                                                   |
| :--------------- | :------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ |
| Prisma Client JS | [`Decimal`](https://mikemcl.github.io/decimal.js/) | See [examples of working with `Decimal`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types#working-with-decimal) |

### `DateTime` [#datetime]

#### Remarks [#remarks-3]

* Prisma Client returns all `DateTime` as native [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) objects.
* Currently, Prisma ORM [does not support](https://github.com/prisma/orm/issues/5006) [zero dates](https://dev.mysql.com/doc/refman/8.3/en/date-and-time-types.html#:~\:text=The%20following%20table%20shows%20the%20format%20of%20the%20%E2%80%9Czero%E2%80%9D%20value%20for%20each%20type) (`0000-00-00 00:00:00`, `0000-00-00`, `00:00:00`) in MySQL.
* There currently is a [bug](https://github.com/prisma/orm/issues/9516) that doesn't allow you to pass in `DateTime` values as strings and produces a runtime error when you do. `DateTime` values need to be passed as [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) objects (i.e. `new Date('2024-12-04')` instead of `'2024-12-04'`).

You can find more info and examples in this section: [Working with `DateTime`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types#working-with-datetime).

#### Default type mappings [#default-type-mappings-6]

| Connector   | Default mapping |
| ----------- | --------------- |
| PostgreSQL  | `timestamp(3)`  |
| SQL Server  | `datetime2`     |
| MySQL       | `DATETIME(3)`   |
| MongoDB     | `Timestamp`     |
| SQLite      | `NUMERIC`       |
| CockroachDB | `TIMESTAMP`     |

#### PostgreSQL [#postgresql-6]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `timestamp(x)`        | `@db.Timestamp(x)`             |       |
| `timestamptz(x)`      | `@db.Timestamptz(x)`           |       |
| `date`                | `@db.Date`                     |       |
| `time(x)`             | `@db.Time(x)`                  |       |
| `timetz(x)`           | `@db.Timetz(x)`                |       |

#### MySQL [#mysql-6]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `DATETIME(x)`         | `@db.DateTime(x)`              |       |
| `DATE(x)`             | `@db.Date(x)`                  |       |
| `TIME(x)`             | `@db.Time(x)`                  |       |
| `TIMESTAMP(x)`        | `@db.Timestamp(x)`             |       |

You can also use MySQL's `YEAR` type with `Int`:

```prisma
yearField     Int    @db.Year
```

#### MongoDB [#mongodb-6]

`Timestamp`

#### Microsoft SQL Server [#microsoft-sql-server-6]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `date`                | `@db.Date`                     |       |
| `time`                | `@db.Time`                     |       |
| `datetime`            | `@db.DateTime`                 |       |
| `datetime2`           | `@db.DateTime2`                |       |
| `smalldatetime`       | `@db.SmallDateTime`            |       |
| `datetimeoffset`      | `@db.DateTimeOffset`           |       |

#### SQLite [#sqlite-5]

`NUMERIC` or `STRING`. If the underlying data type is `STRING`, you must use one of the following formats:

* [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) (`1996-12-19T16:39:57-08:00`)
* [RFC 2822](https://datatracker.ietf.org/doc/html/rfc2822#section-3.3) (`Tue, 1 Jul 2003 10:52:37 +0200`)

#### CockroachDB [#cockroachdb-6]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `TIMESTAMP(x)`        | `@db.Timestamp(x)`             |       |
| `TIMESTAMPTZ(x)`      | `@db.Timestamptz(x)`           |       |
| `DATE`                | `@db.Date`                     |       |
| `TIME(x)`             | `@db.Time(x)`                  |       |
| `TIMETZ(x)`           | `@db.Timetz(x)`                |       |

#### Clients [#clients-6]

| Prisma Client JS |
| ---------------- |
| `Date`           |

### `Json` [#json]

A JSON object.

#### Default type mappings [#default-type-mappings-7]

| Connector   | Default mapping                                                                                              |
| ----------- | ------------------------------------------------------------------------------------------------------------ |
| PostgreSQL  | `jsonb`                                                                                                      |
| SQL Server  | [Not supported](https://github.com/prisma/orm/issues/7417)                                                   |
| MySQL       | `JSON`                                                                                                       |
| MongoDB     | [A valid `BSON` object (Relaxed mode)](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) |
| SQLite      | `JSONB`                                                                                                      |
| CockroachDB | `JSONB`                                                                                                      |

#### PostgreSQL [#postgresql-7]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `json`                | `@db.Json`                     |       |
| `jsonb`               | `@db.JsonB`                    |       |

#### MySQL [#mysql-7]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `JSON`                | `@db.Json`                     |       |

#### MongoDB [#mongodb-7]

[A valid `BSON` object (Relaxed mode)](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/)

#### Microsoft SQL Server [#microsoft-sql-server-7]

Microsoft SQL Server does not have a specific data type for JSON. However, there are a number of [built-in functions for reading and modifying JSON](https://learn.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server?view=sql-server-ver15#extract-values-from-json-text-and-use-them-in-queries).

#### SQLite [#sqlite-6]

Not supported

#### CockroachDB [#cockroachdb-7]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `JSON` \| `JSONB`     | `@db.JsonB`                    |       |

#### Clients [#clients-7]

| Prisma Client JS |
| ---------------- |
| `object`         |

### `Bytes` [#bytes]

#### Default type mappings [#default-type-mappings-8]

| Connector   | Default mapping |
| ----------- | --------------- |
| PostgreSQL  | `bytea`         |
| SQL Server  | `varbinary`     |
| MySQL       | `LONGBLOB`      |
| MongoDB     | `BinData`       |
| SQLite      | `BLOB`          |
| CockroachDB | `BYTES`         |

#### PostgreSQL [#postgresql-8]

| Native database types | Native database type attribute |
| --------------------- | ------------------------------ |
| `bytea`               | `@db.ByteA`                    |

#### MySQL [#mysql-8]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `LONGBLOB`            | `@db.LongBlob`                 |       |
| `BINARY`              | `@db.Binary`                   |       |
| `VARBINARY`           | `@db.VarBinary`                |       |
| `TINYBLOB`            | `@db.TinyBlob`                 |       |
| `BLOB`                | `@db.Blob`                     |       |
| `MEDIUMBLOB`          | `@db.MediumBlob`               |       |
| `BIT`                 | `@db.Bit`                      |       |

#### MongoDB [#mongodb-8]

`BinData`

| Native database type attribute | Notes                                                                             |
| :----------------------------- | :-------------------------------------------------------------------------------- |
| `@db.ObjectId`                 | Required if the underlying BSON type is `OBJECT_ID` (ID fields, relation scalars) |
| `@db.BinData`                  |                                                                                   |

#### Microsoft SQL Server [#microsoft-sql-server-8]

| Native database types | Native database type attribute | Notes |
| --------------------- | ------------------------------ | ----- |
| `binary`              | `@db.Binary`                   |       |
| `varbinary`           | `@db.VarBinary`                |       |
| `image`               | `@db.Image`                    |       |

#### SQLite [#sqlite-7]

`BLOB`

#### CockroachDB [#cockroachdb-8]

| Native database types        | Native database type attribute |
| ---------------------------- | ------------------------------ |
| `BYTES` \| `BYTEA` \| `BLOB` | `@db.Bytes`                    |

#### Clients [#clients-8]

| Client                                                        | Type                                                                                                        | Description                                                                                               |
| :------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------- |
| Prisma Client JS                                              | [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) | See [examples of working with `Bytes`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types#working-with-bytes) |
| Prisma Client JS ([before v6](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v6)) | [`Buffer`](https://nodejs.org/api/buffer.html)                                                              | See [examples of working with `Bytes`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types#working-with-bytes) |

### `Unsupported` [#unsupported]

> [!WARNING]
> **Not supported by MongoDB** <br />
> The [MongoDB connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb) does not support the `Unsupported` type.

The `Unsupported` type was introduced in [2.17.0](https://github.com/prisma/orm/releases/tag/2.17.0) and allows you to represent data types in the Prisma schema that are not supported by Prisma Client. Fields of type `Unsupported` can be created during Introspection with `prisma db pull` or written by hand, and created in the database with Prisma Migrate or `db push`.

#### Remarks [#remarks-4]

* Fields with `Unsupported` types are not available in the generated client.
* If a model contains a **required** `Unsupported` type, `prisma.model.create(..)`, `prisma.model.update(...)` and `prisma.model.upsert(...)` are not available in Prisma Client.
* When you introspect a database that contains unsupported types, Prisma ORM will provide the following warning:

  ```
  *** WARNING ***

  These fields are not supported by Prisma Client, because Prisma does not currently support their types.
  * Model "Post", field: "circle", original data type: "circle"
  ```

#### Examples [#examples-3]

```prisma
model Star {
  id       Int                    @id @default(autoincrement())
  position Unsupported("circle")?
  example1 Unsupported("circle")
  circle   Unsupported("circle")? @default(dbgenerated("'<(10,4),11>'::circle"))
}
```

## `model` field type modifiers [#model-field-type-modifiers]

### `[]` modifier [#-modifier]

Makes a field a list.

#### Remarks [#remarks-5]

* Cannot be optional (for example `Post[]?`).

##### Relational databases [#relational-databases]

* Scalar lists (arrays) are only supported in the data model if your database natively supports them. Currently, scalar lists are therefore only supported when using PostgreSQL or CockroachDB (since MySQL and SQLite don't natively support scalar lists).

##### MongoDB [#mongodb-9]

* Scalar lists are supported

#### Examples [#examples-4]

##### Define a scalar list [#define-a-scalar-list]

  

#### Relational databases

```prisma highlight=3;normal 
model User {
  id             Int      @id @default(autoincrement())
  favoriteColors String[] // [!code highlight]
}
```

#### MongoDB

```prisma highlight=3;normal 
model User {
  id             String   @id @default(auto()) @map("_id") @db.ObjectId
  favoriteColors String[] // [!code highlight]
}
```

##### Define a scalar list with a default value [#define-a-scalar-list-with-a-default-value]

  

#### Relational databases

```prisma highlight=3;normal 
model User {
  id             Int      @id @default(autoincrement())
  favoriteColors String[] @default(["red", "blue", "green"]) // [!code highlight]
}
```

#### MongoDB

```prisma highlight=3;normal 
model User {
  id             String   @id @default(auto()) @map("_id") @db.ObjectId
  favoriteColors String[] @default(["red", "blue", "green"]) // [!code highlight]
}
```

### `?` modifier [#-modifier-1]

Makes a field optional.

#### Remarks [#remarks-6]

* Cannot be used with a list field (for example, `Posts[]`)

#### Examples [#examples-5]

##### Optional `name` field [#optional-name-field]

```prisma highlight=3;normal
model User {
  id   Int     @id @default(autoincrement())
  name String? // [!code highlight]
}
```

## Attributes [#attributes]

Attributes modify the behavior of a [field](#model-fields) or block (e.g. [models](#model)). There are two ways to add attributes to your data model:

* *Field* attributes are prefixed with `@`
* *Block* attributes are prefixed with `@@`

Some attributes take arguments. Arguments in attributes are always named, but in most cases the argument *name* can be omitted.

> **Note**: The leading underscore in a signature means the *argument name* can be omitted.

### `@id` [#id]

Defines a single-field ID on the model.

#### Remarks [#remarks-7]

##### General [#general]

* Cannot be defined on a relation field
* Cannot be optional

##### Relational databases [#relational-databases-1]

* Corresponding database construct: `PRIMARY KEY`

* Can be annotated with a [`@default`](#default) attribute that uses [functions](#attribute-functions) to auto-generate an ID:
  * [`autoincrement()`](#autoincrement)
  * [`cuid()`](#cuid)
  * [`uuid()`](#uuid)
  * [`ulid()`](#ulid)

* Can be defined on any scalar field (`String`, `Int`, `enum`)

##### MongoDB [#mongodb-10]

* Corresponding database construct: [Any valid BSON type, except arrays](https://www.mongodb.com/docs/manual/core/document/#the-_id-field)

* Every model must define an `@id` field

* The [underlying ID field name is always `_id`](https://www.mongodb.com/docs/manual/core/document/#the-_id-field), and must be mapped with `@map("_id")`

* Can be defined on any scalar field (`String`, `Int`, `enum`) unless you want to use `ObjectId` in your database

* To use an [`ObjectId`](https://www.mongodb.com/docs/manual/reference/method/ObjectId/) as your ID, you must:
  * Use the `String` or `Bytes` field type

  * Annotate your field with `@db.ObjectId`:

    ```prisma
    id   String  @db.ObjectId  @map("_id")
    ```

  * Optionally, annotate your field with a [`@default`](#default) attribute that uses [the `auto()` function](#auto) to auto-generate an `ObjectId`

    ```prisma
    id   String  @db.ObjectId  @map("_id") @default(auto())
    ```

* [`cuid()`](#cuid), [`uuid()`](#uuid) and [`ulid()`](#ulid) are supported but do not generate a valid `ObjectId` - use `auto()` instead for `@id`

* `autoincrement()` is **not supported**

#### Arguments [#arguments]

| Name        | Required | Type      | Description                                                                                                                                                   |
| ----------- | -------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `map`       | **No**   | `String`  | The name of the underlying primary key constraint in the database.<br /><br /> Not supported for MySQL or MongoDB.                                            |
| `length`    | **No**   | `number`  | Allows you to specify a maximum length for the subpart of the value to be indexed.<br /><br />MySQL only.                                                     |
| `sort`      | **No**   | `String`  | Allows you to specify in what order the entries of the ID are stored in the database. The available options are `Asc` and `Desc`.<br /><br />SQL Server only. |
| `clustered` | **No**   | `Boolean` | Defines whether the ID is clustered or non-clustered. Defaults to `true`. <br /><br />SQL Server only.                                                        |

#### Signature [#signature]

```prisma no-lines
@id(map: String?, length: number?, sort: String?, clustered: Boolean?)
```

#### Examples [#examples-6]

In most cases, you want your database to create the ID. To do this, annotate the ID field with the `@default` attribute and initialize the field with a [function](#attribute-functions).

##### Generate autoincrementing integers as IDs (Relational databases only) [#generate-autoincrementing-integers-as-ids-relational-databases-only]

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

##### Generate `ObjectId` as IDs (MongoDB only) [#generate-objectid-as-ids-mongodb-only]

```prisma
model User {
  id   String @id @default(auto()) @map("_id") @db.ObjectId
  name String
}
```

##### Generate `cuid()` values as IDs [#generate-cuid-values-as-ids]

  

#### Relational databases

```prisma
model User {
  id   String @id @default(cuid())
  name String
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(cuid()) @map("_id")
  name String
}
```

> [!WARNING]
> You cannot use `cuid()` to generate a default value if your `id` field is of type `ObjectId`. Use the following syntax to generate a valid `ObjectId`:
> 
> ```prisma
> id    String  @id @default(auto()) @db.ObjectId @map("_id")
> ```

##### Generate `uuid()` values as IDs [#generate-uuid-values-as-ids]

  

#### Relational databases

```prisma
model User {
  id   String @id @default(uuid())
  name String
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(uuid()) @map("_id")
  name String
}
```

> [!WARNING]
> You cannot use `uuid()` to generate a default value if your `id` field is of type `ObjectId`. Use the following syntax to generate a valid `ObjectId`:
> 
> ```prisma
> id    String  @id @default(auto()) @db.ObjectId @map("_id")
> ```

##### Generate `ulid()` values as IDs [#generate-ulid-values-as-ids]

  

#### Relational databases

```prisma
model User {
  id   String @id @default(ulid())
  name String
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(ulid()) @map("_id")
  name String
}
```

> [!WARNING]
> You cannot use `ulid()` to generate a default value if your `id` field is of type `ObjectId`. Use the following syntax to generate a valid `ObjectId`:
> 
> ```prisma
> id    String  @id @default(auto()) @db.ObjectId @map("_id")
> ```

##### Single-field IDs *without* default values [#single-field-ids-without-default-values]

In the following example, `id` does not have a default value:

  

#### Relational databases

```prisma
model User {
  id   String @id
  name String
}
```

#### MongoDB

```prisma
model User {
id    String   @id  @map("_id") @db.ObjectId
name  String
}
```

```prisma
model User {
id    String   @id  @map("_id")
name  String
}
```

Note that in the above case, you *must* provide your own ID values when creating new records for the `User` model using Prisma Client, e.g.:

```ts
const newUser = await prisma.user.create({
  data: {
    id: 1,
    name: "Alice",
  },
});
```

###### Specify an ID on relation scalar field without a default value [#specify-an-id-on-relation-scalar-field-without-a-default-value]

In the following example, `authorId` is a both a relation scalar and the ID of `Profile`:

  

#### Relational databases

```prisma
model Profile {
  authorId Int    @id
  author   User   @relation(fields: [authorId], references: [id])
  bio      String
}

model User {
  id      Int      @id
  email   String   @unique
  name    String?
  profile Profile?
}
```

#### MongoDB

```prisma
model Profile {
  authorId String @id @map("_id") @db.ObjectId
  author   User   @relation(fields: [authorId], references: [id])
  bio      String
}

model User {
  id      String   @id @map("_id") @db.ObjectId
  email   String   @unique
  name    String?
  profile Profile?
}
```

In this scenario, you cannot create a `Profile` only - you must use Prisma Client's [nested writes](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-writes) create a `User` **or** connect the profile to an existing user.

The following example creates a user and a profile:

```ts
const userWithProfile = await prisma.user.create({
  data: {
    id: 3,
    email: "bob@prisma.io",
    name: "Bob Prismo",
    profile: {
      create: {
        bio: "Hello, I'm Bob Prismo and I love apples, blue nail varnish, and the sound of buzzing mosquitoes.",
      },
    },
  },
});
```

The following example connects a new profile to a user:

```ts
const profileWithUser = await prisma.profile.create({
  data: {
    bio: "Hello, I'm Bob and I like nothing at all. Just nothing.",
    author: {
      connect: {
        id: 22,
      },
    },
  },
});
```

### `@@id` [#id-1]

> [!WARNING]
> **Not supported by MongoDB** <br />
> The [MongoDB connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb) does not support composite IDs.

Defines a multi-field ID (composite ID) on the model.

#### Remarks [#remarks-8]

* Corresponding database type: `PRIMARY KEY`
* Can be annotated with a [`@default`](#default) attribute that uses [functions](#attribute-functions) to auto-generate an ID
* Cannot be optional
* Can be defined on any scalar field (`String`, `Int`, `enum`)
* Cannot be defined on a relation field
* The name of the composite ID field in Prisma Client has the following pattern: `field1_field2_field3`

#### Arguments [#arguments-1]

| Name        | Required | Type               | Description                                                                                                                                                   |
| ----------- | -------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fields`    | **Yes**  | `FieldReference[]` | A list of field names - for example, `["firstname", "lastname"]`                                                                                              |
| `name`      | **No**   | `String`           | The name that Prisma Client will expose for the argument covering all fields, e.g. `fullName` in `fullName: { firstName: "First", lastName: "Last"}`          |
| `map`       | **No**   | `String`           | The name of the underlying primary key constraint in the database.<br /><br />Not supported for MySQL.                                                        |
| `length`    | **No**   | `number`           | Allows you to specify a maximum length for the subpart of the value to be indexed.<br /><br />MySQL only.                                                     |
| `sort`      | **No**   | `String`           | Allows you to specify in what order the entries of the ID are stored in the database. The available options are `Asc` and `Desc`.<br /><br />SQL Server only. |
| `clustered` | **No**   | `Boolean`          | Defines whether the ID is clustered or non-clustered. Defaults to `true`.<br /><br />SQL Server only.                                                         |

The name of the `fields` argument on the `@@id` attribute can be omitted:

```prisma no-lines
@@id(fields: [title, author])
@@id([title, author])
```

#### Signature [#signature-1]

```prisma no-lines
@@id(_ fields: FieldReference[], name: String?, map: String?)
```

#### Examples [#examples-7]

##### Specify a multi-field ID on two `String` fields (Relational databases only) [#specify-a-multi-field-id-on-two-string-fields-relational-databases-only]

```prisma
model User {
  firstName String
  lastName  String
  email     String  @unique
  isAdmin   Boolean @default(false)

  @@id([firstName, lastName])
}
```

When you create a user, you must provide a unique combination of `firstName` and `lastName`:

```ts
const user = await prisma.user.create({
  data: {
    firstName: "Alice",
    lastName: "Smith",
  },
});
```

To retrieve a user, use the generated composite ID field (`firstName_lastName`):

```ts
const user = await prisma.user.findUnique({
  where: {
    firstName_lastName: {
      firstName: "Alice",
      lastName: "Smith",
    },
  },
});
```

##### Specify a multi-field ID on two `String` fields and one `Boolean` field (Relational databases only) [#specify-a-multi-field-id-on-two-string-fields-and-one-boolean-field-relational-databases-only]

```prisma
model User {
  firstName String
  lastName  String
  email     String  @unique
  isAdmin   Boolean @default(false)

  @@id([firstName, lastName, isAdmin])
}
```

When creating new `User` records, you now must provide a unique combination of values for `firstName`, `lastName` and `isAdmin`:

```ts
const user = await prisma.user.create({
  data: {
    firstName: "Alice",
    lastName: "Smith",
    isAdmin: true,
  },
});
```

##### Specify a multi-field ID that includes a relation field (Relational databases only) [#specify-a-multi-field-id-that-includes-a-relation-field-relational-databases-only]

```prisma
model Post {
  title     String
  published Boolean @default(false)
  author    User    @relation(fields: [authorId], references: [id])
  authorId  Int

  @@id([authorId, title])
}

model User {
  id    Int     @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}
```

When creating new `Post` records, you now must provide a unique combination of values for `authorId` (foreign key) and `title`:

```ts
const post = await prisma.post.create({
  data: {
    title: "Hello World",
    author: {
      connect: {
        email: "alice@prisma.io",
      },
    },
  },
});
```

### `@default` [#default]

Defines a [default value for a field](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-a-default-value).

#### Remarks [#remarks-9]

* Default values that cannot yet be represented in the Prisma schema are represented by the [`dbgenerated()` function](#dbgenerated) when you use [introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection).
* Default values are not allowed on relation fields in the Prisma schema. Note however that you can still define default values on the fields backing a relation (the ones listed in the `fields` argument in the `@relation` attribute). A default value on the field backing a relation will mean that relation is populated automatically for you.
* Default values can be used with [scalar lists](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-scalar-lists-arrays) in databases that natively support them.
* JSON data. Note that JSON needs to be enclosed with double-quotes inside the `@default` attribute, e.g.: `@default("[]")`. If you want to provide a JSON object, you need to enclose it with double-quotes and then escape any internal double quotes using a backslash, e.g.: `@default("{ \"hello\": \"world\" }")`.

##### Relational databases [#relational-databases-2]

* Corresponding database construct: `DEFAULT`
* Default values can be a static value (`4`, `"hello"`) or one of the following [functions](#attribute-functions):
  * [`autoincrement()`](#autoincrement)
  * [`sequence()`](#sequence) (CockroachDB only)
  * [`dbgenerated(...)`](#dbgenerated)
  * [`cuid()`](#cuid)
  * [`cuid(2)`](#cuid)
  * [`uuid()`](#uuid)
  * [`uuid(4)`](#uuid)
  * [`uuid(7)`](#uuid)
  * [`ulid()`](#ulid)
  * [`nanoid()`](#nanoid)
  * [`now()`](#now)

##### MongoDB [#mongodb-11]

* Default values can be a static value (`4`, `"hello"`) or one of the following [functions](#attribute-functions):
  * [`auto()`](#auto) (can only be used with `@db.ObjectId` to generate an `ObjectId` in MongoDB)
  * [`cuid()`](#cuid)
  * [`uuid()`](#uuid)
  * [`ulid()`](#ulid)
  * [`now()`](#now)

#### Arguments [#arguments-2]

| Name    | Required | Type                                      | Description          |
| ------- | -------- | ----------------------------------------- | -------------------- |
| `value` | **Yes**  | An expression (e.g. `5`, `true`, `now()`) |                      |
| `map`   | **No**   | String                                    | **SQL Server only.** |

The name of the `value` argument on the `@default` attribute can be omitted:

```prisma no-lines
id Int @id @default(value: autoincrement())
id Int @id @default(autoincrement())
```

#### Signature [#signature-2]

```prisma no-lines
@default(_ value: Expression, map: String?)
```

#### Examples [#examples-8]

##### Default value for an `Int` [#default-value-for-an-int]

  

#### Relational databases

```prisma
model User {
  email        String @unique
  profileViews Int    @default(0)
}
```

#### MongoDB

```prisma
model User {
  id           String @default(auto()) @map("_id") @db.ObjectId
  profileViews Int    @default(0)
}
```

##### Default value for a `Float` [#default-value-for-a-float]

  

#### Relational databases

```prisma
model User {
  email  String @unique
  number Float  @default(1.1)
}
```

#### MongoDB

```prisma
model User {
  id     String @default(auto()) @map("_id") @db.ObjectId
  number Float  @default(1.1)
}
```

##### Default value for `Decimal` [#default-value-for-decimal]

  

#### Relational databases

```prisma
model User {
  email  String  @unique
  number Decimal @default(22.99)
}
```

#### MongoDB

```text
[Not supported](https://github.com/prisma/orm/issues/12637).
```

##### Default value for `BigInt` [#default-value-for-bigint]

  

#### Relational databases

```prisma
model User {
  email  String @unique
  number BigInt @default(34534535435353)
}
```

#### MongoDB

```prisma
model User {
  id     String @default(auto()) @map("_id") @db.ObjectId
  number BigInt @default(34534535435353)
}
```

##### Default value for a `String` [#default-value-for-a-string]

  

#### Relational databases

```prisma
model User {
  email String @unique
  name  String @default("")
}
```

#### MongoDB

```prisma
model User {
  id   String @default(auto()) @map("_id") @db.ObjectId
  name String @default("")
}
```

##### Default value for a `Boolean` [#default-value-for-a-boolean]

  

#### Relational databases

```prisma
model User {
  email   String  @unique
  isAdmin Boolean @default(false)
}
```

#### MongoDB

```prisma
model User {
  id      String  @default(auto()) @map("_id") @db.ObjectId
  isAdmin Boolean @default(false)
}
```

##### Default value for a `DateTime` [#default-value-for-a-datetime]

Note that static default values for `DateTime` are based on the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard.

  

#### Relational databases

```prisma
model User {
  email String   @unique
  data  DateTime @default("2020-03-19T14:21:00+02:00")
}
```

#### MongoDB

```prisma
model User {
  id   String   @default(auto()) @map("_id") @db.ObjectId
  data DateTime @default("2020-03-19T14:21:00+02:00")
}
```

##### Default value for a `Bytes` [#default-value-for-a-bytes]

  

#### Relational databases

```prisma
model User {
  email  String @unique
  secret Bytes  @default("SGVsbG8gd29ybGQ=")
}
```

#### MongoDB

```prisma
model User {
  id     String @default(auto()) @map("_id") @db.ObjectId
  secret Bytes  @default("SGVsbG8gd29ybGQ=")
}
```

##### Default value for an `enum` [#default-value-for-an-enum]

  

#### Relational databases

```prisma
enum Role {
  USER
  ADMIN
}
```

```prisma highlight=5;normal
model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique
  name    String?
  role    Role     @default(USER) // [!code highlight]
  posts   Post[]
  profile Profile?
}
```

  

#### MongoDB

```prisma
enum Role {
  USER
  ADMIN
}
```

```prisma highlight=5;normal
model User {
  id      String   @id @default(auto()) @map("_id") @db.ObjectId
  email   String   @unique
  name    String?
  role    Role     @default(USER) // [!code highlight]
  posts   Post[]
  profile Profile?
}
```

##### Default values for scalar lists [#default-values-for-scalar-lists]

  

#### Relational databases

```prisma highlight=4;normal 
model User {
  id             Int      @id @default(autoincrement())
  posts          Post[]
  favoriteColors String[] @default(["red", "yellow", "purple"]) // [!code highlight]
  roles          Role[]   @default([USER, DEVELOPER])
}

enum Role {
  USER
  DEVELOPER
  ADMIN
}
```

#### MongoDB

```prisma highlight=4;normal 
model User {
  id             String   @id @default(auto()) @map("_id") @db.ObjectId
  posts          Post[]
  favoriteColors String[] @default(["red", "yellow", "purple"]) // [!code highlight]
  roles          Role[]   @default([USER, DEVELOPER])
}

enum Role {
  USER
  DEVELOPER
  ADMIN
}
```

### `@unique` [#unique]

Defines a unique constraint for this field.

#### Remarks [#remarks-10]

##### General [#general-1]

* A field annotated with `@unique` can be optional or required
* A field annotated with `@unique` *must* be required if it represents the only unique constraint on a model without an `@id` / `@@id`
* A model can have any number of unique constraints
* Can be defined on any scalar field
* **Cannot** be defined on a relation field

##### Relational databases [#relational-databases-3]

* Corresponding database construct: `UNIQUE`
* `NULL` values are considered to be distinct (multiple rows with `NULL` values in the same column are allowed)
* Adding a unique constraint automatically adds a corresponding *unique index* to the specified column(s).

##### MongoDB [#mongodb-12]

* Enforced by a [unique index in MongoDB](https://www.mongodb.com/docs/manual/core/index-unique/)

#### Arguments [#arguments-3]

| Name        | Required | Type                   | Description                                                                                                                                                                                                                                                                                                                                                   |
| ----------- | -------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `map`       | **No**   | `String`               |                                                                                                                                                                                                                                                                                                                                                               |
| `length`    | **No**   | `number`               | Allows you to specify a maximum length for the subpart of the value to be indexed.<br /><br />MySQL only.                                                                                                                                                                                                                                                     |
| `sort`      | **No**   | `String`               | Allows you to specify in what order the entries of the constraint are stored in the database. The available options are `Asc` and `Desc`.                                                                                                                                                                                                                     |
| `clustered` | **No**   | `Boolean`              | Defines whether the constraint is clustered or non-clustered. Defaults to `false`.<br /><br />SQL Server only.                                                                                                                                                                                                                                                |
| `where`     | **No**   | `function` or `object` | Defines a [partial index](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#configuring-partial-indexes-with-where) that only includes rows matching the specified condition. Accepts `raw("SQL expression")` or an object literal like `{ field: value }`.<br /><br />PostgreSQL, SQLite, SQL Server, and CockroachDB. Requires the `partialIndexes` Preview feature. |

* ¹ Can be required by some of the index and field types.

#### Signature [#signature-3]

```prisma no-lines
@unique(map: String?, length: number?, sort: String?, clustered: Boolean?, where: raw(String) | { field: value }?)
```

> **Note**: The `where` argument accepts either `raw("SQL expression")` for raw SQL predicates or an object literal like `{ field: value }` for type-safe conditions. See [Configuring partial indexes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#configuring-partial-indexes-with-where) for details.

> **Note**: Before the `partialIndexes` Preview feature, the signature was:
>
> ```prisma no-lines
> @unique(map: String?, length: number?, sort: String?, clustered: Boolean?)
> ```

#### Examples [#examples-9]

##### Specify a unique attribute on a required `String` field [#specify-a-unique-attribute-on-a-required-string-field]

  

#### Relational databases

```prisma
model User {
  email String @unique
  name  String
}
```

#### MongoDB

```prisma
model User {
  id   String @default(auto()) @map("_id") @db.ObjectId
  name String
}
```

##### Specify a unique attribute on an optional `String` field [#specify-a-unique-attribute-on-an-optional-string-field]

  

#### Relational databases

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

#### MongoDB

```prisma
model User {
  id    String  @id @default(auto()) @map("_id") @db.ObjectId
  email String? @unique
  name  String
}
```

##### Specify a unique attribute on relation scalar field `authorId` [#specify-a-unique-attribute-on-relation-scalar-field-authorid]

  

#### Relational databases

```prisma
model Post {
  author    User    @relation(fields: [authorId], references: [id])
  authorId  Int     @unique
  title     String
  published Boolean @default(false)
}

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

#### MongoDB

```prisma
model Post {
  author    User    @relation(fields: [authorId], references: [id])
  authorId  String  @unique @db.ObjectId
  title     String
  published Boolean @default(false)
}

model User {
  id    String  @id @default(auto()) @map("_id") @db.ObjectId
  email String? @unique
  name  String
  Post  Post[]
}
```

##### Specify a unique attribute with `cuid()` values as default values [#specify-a-unique-attribute-with-cuid-values-as-default-values]

  

#### Relational databases

```prisma
model User {
  token String @unique @default(cuid())
  name  String
}
```

#### MongoDB

```prisma
model User {
  id    String @id @default(auto()) @map("_id") @db.ObjectId
  token String @unique @default(cuid())
  name  String
}
```

### `@@unique` [#unique-1]

Defines a compound [unique constraint](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-a-unique-field) for the specified fields.

#### Remarks [#remarks-11]

##### General [#general-2]

* All fields that make up the unique constraint **must** be mandatory fields. The following model is **not** valid because `id` could be `null`:

  ```prisma
  model User {
    firstname Int
    lastname  Int
    id        Int?

    @@unique([firstname, lastname, id])
  }
  ```

  The reason for this behavior is that all connectors consider `null` values to be distinct, which means that two rows that *look* identical are considered unique:

  ```
   firstname  | lastname | id
   -----------+----------+------
   John       | Smith    | null
   John       | Smith    | null
  ```

* A model can have any number of `@@unique` blocks

##### Relational databases [#relational-databases-4]

* Corresponding database construct: `UNIQUE`
* A `@@unique` block is required if it represents the only unique constraint on a model without an `@id` / `@@id`
* Adding a unique constraint automatically adds a corresponding *unique index* to the specified column(s)

##### MongoDB [#mongodb-13]

* Enforced by a [compound index in MongoDB](https://www.mongodb.com/docs/manual/core/index-compound/)
* A `@@unique` block cannot be used as the only unique identifier for a model - MongoDB requires an `@id` field

#### Arguments [#arguments-4]

| Name        | Required | Type                   | Description                                                                                                                                                                                                                                                                                                                                                   |
| ----------- | -------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fields`    | **Yes**  | `FieldReference[]`     | A list of field names - for example, `["firstname", "lastname"]`. Fields must be mandatory - see remarks.                                                                                                                                                                                                                                                     |
| `name`      | **No**   | `String`               | The name of the unique combination of fields - defaults to `fieldName1_fieldName2_fieldName3`                                                                                                                                                                                                                                                                 |
| `map`       | **No**   | `String`               |                                                                                                                                                                                                                                                                                                                                                               |
| `length`    | **No**   | `number`               | Allows you to specify a maximum length for the subpart of the value to be indexed.<br /><br />MySQL only.                                                                                                                                                                                                                                                     |
| `sort`      | **No**   | `String`               | Allows you to specify in what order the entries of the constraint are stored in the database. The available options are `Asc` and `Desc`.                                                                                                                                                                                                                     |
| `clustered` | **No**   | `Boolean`              | Defines whether the constraint is clustered or non-clustered. Defaults to `false`.<br /><br />SQL Server only.                                                                                                                                                                                                                                                |
| `where`     | **No**   | `function` or `object` | Defines a [partial index](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#configuring-partial-indexes-with-where) that only includes rows matching the specified condition. Accepts `raw("SQL expression")` or an object literal like `{ field: value }`.<br /><br />PostgreSQL, SQLite, SQL Server, and CockroachDB. Requires the `partialIndexes` Preview feature. |

The name of the `fields` argument on the `@@unique` attribute can be omitted:

```prisma no-lines
@@unique(fields: [title, author])
@@unique([title, author])
@@unique(fields: [title, author], name: "titleAuthor")
```

The `length` and `sort` arguments are added to the relevant field names:

```prisma no-lines
@@unique(fields: [title(length:10), author])
@@unique([title(sort: Desc), author(sort: Asc)])
```

#### Signature [#signature-4]

> ```prisma no-lines
> @@unique(_ fields: FieldReference[], name: String?, map: String?, where: raw(String) | { field: value }?)
> ```

> **Note**: The `where` argument accepts either `raw("SQL expression")` for raw SQL predicates or an object literal like `{ field: value }` for type-safe conditions. See [Configuring partial indexes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#configuring-partial-indexes-with-where) for details.

> **Note**: Before the `partialIndexes` Preview feature (and before version 4.0.0 / 3.5.0 with the `extendedIndexes` Preview feature), the signature was:
>
> ```prisma no-lines
> @@unique(_ fields: FieldReference[], name: String?, map: String?)
> ```

#### Examples [#examples-10]

##### Specify a multi-field unique attribute on two `String` fields [#specify-a-multi-field-unique-attribute-on-two-string-fields]

  

#### Relational databases

```prisma
model User {
  id        Int     @default(autoincrement())
  firstName String
  lastName  String
  isAdmin   Boolean @default(false)

  @@unique([firstName, lastName])
}
```

#### MongoDB

```prisma
model User {
  id        String  @id @default(auto()) @map("_id") @db.ObjectId
  firstName String
  lastName  String
  isAdmin   Boolean @default(false)

  @@unique([firstName, lastName])
}
```

To retrieve a user, use the generated field name (`firstname_lastname`):

```ts highlight=3;normal
const user = await prisma.user.findUnique({
  where: {
    firstName_lastName: {
      firstName: "Alice",
      lastName: "Smith",
      isAdmin: true,
    },
  },
});
```

##### Specify a multi-field unique attribute on two `String` fields and one `Boolean` field [#specify-a-multi-field-unique-attribute-on-two-string-fields-and-one-boolean-field]

  

#### Relational databases

```prisma
model User {
  id        Int     @default(autoincrement())
  firstName String
  lastName  String
  isAdmin   Boolean @default(false)

  @@unique([firstName, lastName, isAdmin])
}
```

#### MongoDB

```prisma
model User {
  id        String  @id @default(auto()) @map("_id") @db.ObjectId
  firstName String
  lastName  String
  isAdmin   Boolean @default(false)

  @@unique([firstName, lastName, isAdmin])
}
```

##### Specify a multi-field unique attribute that includes a relation field [#specify-a-multi-field-unique-attribute-that-includes-a-relation-field]

  

#### Relational databases

```prisma
model Post {
  id        Int     @default(autoincrement())
  author    User    @relation(fields: [authorId], references: [id])
  authorId  Int
  title     String
  published Boolean @default(false)

  @@unique([authorId, title])
}

model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  posts Post[]
}
```

#### MongoDB

```prisma
model Post {
  id        String  @id @default(auto()) @map("_id") @db.ObjectId
  author    User    @relation(fields: [authorId], references: [id])
  authorId  String  @db.ObjectId
  title     String
  published Boolean @default(false)

  @@unique([authorId, title])
}

model User {
  id    String @id @default(auto()) @map("_id") @db.ObjectId
  email String @unique
  posts Post[]
}
```

##### Specify a custom `name` for a multi-field unique attribute [#specify-a-custom-name-for-a-multi-field-unique-attribute]

  

#### Relational databases

```prisma
model User {
  id        Int     @default(autoincrement())
  firstName String
  lastName  String
  isAdmin   Boolean @default(false)

  @@unique(fields: [firstName, lastName, isAdmin], name: "admin_identifier")
}
```

#### MongoDB

```prisma
model User {
  id        String  @id @default(auto()) @map("_id") @db.ObjectId
  firstName String
  lastName  String
  isAdmin   Boolean @default(false)

  @@unique(fields: [firstName, lastName, isAdmin], name: "admin_identifier")
}
```

To retrieve a user, use the custom field name (`admin_identifier`):

```ts highlight=3;normal
const user = await prisma.user.findUnique({
  where: {
    admin_identifier: {
      firstName: "Alice",
      lastName: "Smith",
      isAdmin: true,
    },
  },
});
```

### `@@index` [#index]

Defines an index in the database.

#### Remarks [#remarks-12]

##### Relational databases [#relational-databases-5]

* Corresponding database construct: `INDEX`
* There are some additional index configuration options that cannot be provided via the Prisma schema yet. These include:
  * PostgreSQL and CockroachDB:
    * Define index fields as expressions (e.g. `CREATE INDEX title ON public."Post"((lower(title)) text_ops);`)
    * Create indexes concurrently with `CONCURRENTLY`

> [!NOTE]
> While you cannot configure these option in your Prisma schema, you can still configure them on the database-level directly.

##### MongoDB [#mongodb-14]

#### Arguments [#arguments-5]

| Name        | Required | Type                         | Description                                                                                                                                                                                                                                                                                                                                                   |
| ----------- | -------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fields`    | **Yes**  | `FieldReference[]`           | A list of field names - for example, `["firstname", "lastname"]`                                                                                                                                                                                                                                                                                              |
| `name`      | **No**   | `String`                     | The name that Prisma Client will expose for the argument covering all fields, e.g. `fullName` in `fullName: { firstName: "First", lastName: "Last"}`                                                                                                                                                                                                          |
| `map`       | **No**   | `map`                        | The name of the index in the underlying database (Prisma generates an index name that respects identifier length limits if you do not specify a name. Prisma uses the following naming convention: `tablename.field1_field2_field3_unique`)                                                                                                                   |
| `length`    | **No**   | `number`                     | Allows you to specify a maximum length for the subpart of the value to be indexed.<br /><br />MySQL only.                                                                                                                                                                                                                                                     |
| `sort`      | **No**   | `String`                     | Allows you to specify in what order the entries of the index or constraint are stored in the database. The available options are `asc` and `desc`.                                                                                                                                                                                                            |
| `clustered` | **No**   | `Boolean`                    | Defines whether the index is clustered or non-clustered. Defaults to `false`.<br /><br />SQL Server only.                                                                                                                                                                                                                                                     |
| `type`      | **No**   | `identifier`                 | Allows you to specify an index access method. Defaults to `BTree`.<br /><br />PostgreSQL and CockroachDB only.                                                                                                                                                                                                                                                |
| `ops`       | **No**   | `identifier` or a `function` | Allows you to define the index operators for certain index types.<br /><br />PostgreSQL only.                                                                                                                                                                                                                                                                 |
| `where`     | **No**   | `function` or `object`       | Defines a [partial index](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#configuring-partial-indexes-with-where) that only includes rows matching the specified condition. Accepts `raw("SQL expression")` or an object literal like `{ field: value }`.<br /><br />PostgreSQL, SQLite, SQL Server, and CockroachDB. Requires the `partialIndexes` Preview feature. |

The *name* of the `fields` argument on the `@@index` attribute can be omitted:

```prisma no-lines
@@index(fields: [title, author])
@@index([title, author])
```

The `length` and `sort` arguments are added to the relevant field names:

```prisma no-lines
@@index(fields: [title(length:10), author])
@@index([title(sort: Asc), author(sort: Desc)])
```

#### Signature [#signature-5]

```prisma no-lines
@@index(_ fields: FieldReference[], map: String?, where: raw(String) | { field: value }?)
```

> **Note**: The `where` argument accepts either `raw("SQL expression")` for raw SQL predicates or an object literal like `{ field: value }` for type-safe conditions. See [Configuring partial indexes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#configuring-partial-indexes-with-where) for details.

> **Note**: With the `partialIndexes` Preview feature, the `where` argument is available. Before this Preview feature, the signature was:
>
> ```prisma no-lines
> @@index(_ fields: FieldReference[], map: String?)
> ```

#### Examples [#examples-11]

Assume you want to add an index for the `title` field of the `Post` model

##### Define a single-column index (Relational databases only) [#define-a-single-column-index-relational-databases-only]

```prisma
model Post {
  id      Int     @id @default(autoincrement())
  title   String
  content String?

  @@index([title])
}
```

##### Define a multi-column index (Relational databases only) [#define-a-multi-column-index-relational-databases-only]

```prisma
model Post {
  id      Int     @id @default(autoincrement())
  title   String
  content String?

  @@index([title, content])
}
```

##### Define an index with a name (Relational databases only) [#define-an-index-with-a-name-relational-databases-only]

```prisma
model Post {
  id      Int     @id @default(autoincrement())
  title   String
  content String?

  @@index(fields: [title, content], name: "main_index")
}
```

##### Define an index on a composite type field (Relational databases only) [#define-an-index-on-a-composite-type-field-relational-databases-only]

```prisma
type Address {
  street String
  number Int
}

model User {
  id      Int     @id
  email   String
  address Address

  @@index([address.number])
}
```

### `@relation` [#relation]

Defines meta information about the relation. Learn more about [the `@relation` attribute](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#the-relation-attribute).

#### Remarks [#remarks-13]

##### Relational databases [#relational-databases-6]

* Corresponding database constructs: `FOREIGN KEY` / `REFERENCES`

##### MongoDB [#mongodb-15]

* If your model's primary key is of type `ObjectId` in the underlying database, both the primary key *and* the foreign key must have the `@db.ObjectId` attribute

#### Arguments [#arguments-6]

| Name         | Type                                                                                                                                              | Required                                                                                   | Description                                                                                                                                                                   | Example                                               |
| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------- |
| `name`       | `String`                                                                                                                                          | Sometimes (e.g. to disambiguate a relation)                                                | Defines the name of the relationship. In an m-n-relation, it also determines the name of the underlying relation table.                                                       | `"CategoryOnPost"`, `"MyRelation"`                    |
| `fields`     | `FieldReference[]`                                                                                                                                | On [annotated](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields) relation fields | A list of [fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-fields) of the *current* model                                                                            | `["authorId"]`, `["authorFirstName, authorLastName"]` |
| `references` | `FieldReference[]`                                                                                                                                | On [annotated](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields) relation fields | A list of [fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-fields) of the model on *the other side of the relation*                                                  | `["id"]`, `["firstName, lastName"]`                   |
| `map`        | `String`                                                                                                                                          | No                                                                                         | Defines a [custom name](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping#constraint-and-index-names) for the foreign key in the database.                                    | `["id"]`, `["firstName, lastName"]`                   |
| `onUpdate`   | Enum. See [Types of referential actions](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions#types-of-referential-actions) for values. | No                                                                                         | Defines the [referential action](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions) to perform when a referenced entry in the referenced model is being updated. | `Cascade`, `NoAction`                                 |
| `onDelete`   | Enum. See [Types of referential actions](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions#types-of-referential-actions) for values. | No                                                                                         | Defines the [referential action](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions) to perform when a referenced entry in the referenced model is being deleted. | `Cascade`, `NoAction`                                 |

The name of the `name` argument on the `@relation` attribute can be omitted (`references` is required):

```prisma
@relation(name: "UserOnPost", references: [id])
@relation("UserOnPost", references: [id])

// or

@relation(name: "UserOnPost")
@relation("UserOnPost")
```

#### Signature [#signature-6]

```prisma no-lines
@relation(_ name: String?, fields: FieldReference[]?, references: FieldReference[]?, onDelete: ReferentialAction?, onUpdate: ReferentialAction?, map: String?)
```

With SQLite, the signature changes to:

```prisma no-lines
@relation(_ name: String?, fields: FieldReference[]?, references: FieldReference[]?, onDelete: ReferentialAction?, onUpdate: ReferentialAction?)
```

#### Examples [#examples-12]

See: [The `@relation` attribute](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#the-relation-attribute).

### `@map` [#map]

Maps a field name or enum value from the Prisma schema to a column or document field with a different name in the database. If you do not use `@map`, the Prisma field name matches the column name or document field name exactly.

> See [Using custom model and field names](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names) to see how `@map` and `@@map` changes the generated Prisma Client.

#### Remarks [#remarks-14]

##### General [#general-3]

* `@map` **does not** rename the columns / fields in the database
* `@map` **does** [change the field names in the generated client](#map-the-firstname-field-to-a-column-called-first_name)

##### MongoDB [#mongodb-16]

Your `@id` field must include `@map("_id")`. For example:

```prisma
model User {
  id String @default(auto()) @map("_id") @db.ObjectId
}
```

#### Arguments [#arguments-7]

| Name   | Type     | Required | Description                                                                  | Example                         |
| :----- | :------- | :------- | :--------------------------------------------------------------------------- | :------------------------------ |
| `name` | `String` | **Yes**  | The database column (relational databases) or document field (MongoDB) name. | `"comments"`, `"someFieldName"` |

The name of the `name` argument on the `@map` attribute can be omitted:

```prisma
@map(name: "is_admin")
@map("users")
```

#### Signature [#signature-7]

```prisma no-lines
@map(_ name: String)
```

#### Examples [#examples-13]

##### Map the `firstName` field to a column called `first_name` [#map-the-firstname-field-to-a-column-called-first_name]

  

#### Relational databases

```prisma
model User {
  id        Int    @id @default(autoincrement())
  firstName String @map("first_name")
}
```

#### MongoDB

```prisma
model User {
  id        String @id @default(auto()) @map("_id") @db.ObjectId
  firstName String @map("first_name")
}
```

The generated client:

```ts highlight=3;normal
await prisma.user.create({
  data: {
    firstName: "Yewande", // first_name */} firstName
  },
});
```

##### Map an enum named `ADMIN` to a database enum named `admin` [#map-an-enum-named-admin-to-a-database-enum-named-admin]

```prisma
enum Role {
  ADMIN    @map("admin")
  CUSTOMER
}
```

In Prisma ORM v7 and later, the generated TypeScript enum uses the mapped values:

```ts
export const Role = {
  ADMIN: "admin",
  CUSTOMER: "CUSTOMER",
} as const;
```

This means `Role.ADMIN` evaluates to `"admin"`, not `"ADMIN"`.

### `@@map` [#map-1]

Maps the Prisma schema model name to a table (relational databases) or collection (MongoDB) with a different name, or an enum name to a different underlying enum in the database. If you do not use `@@map`, the model name matches the table (relational databases) or collection (MongoDB) name exactly.

> See [Using custom model and field names](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names) to see how `@map` and `@@map` changes the generated Prisma Client.

#### Arguments [#arguments-8]

| Name   | Type     | Required | Description                                                             | Example                                     |
| :----- | :------- | :------- | :---------------------------------------------------------------------- | :------------------------------------------ |
| `name` | `String` | **Yes**  | The database table (relational databases) or collection (MongoDB) name. | `"comments"`, `"someTableOrCollectionName"` |

The name of the `name` argument on the `@@map` attribute can be omitted

```prisma
@@map(name: "users")
@@map("users")
```

#### Signature [#signature-8]

```prisma no-lines
@@map(_ name: String)
```

#### Examples [#examples-14]

##### Map the `User` model to a database table/collection named `users` [#map-the-user-model-to-a-database-tablecollection-named-users]

  

#### Relational databases

```prisma
model User {
  id   Int    @id @default(autoincrement())
  name String

  @@map("users")
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(auto()) @map("_id") @db.ObjectId
  name String

  @@map("users")
}
```

The generated client:

```ts highlight=1;normal
await prisma.user.create({
  // users */} user
  data: {
    name: "Yewande",
  },
});
```

##### Map the `Role` enum to a native enum in the database named `_Role` its values to lowercase values in the database [#map-the-role-enum-to-a-native-enum-in-the-database-named-_role-its-values-to-lowercase-values-in-the-database]

```prisma
enum Role {
  ADMIN    @map("admin")
  CUSTOMER @map("customer")

  @@map("_Role")
}
```

### `@updatedAt` [#updatedat]

Automatically stores the time when a record was last updated. If you do not supply a time yourself, Prisma Client will automatically set the value for fields with this attribute.

#### Remarks [#remarks-15]

* Compatible with [`DateTime`](#datetime) fields
* Implemented at Prisma ORM level

> [!WARNING]
> In versions before [4.4.0](https://github.com/prisma/orm/releases/tag/4.4.0), if you're also using [`now()`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#now), the time might differ from the `@updatedAt` values if your database and app have different time zones. This happens because `@updatedAt` operates at the Prisma ORM level, while `now()` operates at the database level.

> [!NOTE]
> If you pass an empty update clause, the @updatedAt value will remain unchanged. For example:
> 
> ```ts
> await prisma.user.update({
>   where: {
>     id: 1,
>   },
>   data: {}, //<- Empty update clause
> });
> ```

#### Arguments [#arguments-9]

N/A

#### Signature [#signature-9]

```prisma no-lines
@updatedAt
```

#### Examples [#examples-15]

  

#### Relational databases

```prisma line-number 
model Post {
  id        String   @id
  updatedAt DateTime @updatedAt
}
```

#### MongoDB

```prisma line-number 
model Post {
  id        String   @id @map("_id") @db.ObjectId
  updatedAt DateTime @updatedAt
}
```

### `@ignore` [#ignore]

Add `@ignore` to a field that you want to exclude from Prisma Client (for example, a field that you do not want Prisma Client users to update). Ignored fields are excluded from the generated Prisma Client. The model's `create` method is disabled when doing this for *required* fields with no `@default` (because the database cannot create an entry without that data).

#### Remarks [#remarks-16]

* Prisma ORM automatically adds `@ignore` to fields that *refer to* invalid models when you introspect.

#### Examples [#examples-16]

The following example demonstrates manually adding `@ignore` to exclude the `email` field from Prisma Client:

```prisma title="schema.prisma" highlight=4;normal
model User {
  id    Int    @id
  name  String
  email String @ignore // this field will be excluded // [!code highlight]
}
```

### `@@ignore` [#ignore-1]

Add `@@ignore` to a model that you want to exclude from Prisma Client (for example, a model that you do not want Prisma users to update). Ignored models are excluded from the generated Prisma Client.

#### Remarks [#remarks-17]

* Prisma ORM adds `@@ignore` to an invalid model during introspection. (It also adds [`@ignore`](#ignore) to relations pointing to such a model)

#### Examples [#examples-17]

In the following example, the `Post` model is invalid because it does not have a unique identifier. Use `@@ignore` to exclude it from the generated Prisma Client API:

```prisma title="schema.prisma" highlight=7;normal
/// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by Prisma Client.
model Post {
  id       Int  @default(autoincrement()) // no unique identifier
  author   User @relation(fields: [authorId], references: [id])
  authorId Int

  @@ignore // [!code highlight]
}
```

In the following example, the `Post` model is invalid because it does not have a unique identifier, and the `posts` relation field on `User` is invalid because it refers to the invalid `Post` model. Use `@@ignore` on the `Post` model and `@ignore` on the `posts` relation field in `User` to exclude both the model and the relation field from the generated Prisma Client API:

```prisma title="schema.prisma" highlight=7,13;normal
/// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by Prisma Client.
model Post {
  id       Int  @default(autoincrement()) // no unique identifier
  author   User @relation(fields: [authorId], references: [id])
  authorId Int

  @@ignore // [!code highlight]
}

model User {
  id    Int     @id @default(autoincrement())
  name  String?
  posts Post[]  @ignore // [!code highlight]
}
```

### `@@schema` [#schema]

Add `@@schema` to a model to specify which schema in your database should contain the table associated with that model. Learn more about [adding multiple schema's here](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema).

> [!NOTE]
> [Multiple database schema](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema) support is only available with the PostgreSQL, CockroachDB, and SQL Server connectors.

#### Arguments [#arguments-10]

| Name   | Type     | Required | Description                      | Example            |
| :----- | :------- | :------- | :------------------------------- | :----------------- |
| `name` | `String` | **Yes**  | The name of the database schema. | `"base"`, `"auth"` |

The name of the `name` argument on the `@@schema` attribute can be omitted

```prisma
@@schema(name: "auth")
@@schema("auth")
```

#### Signature [#signature-10]

```prisma no-lines
@@schema(_ name: String)
```

#### Examples [#examples-18]

##### Map the `User` model to a database schema named `auth` [#map-the-user-model-to-a-database-schema-named-auth]

```prisma highlight=3,9,16;normal
generator client {
  provider        = "prisma-client"
  output          = "./generated"
}

datasource db {
  provider = "postgresql"
  schemas  = ["auth"] // [!code highlight]
}

model User {
  id   Int    @id @default(autoincrement())
  name String

  @@schema("auth") // [!code highlight]
}
```

> [!NOTE]
> For more information about using the `multiSchema` feature, refer to [Multi-schema](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema).

### `@shardKey` [#shardkey]

> [!NOTE]
> This feature requires the `shardKeys` Preview feature flag on your `generator`:
> 
> ```prisma
> generator client {
>   provider = "prisma-client"
>   output = "../generated/prisma"
>   previewFeatures = ["shardKeys"]
> }
> ```

The `@shardKey` attribute is only compatible with [PlanetScale](http://planetscale.com/) databases. It enables you define a [shard key](https://planetscale.com/docs/vitess/sharding) on a field of your model:

```prisma
model User {
  id     String @default(uuid())
  region String @shardKey
}
```

### `@@shardKey` [#shardkey-1]

> [!NOTE]
> This feature requires the `shardKeys` Preview feature flag on your `generator`:
> 
> ```prisma
> generator client {
>   provider = "prisma-client"
>   output = "../generated/prisma"
>   previewFeatures = ["shardKeys"]
> }
> ```

The `@@shardKey` attribute is only compatible with [PlanetScale](http://planetscale.com/) databases. It enables you define a [shard key](https://planetscale.com/docs/vitess/sharding) on multiple fields of your model:

```prisma
model User {
  id         String @default(uuid())
  country    String
  customerId String
  @@shardKey([country, customerId])
}
```

## Attribute functions [#attribute-functions]

### `auto()` [#auto]

> [!WARNING]
> This function is available on MongoDB only.

Represents **default values** that are automatically generated by the database.

#### Remarks [#remarks-18]

##### MongoDB [#mongodb-17]

Used to generate an `ObjectId` for `@id` fields:

```prisma
id  String  @map("_id") @db.ObjectId @default(auto())
```

##### Relational databases [#relational-databases-7]

The `auto()` function is not available on relational databases.

#### Example [#example]

##### Generate `ObjectId` (MongoDB only) [#generate-objectid-mongodb-only]

```prisma
model User {
  id   String  @id @default(auto()) @map("_id") @db.ObjectId
  name String?
}
```

### `autoincrement()` [#autoincrement]

> [!WARNING]
> **Not supported by MongoDB** <br />
> The [MongoDB connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb) does not support the `autoincrement()` function.

Create a sequence of integers in the underlying database and assign the incremented values to the ID values of the created records based on the sequence.

#### Remarks [#remarks-19]

* Compatible with `Int` on most databases (`BigInt` on CockroachDB)
* Implemented on the database-level, meaning that it manifests in the database schema and can be recognized through introspection. Database implementations:

  | Database    | Implementation                                                                                    |
  | ----------- | ------------------------------------------------------------------------------------------------- |
  | PostgreSQL  | [`SERIAL`](https://www.postgresql.org/docs/9.1/datatype-numeric.html#DATATYPE-SERIAL) type        |
  | MySQL       | [`AUTO_INCREMENT`](https://dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html) attribute |
  | SQLite      | [`AUTOINCREMENT`](https://www.sqlite.org/autoinc.html) keyword                                    |
  | CockroachDB | [`SERIAL`](https://www.postgresql.org/docs/9.1/datatype-numeric.html#DATATYPE-SERIAL) type        |

#### Examples [#examples-19]

##### Generate autoincrementing integers as IDs (Relational databases only) [#generate-autoincrementing-integers-as-ids-relational-databases-only-1]

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

### `sequence()` [#sequence]

> [!NOTE]
> **Only supported by CockroachDB** <br />
> The sequence function is only supported by [CockroachDB connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#cockroachdb).

Create a sequence of integers in the underlying database and assign the incremented values to the values of the created records based on the sequence.

#### Optional arguments [#optional-arguments]

| Argument    | Example                                                                                                                                                                                                            |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `virtual`   | `@default(sequence(virtual))`<br />Virtual sequences are sequences that do not generate monotonically increasing values and instead produce values like those generated by the built-in function `unique_rowid()`. |
| `cache`     | `@default(sequence(cache: 20))`<br />The number of sequence values to cache in memory for reuse in the session. A cache size of `1` means that there is no cache, and cache sizes of less than `1` are not valid.  |
| `increment` | `@default(sequence(increment: 4))`<br />The new value by which the sequence is incremented. A negative number creates a descending sequence. A positive number creates an ascending sequence.                      |
| `minValue`  | `@default(sequence(minValue: 10))`<br />The new minimum value of the sequence.                                                                                                                                     |
| `maxValue`  | `@default(sequence(maxValue: 3030303))`<br />The new maximum value of the sequence.                                                                                                                                |
| `start`     | `@default(sequence(start: 2))`<br />The value the sequence starts at, if it's restarted or if the sequence hits the `maxValue`.                                                                                    |

#### Examples [#examples-20]

##### Generate sequencing integers as IDs [#generate-sequencing-integers-as-ids]

```prisma
model User {
  id   Int    @id @default(sequence(maxValue: 4294967295))
  name String
}
```

### `cuid()` [#cuid]

Generate a globally unique identifier based on the [`cuid`](https://github.com/ericelliott/cuid) spec.

If you'd like to use [`cuid2`](https://github.com/paralleldrive/cuid2) values, you can pass `2` as an argument to the `cuid` function: `cuid(2)`.

#### Remarks [#remarks-20]

* Compatible with `String`.
* Implemented by Prisma ORM and therefore not "visible" in the underlying database schema. You can still use `cuid()` when using [introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) by [manually changing your Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names) and generating Prisma Client, in that case the values will be generated by Prisma ORM.
* Since the length of `cuid()` output is undefined per the cuid creator, a safe field size is 30 characters, in order to allow for enough characters for very large values. If you set the field size as less than 30, and then a larger value is generated by `cuid()`, you might see Prisma Client errors such as `Error: The provided value for the column is too long for the column's type.`
* For **MongoDB**: `cuid()` does not generate a valid `ObjectId`. You can use [`@db.ObjectId` syntax](#generate-objectid-as-ids-mongodb-only) if you want to use `ObjectId` in the underlying database. However, you can still use `cuid()` if your `_id` field is not of type `ObjectId`.

#### Examples [#examples-21]

##### Generate `cuid()` values as IDs [#generate-cuid-values-as-ids-1]

  

#### Relational databases

```prisma
model User {
  id   String @id @default(cuid())
  name String
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(cuid()) @map("_id")
  name String
}
```

##### Generate `cuid(2)` values as IDs based on the `cuid2` spec [#generate-cuid2-values-as-ids-based-on-the-cuid2-spec]

  

#### Relational databases

```prisma
model User {
  id   String @id @default(cuid(2))
  name String
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(cuid(2)) @map("_id")
  name String
}
```

### `uuid()` [#uuid]

Generate a globally unique identifier based on the [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) spec. Prisma ORM supports versions 4 (default) and 7.

#### Remarks [#remarks-21]

* Compatible with `String`.
* Implemented by Prisma ORM and therefore not "visible" in the underlying database schema. You can still use `uuid()` when using [introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) by [manually changing your Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names) and generating Prisma Client, in that case the values will be generated by Prisma ORM.
* For **relational databases**: If you do not want to use Prisma ORM's `uuid()` function, you can use [the native database function with `dbgenerated`](#override-default-value-behavior-for-supported-types).
* For **MongoDB**: `uuid()` does not generate a valid `ObjectId`. You can use [`@db.ObjectId` syntax](#generate-objectid-as-ids-mongodb-only) if you want to use `ObjectId` in the underlying database. However, you can still use `uuid()` if your `_id` field is not of type `ObjectId`.

#### Examples [#examples-22]

##### Generate `uuid()` values as IDs using UUID v4 [#generate-uuid-values-as-ids-using-uuid-v4]

  

#### Relational databases

```prisma
model User {
  id   String @id @default(uuid())
  name String
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(uuid()) @map("_id")
  name String
}
```

##### Generate `uuid(7)` values as IDs using UUID v7 [#generate-uuid7-values-as-ids-using-uuid-v7]

  

#### Relational databases

```prisma
model User {
  id   String @id @default(uuid(7))
  name String
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(uuid(7)) @map("_id")
  name String
}
```

### `ulid()` [#ulid]

Generate a universally unique lexicographically sortable identifier based on the [ULID](https://github.com/ulid/spec) spec.

#### Remarks [#remarks-22]

* `ulid()` will produce 128-bit random identifier represented as a 26-character long alphanumeric string, e.g.: `01ARZ3NDEKTSV4RRFFQ69G5FAV`

#### Examples [#examples-23]

##### Generate `ulid()` values as IDs [#generate-ulid-values-as-ids-1]

  

#### Relational databases

```prisma
model User {
  id   String @id @default(ulid())
  name String
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(ulid()) @map("_id")
  name String
}
```

### `nanoid()` [#nanoid]

Generated values based on the [Nano ID](https://github.com/ai/nanoid) spec. `nanoid()` accepts an integer value between 2 and 255 that specifies the *length* of the generate ID value, e.g. `nanoid(16)` will generated ID with 16 characters. If you don't provide a value to the nanoid() function, the default value is 21.

> [!NOTE]
> Nano ID is quite comparable to UUID v4 (random-based). It has a similar number of random bits in the ID (126 in Nano ID and 122 in UUID), so it has a similar collision probability:
> 
> For there to be a one in a billion chance of duplication, 103 trillion version 4 IDs must be generated.
> 
> There are two main differences between Nano ID and UUID v4:
> 
> * Nano ID uses a bigger alphabet, so a similar number of random bits are packed in just 21 symbols instead of 36.
> * Nano ID code is 4 times smaller than uuid/v4 package: 130 bytes instead of 423.

#### Remarks [#remarks-23]

* Compatible with `String`.
* Implemented by Prisma ORM and therefore not "visible" in the underlying database schema. You can still use `uuid()` when using [introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) by [manually changing your Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names) and [generating Prisma Client](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider), in that case the values will be generated by Prisma ORM.
* For **MongoDB**: `nanoid()` does not generate a valid `ObjectId`. You can use [`@db.ObjectId` syntax](#generate-objectid-as-ids-mongodb-only) if you want to use `ObjectId` in the underlying database. However, you can still use `nanoid()` if your `_id` field is not of type `ObjectId`.

#### Examples [#examples-24]

##### Generate `nanoid()` values with 21 characters as IDs [#generate-nanoid-values-with-21-characters-as-ids]

  

#### Relational databases

```prisma
model User {
  id   String @id @default(nanoid())
  name String
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(nanoid()) @map("_id")
  name String
}
```

##### Generate `nanoid()` values with 16 characters as IDs [#generate-nanoid-values-with-16-characters-as-ids]

  

#### Relational databases

```prisma
model User {
  id   String @id @default(nanoid(16))
  name String
}
```

#### MongoDB

```prisma
model User {
  id   String @id @default(nanoid(16)) @map("_id")
  name String
}
```

### `now()` [#now]

Set a timestamp of the time when a record is created.

#### Remarks [#remarks-24]

##### General [#general-4]

* Compatible with [`DateTime`](#datetime)

> [!WARNING]
> In versions before [4.4.0](https://github.com/prisma/orm/releases/tag/4.4.0), if you're also using [`@updatedAt`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#updatedat), the time might differ from the `now()` values if your database and app have different time zones. This happens because `@updatedAt` operates at the Prisma ORM level, while `now()` operates at the database level.

##### Relational databases [#relational-databases-8]

* Implemented on the database-level, meaning that it manifests in the database schema and can be recognized through introspection. Database implementations:

  | Database    | Implementation                                                                                                                                  |
  | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
  | PostgreSQL  | [`CURRENT_TIMESTAMP`](https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT) and aliases like `now()`      |
  | MySQL       | [`CURRENT_TIMESTAMP`](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_current-timestamp) and aliases like `now()` |
  | SQLite      | `CURRENT_TIMESTAMP` and aliases like `date('now')`                                                                                              |
  | CockroachDB | [`CURRENT_TIMESTAMP`](https://www.cockroachlabs.com/docs/stable/functions-and-operators#special-syntax-forms) and aliases like `now()`          |

##### MongoDB [#mongodb-18]

* Implemented at Prisma ORM level

#### Examples [#examples-25]

##### Set current timestamp value when a record is created [#set-current-timestamp-value-when-a-record-is-created]

  

#### Relational databases

```prisma
model User {
  id        String   @id
  createdAt DateTime @default(now())
}
```

#### MongoDB

```prisma
model User {
  id        String   @id @default(auto()) @map("_id") @db.ObjectId
  createdAt DateTime @default(now())
}
```

### `dbgenerated(...)` [#dbgenerated]

Represents **default values** that cannot be expressed in the Prisma schema (such as `random()`).

#### Remarks [#remarks-25]

##### Relational databases [#relational-databases-9]

* Compatible with any scalar type

* Can not be an empty string `dbgenerated("")`

* Accepts a `String` value, which allows you to:
  * [Set default values for `Unsupported` types](#set-default-value-for-unsupported-type)
  * [Override default value behavior for supported types](#override-default-value-behavior-for-supported-types)

* String values in `dbgenerated(...)` might not match what the DB returns as the default value, because values such as strings may be explicitly cast (e.g. `'hello'::STRING`). When a mismatch is present, Prisma Migrate indicates a migration is still needed. You can use `prisma db pull` to infer the correct value to resolve the discrepancy. ([Related issue](https://github.com/prisma/orm/issues/14917))

#### Examples [#examples-26]

##### Set default value for `Unsupported` type [#set-default-value-for-unsupported-type]

```prisma
circle     Unsupported("circle")?   @default(dbgenerated("'<(10,4),11>'::circle"))
```

##### Override default value behavior for supported types [#override-default-value-behavior-for-supported-types]

You can also use `dbgenerated(...)` to set the default value for supported types. For example, in PostgreSQL you can generate UUIDs at the database level rather than rely on Prisma ORM's `uuid()`:

```prisma highlight=2;add|3;delete
model User {
  id   String  @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid // [!code ++]
  id   String  @id @default(uuid()) @db.Uuid // [!code --]
  test String?
}
```

> [!NOTE]
> [`gen_random_uuid()` is a PostgreSQL function](https://www.postgresql.org/docs/13/functions-uuid.html). To use it in PostgreSQL versions 12.13 and earlier, you must enable the `pgcrypto` extension. See [PostgreSQL extensions](https://www.prisma.io/docs/orm/v7/prisma-schema/postgresql-extensions) for how to install extensions.

## Attribute argument types [#attribute-argument-types]

### `FieldReference[]` [#fieldreference]

An array of [field](#model-fields) names: `[id]`, `[firstName, lastName]`

### `String` [#string-1]

A variable length text in double quotes: `""`, `"Hello World"`, `"Alice"`

### `Expression` [#expression]

An expression that can be evaluated by Prisma ORM: `42.0`, `""`, `Bob`, `now()`, `cuid()`

## `enum` [#enum]

> [!WARNING]
> **Not supported Microsoft SQL Server** <br />
> The [Microsoft SQL Server connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server) does not support the `enum` type.

Defines an [enum](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-enums) .

### Remarks [#remarks-26]

* Enums are natively supported by [PostgreSQL](https://www.postgresql.org/docs/current/datatype-enum.html) and [MySQL](https://dev.mysql.com/doc/refman/8.0/en/enum.html)
* Enums are implemented and enforced at Prisma ORM level in SQLite and MongoDB

### Naming conventions [#naming-conventions-2]

* Enum names must start with a letter (they are typically spelled in [PascalCase](http://wiki.c2.com/?PascalCase))
* Enums must use the singular form (e.g. `Role` instead of `role`, `roles` or `Roles`).
* Must adhere to the following regular expression: `[A-Za-z][A-Za-z0-9_]*`

### Examples [#examples-27]

#### Specify an `enum` with two possible values [#specify-an-enum-with-two-possible-values]

  

#### Relational databases

```prisma
enum Role {
  USER
  ADMIN
}

model User {
  id   Int  @id @default(autoincrement())
  role Role
}
```

#### MongoDB

```prisma
enum Role {
  USER
  ADMIN
}

model User {
  id   String @id @default(auto()) @map("_id") @db.ObjectId
  role Role
}
```

#### Specify an `enum` with two possible values and set a default value [#specify-an-enum-with-two-possible-values-and-set-a-default-value]

  

#### Relational databases

```prisma
enum Role {
  USER
  ADMIN
}

model User {
  id   Int  @id @default(autoincrement())
  role Role @default(USER)
}
```

#### MongoDB

```prisma
enum Role {
  USER
  ADMIN
}

model User {
  id   String @id @default(auto()) @map("_id") @db.ObjectId
  role Role   @default(USER)
}
```

## `type` [#type]

> [!WARNING]
> Composite types are available **for MongoDB only**.

Defines a [composite type](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-composite-types-mongodb).

### Naming conventions [#naming-conventions-3]

Type names must:

* start with a letter (they are typically spelled in [PascalCase](http://wiki.c2.com/?PascalCase))
* adhere to the following regular expression: `[A-Za-z][A-Za-z0-9_]*`

### Examples [#examples-28]

#### Define a `Product` model with a list of `Photo` composite types [#define-a-product-model-with-a-list-of-photo-composite-types]

```prisma
model Product {
  id     String  @id @default(auto()) @map("_id") @db.ObjectId
  name   String
  photos Photo[]
}

type Photo {
  height Int
  width  Int
  url    String
}
```

## Where to go next [#where-to-go-next]

* [Prisma schema overview](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) if you want a guided explanation of how schema pieces fit together
* [Data model / models](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models) for practical modeling patterns beyond the raw reference
* [Prisma Migrate getting started](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started) if you are ready to apply schema changes to a real database
* [Add Prisma ORM to an existing PostgreSQL project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql) if you want to connect this schema workflow to a live application

## Related pages

- [`Config API`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference): Complete reference for prisma.config.ts configuration options
- [`Connection URLs`](https://www.prisma.io/docs/orm/v7/reference/connection-urls): Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite
- [`Database Features`](https://www.prisma.io/docs/orm/v7/reference/database-features): Database features supported in Prisma ORM
- [`Environment Variables`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference): Reference for Prisma environment variables
- [`Error Reference`](https://www.prisma.io/docs/orm/v7/reference/error-reference): Prisma Client, Migrate, and Introspection error codes

# Supported databases (Prisma ORM v7) (/docs/orm/v7/reference/supported-databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

This page lists all the databases and their versions that are supported by Prisma ORM

Location: ORM > v7 > Reference > Supported databases

Prisma ORM currently supports the following databases.

> See also: [System requirements](https://www.prisma.io/docs/orm/v7/reference/system-requirements).

An asterisk (\*) indicates that the version number is not relevant; either all versions are supported, there is not a public version number, etc.

## Self-hosted databases [#self-hosted-databases]

| Database             | Version |
| -------------------- | ------- |
| CockroachDB          | 21.2.4+ |
| MariaDB              | 10.0+   |
| MariaDB              | 11.0+   |
| Microsoft SQL Server | 2017    |
| Microsoft SQL Server | 2019    |
| Microsoft SQL Server | 2022    |
| MongoDB              | 4.2+    |
| MySQL                | 5.6     |
| MySQL                | 5.7     |
| MySQL                | 8.0     |
| MySQL                | 8.4     |
| PostgreSQL           | 9.6     |
| PostgreSQL           | 10      |
| PostgreSQL           | 11      |
| PostgreSQL           | 12      |
| PostgreSQL           | 13      |
| PostgreSQL           | 14      |
| PostgreSQL           | 15      |
| PostgreSQL           | 16      |
| PostgreSQL           | 17      |
| PostgreSQL           | 18      |
| SQLite               | \*      |

Note that a fixed version of SQLite is shipped with every Prisma ORM release.

## Managed databases [#managed-databases]

| Database                 | Version |
| ------------------------ | ------- |
| AWS Aurora               | \*      |
| AWS Aurora Serverless ¹  | \*      |
| Azure SQL                | \*      |
| CockroachDB-as-a-Service | \*      |
| MongoDB Atlas            | \*      |
| Neon Serverless Postgres | \*      |
| PlanetScale              | \*      |
| Cloudflare D1 (Preview)  | \*      |
| Aiven (MySQL & Postgres) | \*      |

¹ This does not include support for [Data API for Aurora Serverless](https://github.com/prisma/orm/issues/1964).

## Related pages

- [`Config API`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference): Complete reference for prisma.config.ts configuration options
- [`Connection URLs`](https://www.prisma.io/docs/orm/v7/reference/connection-urls): Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite
- [`Database Features`](https://www.prisma.io/docs/orm/v7/reference/database-features): Database features supported in Prisma ORM
- [`Environment Variables`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference): Reference for Prisma environment variables
- [`Error Reference`](https://www.prisma.io/docs/orm/v7/reference/error-reference): Prisma Client, Migrate, and Introspection error codes

# System requirements (Prisma ORM v7) (/docs/orm/v7/reference/system-requirements)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

System requirements for running Prisma ORM

Location: ORM > v7 > Reference > System requirements

This section lists the software that Prisma ORM requires and the supported operating systems, along with runtime dependency requirements for specific operating systems.

### Software requirements [#software-requirements]

The latest version of Prisma ORM requires the following software:

| Tool                  | Minimum required version       |
| :-------------------- | :----------------------------- |
| Node.js               | ^20.19.0, ^22.12.0, or ^24.0.0 |
| TypeScript (optional) | 5.4+                           |
| Yarn (optional)       | 1.19.2                         |

* Prisma ORM supports and tests all *Active LTS* and *Maintenance LTS* **Node.js** releases. [Releases that are not in these states like *Current*, and also odd-numbered versions](https://nodejs.org/en/about/releases/) probably also work, but are not recommended for production use.
* **TypeScript** is only required for TypeScript users.
* When using **Yarn 1**, `1.19.2` is the minimum version compatible with Prisma Client.

See also: [Supported database versions](https://www.prisma.io/docs/orm/v7/reference/supported-databases)

**Expand for earlier versions**

### Prisma ORM v6 [#prisma-orm-v6]

Prisma ORM v6 requires the following software:

|                       | Minimum required version |
| :-------------------- | :----------------------- |
| Node.js               | 16.13 / 18.X / 20.X      |
| TypeScript (optional) | 4.7+                     |
| Yarn (optional)       | 1.19.2                   |

### Operating systems [#operating-systems]

Prisma ORM is supported on macOS, Windows and most Linux distributions.

#### Linux runtime dependencies [#linux-runtime-dependencies]

Prisma ORM requires the following system libraries to be installed to work:

* OpenSSL 1.0.x, 1.1.x or 3.x
* zlib (`libz.so.1`)
* libgcc (`libgcc_s.so.1`)
* C standard library (glibc on most Linux distributions or musl libc on Alpine Linux)

The following two tables show the supported Linux distro families, OpenSSL versions and C standard libraries for each CPU architecture.

On `AMD64` (`x86_64`) architecture:

| Distro family    | OpenSSL version   | libc version |
| ---------------- | ----------------- | ------------ |
| Alpine           | 1.1.x, 3.x        | musl 1.2.x   |
| RHEL             | 1.0.x, 1.1.x, 3.x | glibc 2.17+  |
| Debian or others | 1.0.x             | glibc 2.19+  |
| Debian or others | 1.1.x, 3.x        | glibc 2.24+  |

On `ARM64` (`aarch64`) architecture:

| Distro family    | OpenSSL version   | libc version |
| ---------------- | ----------------- | ------------ |
| Alpine           | 1.1.x, 3.x        | musl 1.2.x   |
| RHEL             | 1.0.x, 1.1.x, 3.x | glibc 2.24+  |
| Debian or others | 1.0.x, 1.1.x, 3.x | glibc 2.24+  |

When Prisma ORM can not resolve the OpenSSL version on a system (e.g. because it is not installed), it will default to OpenSSL 1.1.x.

Systems that can run the supported Node.js versions will most likely have zlib and libgcc available. One notable exception is Google's Distroless images, where `libz.so.1` needs to be copied from a compatible Debian system.

#### Windows runtime dependencies [#windows-runtime-dependencies]

On Windows [Microsoft Visual C++ Redistributable 2015](https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe) or newer must be installed (which is by default the case on most modern installations).

#### macOS runtime dependencies [#macos-runtime-dependencies]

Prisma ORM supports macOS 10.15 or newer. There are no additional platform-specific requirements on macOS other than what is listed for all platforms in the [Software requirements](#software-requirements) section.

## Troubleshooting [#troubleshooting]

There are some common problems caused by using outdated versions of the system requirements:

### Unable to build a TypeScript project with `@prisma/client` [#unable-to-build-a-typescript-project-with-prismaclient]

#### Problem [#problem]

You see the following error when you try type-checking a project after you run `prisma generate`.

```bash wrap
./node_modules/.prisma/client/index.d.ts:10:33
Type error: Type expected.
   8 | export type PrismaPromise<A> = Promise<A> & {[prisma]: true}
   9 | type UnwrapTuple<Tuple extends readonly unknown[]> = {
> 10 |   [K in keyof Tuple]: K extends `${number}` ? Tuple[K] extends PrismaPromise<infer X> ? X : never : never
     |                                 ^
  11 | };
  12 |
  13 |
```

#### Solution [#solution]

Upgrade the TypeScript dependency in your project to a [version supported by Prisma ORM](#software-requirements). `npm install -D typescript`.

### Unable to use `groupBy` preview feature [#unable-to-use-groupby-preview-feature]

#### Problem [#problem-1]

You see the following console error when you attempt to run an app that uses the `groupBy` preview feature:

```bash wrap
server.ts:6:25 - error TS2615: Type of property 'OR' circularly references itself in mapped type '{ [K in keyof { AND?: Enumerable<ProductScalarWhereWithAggregatesInput>; OR?: Enumerable<ProductScalarWhereWithAggregatesInput>; ... 4 more ...; category?: string | StringWithAggregatesFilter; }]: Or<...> extends 1 ? { ...; }[K] extends infer TK ? GetHavingFields<...> : never : {} extends FieldPaths<...> ? never : K...'.
6   const grouped = await prisma.product.groupBy({
                          ~~~~~~~~~~~~~~~~~~~~~~~~
7     by: ['category']
  ~~~~~~~~~~~~~~~~~~~~
8   });
  ~~~~
server.ts:6:48 - error TS2554: Expected 0 arguments, but got 1.
6   const grouped = await prisma.product.groupBy({
                                                 ~
7     by: ['category']
  ~~~~~~~~~~~~~~~~~~~~
8   });
  ~~~
```

#### Solution [#solution-1]

Upgrade the TypeScript dependency in your project to a [version supported by Prisma ORM](#software-requirements). `npm install -D typescript`.

## Related pages

- [`Config API`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference): Complete reference for prisma.config.ts configuration options
- [`Connection URLs`](https://www.prisma.io/docs/orm/v7/reference/connection-urls): Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite
- [`Database Features`](https://www.prisma.io/docs/orm/v7/reference/database-features): Database features supported in Prisma ORM
- [`Environment Variables`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference): Reference for Prisma environment variables
- [`Error Reference`](https://www.prisma.io/docs/orm/v7/reference/error-reference): Prisma Client, Migrate, and Introspection error codes

# Poll an approval (/docs/rest-api/endpoints/agents/get-agent-approvals-by-approval-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Reports where an approval stands, so an agent holding an approval_required response can wait for the sponsor's decision and retry. Only the agent the approval belongs to can read it.

Location: REST API > Endpoints > Agents > Poll an approval



# Delete bucket key (/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id-keys-by-key-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Revokes and deletes the bucket key with the given ID.

Location: REST API > Endpoints > Buckets > Delete bucket key



## Related pages

- [`Create bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets): Creates a new object-store bucket in the specified project.
- [`Create bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets-by-bucket-id-keys): Creates a new access key for the given bucket. The `secretAccessKey` field is returned exactly once in this response and is never stored — copy it immediately.
- [`Delete bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id): Permanently deletes the bucket with the given ID, all objects stored in it, and all its access keys. This action cannot be undone.
- [`Get bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id): Returns the bucket with the given ID.
- [`List bucket keys`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id-keys): Returns all access keys for the given bucket.

# Delete bucket (/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Permanently deletes the bucket with the given ID, all objects stored in it, and all its access keys. This action cannot be undone.

Location: REST API > Endpoints > Buckets > Delete bucket



## Related pages

- [`Create bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets): Creates a new object-store bucket in the specified project.
- [`Create bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets-by-bucket-id-keys): Creates a new access key for the given bucket. The `secretAccessKey` field is returned exactly once in this response and is never stored — copy it immediately.
- [`Delete bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id-keys-by-key-id): Revokes and deletes the bucket key with the given ID.
- [`Get bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id): Returns the bucket with the given ID.
- [`List bucket keys`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id-keys): Returns all access keys for the given bucket.

# List bucket keys (/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id-keys)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns all access keys for the given bucket.

Location: REST API > Endpoints > Buckets > List bucket keys



## Related pages

- [`Create bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets): Creates a new object-store bucket in the specified project.
- [`Create bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets-by-bucket-id-keys): Creates a new access key for the given bucket. The `secretAccessKey` field is returned exactly once in this response and is never stored — copy it immediately.
- [`Delete bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id): Permanently deletes the bucket with the given ID, all objects stored in it, and all its access keys. This action cannot be undone.
- [`Delete bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id-keys-by-key-id): Revokes and deletes the bucket key with the given ID.
- [`Get bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id): Returns the bucket with the given ID.

# Get bucket (/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns the bucket with the given ID.

Location: REST API > Endpoints > Buckets > Get bucket



## Related pages

- [`Create bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets): Creates a new object-store bucket in the specified project.
- [`Create bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets-by-bucket-id-keys): Creates a new access key for the given bucket. The `secretAccessKey` field is returned exactly once in this response and is never stored — copy it immediately.
- [`Delete bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id): Permanently deletes the bucket with the given ID, all objects stored in it, and all its access keys. This action cannot be undone.
- [`Delete bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id-keys-by-key-id): Revokes and deletes the bucket key with the given ID.
- [`List bucket keys`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id-keys): Returns all access keys for the given bucket.

# List buckets (/docs/rest-api/endpoints/buckets/get-buckets)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns all object-store buckets the token has access to. Optionally filter by project ID.

Location: REST API > Endpoints > Buckets > List buckets



## Related pages

- [`Create bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets): Creates a new object-store bucket in the specified project.
- [`Create bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets-by-bucket-id-keys): Creates a new access key for the given bucket. The `secretAccessKey` field is returned exactly once in this response and is never stored — copy it immediately.
- [`Delete bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id): Permanently deletes the bucket with the given ID, all objects stored in it, and all its access keys. This action cannot be undone.
- [`Delete bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id-keys-by-key-id): Revokes and deletes the bucket key with the given ID.
- [`Get bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id): Returns the bucket with the given ID.

# Update bucket (/docs/rest-api/endpoints/buckets/patch-buckets-by-bucket-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Updates the display name, logical id, or branch of the bucket with the given ID. The display name is a label only: the provider bucket name, the objects, and the access keys do not change. `logicalId` cannot be combined with `branchId` or `branchGitName` in one request; move the bucket first, then set its `logicalId`.

Location: REST API > Endpoints > Buckets > Update bucket



## Related pages

- [`Create bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets): Creates a new object-store bucket in the specified project.
- [`Create bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets-by-bucket-id-keys): Creates a new access key for the given bucket. The `secretAccessKey` field is returned exactly once in this response and is never stored — copy it immediately.
- [`Delete bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id): Permanently deletes the bucket with the given ID, all objects stored in it, and all its access keys. This action cannot be undone.
- [`Delete bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id-keys-by-key-id): Revokes and deletes the bucket key with the given ID.
- [`Get bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id): Returns the bucket with the given ID.

# Create bucket key (/docs/rest-api/endpoints/buckets/post-buckets-by-bucket-id-keys)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Creates a new access key for the given bucket. The `secretAccessKey` field is returned exactly once in this response and is never stored — copy it immediately.

Location: REST API > Endpoints > Buckets > Create bucket key



## Related pages

- [`Create bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets): Creates a new object-store bucket in the specified project.
- [`Delete bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id): Permanently deletes the bucket with the given ID, all objects stored in it, and all its access keys. This action cannot be undone.
- [`Delete bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id-keys-by-key-id): Revokes and deletes the bucket key with the given ID.
- [`Get bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id): Returns the bucket with the given ID.
- [`List bucket keys`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id-keys): Returns all access keys for the given bucket.

# Create bucket (/docs/rest-api/endpoints/buckets/post-buckets)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Creates a new object-store bucket in the specified project.

Location: REST API > Endpoints > Buckets > Create bucket



## Related pages

- [`Create bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/post-buckets-by-bucket-id-keys): Creates a new access key for the given bucket. The `secretAccessKey` field is returned exactly once in this response and is never stored — copy it immediately.
- [`Delete bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id): Permanently deletes the bucket with the given ID, all objects stored in it, and all its access keys. This action cannot be undone.
- [`Delete bucket key`](https://www.prisma.io/docs/rest-api/endpoints/buckets/delete-buckets-by-bucket-id-keys-by-key-id): Revokes and deletes the bucket key with the given ID.
- [`Get bucket`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id): Returns the bucket with the given ID.
- [`List bucket keys`](https://www.prisma.io/docs/rest-api/endpoints/buckets/get-buckets-by-bucket-id-keys): Returns all access keys for the given bucket.

# Delete connection (/docs/rest-api/endpoints/connections/delete-connections-by-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Deletes the connection with the given ID.

Location: REST API > Endpoints > Connections > Delete connection



## Related pages

- [`Create connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/post-connections): Creates a new connection for the specified database.
- [`Get connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/get-connections-by-id): Returns the connection with the given ID.
- [`List connections`](https://www.prisma.io/docs/rest-api/endpoints/connections/get-connections): Returns all connections the actor has access to, with optional database filter.
- [`Rotate connection credentials`](https://www.prisma.io/docs/rest-api/endpoints/connections/post-connections-by-id-rotate): Generates new credentials for the connection with the given ID. Revocation of the previous credentials is best-effort.

# Get connection (/docs/rest-api/endpoints/connections/get-connections-by-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns the connection with the given ID.

Location: REST API > Endpoints > Connections > Get connection



## Related pages

- [`Create connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/post-connections): Creates a new connection for the specified database.
- [`Delete connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/delete-connections-by-id): Deletes the connection with the given ID.
- [`List connections`](https://www.prisma.io/docs/rest-api/endpoints/connections/get-connections): Returns all connections the actor has access to, with optional database filter.
- [`Rotate connection credentials`](https://www.prisma.io/docs/rest-api/endpoints/connections/post-connections-by-id-rotate): Generates new credentials for the connection with the given ID. Revocation of the previous credentials is best-effort.

# List connections (/docs/rest-api/endpoints/connections/get-connections)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns all connections the actor has access to, with optional database filter.

Location: REST API > Endpoints > Connections > List connections



## Related pages

- [`Create connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/post-connections): Creates a new connection for the specified database.
- [`Delete connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/delete-connections-by-id): Deletes the connection with the given ID.
- [`Get connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/get-connections-by-id): Returns the connection with the given ID.
- [`Rotate connection credentials`](https://www.prisma.io/docs/rest-api/endpoints/connections/post-connections-by-id-rotate): Generates new credentials for the connection with the given ID. Revocation of the previous credentials is best-effort.

# Rotate connection credentials (/docs/rest-api/endpoints/connections/post-connections-by-id-rotate)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Generates new credentials for the connection with the given ID. Revocation of the previous credentials is best-effort.

Location: REST API > Endpoints > Connections > Rotate connection credentials



## Related pages

- [`Create connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/post-connections): Creates a new connection for the specified database.
- [`Delete connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/delete-connections-by-id): Deletes the connection with the given ID.
- [`Get connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/get-connections-by-id): Returns the connection with the given ID.
- [`List connections`](https://www.prisma.io/docs/rest-api/endpoints/connections/get-connections): Returns all connections the actor has access to, with optional database filter.

# Create connection (/docs/rest-api/endpoints/connections/post-connections)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Creates a new connection for the specified database.

Location: REST API > Endpoints > Connections > Create connection



## Related pages

- [`Delete connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/delete-connections-by-id): Deletes the connection with the given ID.
- [`Get connection`](https://www.prisma.io/docs/rest-api/endpoints/connections/get-connections-by-id): Returns the connection with the given ID.
- [`List connections`](https://www.prisma.io/docs/rest-api/endpoints/connections/get-connections): Returns all connections the actor has access to, with optional database filter.
- [`Rotate connection credentials`](https://www.prisma.io/docs/rest-api/endpoints/connections/post-connections-by-id-rotate): Generates new credentials for the connection with the given ID. Revocation of the previous credentials is best-effort.

# Get list of backups (/docs/rest-api/endpoints/database-backups/get-databases-by-database-id-backups)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns backups for the specified database.

Location: REST API > Endpoints > Database Backups > Get list of backups



# Get database usage metrics (/docs/rest-api/endpoints/database-usage/get-databases-by-database-id-usage)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns usage metrics for the specified database.

Location: REST API > Endpoints > Database Usage > Get database usage metrics



# Delete database (/docs/rest-api/endpoints/databases/delete-databases-by-database-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Deletes the database with the given ID.

Location: REST API > Endpoints > Databases > Delete database



## Related pages

- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-databases): Creates a new database in the specified project. `logicalId` cannot be combined with `branchGitName`; pass `branchId` instead.
- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-projects-by-project-id-databases): Creates a new database for the given project.
- [`Get database`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases-by-database-id): Returns the database with the given ID.
- [`Get list of databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-projects-by-project-id-databases): Returns databases for the given project.
- [`List databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases): Returns all databases the token has access to. Optionally filter by project ID.

# Get database (/docs/rest-api/endpoints/databases/get-databases-by-database-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns the database with the given ID.

Location: REST API > Endpoints > Databases > Get database



## Related pages

- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-databases): Creates a new database in the specified project. `logicalId` cannot be combined with `branchGitName`; pass `branchId` instead.
- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-projects-by-project-id-databases): Creates a new database for the given project.
- [`Delete database`](https://www.prisma.io/docs/rest-api/endpoints/databases/delete-databases-by-database-id): Deletes the database with the given ID.
- [`Get list of databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-projects-by-project-id-databases): Returns databases for the given project.
- [`List databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases): Returns all databases the token has access to. Optionally filter by project ID.

# List databases (/docs/rest-api/endpoints/databases/get-databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns all databases the token has access to. Optionally filter by project ID.

Location: REST API > Endpoints > Databases > List databases



## Related pages

- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-databases): Creates a new database in the specified project. `logicalId` cannot be combined with `branchGitName`; pass `branchId` instead.
- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-projects-by-project-id-databases): Creates a new database for the given project.
- [`Delete database`](https://www.prisma.io/docs/rest-api/endpoints/databases/delete-databases-by-database-id): Deletes the database with the given ID.
- [`Get database`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases-by-database-id): Returns the database with the given ID.
- [`Get list of databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-projects-by-project-id-databases): Returns databases for the given project.

# Get list of databases (/docs/rest-api/endpoints/databases/get-projects-by-project-id-databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns databases for the given project.

Location: REST API > Endpoints > Databases > Get list of databases



## Related pages

- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-databases): Creates a new database in the specified project. `logicalId` cannot be combined with `branchGitName`; pass `branchId` instead.
- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-projects-by-project-id-databases): Creates a new database for the given project.
- [`Delete database`](https://www.prisma.io/docs/rest-api/endpoints/databases/delete-databases-by-database-id): Deletes the database with the given ID.
- [`Get database`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases-by-database-id): Returns the database with the given ID.
- [`List databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases): Returns all databases the token has access to. Optionally filter by project ID.

# Update database (/docs/rest-api/endpoints/databases/patch-databases-by-database-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Updates the database with the given ID. `logicalId` cannot be combined with `branchId` or `branchGitName` in one request; move the database first, then set its `logicalId`.

Location: REST API > Endpoints > Databases > Update database



## Related pages

- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-databases): Creates a new database in the specified project. `logicalId` cannot be combined with `branchGitName`; pass `branchId` instead.
- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-projects-by-project-id-databases): Creates a new database for the given project.
- [`Delete database`](https://www.prisma.io/docs/rest-api/endpoints/databases/delete-databases-by-database-id): Deletes the database with the given ID.
- [`Get database`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases-by-database-id): Returns the database with the given ID.
- [`Get list of databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-projects-by-project-id-databases): Returns databases for the given project.

# Restore database (destructive) (/docs/rest-api/endpoints/databases/post-databases-by-target-database-id-restore)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

**Destructive operation** — this immediately and irreversibly overwrites all data in the target database with the contents of the specified backup. Any data written since the backup was taken will be lost. Ensure you have a recent backup of the target database before proceeding. Replaces the data in an existing database from a backup. Connections and credentials are preserved — only the data layer is replaced.

Location: REST API > Endpoints > Databases > Restore database (destructive)



## Related pages

- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-databases): Creates a new database in the specified project. `logicalId` cannot be combined with `branchGitName`; pass `branchId` instead.
- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-projects-by-project-id-databases): Creates a new database for the given project.
- [`Delete database`](https://www.prisma.io/docs/rest-api/endpoints/databases/delete-databases-by-database-id): Deletes the database with the given ID.
- [`Get database`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases-by-database-id): Returns the database with the given ID.
- [`Get list of databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-projects-by-project-id-databases): Returns databases for the given project.

# Create database (/docs/rest-api/endpoints/databases/post-databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Creates a new database in the specified project. `logicalId` cannot be combined with `branchGitName`; pass `branchId` instead.

Location: REST API > Endpoints > Databases > Create database



## Related pages

- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-projects-by-project-id-databases): Creates a new database for the given project.
- [`Delete database`](https://www.prisma.io/docs/rest-api/endpoints/databases/delete-databases-by-database-id): Deletes the database with the given ID.
- [`Get database`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases-by-database-id): Returns the database with the given ID.
- [`Get list of databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-projects-by-project-id-databases): Returns databases for the given project.
- [`List databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases): Returns all databases the token has access to. Optionally filter by project ID.

# Create database (/docs/rest-api/endpoints/databases/post-projects-by-project-id-databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Creates a new database for the given project.

Location: REST API > Endpoints > Databases > Create database



## Related pages

- [`Create database`](https://www.prisma.io/docs/rest-api/endpoints/databases/post-databases): Creates a new database in the specified project. `logicalId` cannot be combined with `branchGitName`; pass `branchId` instead.
- [`Delete database`](https://www.prisma.io/docs/rest-api/endpoints/databases/delete-databases-by-database-id): Deletes the database with the given ID.
- [`Get database`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases-by-database-id): Returns the database with the given ID.
- [`Get list of databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-projects-by-project-id-databases): Returns databases for the given project.
- [`List databases`](https://www.prisma.io/docs/rest-api/endpoints/databases/get-databases): Returns all databases the token has access to. Optionally filter by project ID.

# Get list of database connections (/docs/rest-api/endpoints/databases-connections/get-databases-by-database-id-connections)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns all connections for the given database.

Location: REST API > Endpoints > Databases Connections > Get list of database connections



## Related pages

- [`Create database connection string`](https://www.prisma.io/docs/rest-api/endpoints/databases-connections/post-databases-by-database-id-connections): Creates a new connection string for the given database.

# Create database connection string (/docs/rest-api/endpoints/databases-connections/post-databases-by-database-id-connections)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Creates a new connection string for the given database.

Location: REST API > Endpoints > Databases Connections > Create database connection string



## Related pages

- [`Get list of database connections`](https://www.prisma.io/docs/rest-api/endpoints/databases-connections/get-databases-by-database-id-connections): Returns all connections for the given database.

# Delete integration (/docs/rest-api/endpoints/integrations/delete-integrations-by-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Revokes the integration tokens by integration ID.

Location: REST API > Endpoints > Integrations > Delete integration



## Related pages

- [`Get integration by ID`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-integrations-by-id): Returns a single integration by its ID.
- [`Get list of integrations`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-integrations): Returns integrations filtered by workspace ID.
- [`Get list of integrations`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-workspaces-by-workspace-id-integrations): Returns integrations for the given workspace.
- [`Revoke integration tokens`](https://www.prisma.io/docs/rest-api/endpoints/integrations/delete-workspaces-by-workspace-id-integrations-by-client-id): Revokes the integration tokens with the given client ID.

# Revoke integration tokens (/docs/rest-api/endpoints/integrations/delete-workspaces-by-workspace-id-integrations-by-client-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Revokes the integration tokens with the given client ID.

Location: REST API > Endpoints > Integrations > Revoke integration tokens



## Related pages

- [`Delete integration`](https://www.prisma.io/docs/rest-api/endpoints/integrations/delete-integrations-by-id): Revokes the integration tokens by integration ID.
- [`Get integration by ID`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-integrations-by-id): Returns a single integration by its ID.
- [`Get list of integrations`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-integrations): Returns integrations filtered by workspace ID.
- [`Get list of integrations`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-workspaces-by-workspace-id-integrations): Returns integrations for the given workspace.

# Get integration by ID (/docs/rest-api/endpoints/integrations/get-integrations-by-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns a single integration by its ID.

Location: REST API > Endpoints > Integrations > Get integration by ID



## Related pages

- [`Delete integration`](https://www.prisma.io/docs/rest-api/endpoints/integrations/delete-integrations-by-id): Revokes the integration tokens by integration ID.
- [`Get list of integrations`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-integrations): Returns integrations filtered by workspace ID.
- [`Get list of integrations`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-workspaces-by-workspace-id-integrations): Returns integrations for the given workspace.
- [`Revoke integration tokens`](https://www.prisma.io/docs/rest-api/endpoints/integrations/delete-workspaces-by-workspace-id-integrations-by-client-id): Revokes the integration tokens with the given client ID.

# Get list of integrations (/docs/rest-api/endpoints/integrations/get-integrations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns integrations filtered by workspace ID.

Location: REST API > Endpoints > Integrations > Get list of integrations



## Related pages

- [`Delete integration`](https://www.prisma.io/docs/rest-api/endpoints/integrations/delete-integrations-by-id): Revokes the integration tokens by integration ID.
- [`Get integration by ID`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-integrations-by-id): Returns a single integration by its ID.
- [`Get list of integrations`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-workspaces-by-workspace-id-integrations): Returns integrations for the given workspace.
- [`Revoke integration tokens`](https://www.prisma.io/docs/rest-api/endpoints/integrations/delete-workspaces-by-workspace-id-integrations-by-client-id): Revokes the integration tokens with the given client ID.

# Get list of integrations (/docs/rest-api/endpoints/integrations/get-workspaces-by-workspace-id-integrations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns integrations for the given workspace.

Location: REST API > Endpoints > Integrations > Get list of integrations



## Related pages

- [`Delete integration`](https://www.prisma.io/docs/rest-api/endpoints/integrations/delete-integrations-by-id): Revokes the integration tokens by integration ID.
- [`Get integration by ID`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-integrations-by-id): Returns a single integration by its ID.
- [`Get list of integrations`](https://www.prisma.io/docs/rest-api/endpoints/integrations/get-integrations): Returns integrations filtered by workspace ID.
- [`Revoke integration tokens`](https://www.prisma.io/docs/rest-api/endpoints/integrations/delete-workspaces-by-workspace-id-integrations-by-client-id): Revokes the integration tokens with the given client ID.

# Get current authenticated principal (/docs/rest-api/endpoints/misc/get-me)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns the user, workspace, and credential represented by the current token.

Location: REST API > Endpoints > Misc > Get current authenticated principal



## Related pages

- [`Get Prisma Accelerate regions`](https://www.prisma.io/docs/rest-api/endpoints/misc/get-regions-accelerate): Returns all available regions for Prisma Accelerate.
- [`Get Prisma Postgres regions`](https://www.prisma.io/docs/rest-api/endpoints/misc/get-regions-postgres): Returns all available regions for Prisma Postgres.

# Get Prisma Postgres regions (/docs/rest-api/endpoints/misc/get-regions-postgres)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns all available regions for Prisma Postgres.

Location: REST API > Endpoints > Misc > Get Prisma Postgres regions



## Related pages

- [`Get current authenticated principal`](https://www.prisma.io/docs/rest-api/endpoints/misc/get-me): Returns the user, workspace, and credential represented by the current token.
- [`Get Prisma Accelerate regions`](https://www.prisma.io/docs/rest-api/endpoints/misc/get-regions-accelerate): Returns all available regions for Prisma Accelerate.

# Delete project (/docs/rest-api/endpoints/projects/delete-projects-by-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Deletes the project with the given ID.

Location: REST API > Endpoints > Projects > Delete project



## Related pages

- [`Create project with a postgres database`](https://www.prisma.io/docs/rest-api/endpoints/projects/post-projects): Creates a new project with a postgres database.
- [`Get list of projects`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects): Returns the list of projects the token has access to.
- [`Get project`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects-by-id): Returns the project with the given ID.
- [`Transfer project`](https://www.prisma.io/docs/rest-api/endpoints/projects/post-projects-by-id-transfer): Transfer the project with the given ID to the new owner's workspace
- [`Update project`](https://www.prisma.io/docs/rest-api/endpoints/projects/patch-projects-by-id): Updates the project with the given ID.

# Get project (/docs/rest-api/endpoints/projects/get-projects-by-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns the project with the given ID.

Location: REST API > Endpoints > Projects > Get project



## Related pages

- [`Create project with a postgres database`](https://www.prisma.io/docs/rest-api/endpoints/projects/post-projects): Creates a new project with a postgres database.
- [`Delete project`](https://www.prisma.io/docs/rest-api/endpoints/projects/delete-projects-by-id): Deletes the project with the given ID.
- [`Get list of projects`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects): Returns the list of projects the token has access to.
- [`Transfer project`](https://www.prisma.io/docs/rest-api/endpoints/projects/post-projects-by-id-transfer): Transfer the project with the given ID to the new owner's workspace
- [`Update project`](https://www.prisma.io/docs/rest-api/endpoints/projects/patch-projects-by-id): Updates the project with the given ID.

# Get list of projects (/docs/rest-api/endpoints/projects/get-projects)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns the list of projects the token has access to.

Location: REST API > Endpoints > Projects > Get list of projects



## Related pages

- [`Create project with a postgres database`](https://www.prisma.io/docs/rest-api/endpoints/projects/post-projects): Creates a new project with a postgres database.
- [`Delete project`](https://www.prisma.io/docs/rest-api/endpoints/projects/delete-projects-by-id): Deletes the project with the given ID.
- [`Get project`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects-by-id): Returns the project with the given ID.
- [`Transfer project`](https://www.prisma.io/docs/rest-api/endpoints/projects/post-projects-by-id-transfer): Transfer the project with the given ID to the new owner's workspace
- [`Update project`](https://www.prisma.io/docs/rest-api/endpoints/projects/patch-projects-by-id): Updates the project with the given ID.

# Update project (/docs/rest-api/endpoints/projects/patch-projects-by-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Updates the project with the given ID.

Location: REST API > Endpoints > Projects > Update project



## Related pages

- [`Create project with a postgres database`](https://www.prisma.io/docs/rest-api/endpoints/projects/post-projects): Creates a new project with a postgres database.
- [`Delete project`](https://www.prisma.io/docs/rest-api/endpoints/projects/delete-projects-by-id): Deletes the project with the given ID.
- [`Get list of projects`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects): Returns the list of projects the token has access to.
- [`Get project`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects-by-id): Returns the project with the given ID.
- [`Transfer project`](https://www.prisma.io/docs/rest-api/endpoints/projects/post-projects-by-id-transfer): Transfer the project with the given ID to the new owner's workspace

# Transfer project (/docs/rest-api/endpoints/projects/post-projects-by-id-transfer)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Transfer the project with the given ID to the new owner's workspace

Location: REST API > Endpoints > Projects > Transfer project



## Related pages

- [`Create project with a postgres database`](https://www.prisma.io/docs/rest-api/endpoints/projects/post-projects): Creates a new project with a postgres database.
- [`Delete project`](https://www.prisma.io/docs/rest-api/endpoints/projects/delete-projects-by-id): Deletes the project with the given ID.
- [`Get list of projects`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects): Returns the list of projects the token has access to.
- [`Get project`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects-by-id): Returns the project with the given ID.
- [`Update project`](https://www.prisma.io/docs/rest-api/endpoints/projects/patch-projects-by-id): Updates the project with the given ID.

# Create project with a postgres database (/docs/rest-api/endpoints/projects/post-projects)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Creates a new project with a postgres database.

Location: REST API > Endpoints > Projects > Create project with a postgres database



## Related pages

- [`Delete project`](https://www.prisma.io/docs/rest-api/endpoints/projects/delete-projects-by-id): Deletes the project with the given ID.
- [`Get list of projects`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects): Returns the list of projects the token has access to.
- [`Get project`](https://www.prisma.io/docs/rest-api/endpoints/projects/get-projects-by-id): Returns the project with the given ID.
- [`Transfer project`](https://www.prisma.io/docs/rest-api/endpoints/projects/post-projects-by-id-transfer): Transfer the project with the given ID to the new owner's workspace
- [`Update project`](https://www.prisma.io/docs/rest-api/endpoints/projects/patch-projects-by-id): Updates the project with the given ID.

# Get all regions (/docs/rest-api/endpoints/regions/get-regions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns all available regions across products. Optionally filter by product.

Location: REST API > Endpoints > Regions > Get all regions



# Delete service token (/docs/rest-api/endpoints/service-tokens/delete-workspaces-by-workspace-id-service-tokens-by-service-token-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Revokes the service token with the given ID by deleting it.

Location: REST API > Endpoints > Service Tokens > Delete service token



## Related pages

- [`Create service token`](https://www.prisma.io/docs/rest-api/endpoints/service-tokens/post-workspaces-by-workspace-id-service-tokens): Creates a new service token for the given workspace. The `value` field is returned exactly once in this response and is never stored — copy it immediately.
- [`List service tokens`](https://www.prisma.io/docs/rest-api/endpoints/service-tokens/get-workspaces-by-workspace-id-service-tokens): Returns the service tokens for the given workspace, newest first.

# List service tokens (/docs/rest-api/endpoints/service-tokens/get-workspaces-by-workspace-id-service-tokens)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns the service tokens for the given workspace, newest first.

Location: REST API > Endpoints > Service Tokens > List service tokens



## Related pages

- [`Create service token`](https://www.prisma.io/docs/rest-api/endpoints/service-tokens/post-workspaces-by-workspace-id-service-tokens): Creates a new service token for the given workspace. The `value` field is returned exactly once in this response and is never stored — copy it immediately.
- [`Delete service token`](https://www.prisma.io/docs/rest-api/endpoints/service-tokens/delete-workspaces-by-workspace-id-service-tokens-by-service-token-id): Revokes the service token with the given ID by deleting it.

# Create service token (/docs/rest-api/endpoints/service-tokens/post-workspaces-by-workspace-id-service-tokens)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Creates a new service token for the given workspace. The `value` field is returned exactly once in this response and is never stored — copy it immediately.

Location: REST API > Endpoints > Service Tokens > Create service token



## Related pages

- [`Delete service token`](https://www.prisma.io/docs/rest-api/endpoints/service-tokens/delete-workspaces-by-workspace-id-service-tokens-by-service-token-id): Revokes the service token with the given ID by deleting it.
- [`List service tokens`](https://www.prisma.io/docs/rest-api/endpoints/service-tokens/get-workspaces-by-workspace-id-service-tokens): Returns the service tokens for the given workspace, newest first.

# Get workspace subscription (/docs/rest-api/endpoints/workspaces/get-workspaces-by-id-subscription)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns subscription information for the workspace with the given ID.

Location: REST API > Endpoints > Workspaces > Get workspace subscription



## Related pages

- [`Get list of workspaces`](https://www.prisma.io/docs/rest-api/endpoints/workspaces/get-workspaces): Returns the list of workspaces the current token can access.
- [`Get workspace`](https://www.prisma.io/docs/rest-api/endpoints/workspaces/get-workspaces-by-id): Returns the workspace with the given ID.

# Get workspace (/docs/rest-api/endpoints/workspaces/get-workspaces-by-id)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns the workspace with the given ID.

Location: REST API > Endpoints > Workspaces > Get workspace



## Related pages

- [`Get list of workspaces`](https://www.prisma.io/docs/rest-api/endpoints/workspaces/get-workspaces): Returns the list of workspaces the current token can access.
- [`Get workspace subscription`](https://www.prisma.io/docs/rest-api/endpoints/workspaces/get-workspaces-by-id-subscription): Returns subscription information for the workspace with the given ID.

# Get list of workspaces (/docs/rest-api/endpoints/workspaces/get-workspaces)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Returns the list of workspaces the current token can access.

Location: REST API > Endpoints > Workspaces > Get list of workspaces



## Related pages

- [`Get workspace`](https://www.prisma.io/docs/rest-api/endpoints/workspaces/get-workspaces-by-id): Returns the workspace with the given ID.
- [`Get workspace subscription`](https://www.prisma.io/docs/rest-api/endpoints/workspaces/get-workspaces-by-id-subscription): Returns subscription information for the workspace with the given ID.

# CockroachDB (Prisma ORM v7) (/docs/v7/prisma-orm/add-to-existing-project/cockroachdb)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to an existing TypeScript project with CockroachDB and learn database introspection, baselining, and querying

Location: v7 > Prisma ORM > Add to Existing Project > CockroachDB

[CockroachDB](https://www.cockroachlabs.com/) is a distributed SQL database designed for cloud applications, offering horizontal scalability, strong consistency, and high availability. In this guide, you will learn how to add Prisma ORM to an existing TypeScript project, connect it to CockroachDB, introspect your existing database schema, and start querying with type-safe Prisma Client.

## Prerequisites [#prerequisites]

## 1. Set up Prisma ORM [#1-set-up-prisma-orm]

Navigate to your existing project directory and install the required dependencies:

  

#### bun

```bash
bun add prisma@prev @types/node @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/node @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/node @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### npm

```bash
npm install prisma@prev @types/node @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma db pull`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-pg`** - The [`node-postgres` driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters) that connects Prisma Client to your database (CockroachDB is PostgreSQL-compatible)
* **`pg`** - The node-postgres database driver
* **`@types/pg`** - TypeScript type definitions for node-postgres
* **`dotenv`** - Loads environment variables from your `.env` file

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

Set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider cockroachdb --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider cockroachdb --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider cockroachdb --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider cockroachdb --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection configuration
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "cockroachdb"
}
```

## 3. Connect your database [#3-connect-your-database]

Update the `.env` file with your CockroachDB connection URL:

```text title=".env"
DATABASE_URL="postgresql://user:password@host:26257/mydb?sslmode=require"
```

The [format of the connection URL](https://www.prisma.io/docs/orm/v7/reference/connection-urls) for CockroachDB looks as follows:

```
postgresql://USER:PASSWORD@HOST:PORT/DATABASE?sslmode=require
```

## 4. Introspect your database [#4-introspect-your-database]

Run the following command to introspect your existing database:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This command reads the `DATABASE_URL` environment variable, connects to your database, and introspects the database schema. It then translates the database schema from SQL into a data model in your Prisma schema.

![Introspect your database with Prisma ORM](https://www.prisma.io/img/getting-started/prisma-db-pull-generate-schema.png)

After introspection, your Prisma schema will contain models that represent your existing database tables.

## 5. Baseline your database [#5-baseline-your-database]

To use Prisma Migrate with your existing database, you need to [baseline your database](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started).

First, create a `migrations` directory:

```bash
mkdir -p prisma/migrations/0_init
```

Next, generate the migration file with `prisma migrate diff`:

  

#### bun

```bash
bunx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### pnpm

```bash
pnpm prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### yarn

```bash
yarn prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### npm

```bash
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

Review the generated migration file to ensure it matches your database schema.

Then, mark the migration as applied:

  

#### bun

```bash
bunx prisma migrate resolve --applied 0_init
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied 0_init
```

#### yarn

```bash
yarn prisma migrate resolve --applied 0_init
```

#### npm

```bash
npx prisma migrate resolve --applied 0_init
```

You now have a baseline for your current database schema.

## 6. Generate Prisma ORM types [#6-generate-prisma-orm-types]

Generate Prisma Client based on your introspected schema:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This creates a type-safe Prisma Client tailored to your database schema in the `generated/prisma` directory.

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Create a utility file to instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 8. Query your database [#8-query-your-database]

Now you can use Prisma Client to query your database. Create a `script.ts` file:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Example: Fetch all records from a table
  // Replace 'user' with your actual model name
  const allUsers = await prisma.user.findMany();
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 9. Evolve your schema [#9-evolve-your-schema]

To make changes to your database schema:

### 9.1. Update your Prisma schema file [#91-update-your-prisma-schema-file]

Update your Prisma schema file to reflect the changes you want to make to your database schema. For example, add a new model:

```prisma title="prisma/schema.prisma"
model Post { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]

model User { // [!code ++]
  id    Int    @id @default(autoincrement()) // [!code ++]
  email String @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
```

### 9.2. Create and apply a migration: [#92-create-and-apply-a-migration]

  

#### bun

```bash
bunx prisma migrate dev --name your_migration_name
```

#### pnpm

```bash
pnpm prisma migrate dev --name your_migration_name
```

#### yarn

```bash
yarn prisma migrate dev --name your_migration_name
```

#### npm

```bash
npx prisma migrate dev --name your_migration_name
```

This command will:

* Create a new SQL migration file
* Apply the migration to your database
* Regenerate Prisma Client

## 10. Explore your data [#10-explore-your-data]

Explore the options suggested by [CockroachDB](https://www.cockroachlabs.com/blog/cockroachdb-gui-options/) to view and manage your data.

> [!WARNING]
> [Prisma Studio](https://www.prisma.io/docs/studio) does not currently support CockroachDB. Support may be added in a future release. See [Databases supported by Prisma Studio](https://www.prisma.io/docs/studio#supported-databases) for more information.

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [CockroachDB database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#cockroachdb)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection)
* [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)

## Related pages

- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mongodb): Add Prisma ORM to an existing TypeScript project with MongoDB and learn database introspection and querying
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mysql): Add Prisma ORM to an existing TypeScript project with MySQL and learn database introspection, baselining, and querying
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/planetscale): Add Prisma ORM to an existing TypeScript project with PlanetScale and learn database introspection and querying
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql): Add Prisma ORM to an existing TypeScript project with PostgreSQL and learn database introspection, baselining, and querying
- [`Prisma Postgres`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/prisma-postgres): Add Prisma ORM to an existing TypeScript project with Prisma Postgres and learn database introspection, baselining, and querying

# MongoDB (Prisma ORM v7) (/docs/v7/prisma-orm/add-to-existing-project/mongodb)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to an existing TypeScript project with MongoDB and learn database introspection and querying

Location: v7 > Prisma ORM > Add to Existing Project > MongoDB

[MongoDB](https://www.mongodb.com/) is a document-based NoSQL database. In this guide, you will learn how to add Prisma ORM to an existing TypeScript project, connect it to MongoDB, introspect your existing database schema, and start querying with type-safe Prisma Client.

> [!WARNING]
> MongoDB support for Prisma ORM v7
> 
> **MongoDB support for Prisma ORM v7 is coming in the near future.** In the meantime, please use **Prisma ORM v6.19** (the latest v6 release) when working with MongoDB.
> 
> This guide uses Prisma ORM v6.19 to ensure full compatibility with MongoDB.

> [!NOTE]
> If you're migrating to Prisma ORM from Mongoose, see our [Migrate from Mongoose guide](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-mongoose).

## Prerequisites [#prerequisites]

To complete this guide, you need:

* [Node.js](https://nodejs.org/en/) installed on your machine (see [system requirements](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v6#minimum-supported-nodejs-versions) for officially supported versions)
* An existing TypeScript project with a `package.json` file
* Access to a MongoDB 4.2+ server with a replica set deployment. We recommend using [MongoDB Atlas](https://www.mongodb.com/cloud/atlas).

> [!WARNING]
> The MongoDB database connector uses transactions to support nested writes. Transactions **require** a [replica set](https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set/) deployment. The quickest way to get a replica set is [Atlas](https://www.mongodb.com/docs/atlas/getting-started/), which has a free tier.

Make sure you have your database [connection URL](https://www.prisma.io/docs/orm/v7/reference/connection-urls) (that includes your authentication credentials) at hand.

> [!NOTE]
> If your project contains multiple directories with `package.json` files (e.g., `frontend`, `backend`, etc.), note that Prisma ORM is specifically designed for use in the API/backend layer. To set up Prisma, navigate to the appropriate backend directory containing the relevant `package.json` file and configure Prisma there.

## 1. Set up Prisma ORM [#1-set-up-prisma-orm]

Navigate to your existing project directory and install the required dependencies:

  

#### bun

```bash
bun add prisma@6.19.3 @types/node --dev
bun add @prisma/client@6.19.3 dotenv
```

#### pnpm

```bash
pnpm add prisma@6.19.3 @types/node --save-dev
pnpm add @prisma/client@6.19.3 dotenv
```

#### yarn

```bash
yarn add prisma@6.19.3 @types/node --dev
yarn add @prisma/client@6.19.3 dotenv
```

#### npm

```bash
npm install prisma@6.19.3 @types/node --save-dev
npm install @prisma/client@6.19.3 dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma db pull`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`dotenv`** - Loads environment variables from your `.env` file

> [!NOTE]
> Prisma v6.19 and MongoDB
> 
> This is the latest stable version of Prisma ORM v6 that fully supports MongoDB. MongoDB support for Prisma ORM v7 is coming soon.
> 
> You can also install `prisma@6` and `@prisma/client@6` to automatically get the latest v6 release.

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

Set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider mongodb --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider mongodb --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider mongodb --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider mongodb --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection configuration
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma.config.ts` file for Prisma configuration

The generated `prisma.config.ts` file looks like this:

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  engine: "classic",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Add `dotenv` to `prisma.config.ts` so that Prisma can load environment variables from your `.env` file:

```typescript title="prisma.config.ts"
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  engine: "classic",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "mongodb"
  url = env("DATABASE_URL")
}
```

## 3. Connect your database [#3-connect-your-database]

Update the `.env` file with your MongoDB connection URL:

```text title=".env"
DATABASE_URL="mongodb+srv://username:password@cluster.mongodb.net/mydb"
```

For MongoDB Atlas, the connection URL format is:

```
mongodb+srv://USERNAME:PASSWORD@CLUSTER.mongodb.net/DATABASE
```

Self-hosted MongoDB connection URL format:

```
mongodb://USERNAME:PASSWORD@HOST:PORT/DATABASE
```

Connection URL components:

* **`USERNAME`**: Your database user name
* **`PASSWORD`**: Your database user password
* **`HOST`**: The host where [`mongod`](https://www.mongodb.com/docs/manual/reference/program/mongod/#mongodb-binary-bin.mongod) or [`mongos`](https://www.mongodb.com/docs/manual/reference/program/mongos/#mongodb-binary-bin.mongos) is running
* **`PORT`**: The port where your database server is running (typically `27017`)
* **`DATABASE`**: The name of your database

> [!NOTE]
> For MongoDB Atlas, you can manually append the database name to the connection URL, as Atlas doesn't include it by default.

### Troubleshooting connection issues [#troubleshooting-connection-issues]

* **Authentication failed**: If you see a `SCRAM failure: Authentication failed` error, [add `?authSource=admin`](https://github.com/prisma/orm/discussions/9994#discussioncomment-1562283) to the end of your connection string.
* **Empty database name**: If you see an `Error code 8000 (AtlasError): empty database name not allowed` error, append the database name to your connection URL. See this [GitHub issue](https://github.com/prisma/web/issues/5562) for details.

## 4. Introspect your database [#4-introspect-your-database]

Run the following command to introspect your existing database:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This command:

* Reads the `DATABASE_URL` from your `.env` file
* Connects to your MongoDB database
* Samples documents in your collections to infer the schema
* Generates Prisma models in your `schema.prisma` file

![Introspect your database with Prisma ORM](https://www.prisma.io/img/getting-started/prisma-db-pull-generate-schema.png)

> [!NOTE]
> **MongoDB introspection limitations:** Prisma introspects MongoDB by sampling documents. You may need to manually:
> 
> * Add relation fields using the `@relation` attribute
> * Adjust field types if the sampling didn't capture all variations
> * Add indexes and constraints not detected during introspection

## 5. Generate Prisma ORM types [#5-generate-prisma-orm-types]

Generate Prisma Client based on your introspected schema:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This creates a type-safe Prisma Client tailored to your database schema in the `generated/prisma` directory.

## 6. Instantiate Prisma Client [#6-instantiate-prisma-client]

Create a utility file to instantiate Prisma Client:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaClient } from "../generated/prisma/client";

const prisma = new PrismaClient();

export { prisma };
```

## 7. Query your database [#7-query-your-database]

Now you can use Prisma Client to query your database. Create a `script.ts` file:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Example: Fetch all records from a collection
  // Replace 'user' with your actual model name
  const allUsers = await prisma.user.findMany();
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 8. Evolve your schema [#8-evolve-your-schema]

MongoDB doesn't support migrations like relational databases. Instead, use `db push` to sync schema changes:

### 8.1. Update your Prisma schema file [#81-update-your-prisma-schema-file]

Modify your Prisma schema file with the changes you want. For example, add a new model:

```prisma title="prisma/schema.prisma"
model Post { // [!code ++]
  id        String   @id @default(auto()) @map("_id") @db.ObjectId // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  String   @db.ObjectId // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]

model User { // [!code ++]
  id    String @id @default(auto()) @map("_id") @db.ObjectId // [!code ++]
  email String @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
```

> [!NOTE]
> In MongoDB, the `id` field is mapped to `_id` and uses `@db.ObjectId` type. Relations use `String` type with `@db.ObjectId` annotation.

### 8.2. Push the changes to your database [#82-push-the-changes-to-your-database]

  

#### bun

```bash
bunx prisma db push
```

#### pnpm

```bash
pnpm prisma db push
```

#### yarn

```bash
yarn prisma db push
```

#### npm

```bash
npx prisma db push
```

This command:

* Applies schema changes to your MongoDB database
* Automatically regenerates Prisma Client

> [!NOTE]
> `db push`
> 
>  instead of migrations
> 
> MongoDB uses a flexible schema model. Prisma Migrate (which creates migration files) is not supported for MongoDB. Always use `prisma db push` to sync your schema changes.

## 9. Explore your data [#9-explore-your-data]

You can use [MongoDB Atlas](https://www.mongodb.com/cloud/atlas), the MongoDB shell, or MongoDB Compass to view and manage your data.

> [!WARNING]
> [Prisma Studio](https://www.prisma.io/docs/studio) does not currently support MongoDB. Support may be added in a future release. See [Databases supported by Prisma Studio](https://www.prisma.io/docs/studio#supported-databases) for more information.

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [MongoDB database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/cockroachdb): Add Prisma ORM to an existing TypeScript project with CockroachDB and learn database introspection, baselining, and querying
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mysql): Add Prisma ORM to an existing TypeScript project with MySQL and learn database introspection, baselining, and querying
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/planetscale): Add Prisma ORM to an existing TypeScript project with PlanetScale and learn database introspection and querying
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql): Add Prisma ORM to an existing TypeScript project with PostgreSQL and learn database introspection, baselining, and querying
- [`Prisma Postgres`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/prisma-postgres): Add Prisma ORM to an existing TypeScript project with Prisma Postgres and learn database introspection, baselining, and querying

# MySQL (Prisma ORM v7) (/docs/v7/prisma-orm/add-to-existing-project/mysql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to an existing TypeScript project with MySQL and learn database introspection, baselining, and querying

Location: v7 > Prisma ORM > Add to Existing Project > MySQL

[MySQL](https://www.mysql.com/) is a widely used open-source relational database management system. In this guide, you will learn how to add Prisma ORM to an existing TypeScript project, connect it to MySQL, introspect your existing database schema, and start querying with type-safe Prisma Client.

## Prerequisites [#prerequisites]

## 1. Set up Prisma ORM [#1-set-up-prisma-orm]

Navigate to your existing project directory and install the required dependencies:

  

#### bun

```bash
bun add prisma@prev @types/node --dev
bun add @prisma/client@7 @prisma/adapter-mariadb dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/node --save-dev
pnpm add @prisma/client@7 @prisma/adapter-mariadb dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/node --dev
yarn add @prisma/client@7 @prisma/adapter-mariadb dotenv
```

#### npm

```bash
npm install prisma@prev @types/node --save-dev
npm install @prisma/client@7 @prisma/adapter-mariadb dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma db pull`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-mariadb`** - The MySQL/MariaDB driver adapter that connects Prisma Client to your database
* **`dotenv`** - Loads environment variables from your `.env` file

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

Set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider mysql --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider mysql --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider mysql --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider mysql --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection configuration
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "mysql"
}
```

## 3. Connect your database [#3-connect-your-database]

Update the `.env` file with your MySQL connection string details:

```bash title=".env"
DATABASE_URL="mysql://username:password@localhost:3306/mydb"
DATABASE_USER="username" # [!code ++]
DATABASE_PASSWORD="password" # [!code ++]
DATABASE_NAME="mydb" # [!code ++]
DATABASE_HOST="localhost" # [!code ++]
DATABASE_PORT=3306 # [!code ++]
```

Replace the placeholders with your actual database credentials:

* `username`: Your MySQL username
* `password`: Your MySQL password
* `localhost:3306`: Your MySQL host and port
* `mydb`: Your database name

## 4. Introspect your database [#4-introspect-your-database]

Run the following command to introspect your existing database:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This command reads the `DATABASE_URL` environment variable, connects to your database, and introspects the database schema. It then translates the database schema from SQL into a data model in your Prisma schema.

![Introspect your database with Prisma ORM](https://www.prisma.io/img/getting-started/prisma-db-pull-generate-schema.png)

After introspection, your Prisma schema will contain models that represent your existing database tables.

## 5. Baseline your database [#5-baseline-your-database]

To use Prisma Migrate with your existing database, you need to [baseline your database](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started).

First, create a `migrations` directory:

```bash
mkdir -p prisma/migrations/0_init
```

Next, generate the migration file with `prisma migrate diff`:

  

#### bun

```bash
bunx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### pnpm

```bash
pnpm prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### yarn

```bash
yarn prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### npm

```bash
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

Review the generated migration file to ensure it matches your database schema.

Then, mark the migration as applied:

  

#### bun

```bash
bunx prisma migrate resolve --applied 0_init
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied 0_init
```

#### yarn

```bash
yarn prisma migrate resolve --applied 0_init
```

#### npm

```bash
npx prisma migrate resolve --applied 0_init
```

You now have a baseline for your current database schema.

## 6. Generate Prisma ORM types [#6-generate-prisma-orm-types]

Generate Prisma Client based on your introspected schema:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This creates a type-safe Prisma Client tailored to your database schema in the `generated/prisma` directory.

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Create a utility file to instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
import { PrismaClient } from "../generated/prisma/client";

const adapter = new PrismaMariaDb({
  host: process.env.DATABASE_HOST,
  user: process.env.DATABASE_USER,
  password: process.env.DATABASE_PASSWORD,
  database: process.env.DATABASE_NAME,
  connectionLimit: 5,
});
const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 8. Query your database [#8-query-your-database]

Now you can use Prisma Client to query your database. Create a `script.ts` file:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Example: Fetch all records from a table
  // Replace 'user' with your actual model name
  const allUsers = await prisma.user.findMany();
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 9. Evolve your schema [#9-evolve-your-schema]

To make changes to your database schema:

### 9.1. Update your Prisma schema file [#91-update-your-prisma-schema-file]

Update your Prisma schema file to reflect the changes you want to make to your database schema. For example, add a new model:

```prisma title="prisma/schema.prisma"
model Post { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]

model User { // [!code ++]
  id    Int    @id @default(autoincrement()) // [!code ++]
  email String @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
```

### 9.2. Create and apply a migration: [#92-create-and-apply-a-migration]

  

#### bun

```bash
bunx prisma migrate dev --name your_migration_name
```

#### pnpm

```bash
pnpm prisma migrate dev --name your_migration_name
```

#### yarn

```bash
yarn prisma migrate dev --name your_migration_name
```

#### npm

```bash
npx prisma migrate dev --name your_migration_name
```

This command will:

* Create a new SQL migration file
* Apply the migration to your database
* Regenerate Prisma Client

## 10. Explore your data with Prisma Studio [#10-explore-your-data-with-prisma-studio]

Prisma Studio is a visual editor for your database. Launch it with:

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [MySQL database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection)
* [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/cockroachdb): Add Prisma ORM to an existing TypeScript project with CockroachDB and learn database introspection, baselining, and querying
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mongodb): Add Prisma ORM to an existing TypeScript project with MongoDB and learn database introspection and querying
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/planetscale): Add Prisma ORM to an existing TypeScript project with PlanetScale and learn database introspection and querying
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql): Add Prisma ORM to an existing TypeScript project with PostgreSQL and learn database introspection, baselining, and querying
- [`Prisma Postgres`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/prisma-postgres): Add Prisma ORM to an existing TypeScript project with Prisma Postgres and learn database introspection, baselining, and querying

# PlanetScale (Prisma ORM v7) (/docs/v7/prisma-orm/add-to-existing-project/planetscale)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to an existing TypeScript project with PlanetScale and learn database introspection and querying

Location: v7 > Prisma ORM > Add to Existing Project > PlanetScale

[PlanetScale](https://planetscale.com) is a serverless database platform. This guide covers both **PlanetScale MySQL** and **PlanetScale Postgres**. In this guide, you will learn how to add Prisma ORM to an existing TypeScript project, connect it to PlanetScale, introspect your existing database schema, and start querying with type-safe Prisma Client.

## Prerequisites [#prerequisites]

## 1. Set up Prisma ORM [#1-set-up-prisma-orm]

Navigate to your existing project directory and install the required dependencies:

### MySQL [#mysql]

  

#### bun

```bash
bun add prisma@prev @types/node --dev
bun add @prisma/client@7 @prisma/adapter-planetscale undici dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/node --save-dev
pnpm add @prisma/client@7 @prisma/adapter-planetscale undici dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/node --dev
yarn add @prisma/client@7 @prisma/adapter-planetscale undici dotenv
```

#### npm

```bash
npm install prisma@prev @types/node --save-dev
npm install @prisma/client@7 @prisma/adapter-planetscale undici dotenv
```

### Postgres [#postgres]

  

#### bun

```bash
bun add prisma@prev @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### npm

```bash
npm install prisma@prev @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

Set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

### MySQL [#mysql-1]

  

#### bun

```bash
bunx --bun prisma init --datasource-provider mysql --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider mysql --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider mysql --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider mysql --output ../generated/prisma
```

### Postgres [#postgres-1]

  

#### bun

```bash
bunx --bun prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider postgresql --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection configuration
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

  

#### MySQL

```prisma title="prisma/schema.prisma" 
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider     = "mysql"
  relationMode = "prisma"
}
```

#### Postgres

```prisma title="prisma/schema.prisma" 
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}
```

> [!NOTE]
> **PlanetScale MySQL** requires `relationMode = "prisma"` because it doesn't support foreign key constraints.

## 3. Connect your database [#3-connect-your-database]

Update the `.env` file with your PlanetScale connection URL:

  

#### MySQL

```text title=".env" 
DATABASE_URL="mysql://username:password@host.connect.psdb.cloud/mydb?sslaccept=strict"
```

#### Postgres

```text title=".env" 
DATABASE_URL="postgresql://{username}:{password}@{host}:6432/postgres?sslmode=verify-full"
```

You can find your connection string in the PlanetScale dashboard.

> [!NOTE]
> **PlanetScale Postgres connection types:**
> 
> | Type          | Port   | Use case                                                       |
> | ------------- | ------ | -------------------------------------------------------------- |
> | **Direct**    | `5432` | Prisma CLI commands (migrations, introspection), Prisma Studio |
> | **PgBouncer** | `6432` | Application connections, serverless environments               |
> 
> For production applications, we recommend using PgBouncer (port 6432) for application connections.

## 4. Introspect your database [#4-introspect-your-database]

Run the following command to introspect your existing database:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This command reads the `DATABASE_URL` environment variable, connects to your database, and introspects the database schema. It then translates the database schema from SQL into a data model in your Prisma schema.

![Introspect your database with Prisma ORM](https://www.prisma.io/img/getting-started/prisma-db-pull-generate-schema.png)

After introspection, your Prisma schema will contain models that represent your existing database tables.

## 5. Generate Prisma ORM types [#5-generate-prisma-orm-types]

Generate Prisma Client based on your introspected schema:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This creates a type-safe Prisma Client tailored to your database schema in the `generated/prisma` directory.

## 6. Instantiate Prisma Client [#6-instantiate-prisma-client]

Create a utility file to instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

  

#### MySQL

```typescript title="lib/prisma.ts" 
import "dotenv/config";
import { PrismaPlanetScale } from "@prisma/adapter-planetscale";
import { PrismaClient } from "../generated/prisma/client";
import { fetch as undiciFetch } from "undici";

const adapter = new PrismaPlanetScale({ url: process.env.DATABASE_URL, fetch: undiciFetch });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

#### Postgres

```typescript title="lib/prisma.ts" 
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 7. Query your database [#7-query-your-database]

Now you can use Prisma Client to query your database. Create a `script.ts` file:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Example: Fetch all records from a table
  // Replace 'user' with your actual model name
  const allUsers = await prisma.user.findMany();
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 8. Evolve your schema [#8-evolve-your-schema]

PlanetScale uses a branching workflow instead of traditional migrations. To make changes to your database schema:

### 8.1. Update your Prisma schema file [#81-update-your-prisma-schema-file]

Update your Prisma schema file to reflect the changes you want to make to your database schema. For example, add a new model:

```prisma title="prisma/schema.prisma"
model Post { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]

model User { // [!code ++]
  id    Int    @id @default(autoincrement()) // [!code ++]
  email String @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
```

### 8.2. Push the changes to your development branch: [#82-push-the-changes-to-your-development-branch]

  

#### bun

```bash
bunx prisma db push
```

#### pnpm

```bash
pnpm prisma db push
```

#### yarn

```bash
yarn prisma db push
```

#### npm

```bash
npx prisma db push
```

This command will:

* Apply the schema changes to your PlanetScale database
* Regenerate Prisma Client

> [!NOTE]
> For production deployments, use PlanetScale's [branching workflow](https://planetscale.com/docs/concepts/branching) to create deploy requests.

## 9. Explore your data with Prisma Studio [#9-explore-your-data-with-prisma-studio]

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [PlanetScale database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection)
* [PlanetScale branching workflow](https://planetscale.com/docs/concepts/branching)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/cockroachdb): Add Prisma ORM to an existing TypeScript project with CockroachDB and learn database introspection, baselining, and querying
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mongodb): Add Prisma ORM to an existing TypeScript project with MongoDB and learn database introspection and querying
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mysql): Add Prisma ORM to an existing TypeScript project with MySQL and learn database introspection, baselining, and querying
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql): Add Prisma ORM to an existing TypeScript project with PostgreSQL and learn database introspection, baselining, and querying
- [`Prisma Postgres`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/prisma-postgres): Add Prisma ORM to an existing TypeScript project with Prisma Postgres and learn database introspection, baselining, and querying

# PostgreSQL (Prisma ORM v7) (/docs/v7/prisma-orm/add-to-existing-project/postgresql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to an existing TypeScript project with PostgreSQL and learn database introspection, baselining, and querying

Location: v7 > Prisma ORM > Add to Existing Project > PostgreSQL

[PostgreSQL](https://www.postgresql.org/) is a widely used open-source relational database. In this guide, you will learn how to add Prisma ORM to an existing TypeScript project, connect it to PostgreSQL, introspect your existing database schema, and start querying with type-safe Prisma Client.

## Prerequisites [#prerequisites]

## 1. Set up Prisma ORM [#1-set-up-prisma-orm]

Navigate to your existing project directory and install the required dependencies:

  

#### bun

```bash
bun add prisma@prev @types/node @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/node @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/node @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### npm

```bash
npm install prisma@prev @types/node @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma db pull`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-pg`** - The [`node-postgres` driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters) that connects Prisma Client to your database
* **`pg`** - The node-postgres database driver
* **`@types/pg`** - TypeScript type definitions for node-postgres
* **`dotenv`** - Loads environment variables from your `.env` file

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

Set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider postgresql --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection configuration
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}
```

## 3. Connect your database [#3-connect-your-database]

Update the `.env` file with your PostgreSQL connection URL:

```text title=".env"
DATABASE_URL="postgresql://user:password@localhost:5432/mydb?schema=public"
```

The [format of the connection URL](https://www.prisma.io/docs/orm/v7/reference/connection-urls) for PostgreSQL looks as follows:

```
postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=SCHEMA
```

## 4. Introspect your database [#4-introspect-your-database]

Run the following command to introspect your existing database:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This command reads the `DATABASE_URL` environment variable, connects to your database, and introspects the database schema. It then translates the database schema from SQL into a data model in your Prisma schema.

![Introspect your database with Prisma ORM](https://www.prisma.io/img/getting-started/prisma-db-pull-generate-schema.png)

After introspection, your Prisma schema will contain models that represent your existing database tables.

## 5. Baseline your database [#5-baseline-your-database]

To use Prisma Migrate with your existing database, you need to [baseline your database](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started).

First, create a `migrations` directory:

```bash
mkdir -p prisma/migrations/0_init
```

Next, generate the migration file with `prisma migrate diff`:

  

#### bun

```bash
bunx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### pnpm

```bash
pnpm prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### yarn

```bash
yarn prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### npm

```bash
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

Review the generated migration file to ensure it matches your database schema.

Then, mark the migration as applied:

  

#### bun

```bash
bunx prisma migrate resolve --applied 0_init
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied 0_init
```

#### yarn

```bash
yarn prisma migrate resolve --applied 0_init
```

#### npm

```bash
npx prisma migrate resolve --applied 0_init
```

You now have a baseline for your current database schema.

## 6. Generate Prisma ORM types [#6-generate-prisma-orm-types]

Generate Prisma Client based on your introspected schema:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This creates a type-safe Prisma Client tailored to your database schema in the `generated/prisma` directory.

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Create a utility file to instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 8. Query your database [#8-query-your-database]

Now you can use Prisma Client to query your database. Create a `script.ts` file:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Example: Fetch all records from a table
  // Replace 'user' with your actual model name
  const allUsers = await prisma.user.findMany();
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 9. Evolve your schema [#9-evolve-your-schema]

To make changes to your database schema:

### 9.1. Update your Prisma schema file [#91-update-your-prisma-schema-file]

Update your Prisma schema file to reflect the changes you want to make to your database schema. For example, add a new model:

```prisma title="prisma/schema.prisma"
model Post { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]

model User { // [!code ++]
  id    Int    @id @default(autoincrement()) // [!code ++]
  email String @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
```

### 9.2. Create and apply a migration: [#92-create-and-apply-a-migration]

  

#### bun

```bash
bunx prisma migrate dev --name your_migration_name
```

#### pnpm

```bash
pnpm prisma migrate dev --name your_migration_name
```

#### yarn

```bash
yarn prisma migrate dev --name your_migration_name
```

#### npm

```bash
npx prisma migrate dev --name your_migration_name
```

This command will:

* Create a new SQL migration file
* Apply the migration to your database
* Regenerate Prisma Client

## 10. Explore your data with Prisma Studio [#10-explore-your-data-with-prisma-studio]

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [PostgreSQL database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection)
* [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/cockroachdb): Add Prisma ORM to an existing TypeScript project with CockroachDB and learn database introspection, baselining, and querying
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mongodb): Add Prisma ORM to an existing TypeScript project with MongoDB and learn database introspection and querying
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mysql): Add Prisma ORM to an existing TypeScript project with MySQL and learn database introspection, baselining, and querying
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/planetscale): Add Prisma ORM to an existing TypeScript project with PlanetScale and learn database introspection and querying
- [`Prisma Postgres`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/prisma-postgres): Add Prisma ORM to an existing TypeScript project with Prisma Postgres and learn database introspection, baselining, and querying

# Prisma Postgres (Prisma ORM v7) (/docs/v7/prisma-orm/add-to-existing-project/prisma-postgres)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to an existing TypeScript project with Prisma Postgres and learn database introspection, baselining, and querying

Location: v7 > Prisma ORM > Add to Existing Project > Prisma Postgres

[Prisma Postgres](https://www.prisma.io/docs/postgres) is a managed PostgreSQL database that scales to zero and works with Prisma ORM and Prisma Studio. In this guide, you will learn how to add Prisma ORM to an existing TypeScript project, connect it to Prisma Postgres, introspect your existing database schema, and start querying with type-safe Prisma Client.

## Prerequisites [#prerequisites]

## 1. Set up Prisma ORM [#1-set-up-prisma-orm]

Navigate to your existing project directory and install the required dependencies:

  

#### bun

```bash
bun add prisma@prev @types/node @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/node @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/node @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### npm

```bash
npm install prisma@prev @types/node @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma db pull`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-pg`** - The [`node-postgres` driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters) that connects Prisma Client to your database
* **`pg`** - The node-postgres database driver
* **`@types/pg`** - TypeScript type definitions for node-postgres
* **`dotenv`** - Loads environment variables from your `.env` file

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

Set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider postgresql --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection configuration
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}
```

## 3. Connect your database [#3-connect-your-database]

Update the `.env` file with your Prisma Postgres connection URL:

```text title=".env"
DATABASE_URL="postgresql://user:password@host:5432/database?schema=public"
```

Replace the placeholder values with your actual Prisma Postgres connection details.

## 4. Introspect your database [#4-introspect-your-database]

Run the following command to introspect your existing database:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This command reads the `DATABASE_URL` environment variable, connects to your database, and introspects the database schema. It then translates the database schema from SQL into a data model in your Prisma schema.

![Introspect your database with Prisma ORM](https://www.prisma.io/img/getting-started/prisma-db-pull-generate-schema.png)

After introspection, your Prisma schema will contain models that represent your existing database tables.

## 5. Baseline your database [#5-baseline-your-database]

To use Prisma Migrate with your existing database, you need to [baseline your database](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started).

First, create a `migrations` directory:

```bash
mkdir -p prisma/migrations/0_init
```

Next, generate the migration file with `prisma migrate diff`:

  

#### bun

```bash
bunx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### pnpm

```bash
pnpm prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### yarn

```bash
yarn prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### npm

```bash
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

Review the generated migration file to ensure it matches your database schema.

Then, mark the migration as applied:

  

#### bun

```bash
bunx prisma migrate resolve --applied 0_init
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied 0_init
```

#### yarn

```bash
yarn prisma migrate resolve --applied 0_init
```

#### npm

```bash
npx prisma migrate resolve --applied 0_init
```

You now have a baseline for your current database schema.

## 6. Generate Prisma ORM types [#6-generate-prisma-orm-types]

Generate Prisma Client based on your introspected schema:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This creates a type-safe Prisma Client tailored to your database schema in the `generated/prisma` directory.

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Create a utility file to instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

> [!NOTE]
> If you need to query your database via HTTP from an edge runtime (Cloudflare Workers, Vercel Edge Functions, etc.), use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver#use-with-prisma-orm).

## 8. Query your database [#8-query-your-database]

Now you can use Prisma Client to query your database. Create a `script.ts` file:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Example: Fetch all records from a table
  // Replace 'user' with your actual model name
  const allUsers = await prisma.user.findMany();
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 9. Evolve your schema [#9-evolve-your-schema]

To make changes to your database schema:

### 9.1. Update your Prisma schema file [#91-update-your-prisma-schema-file]

Update your Prisma schema file to reflect the changes you want to make to your database schema. For example, add a new model:

```prisma title="prisma/schema.prisma"
model Post { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]

model User { // [!code ++]
  id    Int    @id @default(autoincrement()) // [!code ++]
  email String @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
```

### 9.2. Create and apply a migration: [#92-create-and-apply-a-migration]

  

#### bun

```bash
bunx prisma migrate dev --name your_migration_name
```

#### pnpm

```bash
pnpm prisma migrate dev --name your_migration_name
```

#### yarn

```bash
yarn prisma migrate dev --name your_migration_name
```

#### npm

```bash
npx prisma migrate dev --name your_migration_name
```

This command will:

* Create a new SQL migration file
* Apply the migration to your database
* Regenerate Prisma Client

## 10. Explore your data with Prisma Studio [#10-explore-your-data-with-prisma-studio]

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [Prisma Postgres documentation](https://www.prisma.io/docs/postgres)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection)
* [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/cockroachdb): Add Prisma ORM to an existing TypeScript project with CockroachDB and learn database introspection, baselining, and querying
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mongodb): Add Prisma ORM to an existing TypeScript project with MongoDB and learn database introspection and querying
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mysql): Add Prisma ORM to an existing TypeScript project with MySQL and learn database introspection, baselining, and querying
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/planetscale): Add Prisma ORM to an existing TypeScript project with PlanetScale and learn database introspection and querying
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql): Add Prisma ORM to an existing TypeScript project with PostgreSQL and learn database introspection, baselining, and querying

# SQL Server (Prisma ORM v7) (/docs/v7/prisma-orm/add-to-existing-project/sql-server)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to an existing TypeScript project with SQL Server and learn database introspection, baselining, and querying

Location: v7 > Prisma ORM > Add to Existing Project > SQL Server

[SQL Server](https://www.microsoft.com/en-us/sql-server) is Microsoft's enterprise relational database management system. In this guide, you will learn how to add Prisma ORM to an existing TypeScript project, connect it to SQL Server, introspect your existing database schema, and start querying with type-safe Prisma Client.

## Prerequisites [#prerequisites]

## 1. Set up Prisma ORM [#1-set-up-prisma-orm]

Navigate to your existing project directory and install the required dependencies:

  

#### bun

```bash
bun add prisma@prev @types/node @types/mssql --dev
bun add @prisma/client@7 @prisma/adapter-mssql dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/node @types/mssql --save-dev
pnpm add @prisma/client@7 @prisma/adapter-mssql dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/node @types/mssql --dev
yarn add @prisma/client@7 @prisma/adapter-mssql dotenv
```

#### npm

```bash
npm install prisma@prev @types/node @types/mssql --save-dev
npm install @prisma/client@7 @prisma/adapter-mssql dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma db pull`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-mssql`** - The SQL Server driver adapter that connects Prisma Client to your database
* **`dotenv`** - Loads environment variables from your `.env` file
* **`@types/mssql`** - TypeScript type definitions for mssql

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

Set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider sqlserver --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider sqlserver --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider sqlserver --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider sqlserver --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection configuration
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlserver"
}
```

## 3. Connect your database [#3-connect-your-database]

Update the `.env` file with your SQL Server connection string details:

```bash title=".env"
DATABASE_URL="sqlserver://localhost:1433;database=mydb;user=username;password=password;encrypt=true"
DB_USER="username" # [!code ++]
DB_PASSWORD="password" # [!code ++]
DB_NAME="mydb" # [!code ++]
HOST="localhost" # [!code ++]
```

Replace the placeholders with your actual database credentials:

* `localhost:1433`: Your SQL Server host and port
* `mydb`: Your database name
* `username`: Your SQL Server username
* `password`: Your SQL Server password

## 4. Introspect your database [#4-introspect-your-database]

Run the following command to introspect your existing database:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This command reads the `DATABASE_URL` environment variable, connects to your database, and introspects the database schema. It then translates the database schema from SQL into a data model in your Prisma schema.

![Introspect your database with Prisma ORM](https://www.prisma.io/img/getting-started/prisma-db-pull-generate-schema.png)

After introspection, your Prisma schema will contain models that represent your existing database tables.

## 5. Baseline your database [#5-baseline-your-database]

To use Prisma Migrate with your existing database, you need to [baseline your database](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started).

First, create a `migrations` directory:

```bash
mkdir -p prisma/migrations/0_init
```

Next, generate the migration file with `prisma migrate diff`:

  

#### bun

```bash
bunx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### pnpm

```bash
pnpm prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### yarn

```bash
yarn prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### npm

```bash
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

Review the generated migration file to ensure it matches your database schema.

Then, mark the migration as applied:

  

#### bun

```bash
bunx prisma migrate resolve --applied 0_init
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied 0_init
```

#### yarn

```bash
yarn prisma migrate resolve --applied 0_init
```

#### npm

```bash
npx prisma migrate resolve --applied 0_init
```

You now have a baseline for your current database schema.

## 6. Generate Prisma ORM types [#6-generate-prisma-orm-types]

Generate Prisma Client based on your introspected schema:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This creates a type-safe Prisma Client tailored to your database schema in the `generated/prisma` directory.

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Create a utility file to instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaMssql } from "@prisma/adapter-mssql";
import { PrismaClient } from "../generated/prisma/client";

const sqlConfig = {
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  server: process.env.HOST,
  pool: {
    max: 10,
    min: 0,
    idleTimeoutMillis: 30000,
  },
  options: {
    encrypt: true, // for azure
    trustServerCertificate: false, // change to true for local dev / self-signed certs
  },
};

const adapter = new PrismaMssql(sqlConfig);
const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 8. Query your database [#8-query-your-database]

Now you can use Prisma Client to query your database. Create a `script.ts` file:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Example: Fetch all records from a table
  // Replace 'user' with your actual model name
  const allUsers = await prisma.user.findMany();
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 9. Evolve your schema [#9-evolve-your-schema]

To make changes to your database schema:

### 9.1. Update your Prisma schema file [#91-update-your-prisma-schema-file]

Update your Prisma schema file to reflect the changes you want to make to your database schema. For example, add a new model:

```prisma title="prisma/schema.prisma"
model Post { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]

model User { // [!code ++]
  id    Int    @id @default(autoincrement()) // [!code ++]
  email String @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
```

### 9.2. Create and apply a migration: [#92-create-and-apply-a-migration]

  

#### bun

```bash
bunx prisma migrate dev --name your_migration_name
```

#### pnpm

```bash
pnpm prisma migrate dev --name your_migration_name
```

#### yarn

```bash
yarn prisma migrate dev --name your_migration_name
```

#### npm

```bash
npx prisma migrate dev --name your_migration_name
```

This command will:

* Create a new SQL migration file
* Apply the migration to your database
* Regenerate Prisma Client

## 10. Explore your data with Prisma Studio [#10-explore-your-data-with-prisma-studio]

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [SQL Server database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection)
* [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/cockroachdb): Add Prisma ORM to an existing TypeScript project with CockroachDB and learn database introspection, baselining, and querying
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mongodb): Add Prisma ORM to an existing TypeScript project with MongoDB and learn database introspection and querying
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mysql): Add Prisma ORM to an existing TypeScript project with MySQL and learn database introspection, baselining, and querying
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/planetscale): Add Prisma ORM to an existing TypeScript project with PlanetScale and learn database introspection and querying
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql): Add Prisma ORM to an existing TypeScript project with PostgreSQL and learn database introspection, baselining, and querying

# SQLite (Prisma ORM v7) (/docs/v7/prisma-orm/add-to-existing-project/sqlite)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add Prisma ORM to an existing TypeScript project with SQLite and learn database introspection, baselining, and querying

Location: v7 > Prisma ORM > Add to Existing Project > SQLite

[SQLite](https://sqlite.org) is a lightweight, file-based database suited to development, prototyping, and small applications. It requires no setup and stores data in a local file. In this guide, you will learn how to add Prisma ORM to an existing TypeScript project, connect it to SQLite, introspect your existing database schema, and start querying with type-safe Prisma Client.

## Prerequisites [#prerequisites]

## 1. Set up Prisma ORM [#1-set-up-prisma-orm]

Navigate to your existing project directory and install the required dependencies:

  

#### bun

```bash
bun add prisma@prev @types/node @types/better-sqlite3 --dev
bun add @prisma/client@7 @prisma/adapter-better-sqlite3 dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/node @types/better-sqlite3 --save-dev
pnpm add @prisma/client@7 @prisma/adapter-better-sqlite3 dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/node @types/better-sqlite3 --dev
yarn add @prisma/client@7 @prisma/adapter-better-sqlite3 dotenv
```

#### npm

```bash
npm install prisma@prev @types/node @types/better-sqlite3 --save-dev
npm install @prisma/client@7 @prisma/adapter-better-sqlite3 dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma db pull`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-better-sqlite3`** - The SQLite driver adapter that connects Prisma Client to your database
* **`@types/better-sqlite3`** - TypeScript type definitions for better-sqlite3
* **`dotenv`** - Loads environment variables from your `.env` file

## 2. Initialize Prisma ORM [#2-initialize-prisma-orm]

Set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider sqlite --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider sqlite --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider sqlite --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider sqlite --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection configuration
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

A `.env` file should be created with the following value:

```text title=".env"
DATABASE_URL="file:./dev.db"
```

## 3. Connect your database [#3-connect-your-database]

Update the `.env` file to point to your existing SQLite database file:

```text title=".env"
DATABASE_URL="file:./path/to/your/database.db"
```

## 4. Introspect your database [#4-introspect-your-database]

Run the following command to introspect your existing database:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This command reads the `DATABASE_URL` environment variable, connects to your database, and introspects the database schema. It then translates the database schema from SQL into a data model in your Prisma schema.

![Introspect your database with Prisma ORM](https://www.prisma.io/img/getting-started/prisma-db-pull-generate-schema.png)

After introspection, your Prisma schema will contain models that represent your existing database tables.

## 5. Baseline your database [#5-baseline-your-database]

To use Prisma Migrate with your existing database, you need to [baseline your database](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started).

First, create a `migrations` directory:

```bash
mkdir -p prisma/migrations/0_init
```

Next, generate the migration file with `prisma migrate diff`:

  

#### bun

```bash
bunx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### pnpm

```bash
pnpm prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### yarn

```bash
yarn prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

#### npm

```bash
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql
```

Review the generated migration file to ensure it matches your database schema.

Then, mark the migration as applied:

  

#### bun

```bash
bunx prisma migrate resolve --applied 0_init
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied 0_init
```

#### yarn

```bash
yarn prisma migrate resolve --applied 0_init
```

#### npm

```bash
npx prisma migrate resolve --applied 0_init
```

You now have a baseline for your current database schema.

## 6. Generate Prisma ORM types [#6-generate-prisma-orm-types]

Generate Prisma Client based on your introspected schema:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This creates a type-safe Prisma Client tailored to your database schema in the `generated/prisma` directory.

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Create a utility file to instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaBetterSqlite3({ url: connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

### Using SQLite with Bun [#using-sqlite-with-bun]

Bun doesn't support the native SQLite driver that `better-sqlite3` relies on (see the [`node:sqlite` reference](https://bun.com/reference/node/sqlite)). When targeting Bun, use the `@prisma/adapter-libsql` adapter instead:

```ts
import "dotenv/config";
import { PrismaLibSql } from "@prisma/adapter-libsql";
import { PrismaClient } from "../generated/prisma/client";

const adapter = new PrismaLibSql({
  url: process.env.DATABASE_URL ?? "",
});

const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 8. Query your database [#8-query-your-database]

Now you can use Prisma Client to query your database. Create a `script.ts` file:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Example: Fetch all records from a table
  // Replace 'user' with your actual model name
  const allUsers = await prisma.user.findMany();
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

## 9. Evolve your schema [#9-evolve-your-schema]

To make changes to your database schema:

### 9.1. Update your Prisma schema file [#91-update-your-prisma-schema-file]

Update your Prisma schema file to reflect the changes you want to make to your database schema. For example, add a new model:

```prisma title="prisma/schema.prisma"
model Post { // [!code ++]
  id        Int      @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean  @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User     @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]

model User { // [!code ++]
  id    Int    @id @default(autoincrement()) // [!code ++]
  email String @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]
```

### 9.2. Create and apply a migration: [#92-create-and-apply-a-migration]

  

#### bun

```bash
bunx prisma migrate dev --name your_migration_name
```

#### pnpm

```bash
pnpm prisma migrate dev --name your_migration_name
```

#### yarn

```bash
yarn prisma migrate dev --name your_migration_name
```

#### npm

```bash
npx prisma migrate dev --name your_migration_name
```

This command will:

* Create a new SQL migration file
* Apply the migration to your database
* Regenerate Prisma Client

## 10. Explore your data with Prisma Studio [#10-explore-your-data-with-prisma-studio]

* File paths must have a `file:` protocol right now in the database URL for SQLite
* **Node.js 22.5+**: Works out of the box with the built-in `node:sqlite` module
  * May require `NODE_OPTIONS=--experimental-sqlite` environment variable
* **Node.js 20**: Requires installing `better-sqlite3` as a dependency
  * If using pnpm 10+ with `pnpx`, you'll need the [`--allow-build=better-sqlite3`](https://pnpm.io/cli/dlx#--allow-build) flag
* **Deno >= 2.2**: Supported via [built-in SQLite module](https://docs.deno.com/api/node/sqlite/)
* **Bun**: Support for Prisma Studio with SQLite is coming soon and is not available yet

### Using `npx` with `better-sqlite3` [#using-npx-with-better-sqlite3]

If you don't have `node:sqlite` available in your runtime or prefer not to install `better-sqlite3` as a hard dependency (it adds \~10MB), you can use `npx` to temporarily install the required packages:

  

#### bun

```bash
bunx -p better-sqlite3 -p prisma prisma studio --url file:./path/to/your/database.db
```

#### pnpm

```bash
pnpm dlx -p better-sqlite3 -p prisma prisma studio --url file:./path/to/your/database.db
```

#### yarn

```bash
yarn dlx -p better-sqlite3 -p prisma prisma studio --url file:./path/to/your/database.db
```

#### npm

```bash
npx -p better-sqlite3 -p prisma prisma studio --url file:./path/to/your/database.db
```

This command:

* Temporarily installs `better-sqlite3` without adding it to your project dependencies
* Runs Prisma Studio with the specified SQLite database file
* Avoids the 10MB overhead of `better-sqlite3` in your project

## Next steps [#next-steps]

* [SQLite database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection)
* [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/cockroachdb): Add Prisma ORM to an existing TypeScript project with CockroachDB and learn database introspection, baselining, and querying
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mongodb): Add Prisma ORM to an existing TypeScript project with MongoDB and learn database introspection and querying
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mysql): Add Prisma ORM to an existing TypeScript project with MySQL and learn database introspection, baselining, and querying
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/planetscale): Add Prisma ORM to an existing TypeScript project with PlanetScale and learn database introspection and querying
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/postgresql): Add Prisma ORM to an existing TypeScript project with PostgreSQL and learn database introspection, baselining, and querying

# CockroachDB (Prisma ORM v7) (/docs/v7/prisma-orm/quickstart/cockroachdb)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new TypeScript project from scratch by connecting Prisma ORM to CockroachDB and generating a Prisma Client for database access

Location: v7 > Prisma ORM > Quickstart > CockroachDB

[CockroachDB](https://www.cockroachlabs.com) is a distributed SQL database built for cloud applications. In this guide, you will learn how to set up a new TypeScript project from scratch, connect it to CockroachDB using Prisma ORM, and generate a Prisma Client for type-safe access to your database.

## Prerequisites [#prerequisites]

You also need:

* A [CockroachDB](https://www.cockroachlabs.com/) database
* Database connection string from CockroachDB

## 1. Create a new project [#1-create-a-new-project]

```shell
mkdir hello-prisma
cd hello-prisma
```

Initialize a TypeScript project:

  

#### bun

```bash
bun init
bun add typescript tsx @types/node --dev
bunx tsc --init
```

#### pnpm

```bash
pnpm init
pnpm add typescript tsx @types/node --save-dev
pnpm tsc --init
```

#### yarn

```bash
yarn init
yarn add typescript tsx @types/node --dev
yarn tsc --init
```

#### npm

```bash
npm init
npm install typescript tsx @types/node --save-dev
npx tsc --init
```

## 2. Install required dependencies [#2-install-required-dependencies]

Install the packages needed for this quickstart:

  

#### bun

```bash
bun add prisma@prev @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### npm

```bash
npm install prisma@prev @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma migrate`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-pg`** - The [`node-postgres` driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters) that connects Prisma Client to your database (CockroachDB is PostgreSQL-compatible)
* **`pg`** - The node-postgres database driver
* **`@types/pg`** - TypeScript type definitions for node-postgres
* **`dotenv`** - Loads environment variables from your `.env` file

## 3. Configure ESM support [#3-configure-esm-support]

Update `tsconfig.json` for ESM compatibility:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "ignoreDeprecations": "6.0"
  }
}
```

Update `package.json` to enable ESM:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

## 4. Initialize Prisma ORM [#4-initialize-prisma-orm]

You can now run Prisma CLI commands using your package manager:

  

#### bun

```bash
bunx prisma
```

#### pnpm

```bash
pnpm prisma
```

#### yarn

```bash
yarn prisma
```

#### npm

```bash
npx prisma
```

Next, set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider cockroachdb --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider cockroachdb --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider cockroachdb --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider cockroachdb --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection and schema models
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "cockroachdb"
}
```

Update your `.env` file with your CockroachDB connection string:

```text title=".env"
DATABASE_URL="postgresql://username:password@host:26257/mydb?sslmode=require"
```

Replace with your actual CockroachDB connection string from your cluster dashboard.

## 5. Define your data model [#5-define-your-data-model]

Open `prisma/schema.prisma` and add the following models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "cockroachdb"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId  Int // [!code ++]
} // [!code ++]
```

## 6. Create and apply your first migration [#6-create-and-apply-your-first-migration]

Create your first migration to set up the database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This command creates the database tables based on your schema.

Now run the following command to generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Now that you have all the dependencies installed, you can instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 8. Write your first query [#8-write-your-first-query]

Create a `script.ts` file to test your setup:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Create a new user with a post
  const user = await prisma.user.create({
    data: {
      name: "Alice",
      email: "alice@prisma.io",
      posts: {
        create: {
          title: "Hello World",
          content: "This is my first post!",
          published: true,
        },
      },
    },
    include: {
      posts: true,
    },
  });
  console.log("Created user:", user);

  // Fetch all users with their posts
  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
    },
  });
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

You should see the created user and all users printed to the console.

## 9. Explore your data [#9-explore-your-data]

Explore the options suggested by [CockroachDB](https://www.cockroachlabs.com/blog/cockroachdb-gui-options/) to view and manage your data.

> [!WARNING]
> [Prisma Studio](https://www.prisma.io/docs/studio) does not currently support CockroachDB. Support may be added in a future release. See [Databases supported by Prisma Studio](https://www.prisma.io/docs/studio#supported-databases) for more information.

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [CockroachDB database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#cockroachdb)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database connection management](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections)

## Related pages

- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mongodb): Create a new TypeScript project from scratch by connecting Prisma ORM to MongoDB and generating a Prisma Client for database access
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mysql): Create a new TypeScript project from scratch by connecting Prisma ORM to MySQL and generating a Prisma Client for database access
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/planetscale): Create a new TypeScript project from scratch by connecting Prisma ORM to PlanetScale and generating a Prisma Client for database access
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/postgresql): Create a new TypeScript project from scratch by connecting Prisma ORM to PostgreSQL and generating a Prisma Client for database access
- [`Prisma Postgres`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres): Create a new TypeScript project from scratch by connecting Prisma ORM to Prisma Postgres and generating a Prisma Client for database access

# MongoDB (Prisma ORM v7) (/docs/v7/prisma-orm/quickstart/mongodb)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new TypeScript project from scratch by connecting Prisma ORM to MongoDB and generating a Prisma Client for database access

Location: v7 > Prisma ORM > Quickstart > MongoDB

[MongoDB](https://www.mongodb.com) is a popular NoSQL document database. In this guide, you will learn how to set up a new TypeScript project from scratch, connect it to MongoDB using Prisma ORM, and generate a Prisma Client for type-safe access to your database.

> [!WARNING]
> MongoDB support for Prisma ORM v7
> 
> **MongoDB support for Prisma ORM v7 is coming in the near future.** In the meantime, please use **Prisma ORM v6.19** (the latest v6 release) when working with MongoDB.
> 
> This guide uses Prisma ORM v6.19 to ensure full compatibility with MongoDB.

## Prerequisites [#prerequisites]

* Node.js installed in your system [with the supported version](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v6#minimum-supported-nodejs-versions)
* A [MongoDB](https://www.mongodb.com/) database accessible via connection string

## 1. Create a new project [#1-create-a-new-project]

```shell
mkdir hello-prisma
cd hello-prisma
```

Initialize a TypeScript project:

  

#### bun

```bash
bun init
bun add typescript tsx @types/node --dev
bunx tsc --init
```

#### pnpm

```bash
pnpm init
pnpm add typescript tsx @types/node --save-dev
pnpm tsc --init
```

#### yarn

```bash
yarn init
yarn add typescript tsx @types/node --dev
yarn tsc --init
```

#### npm

```bash
npm init
npm install typescript tsx @types/node --save-dev
npx tsc --init
```

## 2. Install required dependencies [#2-install-required-dependencies]

Install the packages needed for this quickstart:

  

#### bun

```bash
bun add prisma@6.19.3 @types/node --dev
```

#### pnpm

```bash
pnpm add prisma@6.19.3 @types/node --save-dev
```

#### yarn

```bash
yarn add prisma@6.19.3 @types/node --dev
```

#### npm

```bash
npm install prisma@6.19.3 @types/node --save-dev
```

  

#### bun

```bash
bun add @prisma/client@6.19.3 dotenv
```

#### pnpm

```bash
pnpm add @prisma/client@6.19.3 dotenv
```

#### yarn

```bash
yarn add @prisma/client@6.19.3 dotenv
```

#### npm

```bash
npm install @prisma/client@6.19.3 dotenv
```

> [!NOTE]
> Prisma v6.19 and MongoDB
> 
> This is the latest stable version of Prisma ORM v6 that fully supports MongoDB. MongoDB support for Prisma ORM v7 is coming soon. You can also install `prisma@6` and `@prisma/client@6` to automatically get the latest v6 release.

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma db push`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`dotenv`** - Loads environment variables from your `.env` file

> [!NOTE]
> MongoDB doesn't require driver adapters since Prisma ORM connects directly to MongoDB.

## 3. Configure ESM support [#3-configure-esm-support]

Update `tsconfig.json` for ESM compatibility:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "ignoreDeprecations": "6.0"
  }
}
```

Update `package.json` to enable ESM:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

## 4. Initialize Prisma ORM [#4-initialize-prisma-orm]

You can now run Prisma CLI commands using your package manager:

  

#### bun

```bash
bunx prisma
```

#### pnpm

```bash
pnpm prisma
```

#### yarn

```bash
yarn prisma
```

#### npm

```bash
npx prisma
```

Next, set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider mongodb --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider mongodb --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider mongodb --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider mongodb --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file for your database connection and schema models
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma.config.ts` file for Prisma configuration

> [!NOTE]
> Prisma Client will be generated in the `generated/prisma/` directory when you run `npx prisma generate` later in this guide.

The generated `prisma.config.ts` file looks like this:

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  engine: "classic",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Add `dotenv` to `prisma.config.ts` so that Prisma can load environment variables from your `.env` file:

```typescript title="prisma.config.ts"
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  engine: "classic",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "mongodb"
  url = env("DATABASE_URL")
}
```

Update your `.env` file with your MongoDB connection string:

```text title=".env"
DATABASE_URL="mongodb+srv://username:password@cluster.mongodb.net/mydb"
```

> [!NOTE]
> Replace `username`, `password`, `cluster`, and `mydb` with your actual MongoDB credentials and database name. You can get your connection string from [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) or your MongoDB deployment.

## 5. Define your data model [#5-define-your-data-model]

Open `prisma/schema.prisma` and add the following models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "mongodb"
  url = env("DATABASE_URL")
}

model User { // [!code ++]
  id    String  @id @default(auto()) @map("_id") @db.ObjectId // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        String  @id @default(auto()) @map("_id") @db.ObjectId // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId  String  @db.ObjectId // [!code ++]
} // [!code ++]
```

## 6. Push your schema to MongoDB [#6-push-your-schema-to-mongodb]

MongoDB doesn't support migrations like relational databases. Instead, use `db push` to sync your schema:

  

#### bun

```bash
bunx prisma db push
```

#### pnpm

```bash
pnpm prisma db push
```

#### yarn

```bash
yarn prisma db push
```

#### npm

```bash
npx prisma db push
```

This command:

* Creates the collections in MongoDB based on your schema
* Automatically generates Prisma Client

> [!NOTE]
> Unlike relational databases, MongoDB uses a flexible schema. The `db push` command ensures your Prisma schema is reflected in your database without creating migration files.

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Now that you have all the dependencies installed, you can instantiate Prisma Client:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaClient } from "../generated/prisma/client";

const prisma = new PrismaClient();

export { prisma };
```

## 8. Write your first query [#8-write-your-first-query]

Create a `script.ts` file to test your setup:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Create a new user with a post
  const user = await prisma.user.create({
    data: {
      name: "Alice",
      email: "alice@prisma.io",
      posts: {
        create: {
          title: "Hello World",
          content: "This is my first post!",
          published: true,
        },
      },
    },
    include: {
      posts: true,
    },
  });
  console.log("Created user:", user);

  // Fetch all users with their posts
  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
    },
  });
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

You should see the created user and all users printed to the console.

## 9. Explore your data [#9-explore-your-data]

You can use [MongoDB Atlas](https://www.mongodb.com/cloud/atlas), the MongoDB shell, or MongoDB Compass to view and manage your data.

> [!WARNING]
> [Prisma Studio](https://www.prisma.io/docs/studio) does not currently support MongoDB. Support may be added in a future release. See [Databases supported by Prisma Studio](https://www.prisma.io/docs/studio#supported-databases) for more information.

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## Troubleshooting [#troubleshooting]

* **Authentication failed**: If you see a `SCRAM failure: Authentication failed` error, [add `?authSource=admin`](https://github.com/prisma/orm/discussions/9994#discussioncomment-1562283) to the end of your connection string.
* **Empty database name**: If you see an `Error code 8000 (AtlasError): empty database name not allowed` error, append the database name to your connection URL. See this [GitHub issue](https://github.com/prisma/web/issues/5562) for details.

## More info [#more-info]

* [MongoDB database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb)
* [MongoDB data modeling patterns](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb#type-mapping-between-mongodb-and-the-prisma-schema)
* [MongoDB deployment considerations](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb#differences-to-connectors-for-relational-databases)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/cockroachdb): Create a new TypeScript project from scratch by connecting Prisma ORM to CockroachDB and generating a Prisma Client for database access
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mysql): Create a new TypeScript project from scratch by connecting Prisma ORM to MySQL and generating a Prisma Client for database access
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/planetscale): Create a new TypeScript project from scratch by connecting Prisma ORM to PlanetScale and generating a Prisma Client for database access
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/postgresql): Create a new TypeScript project from scratch by connecting Prisma ORM to PostgreSQL and generating a Prisma Client for database access
- [`Prisma Postgres`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres): Create a new TypeScript project from scratch by connecting Prisma ORM to Prisma Postgres and generating a Prisma Client for database access

# MySQL (Prisma ORM v7) (/docs/v7/prisma-orm/quickstart/mysql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new TypeScript project from scratch by connecting Prisma ORM to MySQL and generating a Prisma Client for database access

Location: v7 > Prisma ORM > Quickstart > MySQL

[MySQL](https://www.mysql.com) is a popular open-source relational database. In this guide, you will learn how to set up a new TypeScript project from scratch, connect it to MySQL using Prisma ORM, and generate a Prisma Client for type-safe access to your database.

> [!NOTE]
> This guide also applies to **MariaDB**, which is MySQL-compatible.

## Prerequisites [#prerequisites]

You also need:

* A [MySQL](https://www.mysql.com/) database server running and accessible
* Database connection details (host, port, username, password, database name)

## 1. Create a new project [#1-create-a-new-project]

```shell
mkdir hello-prisma
cd hello-prisma
```

Initialize a TypeScript project:

  

#### bun

```bash
bun init
bun add typescript tsx @types/node --dev
bunx tsc --init
```

#### pnpm

```bash
pnpm init
pnpm add typescript tsx @types/node --save-dev
pnpm tsc --init
```

#### yarn

```bash
yarn init
yarn add typescript tsx @types/node --dev
yarn tsc --init
```

#### npm

```bash
npm init
npm install typescript tsx @types/node --save-dev
npx tsc --init
```

## 2. Install required dependencies [#2-install-required-dependencies]

Install the packages needed for this quickstart:

  

#### bun

```bash
bun add prisma@prev @types/node --dev
bun add @prisma/client@7 @prisma/adapter-mariadb dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/node --save-dev
pnpm add @prisma/client@7 @prisma/adapter-mariadb dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/node --dev
yarn add @prisma/client@7 @prisma/adapter-mariadb dotenv
```

#### npm

```bash
npm install prisma@prev @types/node --save-dev
npm install @prisma/client@7 @prisma/adapter-mariadb dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma migrate`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-mariadb`** - The MySQL/MariaDB driver adapter that connects Prisma Client to your database
* **`dotenv`** - Loads environment variables from your `.env` file

## 3. Configure ESM support [#3-configure-esm-support]

Update `tsconfig.json` for ESM compatibility:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "ignoreDeprecations": "6.0"
  }
}
```

Update `package.json` to enable ESM:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

## 4. Initialize Prisma ORM [#4-initialize-prisma-orm]

You can now run Prisma CLI commands using your package manager:

  

#### bun

```bash
bunx prisma
```

#### pnpm

```bash
pnpm prisma
```

#### yarn

```bash
yarn prisma
```

#### npm

```bash
npx prisma
```

Next, set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider mysql --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider mysql --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider mysql --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider mysql --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection and schema models
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "mysql"
}
```

Update your `.env` file with your MySQL connection string details:

```bash title=".env"
DATABASE_URL="mysql://username:password@localhost:3306/mydb"
DATABASE_USER="username" # [!code ++]
DATABASE_PASSWORD="password" # [!code ++]
DATABASE_NAME="mydb" # [!code ++]
DATABASE_HOST="localhost" # [!code ++]
DATABASE_PORT=3306 # [!code ++]
```

Replace the placeholders with your actual database credentials:

* `username`: Your MySQL username
* `password`: Your MySQL password
* `localhost:3306`: Your MySQL host and port
* `mydb`: Your database name

## 5. Define your data model [#5-define-your-data-model]

Open `prisma/schema.prisma` and add the following models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "mysql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? @db.Text // [!code ++]
  published Boolean @default(false) // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId  Int // [!code ++]
} // [!code ++]
```

## 6. Create and apply your first migration [#6-create-and-apply-your-first-migration]

Create your first migration to set up the database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This command creates the database tables based on your schema.

Now run the following command to generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Now that you have all the dependencies installed, you can instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
import { PrismaClient } from "../generated/prisma/client";

const adapter = new PrismaMariaDb({
  host: process.env.DATABASE_HOST,
  user: process.env.DATABASE_USER,
  password: process.env.DATABASE_PASSWORD,
  database: process.env.DATABASE_NAME,
  connectionLimit: 5,
});
const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 8. Write your first query [#8-write-your-first-query]

Create a `script.ts` file to test your setup:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  const user = await prisma.user.create({
    data: {
      name: "Alice",
      email: "alice@prisma.io",
      posts: {
        create: {
          title: "Hello World",
          content: "This is my first post!",
          published: true,
        },
      },
    },
    include: {
      posts: true,
    },
  });
  console.log("Created user:", user);

  // Fetch all users with their posts
  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
    },
  });
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

You should see the created user and all users printed to the console.

## 9. Explore your data with Prisma Studio [#9-explore-your-data-with-prisma-studio]

Prisma Studio is a visual editor for your database. Launch it with:

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [MySQL database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database connection management](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/cockroachdb): Create a new TypeScript project from scratch by connecting Prisma ORM to CockroachDB and generating a Prisma Client for database access
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mongodb): Create a new TypeScript project from scratch by connecting Prisma ORM to MongoDB and generating a Prisma Client for database access
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/planetscale): Create a new TypeScript project from scratch by connecting Prisma ORM to PlanetScale and generating a Prisma Client for database access
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/postgresql): Create a new TypeScript project from scratch by connecting Prisma ORM to PostgreSQL and generating a Prisma Client for database access
- [`Prisma Postgres`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres): Create a new TypeScript project from scratch by connecting Prisma ORM to Prisma Postgres and generating a Prisma Client for database access

# PlanetScale (Prisma ORM v7) (/docs/v7/prisma-orm/quickstart/planetscale)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new TypeScript project from scratch by connecting Prisma ORM to PlanetScale and generating a Prisma Client for database access

Location: v7 > Prisma ORM > Quickstart > PlanetScale

[PlanetScale](https://planetscale.com) is a serverless database platform. This guide covers both **PlanetScale MySQL** and **PlanetScale Postgres**. In this guide, you will learn how to set up a new TypeScript project from scratch, connect it to PlanetScale using Prisma ORM, and generate a Prisma Client for type-safe access to your database.

## Prerequisites [#prerequisites]

You also need:

* A [PlanetScale](https://planetscale.com) account
* A PlanetScale database (MySQL or Postgres)
* Database connection credentials from PlanetScale

## 1. Create a new project [#1-create-a-new-project]

```shell
mkdir hello-prisma
cd hello-prisma
```

Initialize a TypeScript project:

  

#### bun

```bash
bun init
bun add typescript tsx @types/node --dev
bunx tsc --init
```

#### pnpm

```bash
pnpm init
pnpm add typescript tsx @types/node --save-dev
pnpm tsc --init
```

#### yarn

```bash
yarn init
yarn add typescript tsx @types/node --dev
yarn tsc --init
```

#### npm

```bash
npm init
npm install typescript tsx @types/node --save-dev
npx tsc --init
```

## 2. Install required dependencies [#2-install-required-dependencies]

Install the packages needed for this quickstart:

### MySQL [#mysql]

  

#### bun

```bash
bun add prisma@prev --dev
bun add @prisma/client@7 @prisma/adapter-planetscale undici dotenv
```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
pnpm add @prisma/client@7 @prisma/adapter-planetscale undici dotenv
```

#### yarn

```bash
yarn add prisma@prev --dev
yarn add @prisma/client@7 @prisma/adapter-planetscale undici dotenv
```

#### npm

```bash
npm install prisma@prev --save-dev
npm install @prisma/client@7 @prisma/adapter-planetscale undici dotenv
```

### Postgres [#postgres]

  

#### bun

```bash
bun add prisma@prev @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### npm

```bash
npm install prisma@prev @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

## 3. Configure ESM support [#3-configure-esm-support]

Update `tsconfig.json` for ESM compatibility:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "ignoreDeprecations": "6.0"
  }
}
```

Update `package.json` to enable ESM:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

## 4. Initialize Prisma ORM [#4-initialize-prisma-orm]

You can now run Prisma CLI commands using your package manager:

  

#### bun

```bash
bunx prisma
```

#### pnpm

```bash
pnpm prisma
```

#### yarn

```bash
yarn prisma
```

#### npm

```bash
npx prisma
```

Next, set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

### MySQL [#mysql-1]

  

#### bun

```bash
bunx --bun prisma init --datasource-provider mysql --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider mysql --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider mysql --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider mysql --output ../generated/prisma
```

### Postgres [#postgres-1]

  

#### bun

```bash
bunx --bun prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider postgresql --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection and schema models
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

  

#### MySQL

```prisma title="prisma/schema.prisma" 
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider     = "mysql"
  relationMode = "prisma"
}
```

#### Postgres

```prisma title="prisma/schema.prisma" 
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}
```

> [!NOTE]
> **PlanetScale MySQL** requires `relationMode = "prisma"` because it doesn't support foreign key constraints.

## 5. Configure your connection [#5-configure-your-connection]

Update your `.env` file with your PlanetScale connection string:

  

#### MySQL

```text title=".env" 
DATABASE_URL="mysql://username:password@host.connect.psdb.cloud/mydb?sslaccept=strict"
```

#### Postgres

```text title=".env" 
DATABASE_URL="postgresql://{username}:{password}@{host}:6432/postgres?sslmode=verify-full"
```

Replace with your actual PlanetScale credentials from your database dashboard.

> [!NOTE]
> **PlanetScale Postgres connection types:**
> 
> | Type          | Port   | Use case                                                       |
> | ------------- | ------ | -------------------------------------------------------------- |
> | **Direct**    | `5432` | Prisma CLI commands (migrations, introspection), Prisma Studio |
> | **PgBouncer** | `6432` | Application connections, serverless environments               |
> 
> For production applications, we recommend using PgBouncer (port 6432) for application connections while keeping a direct connection for Prisma CLI commands.

## 6. Define your data model [#6-define-your-data-model]

Open `prisma/schema.prisma` and add the following models:

  

#### MySQL

```prisma title="prisma/schema.prisma" 
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider     = "mysql"
  relationMode = "prisma"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? @db.Text // [!code ++]
  published Boolean @default(false) // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId  Int // [!code ++]

  @@index([authorId]) // [!code ++]
} // [!code ++]
```

#### Postgres

```prisma title="prisma/schema.prisma" 
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId  Int // [!code ++]
} // [!code ++]
```

> [!NOTE]
> Note the `@@index([authorId])` on the `Post` model for MySQL. PlanetScale MySQL requires indexes on foreign keys when using `relationMode = "prisma"`.

## 7. Apply your schema to the database [#7-apply-your-schema-to-the-database]

### MySQL [#mysql-2]

  

#### bun

```bash
bunx prisma db push
```

#### pnpm

```bash
pnpm prisma db push
```

#### yarn

```bash
yarn prisma db push
```

#### npm

```bash
npx prisma db push
```

### Postgres [#postgres-2]

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This command creates the database tables based on your schema.

Now run the following command to generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

> [!NOTE]
> **PlanetScale MySQL** uses a branching workflow instead of traditional migrations, so we use `prisma db push`. **PlanetScale Postgres** supports standard migrations with `prisma migrate dev`.

## 8. Instantiate Prisma Client [#8-instantiate-prisma-client]

Now that you have all the dependencies installed, you can instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

  

#### MySQL

```typescript title="lib/prisma.ts" 
import "dotenv/config";
import { PrismaPlanetScale } from "@prisma/adapter-planetscale";
import { PrismaClient } from "../generated/prisma/client";
import { fetch as undiciFetch } from "undici";

const adapter = new PrismaPlanetScale({ url: process.env.DATABASE_URL, fetch: undiciFetch });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

#### Postgres

```typescript title="lib/prisma.ts" 
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from '../generated/prisma/client'

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 9. Write your first query [#9-write-your-first-query]

Create a `script.ts` file to test your setup:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Create a new user with a post
  const user = await prisma.user.create({
    data: {
      name: "Alice",
      email: "alice@prisma.io",
      posts: {
        create: {
          title: "Hello World",
          content: "This is my first post!",
          published: true,
        },
      },
    },
    include: {
      posts: true,
    },
  });
  console.log("Created user:", user);

  // Fetch all users with their posts
  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
    },
  });
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

You should see the created user and all users printed to the console.

## 10. Explore your data with Prisma Studio [#10-explore-your-data-with-prisma-studio]

Prisma Studio is a visual editor for your database. Launch it with:

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database connection management](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections)
* [PlanetScale documentation](https://planetscale.com/docs)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/cockroachdb): Create a new TypeScript project from scratch by connecting Prisma ORM to CockroachDB and generating a Prisma Client for database access
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mongodb): Create a new TypeScript project from scratch by connecting Prisma ORM to MongoDB and generating a Prisma Client for database access
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mysql): Create a new TypeScript project from scratch by connecting Prisma ORM to MySQL and generating a Prisma Client for database access
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/postgresql): Create a new TypeScript project from scratch by connecting Prisma ORM to PostgreSQL and generating a Prisma Client for database access
- [`Prisma Postgres`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres): Create a new TypeScript project from scratch by connecting Prisma ORM to Prisma Postgres and generating a Prisma Client for database access

# PostgreSQL (Prisma ORM v7) (/docs/v7/prisma-orm/quickstart/postgresql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new TypeScript project from scratch by connecting Prisma ORM to PostgreSQL and generating a Prisma Client for database access

Location: v7 > Prisma ORM > Quickstart > PostgreSQL

[PostgreSQL](https://www.postgresql.org) is an open-source relational database. In this guide, you will learn how to set up a new TypeScript project from scratch, connect it to PostgreSQL using Prisma ORM, and generate a Prisma Client for type-safe access to your database.

## Prerequisites [#prerequisites]

You also need:

* A [PostgreSQL](https://www.postgresql.org/) database server running and accessible
* Database connection details (host, port, username, password, database name)

> [!NOTE]
> If you need a PostgreSQL database
> 
> If you don't already have a PostgreSQL database, follow the quickstart to set up a production-ready [Prisma Postgres](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres) database with Prisma ORM in a new project.

## 1. Create a new project [#1-create-a-new-project]

```shell
mkdir hello-prisma
cd hello-prisma
```

Initialize a TypeScript project:

  

#### bun

```bash
bun init
bun add typescript tsx @types/node --dev
bunx tsc --init
```

#### pnpm

```bash
pnpm init
pnpm add typescript tsx @types/node --save-dev
pnpm tsc --init
```

#### yarn

```bash
yarn init
yarn add typescript tsx @types/node --dev
yarn tsc --init
```

#### npm

```bash
npm init
npm install typescript tsx @types/node --save-dev
npx tsc --init
```

## 2. Install required dependencies [#2-install-required-dependencies]

Install the packages needed for this quickstart:

  

#### bun

```bash
bun add prisma@prev @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### npm

```bash
npm install prisma@prev @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma migrate`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-pg`** - The [`node-postgres` driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters) that connects Prisma Client to your database
* **`pg`** - The node-postgres database driver
* **`@types/pg`** - TypeScript type definitions for node-postgres
* **`dotenv`** - Loads environment variables from your `.env` file

## 3. Configure ESM support [#3-configure-esm-support]

Update `tsconfig.json` for ESM compatibility:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "ignoreDeprecations": "6.0"
  }
}
```

Update `package.json` to enable ESM:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

## 4. Initialize Prisma ORM [#4-initialize-prisma-orm]

You can now run Prisma CLI commands using your package manager:

  

#### bun

```bash
bunx prisma
```

#### pnpm

```bash
pnpm prisma
```

#### yarn

```bash
yarn prisma
```

#### npm

```bash
npx prisma
```

Next, set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider postgresql --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider postgresql --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection and schema models
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}
```

Update your `.env` file with your PostgreSQL connection string:

```text title=".env"
DATABASE_URL="postgresql://username:password@localhost:5432/mydb?schema=public"
```

Replace the placeholders with your actual database credentials:

* `username`: Your PostgreSQL username
* `password`: Your PostgreSQL password
* `localhost:5432`: Your PostgreSQL host and port
* `mydb`: Your database name

## 5. Define your data model [#5-define-your-data-model]

Open `prisma/schema.prisma` and add the following models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId  Int // [!code ++]
} // [!code ++]
```

## 6. Create and apply your first migration [#6-create-and-apply-your-first-migration]

Create your first migration to set up the database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This command creates the database tables based on your schema.

Now run the following command to generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Now that you have all the dependencies installed, you can instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 8. Write your first query [#8-write-your-first-query]

Create a `script.ts` file to test your setup:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Create a new user with a post
  const user = await prisma.user.create({
    data: {
      name: "Alice",
      email: "alice@prisma.io",
      posts: {
        create: {
          title: "Hello World",
          content: "This is my first post!",
          published: true,
        },
      },
    },
    include: {
      posts: true,
    },
  });
  console.log("Created user:", user);

  // Fetch all users with their posts
  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
    },
  });
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

You should see the created user and all users printed to the console.

## 9. Explore your data with Prisma Studio [#9-explore-your-data-with-prisma-studio]

Prisma Studio is a visual editor for your database. Launch it with:

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [PostgreSQL database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database connection management](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/cockroachdb): Create a new TypeScript project from scratch by connecting Prisma ORM to CockroachDB and generating a Prisma Client for database access
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mongodb): Create a new TypeScript project from scratch by connecting Prisma ORM to MongoDB and generating a Prisma Client for database access
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mysql): Create a new TypeScript project from scratch by connecting Prisma ORM to MySQL and generating a Prisma Client for database access
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/planetscale): Create a new TypeScript project from scratch by connecting Prisma ORM to PlanetScale and generating a Prisma Client for database access
- [`Prisma Postgres`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres): Create a new TypeScript project from scratch by connecting Prisma ORM to Prisma Postgres and generating a Prisma Client for database access

# Prisma Postgres (Prisma ORM v7) (/docs/v7/prisma-orm/quickstart/prisma-postgres)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new TypeScript project from scratch by connecting Prisma ORM to Prisma Postgres and generating a Prisma Client for database access

Location: v7 > Prisma ORM > Quickstart > Prisma Postgres

[Prisma Postgres](https://www.prisma.io/docs/postgres) is a managed PostgreSQL database that scales to zero and works with Prisma ORM and Prisma Studio. In this guide, you will learn how to set up a new TypeScript project from scratch, connect it to Prisma Postgres using Prisma ORM, and generate a Prisma Client for type-safe access to your database.

## Prerequisites [#prerequisites]

* [Node.js](https://nodejs.org) v20.19 or later
* No database needed: you create a Prisma Postgres database with one command in step 4

## 1. Create a new project [#1-create-a-new-project]

```shell
mkdir hello-prisma
cd hello-prisma
```

Initialize a TypeScript project:

  

#### bun

```bash
bun init
bun add typescript tsx @types/node --dev
bunx tsc --init
```

#### pnpm

```bash
pnpm init
pnpm add typescript tsx @types/node --save-dev
pnpm tsc --init
```

#### yarn

```bash
yarn init
yarn add typescript tsx @types/node --dev
yarn tsc --init
```

#### npm

```bash
npm init
npm install typescript tsx @types/node --save-dev
npx tsc --init
```

## 2. Install required dependencies [#2-install-required-dependencies]

Install the packages needed for this quickstart:

  

#### bun

```bash
bun add prisma@prev @types/pg --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/pg --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/pg --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenv
```

#### npm

```bash
npm install prisma@prev @types/pg --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma migrate`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-pg`** - The [`node-postgres` driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters) that connects Prisma Client to your database
* **`pg`** - The node-postgres database driver
* **`@types/pg`** - TypeScript type definitions for node-postgres
* **`dotenv`** - Loads environment variables from your `.env` file

## 3. Configure ESM support [#3-configure-esm-support]

Update `tsconfig.json` for ESM compatibility:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "ignoreDeprecations": "6.0"
  }
}
```

Update `package.json` to enable ESM:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

## 4. Initialize Prisma ORM [#4-initialize-prisma-orm]

You can now run Prisma CLI commands using your package manager:

  

#### bun

```bash
bunx prisma
```

#### pnpm

```bash
pnpm prisma
```

#### yarn

```bash
yarn prisma
```

#### npm

```bash
npx prisma
```

Next, set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../generated/prisma
```

#### npm

```bash
npx prisma init --output ../generated/prisma
```

`prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`.

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection and schema models
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}
```

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db@latest
```

#### pnpm

```bash
pnpm dlx create-db@latest
```

#### yarn

```bash
yarn dlx create-db@latest
```

#### npm

```bash
npx create-db@latest
```

## 5. Define your data model [#5-define-your-data-model]

Open `prisma/schema.prisma` and add the following models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId  Int // [!code ++]
} // [!code ++]
```

## 6. Create and apply your first migration [#6-create-and-apply-your-first-migration]

Create your first migration to set up the database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This command creates the database tables based on your schema.

Now run the following command to generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Now that you have all the dependencies installed, you can instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

> [!NOTE]
> If you need to query your database via HTTP from an edge runtime (Cloudflare Workers, Vercel Edge Functions, etc.), use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver#use-with-prisma-orm).

## 8. Write your first query [#8-write-your-first-query]

Create a `script.ts` file to test your setup:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Create a new user with a post
  const user = await prisma.user.create({
    data: {
      name: "Alice",
      email: "alice@prisma.io",
      posts: {
        create: {
          title: "Hello World",
          content: "This is my first post!",
          published: true,
        },
      },
    },
    include: {
      posts: true,
    },
  });
  console.log("Created user:", user);

  // Fetch all users with their posts
  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
    },
  });
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

You should see the created user and all users printed to the console.

## 9. Explore your data with Prisma Studio [#9-explore-your-data-with-prisma-studio]

Prisma Studio is a visual editor for your database. Launch it with:

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

> [!NOTE]
> Deploy to Compute
> 
> To run this app in the cloud, deploy it to [Prisma Compute](https://www.prisma.io/docs/compute), which runs your app next to your Prisma Postgres database. Follow [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy).

## More info [#more-info]

* [Prisma Postgres documentation](https://www.prisma.io/docs/postgres)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database connection management](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/cockroachdb): Create a new TypeScript project from scratch by connecting Prisma ORM to CockroachDB and generating a Prisma Client for database access
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mongodb): Create a new TypeScript project from scratch by connecting Prisma ORM to MongoDB and generating a Prisma Client for database access
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mysql): Create a new TypeScript project from scratch by connecting Prisma ORM to MySQL and generating a Prisma Client for database access
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/planetscale): Create a new TypeScript project from scratch by connecting Prisma ORM to PlanetScale and generating a Prisma Client for database access
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/postgresql): Create a new TypeScript project from scratch by connecting Prisma ORM to PostgreSQL and generating a Prisma Client for database access

# SQL Server (Prisma ORM v7) (/docs/v7/prisma-orm/quickstart/sql-server)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new TypeScript project from scratch by connecting Prisma ORM to SQL Server and generating a Prisma Client for database access

Location: v7 > Prisma ORM > Quickstart > SQL Server

[Microsoft SQL Server](https://www.microsoft.com/en-us/sql-server) is an enterprise-grade relational database. In this guide, you will learn how to set up a new TypeScript project from scratch, connect it to SQL Server using Prisma ORM, and generate a Prisma Client for type-safe access to your database.

## Prerequisites [#prerequisites]

You also need:

* A [Microsoft SQL Server](https://learn.microsoft.com/en-us/sql/?view=sql-server-ver16) database
  * [Microsoft SQL Server on Linux for Docker](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server#local-setup)
  * [Microsoft SQL Server on Windows (local)](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server#local-setup)
* Database connection details (host, port, username, password, database name)

## 1. Create a new project [#1-create-a-new-project]

```shell
mkdir hello-prisma
cd hello-prisma
```

Initialize a TypeScript project:

  

#### bun

```bash
bun init
bun add typescript tsx @types/node --dev
bunx tsc --init
```

#### pnpm

```bash
pnpm init
pnpm add typescript tsx @types/node --save-dev
pnpm tsc --init
```

#### yarn

```bash
yarn init
yarn add typescript tsx @types/node --dev
yarn tsc --init
```

#### npm

```bash
npm init
npm install typescript tsx @types/node --save-dev
npx tsc --init
```

## 2. Install required dependencies [#2-install-required-dependencies]

Install the packages needed for this quickstart:

  

#### bun

```bash
bun add prisma@prev @types/node @types/mssql --dev
bun add @prisma/client@7 @prisma/adapter-mssql dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/node @types/mssql --save-dev
pnpm add @prisma/client@7 @prisma/adapter-mssql dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/node @types/mssql --dev
yarn add @prisma/client@7 @prisma/adapter-mssql dotenv
```

#### npm

```bash
npm install prisma@prev @types/node @types/mssql --save-dev
npm install @prisma/client@7 @prisma/adapter-mssql dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma migrate`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-mssql`** - The SQL Server driver adapter that connects Prisma Client to your database
* **`@types/mssql`** - TypeScript type definitions for mssql
* **`dotenv`** - Loads environment variables from your `.env` file

## 3. Configure ESM support [#3-configure-esm-support]

Update `tsconfig.json` for ESM compatibility:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "ignoreDeprecations": "6.0"
  }
}
```

Update `package.json` to enable ESM:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

## 4. Initialize Prisma ORM [#4-initialize-prisma-orm]

You can now run Prisma CLI commands using your package manager:

  

#### bun

```bash
bunx prisma
```

#### pnpm

```bash
pnpm prisma
```

#### yarn

```bash
yarn prisma
```

#### npm

```bash
npx prisma
```

Next, set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider sqlserver --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider sqlserver --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider sqlserver --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider sqlserver --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection and schema models
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlserver"
}
```

Update your `.env` file with your SQL Server connection string details:

```bash title=".env"
DATABASE_URL="sqlserver://localhost:1433;database=mydb;user=username;password=password;encrypt=true"
DB_USER="username" # [!code ++]
DB_PASSWORD="password" # [!code ++]
DB_NAME="mydb" # [!code ++]
HOST="localhost" # [!code ++]
```

Replace the placeholders with your actual database credentials:

* `localhost:1433`: Your SQL Server host and port
* `mydb`: Your database name
* `username`: Your SQL Server username
* `password`: Your SQL Server password

## 5. Define your data model [#5-define-your-data-model]

Open `prisma/schema.prisma` and add the following models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlserver"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId  Int // [!code ++]
} // [!code ++]
```

## 6. Create and apply your first migration [#6-create-and-apply-your-first-migration]

Create your first migration to set up the database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This command creates the database tables based on your schema.

Now run the following command to generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Now that you have all the dependencies installed, you can instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaMssql } from "@prisma/adapter-mssql";
import { PrismaClient } from "../generated/prisma/client";

const sqlConfig = {
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  server: process.env.HOST,
  pool: {
    max: 10,
    min: 0,
    idleTimeoutMillis: 30000,
  },
  options: {
    encrypt: true, // for azure
    trustServerCertificate: false, // change to true for local dev / self-signed certs
  },
};

const adapter = new PrismaMssql(sqlConfig);
const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 8. Write your first query [#8-write-your-first-query]

Create a `script.ts` file to test your setup:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Create a new user with a post
  const user = await prisma.user.create({
    data: {
      name: "Alice",
      email: "alice@prisma.io",
      posts: {
        create: {
          title: "Hello World",
          content: "This is my first post!",
          published: true,
        },
      },
    },
    include: {
      posts: true,
    },
  });
  console.log("Created user:", user);

  // Fetch all users with their posts
  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
    },
  });
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

You should see the created user and all users printed to the console.

## 9. Explore your data with Prisma Studio [#9-explore-your-data-with-prisma-studio]

Prisma Studio is a visual editor for your database. Launch it with:

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [SQL Server database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database connection management](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/cockroachdb): Create a new TypeScript project from scratch by connecting Prisma ORM to CockroachDB and generating a Prisma Client for database access
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mongodb): Create a new TypeScript project from scratch by connecting Prisma ORM to MongoDB and generating a Prisma Client for database access
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mysql): Create a new TypeScript project from scratch by connecting Prisma ORM to MySQL and generating a Prisma Client for database access
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/planetscale): Create a new TypeScript project from scratch by connecting Prisma ORM to PlanetScale and generating a Prisma Client for database access
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/postgresql): Create a new TypeScript project from scratch by connecting Prisma ORM to PostgreSQL and generating a Prisma Client for database access

# SQLite (Prisma ORM v7) (/docs/v7/prisma-orm/quickstart/sqlite)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new TypeScript project from scratch by connecting Prisma ORM to SQLite and generating a Prisma Client for database access

Location: v7 > Prisma ORM > Quickstart > SQLite

[SQLite](https://sqlite.org) is a lightweight, file-based database suited to development, prototyping, and small applications. It requires no setup and stores data in a local file.

In this guide, you will learn how to set up a new TypeScript project from scratch, connect it to SQLite using Prisma ORM, and generate a Prisma Client for type-safe access to your database.

## Prerequisites [#prerequisites]

## 1. Create a new project [#1-create-a-new-project]

Create a project directory and navigate into it:

```shell
mkdir hello-prisma
cd hello-prisma
```

Initialize a TypeScript project:

  

#### bun

```bash
bun init
bun add typescript tsx @types/node --dev
bunx tsc --init
```

#### pnpm

```bash
pnpm init
pnpm add typescript tsx @types/node --save-dev
pnpm tsc --init
```

#### yarn

```bash
yarn init
yarn add typescript tsx @types/node --dev
yarn tsc --init
```

#### npm

```bash
npm init
npm install typescript tsx @types/node --save-dev
npx tsc --init
```

## 2. Install required dependencies [#2-install-required-dependencies]

Install the packages needed for this quickstart:

  

#### bun

```bash
bun add prisma@prev @types/node @types/better-sqlite3 --dev
```

#### pnpm

```bash
pnpm add prisma@prev @types/node @types/better-sqlite3 -D
```

#### yarn

```bash
yarn add prisma@prev @types/node @types/better-sqlite3 --dev
```

#### npm

```bash
npm install prisma@prev @types/node @types/better-sqlite3 -D
```

  

#### bun

```bash
bun add @prisma/client@7 @prisma/adapter-better-sqlite3 dotenv
```

#### pnpm

```bash
pnpm add @prisma/client@7 @prisma/adapter-better-sqlite3 dotenv
```

#### yarn

```bash
yarn add @prisma/client@7 @prisma/adapter-better-sqlite3 dotenv
```

#### npm

```bash
npm install @prisma/client@7 @prisma/adapter-better-sqlite3 dotenv
```

> [!NOTE]
> pnpm users with SQLite
> 
> If using pnpm 10+ with `pnpx`, you'll need the [`--allow-build=better-sqlite3`](https://pnpm.io/cli/dlx#--allow-build) flag when running Prisma Studio due to SQLite's native dependency requirements.

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma migrate`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-better-sqlite3`** - The SQLite driver adapter that connects Prisma Client to your database
* **`@types/better-sqlite3`** - TypeScript type definitions for better-sqlite3
* **`dotenv`** - Loads environment variables from your `.env` file

## 3. Configure ESM support [#3-configure-esm-support]

Update `tsconfig.json` for ESM compatibility:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "ignoreDeprecations": "6.0"
  }
}
```

Update `package.json` to enable ESM:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

## 4. Initialize Prisma ORM [#4-initialize-prisma-orm]

You can now run Prisma CLI commands using your package manager:

  

#### bun

```bash
bunx prisma
```

#### pnpm

```bash
pnpm prisma
```

#### yarn

```bash
yarn prisma
```

#### npm

```bash
npx prisma
```

Next, set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --datasource-provider sqlite --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --datasource-provider sqlite --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --datasource-provider sqlite --output ../generated/prisma
```

#### npm

```bash
npx prisma init --datasource-provider sqlite --output ../generated/prisma
```

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection and schema models
* Creates a `.env` file in the root directory for environment variables
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}
```

A `.env` file should be created with the following value:

```text title=".env"
DATABASE_URL="file:./dev.db"
```

## 5. Define your data model [#5-define-your-data-model]

Open `prisma/schema.prisma` and add the following models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "sqlite"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId  Int // [!code ++]
} // [!code ++]
```

## 6. Create and apply your first migration [#6-create-and-apply-your-first-migration]

Create your first migration to set up the database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This command creates the database tables based on your schema.

Now run the following command to generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Now that you have all the dependencies installed, you can instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaBetterSqlite3({ url: connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

### Using SQLite with Bun [#using-sqlite-with-bun]

When targeting Bun, use the `@prisma/adapter-libsql` adapter instead of `@prisma/adapter-better-sqlite3`. Bun doesn't support the native SQLite driver that `better-sqlite3` relies on (see the [`node:sqlite` reference](https://bun.com/reference/node/sqlite)). Instantiate Prisma Client like so:

```ts
import "dotenv/config";
import { PrismaLibSql } from "@prisma/adapter-libsql";
import { PrismaClient } from "../generated/prisma/client";

const adapter = new PrismaLibSql({
  url: process.env.DATABASE_URL ?? "",
});

const prisma = new PrismaClient({ adapter });

export { prisma };
```

## 8. Write your first query [#8-write-your-first-query]

Create a `script.ts` file to test your setup:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Create a new user with a post
  const user = await prisma.user.create({
    data: {
      name: "Alice",
      email: "alice@prisma.io",
      posts: {
        create: {
          title: "Hello World",
          content: "This is my first post!",
          published: true,
        },
      },
    },
    include: {
      posts: true,
    },
  });
  console.log("Created user:", user);

  // Fetch all users with their posts
  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
    },
  });
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

You should see the created user and all users printed to the console.

## 9. Explore your data with Prisma Studio [#9-explore-your-data-with-prisma-studio]

To view SQLite databases within Prisma Studio:

* File paths must have a `file:` protocol right now in the database URL for SQLite
* **Node.js 22.5+**: Works out of the box with the built-in `node:sqlite` module
  * May require `NODE_OPTIONS=--experimental-sqlite` environment variable
* **Node.js 20**: Requires installing `better-sqlite3` as a dependency
  * If using pnpm 10+ with `pnpx`, you'll need the [`--allow-build=better-sqlite3`](https://pnpm.io/cli/dlx#--allow-build) flag
* **Deno >= 2.2**: Supported via [built-in SQLite module](https://docs.deno.com/api/node/sqlite/)
* **Bun**: Support for Prisma Studio with SQLite is coming soon and is not available yet

If you don't have `node:sqlite` available in your runtime or prefer not to install `better-sqlite3` as a hard dependency, you can use `npx` to temporarily install the required packages:

  

#### bun

```bash
bunx -p better-sqlite3 -p prisma prisma studio --url file:./dev.db
```

#### pnpm

```bash
pnpm dlx -p better-sqlite3 -p prisma prisma studio --url file:./dev.db
```

#### yarn

```bash
yarn dlx -p better-sqlite3 -p prisma prisma studio --url file:./dev.db
```

#### npm

```bash
npx -p better-sqlite3 -p prisma prisma studio --url file:./dev.db
```

This command:

* Temporarily installs `better-sqlite3` without adding it to your project dependencies
* Runs Prisma Studio with the specified SQLite database file
* Avoids the 10MB overhead of `better-sqlite3` in your project

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

## More info [#more-info]

* [SQLite database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database connection management](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections)

## Related pages

- [`CockroachDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/cockroachdb): Create a new TypeScript project from scratch by connecting Prisma ORM to CockroachDB and generating a Prisma Client for database access
- [`MongoDB`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mongodb): Create a new TypeScript project from scratch by connecting Prisma ORM to MongoDB and generating a Prisma Client for database access
- [`MySQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mysql): Create a new TypeScript project from scratch by connecting Prisma ORM to MySQL and generating a Prisma Client for database access
- [`PlanetScale`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/planetscale): Create a new TypeScript project from scratch by connecting Prisma ORM to PlanetScale and generating a Prisma Client for database access
- [`PostgreSQL`](https://www.prisma.io/docs/v7/prisma-orm/quickstart/postgresql): Create a new TypeScript project from scratch by connecting Prisma ORM to PostgreSQL and generating a Prisma Client for database access

# Prisma ORM (Prisma ORM v7) (/docs/v7/prisma-postgres/quickstart/prisma-orm)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Create a new TypeScript project from scratch by connecting Prisma ORM to Prisma Postgres and generating a Prisma Client for database access

Location: v7 > Prisma Postgres > Quickstart > Prisma ORM

[Prisma Postgres](https://www.prisma.io/docs/postgres) is a managed PostgreSQL database that scales to zero and works with Prisma ORM and Prisma Studio. In this guide, you will learn how to set up a new TypeScript project from scratch, connect it to Prisma Postgres using Prisma ORM, and generate a Prisma Client for type-safe access to your database.

## Prerequisites [#prerequisites]

## 1. Create a new project [#1-create-a-new-project]

## 2. Install required dependencies [#2-install-required-dependencies]

Install the packages needed for this quickstart:

  

#### bun

```bash
bun add prisma@prev @types/node --dev
bun add @prisma/client@7 @prisma/adapter-pg dotenv
```

#### pnpm

```bash
pnpm add prisma@prev @types/node --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv
```

#### yarn

```bash
yarn add prisma@prev @types/node --dev
yarn add @prisma/client@7 @prisma/adapter-pg dotenv
```

#### npm

```bash
npm install prisma@prev @types/node --save-dev
npm install @prisma/client@7 @prisma/adapter-pg dotenv
```

Here's what each package does:

* **`prisma`** - The Prisma CLI for running commands like `prisma init`, `prisma migrate`, and `prisma generate`
* **`@prisma/client`** - The Prisma Client library for querying your database
* **`@prisma/adapter-pg`** - The [`node-postgres` driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters) that connects Prisma Client to your database
* **`dotenv`** - Loads environment variables from your `.env` file

## 3. Configure ESM support [#3-configure-esm-support]

Update `tsconfig.json` for ESM compatibility:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "ignoreDeprecations": "6.0"
  }
}
```

Update `package.json` to enable ESM:

```json title="package.json"
{
  "type": "module" // [!code ++]
}
```

## 4. Initialize Prisma ORM [#4-initialize-prisma-orm]

Next, set up your Prisma ORM project by creating your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) file with the following command:

  

#### bun

```bash
bunx --bun prisma init --output ../generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../generated/prisma
```

#### npm

```bash
npx prisma init --output ../generated/prisma
```

> [!NOTE]
> `prisma init` creates the Prisma scaffolding and a local `DATABASE_URL`. In the next step, replace that value with a direct `postgres://...` connection string from Prisma Postgres.

This command does a few things:

* Creates a `prisma/` directory with a `schema.prisma` file containing your database connection and schema models
* Creates a `.env` file in the root directory for environment variables
* Generates the Prisma Client in the `generated/prisma/` directory
* Creates a `prisma7.config.ts` file for Prisma configuration

The generated `prisma7.config.ts` file looks like this:

```typescript title="prisma7.config.ts"
// This file was generated by Prisma, and assumes you have installed the following:
// npm install --save-dev prisma dotenv
import "dotenv/config";
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env["DATABASE_URL"],
  },
});
```

> [!NOTE]
> Prisma ORM 7.10 and later name this file `prisma7.config.ts` so that it does not clash with the Prisma 8 config format, which only accepts `prisma.config.ts`. The Prisma 7 CLI discovers either name, so a project that already has a `prisma.config.ts` keeps working.

The generated schema uses [the ESM-first `prisma-client` generator](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#prisma-client) with a custom output path:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}
```

Create a Prisma Postgres database and replace the generated `DATABASE_URL` in your `.env` file with the `postgres://...` connection string from the CLI output:

  

#### bun

```bash
bunx create-db
```

#### pnpm

```bash
pnpm dlx create-db
```

#### yarn

```bash
yarn dlx create-db
```

#### npm

```bash
npx create-db
```

## 5. Define your data model [#5-define-your-data-model]

Open `prisma/schema.prisma` and add the following models:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
  authorId  Int // [!code ++]
} // [!code ++]
```

## 6. Create and apply your first migration [#6-create-and-apply-your-first-migration]

Create your first migration to set up the database tables:

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

This command creates the database tables based on your schema.

Now run the following command to generate the Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## 7. Instantiate Prisma Client [#7-instantiate-prisma-client]

Now that you have all the dependencies installed, you can instantiate Prisma Client. You need to pass an instance of the Prisma ORM driver adapter adapter to the `PrismaClient` constructor:

```typescript title="lib/prisma.ts"
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export { prisma };
```

> [!NOTE]
> If you need to query your database via HTTP from an edge runtime (Cloudflare Workers, Vercel Edge Functions, etc.), use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver#use-with-prisma-orm).

## 8. Write your first query [#8-write-your-first-query]

Create a `script.ts` file to test your setup:

```typescript title="script.ts"
import { prisma } from "./lib/prisma";

async function main() {
  // Create a new user with a post
  const user = await prisma.user.create({
    data: {
      name: "Alice",
      email: "alice@prisma.io",
      posts: {
        create: {
          title: "Hello World",
          content: "This is my first post!",
          published: true,
        },
      },
    },
    include: {
      posts: true,
    },
  });
  console.log("Created user:", user);

  // Fetch all users with their posts
  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
    },
  });
  console.log("All users:", JSON.stringify(allUsers, null, 2));
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Run the script:

  

#### bun

```bash
bunx tsx script.ts
```

#### pnpm

```bash
pnpm dlx tsx script.ts
```

#### yarn

```bash
yarn dlx tsx script.ts
```

#### npm

```bash
npx tsx script.ts
```

You should see the created user and all users printed to the console.

## 9. Explore your data with Prisma Studio [#9-explore-your-data-with-prisma-studio]

```shell
npx prisma studio
```

## Next steps [#next-steps]

Prisma ORM is set up. These are the pages you are most likely to need next:

* **Learn more about Prisma Client**: Explore the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) for advanced querying, filtering, and relations
* **Database migrations**: Learn about [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for evolving your database schema
* **Performance optimization**: Discover [query optimization techniques](https://www.prisma.io/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)
* **Build a full application**: Check out our [framework guides](https://www.prisma.io/docs/guides/v7) to integrate Prisma ORM with Next.js, Express, and more
* **Join the community**: Connect with other developers on [Discord](https://pris.ly/discord)

> [!NOTE]
> Deploy to Compute
> 
> To run this app in the cloud, deploy it to [Prisma Compute](https://www.prisma.io/docs/compute), which runs your app next to your Prisma Postgres database. Follow [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy).

## More info [#more-info]

* [Prisma Postgres documentation](https://www.prisma.io/docs/postgres)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
* [Database connection management](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections)

# Database drivers (Prisma ORM v7) (/docs/orm/v7/core-concepts/supported-databases/database-drivers)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how Prisma connects to your database using driver adapters

Location: ORM > v7 > Core Concepts > Supported databases > Database drivers

## Driver adapters [#driver-adapters]

Prisma Client can connect and run queries against your database using JavaScript database drivers via **driver adapters**. Adapters act as *translators* between Prisma Client and the JavaScript database driver.

Prisma Client will use the Query Engine to transform the Prisma Client query to SQL and run the generated SQL queries via the JavaScript database driver.

![Query flow from the user application to the database using Prisma Client and driver adapters](https://www.prisma.io/img/orm/core-concepts/databases/images/drivers/qe-query-engine-adapter.png)

There are two different types of driver adapters:

* [Database driver adapters](#database-driver-adapters)
* [Serverless driver adapters](#serverless-driver-adapters)

> **Note**: Driver adapters enable [edge deployments](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/overview) of applications that use Prisma ORM.

### Database driver adapters [#database-driver-adapters]

You can connect to your database using a Node.js-based driver from Prisma Client using a database driver adapter. Prisma maintains the adapters for the following drivers:

* PostgreSQL
  * [`pg`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters)
* Prisma Postgres
  * [`@prisma/adapter-ppg`](https://www.prisma.io/docs/postgres/database/serverless-driver#use-with-prisma-orm)
* MySQL/MariaDB
  * [`mariadb`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#using-driver-adapters)
* SQLite
  * [`better-sqlite3`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite#using-driver-adapters)
  * [`libSQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite#using-driver-adapters) (Turso)
* MS SQL Server
  * [`node-mssql`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server#using-driver-adapters)

### Serverless driver adapters [#serverless-driver-adapters]

Database providers, such as Neon and PlanetScale, allow you to connect to your database using other protocols besides TCP, such as HTTP and WebSockets. These database drivers are optimized for connecting to your database in serverless and edge environments.

Prisma ORM maintains the following serverless driver adapters:

* [Prisma Postgres](https://www.prisma.io/docs/postgres/database/serverless-driver#use-with-prisma-orm)
* [Neon](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#neon) (and Vercel Postgres)
* [PlanetScale](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale)
* [Cloudflare D1](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite#cloudflare-d1)

### Community-maintained database driver adapters [#community-maintained-database-driver-adapters]

You can also build your own driver adapter for the database you're using. The following is a list of community-maintained driver adapters:

* [TiDB Cloud Serverless Driver](https://github.com/tidbcloud/prisma-adapter)
* [PGlite - Postgres in WASM](https://github.com/lucasthevenet/pglite-utils/tree/main/packages/prisma-adapter)
* [prisma-sqlite-bun-adapter - SQLite on Bun](https://github.com/quinnjr/prisma-sqlite-bun-adapter)

## How to use driver adapters [#how-to-use-driver-adapters]

Refer to the following pages to learn more about how to use the specific driver adapters with the specific database providers:

* [PostgreSQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters)
* [Prisma Postgres](https://www.prisma.io/docs/postgres/database/serverless-driver#use-with-prisma-orm)
* [MySQL/MariaDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#using-driver-adapters)
* [MS SQL Server](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server#using-driver-adapters)
* [Neon](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#neon)
* [PlanetScale](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale)
* [Turso](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite#turso-libsql)
* [Cloudflare D1](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite#cloudflare-d1)
* [CockroachDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#cockroachdb)

## Notes about using driver adapters [#notes-about-using-driver-adapters]

### New driver adapters API in v6.6.0 [#new-driver-adapters-api-in-v660]

In [v6.6.0](https://github.com/prisma/orm/releases/tag/6.6.0), we introduced a simplified version for instantiating Prisma Client when using driver adapters. You now don't need to create an instance of the driver/client to pass to a driver adapter, instead you create the driver adapter directly (and pass the driver's options to it if needed).

Here is an example using the `@prisma/adapter-libsql` adapter:

#### Before 6.6.0 [#before-660]

Earlier versions of Prisma ORM required you to first instantiate the driver itself, and then use that instance to create the Prisma driver adapter. Here is an example using the `@libsql/client` driver for LibSQL:

```typescript
import { createClient } from "@libsql/client";
import { PrismaLibSQL } from "@prisma/adapter-libsql";
import { PrismaClient } from "../prisma/generated/client";

// Old way of using driver adapters (before 6.6.0)
const driver = createClient({
  url: env.LIBSQL_DATABASE_URL,
  authToken: env.LIBSQL_DATABASE_TOKEN,
});
const adapter = new PrismaLibSQL(driver);

const prisma = new PrismaClient({ adapter });
```

#### 6.6.0 and later [#660-and-later]

As of the 6.6.0 release, you instantiate the driver adapter *directly* with the options of your preferred JS-native driver.:

```typescript
import { PrismaLibSQL } from "@prisma/adapter-libsql";
import { PrismaClient } from "../generated/prisma/client";

const adapter = new PrismaLibSQL({
  url: env.LIBSQL_DATABASE_URL,
  authToken: env.LIBSQL_DATABASE_TOKEN,
});

const prisma = new PrismaClient({ adapter });
```

### Driver adapters and database connection configuration [#driver-adapters-and-database-connection-configuration]

In Prisma ORM 7, the database connection URL is configured in [`prisma.config.ts`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference). However, when using a driver adapter, the connection string needs to be provided in your *application code* when the driver adapter is set up initially.

Here is how this is done for the `pg` driver and the `@prisma/adapter-pg` adapter:

```ts
import "dotenv/config";
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
const prisma = new PrismaClient({ adapter });
```

See the docs for the driver adapter you're using for concrete setup instructions.

> [!NOTE]
> Tuning pool sizes, timeouts, or other connection parameters
> 
> See the [connection pool guide](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool) for the Prisma ORM v7 driver adapter defaults and how they map from Prisma ORM v6 URL parameters.

> [!NOTE]
> Prisma timeouts
> 
> Prisma ORM also has its own configurable timeouts that are separate from the database driver timeouts. If you see a timeout error and are unsure whether it comes from the driver or from Prisma Client, see the [Prisma Client timeouts and transaction options documentation](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#transaction-isolation-level).

### Driver adapters and custom output paths [#driver-adapters-and-custom-output-paths]

In Prisma ORM 7, the recommended approach is to use a custom output path for Prisma Client. The default output path is `../generated/prisma`.

For example, with `output` in your Prisma schema set to `../src/generated/prisma`:

```prisma
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}
```

You can reference Prisma Client using a relative path from your application code:

```ts
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
const client = new PrismaClient({ adapter });
```

Alternatively, you can use a linked dependency for cleaner imports.

  

#### bun

```bash
npm add db@./generated/prisma
# couldn't auto-convert command
```

#### pnpm

```bash
npm add db@./generated/prisma
# couldn't auto-convert command
```

#### yarn

```bash
npm add db@./generated/prisma
# couldn't auto-convert command
```

#### npm

```bash
npm add db@./generated/prisma
```

> [!NOTE]
> For pnpm, use `pnpm add db@link:./generated/prisma`. For yarn, use `yarn add db@link:./generated/prisma`.

You can now import your generated client from `db`:

```ts
import { PrismaClient } from "db";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
const client = new PrismaClient({ adapter });
```

### Driver adapters and specific frameworks [#driver-adapters-and-specific-frameworks]

#### Nuxt [#nuxt]

Using a driver adapter with [Nuxt](https://nuxt.com/) to deploy to an edge function environment does not work out of the box, but adding the `nitro.experimental.wasm` configuration option fixes that:

```ts
export default defineNuxtConfig({
  // ...
  nitro: {
    // ...
    experimental: {
      wasm: true,
    },
  },
  // ...
});
```

### Driver adapters and TypedSQL [#driver-adapters-and-typedsql]

[TypedSQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql) lets you write fully type-safe SQL queries that integrate directly with Prisma Client. This feature is useful if you want the flexibility of writing SQL while still benefiting from Prisma's type-safety.

You can also use driver adapters together with TypedSQL to connect through JavaScript database drivers. TypedSQL works with all supported driver adapters except `@prisma/adapter-better-sqlite3`. For SQLite support, use [`@prisma/adapter-libsql`](https://www.npmjs.com/package/@prisma/adapter-libsql) instead.

## Related pages

- [`MongoDB`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb): How Prisma ORM connects to MongoDB databases
- [`MySQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql): Use Prisma ORM with MySQL databases including self-hosted MySQL/MariaDB and serverless PlanetScale
- [`PostgreSQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql): Use Prisma ORM with PostgreSQL databases including self-hosted, serverless (Neon, Supabase), and CockroachDB
- [`SQL Server`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server): Use Prisma ORM with Microsoft SQL Server databases
- [`SQLite`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite): Use Prisma ORM with SQLite databases including local SQLite, Turso (libSQL), and Cloudflare D1

# Overview (Prisma ORM v7) (/docs/orm/v7/core-concepts/supported-databases)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma ORM supports PostgreSQL, MySQL, SQLite, MongoDB, SQL Server, CockroachDB, and serverless databases

Location: ORM > v7 > Core Concepts > Overview

## Database versions [#database-versions]

### Self-hosted [#self-hosted]

| Database                                                            | Version |
| ------------------------------------------------------------------- | ------- |
| [PostgreSQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql)  | 9.6+    |
| [MySQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql)            | 5.6+    |
| [MariaDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql)          | 10.0+   |
| [SQL Server](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server)  | 2017+   |
| [SQLite](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite)          | All     |
| [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb)        | 4.2+    |
| [CockroachDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql) | 21.2.4+ |

### Managed/Serverless [#managedserverless]

| Database                | Notes               |
| ----------------------- | ------------------- |
| Neon                    | Serverless Postgres |
| Supabase                | Postgres            |
| PlanetScale             | MySQL               |
| Turso                   | libSQL (SQLite)     |
| Cloudflare D1 (Preview) | SQLite              |
| AWS Aurora              | MySQL/Postgres      |
| MongoDB Atlas           | MongoDB             |

## Feature matrix [#feature-matrix]

### Constraints [#constraints]

| Feature     | PostgreSQL | MySQL | SQLite | SQL Server | MongoDB |
| ----------- | :--------: | :---: | :----: | :--------: | :-----: |
| PRIMARY KEY |     ✔️     |   ✔️  |   ✔️   |     ✔️     |    ✔️   |
| FOREIGN KEY |     ✔️     |   ✔️  |   ✔️   |     ✔️     |    —    |
| UNIQUE      |     ✔️     |   ✔️  |   ✔️   |    ✔️\*    |    ✔️   |
| NOT NULL    |     ✔️     |   ✔️  |   ✔️   |     ✔️     |    ✔️   |
| DEFAULT     |     ✔️     |   ✔️  |   ✔️   |     ✔️     |    ✔️   |

\*SQL Server has [limitations with UNIQUE constraints](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server#common-considerations)

### Data types [#data-types]

| Feature | PostgreSQL | MySQL | SQLite | SQL Server | MongoDB |
| ------- | :--------: | :---: | :----: | :--------: | :-----: |
| Arrays  |     ✔️     |   —   |    —   |      —     |    ✔️   |
| JSON    |     ✔️     |   ✔️  |   ✔️   |     ✔️     |    ✔️   |
| Enums   |     ✔️     |   ✔️  |   ✔️   |      —     |    ✔️   |

## Database guides [#database-guides]

* [PostgreSQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql) — Self-hosted, Neon, Supabase, and CockroachDB
* [MySQL/MariaDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql) — Self-hosted and PlanetScale
* [SQLite](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite) — Local, Turso, and Cloudflare D1
* [SQL Server](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server)
* [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb)

### Driver adapters [#driver-adapters]

For custom database drivers, see [Driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

## Related pages

- [`API patterns`](https://www.prisma.io/docs/orm/v7/core-concepts/api-patterns): How to use Prisma ORM with REST APIs, GraphQL servers, and fullstack frameworks
- [`Data modeling`](https://www.prisma.io/docs/orm/v7/core-concepts/data-modeling): Learn how data modeling with Prisma differs from data modeling with SQL or ORMs. Prisma uses a declarative data modeling language to describe a database schema

# MongoDB (Prisma ORM v7) (/docs/orm/v7/core-concepts/supported-databases/mongodb)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How Prisma ORM connects to MongoDB databases

Location: ORM > v7 > Core Concepts > Supported databases > MongoDB

This guide discusses the concepts behind using Prisma ORM and MongoDB, explains the commonalities and differences between MongoDB and other database providers, and leads you through the process for configuring your application to integrate with MongoDB using Prisma ORM.

> [!WARNING]
> MongoDB support for Prisma ORM v7
> 
> **MongoDB support for Prisma ORM v7 is coming in the near future.** In the meantime, please use **Prisma ORM v6.19** (the latest v6 release) when working with MongoDB.
> 
> For getting started guides using Prisma ORM v6.19 with MongoDB, see:
> 
> * [Quickstart with MongoDB](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mongodb)
> * [Add to existing MongoDB project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mongodb)

## What is MongoDB? [#what-is-mongodb]

[MongoDB](https://www.mongodb.com/) is a NoSQL database that stores data in [BSON](https://bsonspec.org/) format, a JSON-like document format designed for storing data in key-value pairs. It is commonly used in JavaScript application development because the document model maps easily to objects in application code, and there is built in support for high availability and horizontal scaling.

MongoDB stores data in collections that do not need a schema to be defined in advance, as you would need to do with tables in a relational database. The structure of each collection can also be changed over time. This flexibility can allow rapid iteration of your data model, but it does mean that there are a number of differences when using Prisma ORM to work with your MongoDB database.

## Commonalities with other database providers [#commonalities-with-other-database-providers]

Some aspects of using Prisma ORM with MongoDB are the same as when using Prisma ORM with a relational database. You can still:

* model your database with the [Prisma Schema Language](https://www.prisma.io/docs/orm/v7/prisma-schema/overview)
* connect to your database, using the [`mongodb` database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases)
* use [Introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) for existing projects if you already have a MongoDB database
* use [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) to push changes in your schema to the database
* use [Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) in your application to query your database in a type safe way based on your Prisma Schema

## Differences to consider [#differences-to-consider]

MongoDB's document-based structure and flexible schema means that using Prisma ORM with MongoDB differs from using it with a relational database in a number of ways. These are some areas where there are differences that you need to be aware of:

* **Defining IDs**: MongoDB documents have an `_id` field (that often contains an [ObjectID](https://www.mongodb.com/docs/manual/reference/bson-types/#std-label-objectid)). Prisma ORM does not support fields starting with `_`, so this needs to be mapped to a Prisma ORM field using the `@map` attribute. For more information, see [Defining IDs in MongoDB](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-ids-in-mongodb).

* **Migrating existing data to match your Prisma schema**: In relational databases, all your data must match your schema. If you change the type of a particular field in your schema when you migrate, all the data must also be updated to match. In contrast, MongoDB does not enforce any particular schema, so you need to take care when migrating. For more information, see [How to migrate old data to new schemas](#how-to-migrate-existing-data-to-match-your-prisma-schema).

* **Introspection and Prisma ORM relations**: When you introspect an existing MongoDB database, you will get a schema with no relations and will need to add the missing relations in manually. For more information, see [How to add in missing relations after Introspection](#how-to-add-in-missing-relations-after-introspection).

* **Filtering for `null` and missing fields**: MongoDB makes a distinction between setting a field to `null` and not setting it at all, which is not present in relational databases. Prisma ORM currently does not express this distinction, which means that you need to be careful when filtering for `null` and missing fields. For more information, see [How to filter for `null` and missing fields](#how-to-filter-for-null-and-missing-fields)

* **Enabling replication**: Prisma ORM uses [MongoDB transactions](https://www.mongodb.com/docs/manual/core/transactions/) internally to avoid partial writes on nested queries. When using transactions, MongoDB requires replication of your data set to be enabled. To do this, you will need to configure a [replica set](https://www.mongodb.com/docs/manual/replication/) — this is a group of MongoDB processes that maintain the same data set. Note that it is still possible to use a single database, by creating a replica set with only one node in it. If you use MongoDB's [Atlas](https://www.mongodb.com/atlas/database) hosting service, the replica set is configured for you, but if you are running MongoDB locally you will need to set up a replica set yourself. For more information, see MongoDB's [guide to deploying a replica set](https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set/).

### Performance considerations for large collections [#performance-considerations-for-large-collections]

#### Problem [#problem]

When working with large MongoDB collections through Prisma, certain operations can become slow and resource-intensive. In particular, operations that require scanning the entire collection, such as `count()`, can hit query execution time limits and significantly impact performance as your dataset grows.

#### Solution [#solution]

To address performance issues with large MongoDB collections, consider the following approaches:

1. For large collections, consider using MongoDB's `estimatedDocumentCount()` instead of `count()`. This method is much faster as it uses metadata about the collection. You can use Prisma's `runCommandRaw` method to execute this command.

2. For frequently accessed counts, consider implementing a counter cache. This involves maintaining a separate document with pre-calculated counts that you update whenever documents are added or removed.

## How to use Prisma ORM with MongoDB [#how-to-use-prisma-orm-with-mongodb]

This section provides instructions for how to carry out tasks that require steps specific to MongoDB.

### How to migrate existing data to match your Prisma schema [#how-to-migrate-existing-data-to-match-your-prisma-schema]

Migrating your database over time is an important part of the development cycle. During development, you will need to update your Prisma schema (for example, to add new fields), then update the data in your development environment’s database, and eventually push both the updated schema and the new data to the production database.

These iterative tasks of updating the schema and the database can result in inconsistencies between your schema and the actual data in the database. The following scenario shows one way this can happen, followed by several strategies you and your team can use to handle these inconsistencies.

**Scenario**: you need to include a phone number for users, as well as an email. You currently have the following `User` model in your `schema.prisma` file:

```prisma title="prisma/schema.prisma" showLineNumbers
model User {
  id    String @id @default(auto()) @map("_id") @db.ObjectId
  email String
}
```

There are a number of strategies you could use for migrating this schema:

* **"On-demand" updates**: with this strategy, you and your team have agreed that updates can be made to the schema as needed. However, in order to avoid migration failures due to inconsistencies between the data and schema, there is agreement in the team that any new fields added are explicitly defined as optional.

  In our scenario above, you can add an optional `phoneNumber` field to the `User` model in your Prisma schema:

  ```prisma title="prisma/schema.prisma" highlight=4;add showLineNumbers
  model User {
    id          String  @id @default(auto()) @map("_id") @db.ObjectId
    email       String
    phoneNumber String? // [!code ++]
  }
  ```

  Then regenerate your Prisma Client using the `npx prisma generate` command.

  Next, update your application to reflect the new field, and redeploy your app.

  As the `phoneNumber` field is optional, you can still query the old users where the phone number has not been defined. The records in the database will be updated "on demand" as the application's users begin to enter their phone number in the new field.

  Another option is to add a default value on a required field, for example:

  ```prisma title="prisma/schema.prisma" highlight=4;add showLineNumbers
  model User {
    id          String @id @default(auto()) @map("_id") @db.ObjectId
    email       String
    phoneNumber String @default("000-000-0000") // [!code ++]
  }
  ```

  Then when you encounter a missing `phoneNumber`, the value will be coerced into `000-000-0000`.

* **"No breaking changes" updates**: this strategy builds on the first one, with further consensus amongst your team that you don't rename or delete fields, only add new fields, and always define the new fields as optional. This policy can be reinforced by adding checks in the CI/CD process to verify that there are no backwards-incompatible changes to the schema.

* **"All-at-once" updates**: this strategy is similar to traditional migrations in relational databases, where all data is updated to reflect the new schema. In the scenario above, you would create a script to add a value for the phone number field to all existing users in your database. You can then make the field a required field in the application because the schema and the data are consistent.

### How to add in missing relations after Introspection [#how-to-add-in-missing-relations-after-introspection]

After introspecting an existing MongoDB database, you will need to manually add in relations between models. MongoDB does not have the concept of defining relations via foreign keys, as you would in a relational database. However, if you have a collection in MongoDB with a "foreign-key-like" field that matches the ID field of another collection, Prisma ORM will allow you to emulate relations between the collections.

As an example, take a MongoDB database with two collections, `User` and `Post`. The data in these collections has the following format, with a `userId` field linking users to posts:

`User` collection:

* `_id` field with a type of `objectId`
* `email` field with a type of `string`

`Post` collection:

* `_id` field with a type of `objectId`
* `title` field with a type of `string`
* `userId` with a type of `objectID`

On introspection with `db pull`, this is pulled in to the Prisma Schema as follows:

```prisma title="prisma/schema.prisma" showLineNumbers
model Post {
  id     String @id @default(auto()) @map("_id") @db.ObjectId
  title  String
  userId String @db.ObjectId
}

model User {
  id    String @id @default(auto()) @map("_id") @db.ObjectId
  email String
}
```

This is missing the relation between the `User` and `Post` models. To fix this, manually add a `user` field to the `Post` model with a `@relation` attribute using `userId` as the `fields` value, linking it to the `User` model, and a `posts` field to the `User` model as the back relation:

```prisma title="prisma/schema.prisma" highlight=5;add|11;add showLineNumbers
model Post {
  id     String @id @default(auto()) @map("_id") @db.ObjectId
  title  String
  userId String @db.ObjectId
  user   User   @relation(fields: [userId], references: [id]) // [!code ++]
}

model User {
  id    String @id @default(auto()) @map("_id") @db.ObjectId
  email String
  posts Post[] // [!code ++]
}
```

For more information on how to use relations in Prisma ORM, see [our documentation](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations).

### How to filter for `null` and missing fields [#how-to-filter-for-null-and-missing-fields]

To understand how MongoDB distinguishes between `null` and missing fields, consider the example of a `User` model with an optional `name` field:

```ts
model User {
  id    String  @id @default(auto()) @map("_id") @db.ObjectId
  email String
  name  String?
}
```

First, try creating a record with the `name` field explicitly set to `null`. Prisma ORM will return `name: null` as expected:

```ts
const createNull = await prisma.user.create({
  data: {
    email: "user1@prisma.io",
    name: null,
  },
});
console.log(createNull);
```

```text no-copy
{
  id: '6242c4ae032bc76da250b207',
  email: 'user1@prisma.io',
  name: null
}
```

If you check your MongoDB database directly, you will also see a new record with `name` set to `null`:

```json
{
  "_id": "6242c4af032bc76da250b207",
  "email": "user1@prisma.io",
  "name": null
}
```

Next, try creating a record without explicitly setting the `name` field:

```ts
const createMissing = await prisma.user.create({
  data: {
    email: "user2@prisma.io",
  },
});
console.log(createMissing);
```

```text no-copy
{
  id: '6242c4ae032bc76da250b208',
  email: 'user2@prisma.io',
  name: null
}
```

Prisma ORM still returns `name: null`, but if you look in the database directly you will see that the record has no `name` field defined at all:

```json
{
  "_id": "6242c4af032bc76da250b208",
  "email": "user2@prisma.io"
}
```

Prisma ORM returns the same result in both cases, because we currently don't have a way to specify this difference in MongoDB between fields that are `null` in the underlying database, and fields that are not defined at all — see [this Github issue](https://github.com/prisma/orm/issues/12555) for more information.

This means that you currently have to be careful when filtering for `null` and missing fields. Filtering for records with `name: null` will only return the first record, with the `name` explicitly set to `null`:

```ts
const findNulls = await prisma.user.findMany({
  where: {
    name: null,
  },
});
console.log(findNulls);
```

```bash no-copy
[
  {
    id: '6242c4ae032bc76da250b207',
    email: 'user1@prisma.io',
    name: null
  }
]
```

This is because `name: null` is checking for equality, and a non-existing field isn't equal to `null`.

To include missing fields as well, use the [`isSet` filter](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#isset) to explicitly search for fields which are either `null` or not set. This will return both records:

```ts
const findNullOrMissing = await prisma.user.findMany({
  where: {
    OR: [
      {
        name: null,
      },
      {
        name: {
          isSet: false,
        },
      },
    ],
  },
});
console.log(findNullOrMissing);
```

```bash no-copy
[
  {
    id: '6242c4ae032bc76da250b207',
    email: 'user1@prisma.io',
    name: null
  },
  {
    id: '6242c4ae032bc76da250b208',
    email: 'user2@prisma.io',
    name: null
  }
]
```

## More on using MongoDB with Prisma ORM [#more-on-using-mongodb-with-prisma-orm]

The fastest way to start using MongoDB with Prisma ORM is to refer to our Getting Started documentation:

* [Start from scratch](https://www.prisma.io/docs/v7/prisma-orm/quickstart/mongodb)
* [Add to existing project](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/mongodb)

These tutorials will take you through the process of connecting to MongoDB, pushing schema changes, and using Prisma Client.

Further reference information is available in the [MongoDB connector documentation](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

For more information on how to set up and manage a MongoDB database, see the [Prisma Data Guide](https://www.prisma.io/dataguide#mongodb).

## Example [#example]

To connect to a MongoDB server, configure the [`datasource`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/data-sources) block in your [Prisma Schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview):

```prisma title="schema.prisma" showLineNumbers
datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}
```

The fields passed to the `datasource` block are:

* `provider`: Specifies the `mongodb` data source connector.
* `url`: Specifies the [connection URL](#connection-url) for the MongoDB server. In this case, an [environment variable is used](https://www.prisma.io/docs/orm/v7/more/dev-environment/environment-variables) to provide the connection URL.

> [!WARNING]
> The MongoDB database connector uses transactions to support nested writes. Transactions **require** a [replica set](https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set/) deployment. The quickest way to get a replica set is [Atlas](https://www.mongodb.com/docs/atlas/getting-started/), which configures one for you and has a free tier.

## Connection details [#connection-details]

### Connection URL [#connection-url]

The MongoDB connection URL can be configured in different ways depending on how you are hosting your database. The standard configuration is made up of the following components:

![Structure of the MongoDB connection URL](https://www.prisma.io/img/orm/core-concepts/databases/mongodb.png)

#### Base URL and path [#base-url-and-path]

The base URL and path sections of the connection URL are made up of your authentication credentials followed by the host (and optionally, a port number) and database.

```
mongodb://USERNAME:PASSWORD@HOST/DATABASE
```

The following components make up the *base URL* of your database:

| Name     | Placeholder | Description                                                                                                                                                                                                                                                                                                                                                        |
| :------- | :---------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| User     | `USERNAME`  | Name of your database user, e.g. `janedoe`                                                                                                                                                                                                                                                                                                                         |
| Password | `PASSWORD`  | Password for your database user                                                                                                                                                                                                                                                                                                                                    |
| Host     | `HOST`      | The host where a [`mongod`](https://www.mongodb.com/docs/manual/reference/program/mongod/#mongodb-binary-bin.mongod) instance is running. If you are running a sharded cluster this will a [`mongos`](https://www.mongodb.com/docs/manual/reference/program/mongos/#mongodb-binary-bin.mongos) instance. This can be a hostname, IP address or UNIX domain socket. |
| Port     | `PORT`      | Port on which your database server is running, e.g. `1234`. If none is provided the default `27017` is used.                                                                                                                                                                                                                                                       |
| Database | `DATABASE`  | Name of the database to use. If none is specified but the `authSource` option is set then the `authSource` database name is used. If neither the database in the connection string nor the `authSource` option is specified then it defaults to `admin`                                                                                                            |

> [!NOTE]
> You must [percentage-encode special characters](https://www.prisma.io/docs/orm/v7/reference/connection-urls#special-characters).

#### Arguments [#arguments]

A connection URL can also take arguments. The following example sets three arguments:

* An `ssl` connection
* A `connectTimeoutMS`
* And the `maxPoolSize`

```
mongodb://USERNAME:PASSWORD@HOST/DATABASE?ssl=true&connectTimeoutMS=5000&maxPoolSize=50
```

Refer to the [MongoDB connection string documentation](https://www.mongodb.com/docs/manual/reference/connection-string/) for a complete list of connection string arguments. There are no Prisma ORM-specific arguments.

## Using `ObjectId` [#using-objectid]

It is common practice for the `_id` field of a MongoDB document to contain an [ObjectId](https://www.mongodb.com/docs/manual/reference/bson-types/#std-label-objectid):

```json
{
  "_id": { "$oid": "60d599cb001ef98000f2cad2" },
  "createdAt": { "$date": { "$numberLong": "1624611275577" } },
  "email": "ella@prisma.io",
  "name": "Ella",
  "role": "ADMIN"
}
```

Any field (most commonly IDs and relation scalar fields) that maps to an `ObjectId` in the underlying database:

* Must be of type `String` or `Bytes`
* Must include the `@db.ObjectId` attribute
* Can optionally use `@default(auto())` to auto-generate a valid `ObjectId` on document creation

Here is an example that uses `String`:

```prisma
model User {
  id String @id @default(auto()) @map("_id") @db.ObjectId
  // Other fields
}
```

And here is another example that uses `Bytes`:

```prisma
model User {
  id Bytes @id @default(auto()) @map("_id") @db.ObjectId
  // Other fields
}
```

See also: [Defining ID fields in MongoDB](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-ids-in-mongodb)

### Generating `ObjectId` [#generating-objectid]

To generate a valid `ObjectId` (for testing purposes or to manually set an ID field value) in your application, use the [`bson`](https://www.npmjs.com/package/bson) package.

  

#### bun

```bash
bun add bson
```

#### pnpm

```bash
pnpm add bson
```

#### yarn

```bash
yarn add bson
```

#### npm

```bash
npm install --save bson
```

```ts
import { ObjectId } from "bson";

const id = new ObjectId();
```

## Differences to connectors for relational databases [#differences-to-connectors-for-relational-databases]

This section covers ways in which the MongoDB connector differs from Prisma ORM connectors for relational databases.

### No support for Prisma Migrate [#no-support-for-prisma-migrate]

Currently, there are no plans to add support for [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) as MongoDB projects do not rely on internal schemas where changes need to be managed with an extra tool. Management of `@unique` indexes is realized through `db push`.

### No support for `@@id` and `autoincrement()` [#no-support-for-id-and-autoincrement]

The [`@@id`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) attribute (an ID for multiple fields) is not supported because primary keys in MongoDB are always on the `_id` field of a model.

The [`autoincrement()`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#generate-autoincrementing-integers-as-ids-relational-databases-only) function (which creates incrementing `@id` values) is not supported because `autoincrement()` does not work with the `ObjectID` type that the `_id` field has in MongoDB.

### Cyclic references and referential actions [#cyclic-references-and-referential-actions]

If you have cyclic references in your models, either from self-relations or a cycle of relations between models, and you use [referential actions](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions), you must set a referential action of `NoAction` to prevent an infinite loop of actions.

See [Special rules for referential actions](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions#special-rules-for-sql-server-and-mongodb) for more details.

### Replica set configuration [#replica-set-configuration]

MongoDB only allows you to start a transaction on a replica set. Prisma ORM uses transactions internally to avoid partial writes on nested queries. This means we inherit the requirement of needing a replica set configured.

When you try to use Prisma ORM's MongoDB connector on a deployment that has no replica set configured, Prisma ORM shows the message `Error: Transactions are not supported by this deployment`. The full text of the error message is the following:

```
PrismaClientUnknownRequestError2 [PrismaClientUnknownRequestError]:
Invalid `prisma.post.create()` invocation in
/index.ts:9:21

   6 await prisma.$connect()
   7
   8 // Create the first post
→  9 await prisma.post.create(
  Error in connector: Database error. error code: unknown, error message: Transactions are not supported by this deployment
    at cb (/node_modules/@prisma/client/runtime/index.js:34804:17)
    at processTicksAndRejections (internal/process/task_queues.js:97:5) {
  clientVersion: '3.xx.0'
}
```

To resolve this, we suggest you change your deployment to one with a replica set configured.

One option is to use [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) to launch a free instance, which comes with a replica set already configured.

There's also an option to run the replica set locally with this guide: [https://www.mongodb.com/docs/manual/tutorial/convert-standalone-to-replica-set](https://www.mongodb.com/docs/manual/tutorial/convert-standalone-to-replica-set)

## Type mapping between MongoDB and the Prisma schema [#type-mapping-between-mongodb-and-the-prisma-schema]

The MongoDB connector maps the [scalar types](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#scalar-fields) from the Prisma ORM [data model](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models) to MongoDB's native column types as follows:

> Alternatively, see [Prisma schema reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) for type mappings organized by Prisma type.

### Native type mapping from Prisma ORM to MongoDB [#native-type-mapping-from-prisma-orm-to-mongodb]

| Prisma ORM | MongoDB                                                             |
| ---------- | ------------------------------------------------------------------- |
| `String`   | `string`                                                            |
| `Boolean`  | `bool`                                                              |
| `Int`      | `int`                                                               |
| `BigInt`   | `long`                                                              |
| `Float`    | `double`                                                            |
| `Decimal`  | [Currently unsupported](https://github.com/prisma/orm/issues/12637) |
| `DateTime` | `timestamp`                                                         |
| `Bytes`    | `binData`                                                           |
| `Json`     |                                                                     |

MongoDB types that are currently unsupported:

* `Decimal128`
* `Undefined`
* `DBPointer`
* `Null`
* `Symbol`
* `MinKey`
* `MaxKey`
* `Object`
* `Javascript`
* `JavascriptWithScope`
* `Regex`

### Mapping from MongoDB to Prisma ORM types on Introspection [#mapping-from-mongodb-to-prisma-orm-types-on-introspection]

When introspecting a MongoDB database, Prisma ORM uses the relevant [scalar types](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#scalar-fields). Some special types also get additional native type annotations:

| MongoDB (Type \| Aliases) | Prisma ORM | Supported | Native database type attribute | Notes |
| ------------------------- | ---------- | :-------: | :----------------------------- | :---- |
| `objectId`                | `String`   |     ✔️    | `@db.ObjectId`                 |       |

[Introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) adds native database types that are **not yet supported** as [`Unsupported`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#unsupported) fields:

```prisma title="schema.prisma" showLineNumbers
model Example {
  id    String                           @id @default(auto()) @map("_id") @db.ObjectId
  name  String
  regex Unsupported("RegularExpression")
}
```

## Related pages

- [`Database drivers`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers): Learn how Prisma connects to your database using driver adapters
- [`MySQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql): Use Prisma ORM with MySQL databases including self-hosted MySQL/MariaDB and serverless PlanetScale
- [`PostgreSQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql): Use Prisma ORM with PostgreSQL databases including self-hosted, serverless (Neon, Supabase), and CockroachDB
- [`SQL Server`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server): Use Prisma ORM with Microsoft SQL Server databases
- [`SQLite`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite): Use Prisma ORM with SQLite databases including local SQLite, Turso (libSQL), and Cloudflare D1

# MySQL (Prisma ORM v7) (/docs/orm/v7/core-concepts/supported-databases/mysql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Use Prisma ORM with MySQL databases including self-hosted MySQL/MariaDB and serverless PlanetScale

Location: ORM > v7 > Core Concepts > Supported databases > MySQL

Prisma ORM supports MySQL and MariaDB databases, including self-hosted servers and serverless PlanetScale.

## Setup [#setup]

Configure the MySQL provider in your Prisma schema:

```prisma title="schema.prisma"
datasource db {
  provider = "mysql"
}
```

**Self-hosted MySQL/MariaDB:**

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"), // mysql://user:pass@host:3306/db
  },
});
```

**PlanetScale:**

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"), // Uses connection string from PlanetScale
  },
});
```

## Using driver adapters [#using-driver-adapters]

Use JavaScript database drivers via [driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers#driver-adapters):

**With `mariadb` driver:**

  

#### bun

```bash
bun add @prisma/adapter-mariadb
```

#### pnpm

```bash
pnpm add @prisma/adapter-mariadb
```

#### yarn

```bash
yarn add @prisma/adapter-mariadb
```

#### npm

```bash
npm install @prisma/adapter-mariadb
```

```ts
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
import { PrismaClient } from "./generated/prisma";

const adapter = new PrismaMariaDb({
  host: "localhost",
  port: 3306,
  connectionLimit: 5,
});
const prisma = new PrismaClient({ adapter });
```

**PlanetScale serverless:**

  

#### bun

```bash
bun add @prisma/adapter-planetscale undici
```

#### pnpm

```bash
pnpm add @prisma/adapter-planetscale undici
```

#### yarn

```bash
yarn add @prisma/adapter-planetscale undici
```

#### npm

```bash
npm install @prisma/adapter-planetscale undici
```

```ts
import { PrismaPlanetScale } from "@prisma/adapter-planetscale";
import { PrismaClient } from "./generated/prisma";
import { fetch as undiciFetch } from "undici"; // Only for Node.js <18

const adapter = new PrismaPlanetScale({
  url: process.env.DATABASE_URL,
  fetch: undiciFetch,
});
const prisma = new PrismaClient({ adapter });
```

## Supported variants [#supported-variants]

### Self-hosted MySQL/MariaDB [#self-hosted-mysqlmariadb]

Standard MySQL (5.6+) or MariaDB (10.0+) servers.

* Connection URL: `mysql://user:pass@host:3306/database`
* Full Prisma Migrate support
* Use `prisma migrate dev` for development
* Both MySQL and MariaDB use the same `mysql` provider

**Connection string arguments:**

| Argument          | Default                | Description                    |
| ----------------- | ---------------------- | ------------------------------ |
| `connect_timeout` | `5`                    | Seconds to wait for connection |
| `sslcert`         |                        | Path to server certificate     |
| `sslidentity`     |                        | Path to PKCS12 certificate     |
| `sslaccept`       | `accept_invalid_certs` | Certificate validation mode    |

### PlanetScale [#planetscale]

Serverless MySQL-compatible database built on Vitess clustering system.

* Connection URL: Update host to `aws.connect.psdb.cloud`
* Uses Vitess for horizontal scaling
* Database branching workflow (development/production branches)
* Non-blocking schema changes

**Key features:**

* Enterprise scalability across multiple servers
* Database branches for schema testing
* Non-blocking schema deployments
* Serverless-optimized (avoids connection limits)

**Branch workflow:**

1. **Development branches** - Test schema changes freely
2. **Production branches** - Protected, require deploy requests
3. **Deploy requests** - Merge dev changes to production

**Schema changes:**

Use `prisma db push` (not `prisma migrate`):

  

#### bun

```bash
bunx prisma db push
```

#### pnpm

```bash
pnpm prisma db push
```

#### yarn

```bash
yarn prisma db push
```

#### npm

```bash
npx prisma db push
```

PlanetScale generates its own schema diff when merging branches.

**Referential integrity options:**

**Option 1: Emulate relations (recommended for default PlanetScale)**

Set `relationMode = "prisma"` to handle relations in Prisma Client:

```prisma title="schema.prisma"
datasource db {
  provider     = "mysql"
  relationMode = "prisma"
}
```

Add indexes on foreign keys manually:

```prisma
model Post {
  id       Int       @id @default(autoincrement())
  title    String
  comments Comment[]
}

model Comment {
  id     Int    @id @default(autoincrement())
  postId Int
  post   Post   @relation(fields: [postId], references: [id])

  @@index([postId]) // Required when using relationMode = "prisma"
}
```

**Option 2: Enable foreign key constraints**

[Enable foreign key constraints](https://planetscale.com/docs/concepts/foreign-key-constraints) in PlanetScale settings to use standard relations without `relationMode = "prisma"`.

**Resources:** [PlanetScale docs](https://planetscale.com/docs) • [Prisma integration](https://planetscale.com/docs/prisma/automatic-prisma-migrations)

## Type mappings [#type-mappings]

### Type mapping between MySQL and Prisma schema [#type-mapping-between-mysql-and-prisma-schema]

| Prisma     | MySQL/MariaDB    |
| ---------- | ---------------- |
| `String`   | `VARCHAR(191)`   |
| `Boolean`  | `TINYINT(1)`     |
| `Int`      | `INT`            |
| `BigInt`   | `BIGINT`         |
| `Float`    | `DOUBLE`         |
| `Decimal`  | `DECIMAL(65,30)` |
| `DateTime` | `DATETIME(3)`    |
| `Json`     | `JSON`           |
| `Bytes`    | `LONGBLOB`       |

See [full type mapping reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) for complete details.

## Common patterns [#common-patterns]

**SSL connections:**

```bash
DATABASE_URL="mysql://user:pass@host:3306/db?sslcert=./cert.pem&sslaccept=strict"
```

**Unix socket connections:**

```bash
DATABASE_URL="mysql://user:pass@localhost/db?socket=/var/run/mysqld/mysqld.sock"
```

**PlanetScale sharding (Preview):**

Define shard keys in your schema:

```prisma
generator client {
  provider        = "prisma-client"
  output          = "./generated/prisma"
  previewFeatures = ["shardKeys"]
}

model User {
  id     String @default(uuid())
  region String @shardKey
}
```

**Connection troubleshooting:**

PlanetScale production branches are read-only for direct DDL. If you get error P3022, ensure you're:

* Using `prisma db push` instead of `prisma migrate`
* Working on a development branch, or
* Using a deploy request to update production

## Related pages

- [`Database drivers`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers): Learn how Prisma connects to your database using driver adapters
- [`MongoDB`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb): How Prisma ORM connects to MongoDB databases
- [`PostgreSQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql): Use Prisma ORM with PostgreSQL databases including self-hosted, serverless (Neon, Supabase), and CockroachDB
- [`SQL Server`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server): Use Prisma ORM with Microsoft SQL Server databases
- [`SQLite`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite): Use Prisma ORM with SQLite databases including local SQLite, Turso (libSQL), and Cloudflare D1

# PostgreSQL (Prisma ORM v7) (/docs/orm/v7/core-concepts/supported-databases/postgresql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Use Prisma ORM with PostgreSQL databases including self-hosted, serverless (Neon, Supabase), and CockroachDB

Location: ORM > v7 > Core Concepts > Supported databases > PostgreSQL

Prisma ORM supports PostgreSQL and PostgreSQL-compatible databases including self-hosted PostgreSQL, serverless providers (Neon, Supabase), and CockroachDB.

## Setup [#setup]

Configure the provider in your Prisma schema:

```prisma title="schema.prisma"
datasource db {
  provider = "postgresql" // or "cockroachdb" for CockroachDB
}
```

**Self-hosted PostgreSQL:**

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"), // postgres://user:pass@host:5432/db
  },
});
```

**Serverless (Neon/Supabase):**

Use separate URLs for CLI (direct) and runtime (pooled):

```text title=".env"
DATABASE_URL="postgres://user:pass@host-pooler:6543/db?pgbouncer=true"
DIRECT_URL="postgres://user:pass@host:5432/db"
```

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DIRECT_URL"), // CLI uses direct connection
  },
});
```

## Using driver adapters [#using-driver-adapters]

Use JavaScript database drivers via [driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers#driver-adapters):

**Standard PostgreSQL with `pg`:**

  

#### bun

```bash
bun add @prisma/adapter-pg
```

#### pnpm

```bash
pnpm add @prisma/adapter-pg
```

#### yarn

```bash
yarn add @prisma/adapter-pg
```

#### npm

```bash
npm install @prisma/adapter-pg
```

```ts
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "./generated/prisma";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
const prisma = new PrismaClient({ adapter });
```

`DATABASE_URL` has to be set in the process environment when this code runs. Node.js does not read `.env` files on its own, so install `dotenv` and add `import "dotenv/config";` at the top of your entry file, or start Node with its [`--env-file`](https://nodejs.org/api/cli.html#--env-filefile) flag. If the variable is missing, `pg` gets no connection string and falls back to its defaults, and the usual symptom is `SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string`.

**Neon serverless:**

  

#### bun

```bash
bun add @prisma/adapter-neon
```

#### pnpm

```bash
pnpm add @prisma/adapter-neon
```

#### yarn

```bash
yarn add @prisma/adapter-neon
```

#### npm

```bash
npm install @prisma/adapter-neon
```

```ts
import { PrismaNeon } from "@prisma/adapter-neon";
import { PrismaClient } from "./generated/prisma";

const adapter = new PrismaNeon({ connectionString: process.env.DATABASE_URL });
const prisma = new PrismaClient({ adapter });
```

## Supported variants [#supported-variants]

### Self-hosted PostgreSQL [#self-hosted-postgresql]

Standard PostgreSQL server (9.6+).

* Connection URL: `postgresql://user:pass@host:5432/database`
* Full Prisma Migrate support
* Use `prisma migrate dev` for development
* TLS/SSL configuration via connection string parameters

**Connection string arguments:**

| Argument          | Default  | Description                                     |
| ----------------- | -------- | ----------------------------------------------- |
| `schema`          | `public` | PostgreSQL schema to use                        |
| `connect_timeout` | `5`      | Seconds to wait for connection (0 = no timeout) |
| `sslmode`         | `prefer` | TLS mode: `prefer`, `disable`, `require`        |
| `sslcert`         |          | Path to server certificate                      |
| `sslidentity`     |          | Path to PKCS12 certificate                      |

### Neon [#neon]

Serverless PostgreSQL with automatic scaling and branching.

* Connection URL: `postgres://user:pass@host-pooler.region.aws.neon.tech:5432/db`
* Add `-pooler` to hostname for connection pooling (PgBouncer, 10k connections)
* Compute scales to zero after 5 minutes inactivity
* Cold start: 500ms - few seconds
* Database branching for development workflows

**Timeout configuration:** Configure connection and pool timeouts via your [driver adapter](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool) (e.g. `connectionTimeoutMillis` for `pg`).

**Resources:** [Neon docs](https://neon.tech/docs) • [Connection pooling](https://neon.tech/docs/connect/connection-pooling)

### Supabase [#supabase]

PostgreSQL hosting with built-in auth, storage, and real-time features.

**Connection types:**

* **Direct:** `db.[project-ref].supabase.co:5432`
* **Transaction pooler:** Port `6543` with `?pgbouncer=true`
* **Session pooler:** Port `5432` on pooler host

**Key features:**

* Supavisor connection pooling
* Built-in PostgreSQL extensions
* Integrated with Supabase ecosystem
* Automated backups

**Resources:** [Supabase docs](https://supabase.com/docs) • [Prisma integration](https://supabase.com/partners/integrations/prisma)

### CockroachDB [#cockroachdb]

Distributed, PostgreSQL-compatible database designed for scalability and high availability.

* Use `provider = "cockroachdb"` in schema
* Connection URL: `postgresql://user:pass@host:26257/database`
* Built-in replication and automated failover
* Horizontal scaling with no single point of failure

**Key differences:**

| Feature        | PostgreSQL        | CockroachDB                           |
| -------------- | ----------------- | ------------------------------------- |
| Native types   | `VARCHAR(n)`      | `STRING(n)`                           |
| ID generation  | `autoincrement()` | Uses `unique_rowid()`                 |
| Sequential IDs | Recommended       | Avoid (use `autoincrement()` instead) |

**ID generation example:**

```prisma
model User {
  id   BigInt @id @default(autoincrement()) // Uses unique_rowid()
  name String
}
```

For compatibility with existing databases, use `sequence()`:

```prisma
model User {
  id   Int    @id @default(sequence())
  name String
}
```

**Resources:** [CockroachDB docs](https://www.cockroachlabs.com/docs/) • [Primary key best practices](https://www.cockroachlabs.com/docs/stable/schema-design-table#primary-key-best-practices)

## Type mappings [#type-mappings]

### Prisma to PostgreSQL [#prisma-to-postgresql]

| Prisma     | PostgreSQL         | CockroachDB |
| ---------- | ------------------ | ----------- |
| `String`   | `text`             | `STRING`    |
| `Boolean`  | `boolean`          | `BOOL`      |
| `Int`      | `integer`          | `INT4`      |
| `BigInt`   | `bigint`           | `INT8`      |
| `Float`    | `double precision` | `FLOAT8`    |
| `Decimal`  | `decimal(65,30)`   | `DECIMAL`   |
| `DateTime` | `timestamp(3)`     | `TIMESTAMP` |
| `Json`     | `jsonb`            | `JSONB`     |
| `Bytes`    | `bytea`            | `BYTES`     |

See [full type mapping reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) for complete details.

## Common patterns [#common-patterns]

**SSL connections:**

```bash
DATABASE_URL="postgresql://user:pass@host:5432/db?sslmode=require&sslcert=./cert.pem"
```

* `sslmode=prefer` (default) - Use TLS if available
* `sslmode=require` - Require TLS or fail
* `sslmode=disable` - No TLS

**Socket connections:**

```bash
DATABASE_URL="postgresql://user:pass@localhost/db?host=/var/run/postgresql/"
```

**Specifying schema with driver adapters:**

```ts
const adapter = new PrismaPg(
  { connectionString: process.env.DATABASE_URL },
  { schema: "mySchema" }
);
```

**Connection pool defaults (Prisma ORM v7):**

Driver adapters use `pg` defaults which differ from v6:

* **Connection timeout:** `0` (no timeout) vs v6's `5s`
* **Idle timeout:** `10s` vs v6's `300s`

See [connection pool guide](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool#postgresql-using-the-pg-driver-adapter) for configuration.

## Related pages

- [`Database drivers`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers): Learn how Prisma connects to your database using driver adapters
- [`MongoDB`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb): How Prisma ORM connects to MongoDB databases
- [`MySQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql): Use Prisma ORM with MySQL databases including self-hosted MySQL/MariaDB and serverless PlanetScale
- [`SQL Server`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server): Use Prisma ORM with Microsoft SQL Server databases
- [`SQLite`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite): Use Prisma ORM with SQLite databases including local SQLite, Turso (libSQL), and Cloudflare D1

# SQL Server (Prisma ORM v7) (/docs/orm/v7/core-concepts/supported-databases/sql-server)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Use Prisma ORM with Microsoft SQL Server databases

Location: ORM > v7 > Core Concepts > Supported databases > SQL Server

Prisma ORM supports Microsoft SQL Server (2017+) databases.

## Setup [#setup]

Configure the SQL Server provider in your Prisma schema:

```prisma title="schema.prisma"
datasource db {
  provider = "sqlserver"
}
```

Set the connection URL in `prisma.config.ts`:

```typescript title="prisma.config.ts"
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"), // sqlserver://host:1433;database=db;...
  },
});
```

## Using driver adapters [#using-driver-adapters]

Use the `node-mssql` JavaScript database driver via [driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers#driver-adapters):

  

#### bun

```bash
bun add @prisma/adapter-mssql
```

#### pnpm

```bash
pnpm add @prisma/adapter-mssql
```

#### yarn

```bash
yarn add @prisma/adapter-mssql
```

#### npm

```bash
npm install @prisma/adapter-mssql
```

```ts
import { PrismaMssql } from "@prisma/adapter-mssql";
import { PrismaClient } from "./generated/prisma";

const config = {
  server: "localhost",
  port: 1433,
  database: "mydb",
  user: "sa",
  password: "mypassword",
  options: {
    encrypt: true,
    trustServerCertificate: true, // For self-signed certificates
  },
};

const adapter = new PrismaMssql(config);
const prisma = new PrismaClient({ adapter });
```

## Connection details [#connection-details]

SQL Server uses JDBC-style connection strings:

```
sqlserver://HOST[:PORT];database=DATABASE;user=USER;password=PASSWORD;encrypt=true
```

**Escaping special characters:**

If your credentials contain `: \ = ; / [ ] { }`, wrap values in curly braces:

```
sqlserver://host:1433;user={MyServer/User};password={Pass:Word;};database=db
```

### Connection string arguments [#connection-string-arguments]

| Argument                       | Default  | Description                                                          |
| ------------------------------ | -------- | -------------------------------------------------------------------- |
| `database` / `initial catalog` | `master` | Database name                                                        |
| `user` / `username` / `uid`    |          | SQL Server login or Windows username (if using `integratedSecurity`) |
| `password` / `pwd`             |          | Password for user                                                    |
| `encrypt`                      | `true`   | Use TLS: `true` (always), `false` (login only)                       |
| `integratedSecurity`           |          | Windows authentication: `true`, `false`, `yes`, `no`                 |
| `schema`                       | `dbo`    | Schema prefix for all queries                                        |
| `connectTimeout`               | `5`      | Seconds to wait for connection                                       |
| `socketTimeout`                |          | Seconds to wait for each query                                       |
| `poolTimeout`                  | `10`     | Seconds to wait for connection from pool                             |
| `trustServerCertificate`       | `false`  | Trust server certificate without validation                          |
| `trustServerCertificateCA`     |          | Path to CA certificate file (`.pem`, `.crt`, `.der`)                 |
| `ApplicationName`              |          | Application name for the connection                                  |

> [!WARNING]
> Prisma ORM v7: Connection pool defaults changed
> 
> Driver adapters use `mssql` driver defaults which differ from v6:
> 
> * **Connection timeout:** `15s` (vs v6's `5s`)
> * **Idle timeout:** `30s` (vs v6's `300s`)
> 
> See [connection pool guide](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool#sql-server-using-the-mssql-driver) for configuration.

## Windows authentication [#windows-authentication]

**Using current Windows user:**

```
sqlserver://localhost:1433;database=sample;integratedSecurity=true;trustServerCertificate=true;
```

**Using specific Active Directory user:**

```
sqlserver://localhost:1433;database=sample;integratedSecurity=true;username=prisma;password=aBcD1234;trustServerCertificate=true;
```

**Named instance:**

```
sqlserver://mycomputer\sql2019;database=sample;integratedSecurity=true;trustServerCertificate=true;
```

## Type mappings [#type-mappings]

| Prisma     | SQL Server       |
| ---------- | ---------------- |
| `String`   | `NVARCHAR(1000)` |
| `Boolean`  | `BIT`            |
| `Int`      | `INT`            |
| `BigInt`   | `BIGINT`         |
| `Float`    | `FLOAT(53)`      |
| `Decimal`  | `DECIMAL(32,16)` |
| `DateTime` | `DATETIME2`      |
| `Json`     | Not supported    |
| `Bytes`    | `VARBINARY(MAX)` |

See [full type mapping reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) for complete details.

## Common considerations [#common-considerations]

**UNIQUE constraints:**

SQL Server [allows only one `NULL` value per `UNIQUE` constraint](https://learn.microsoft.com/en-us/sql/relational-databases/tables/unique-constraints-and-check-constraints). Use filtered indexes to work around this, but note they cannot be used as foreign keys.

**Cyclic references:**

With circular model references, you must use [`NoAction` referential actions](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions#special-rules-for-sql-server-and-mongodb) to avoid validation errors.

**Raw queries with `VARCHAR` columns:**

`String` parameters in raw queries are encoded as `NVARCHAR(4000)` or `NVARCHAR(MAX)`. When querying `VARCHAR(N)` columns, manually cast to avoid index performance issues:

```ts
// ❌ Causes implicit conversion
await prisma.$queryRaw`SELECT * FROM user WHERE name = ${"John"}`;

// ✅ Enables index seek
await prisma.$queryRaw`SELECT * FROM user WHERE name = CAST(${"John"} AS VARCHAR(40))`;
```

## Prisma Migrate caveats [#prisma-migrate-caveats]

**Schema names:**

SQL Server doesn't have `SET search_path`. Ensure your connection URL schema parameter matches production (typically `dbo`):

```
sqlserver://host:1433;database=db;schema=dbo;...
```

**Destructive changes:**

Some operations require table recreation:

* Adding/removing `autoincrement()`
* Dropping all columns from a table

**Shared default values:**

Prisma doesn't support SQL Server's `sp_bindefault`. Use per-column defaults instead.

## Local setup [#local-setup]

**Windows:**

1. Install [SQL Server 2019 Developer](https://www.microsoft.com/en-us/sql-server/sql-server-downloads)
2. Install [SQL Server Management Studio](https://learn.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms)
3. Enable TCP/IP in SQL Server Configuration Manager → **Protocols for MSSQLSERVER**
4. (Optional) Enable SQL authentication: **Properties** → **Security** → **SQL Server and Windows Authentication Mode**

**Docker:**

```bash
docker pull mcr.microsoft.com/mssql/server:2019-latest

docker run --name sql_container \
  -e 'ACCEPT_EULA=Y' \
  -e 'SA_PASSWORD=myPassword' \
  -p 1433:1433 \
  -d mcr.microsoft.com/mssql/server:2019-latest
```

Connect with: Username `sa`, password `myPassword`, port `1433`

## Related pages

- [`Database drivers`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers): Learn how Prisma connects to your database using driver adapters
- [`MongoDB`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb): How Prisma ORM connects to MongoDB databases
- [`MySQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql): Use Prisma ORM with MySQL databases including self-hosted MySQL/MariaDB and serverless PlanetScale
- [`PostgreSQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql): Use Prisma ORM with PostgreSQL databases including self-hosted, serverless (Neon, Supabase), and CockroachDB
- [`SQLite`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite): Use Prisma ORM with SQLite databases including local SQLite, Turso (libSQL), and Cloudflare D1

# SQLite (Prisma ORM v7) (/docs/orm/v7/core-concepts/supported-databases/sqlite)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Use Prisma ORM with SQLite databases including local SQLite, Turso (libSQL), and Cloudflare D1

Location: ORM > v7 > Core Concepts > Supported databases > SQLite

Prisma ORM supports SQLite and SQLite-compatible databases. This includes local SQLite files, Turso's distributed libSQL, and Cloudflare's serverless D1.

## Setup [#setup]

Configure the SQLite provider in your Prisma schema:

```prisma title="schema.prisma"
datasource db {
  provider = "sqlite"
}
```

Set the connection URL in `prisma.config.ts`:

```typescript title="prisma.config.ts"
import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: "file:./dev.db", // or libsql:// for Turso
  },
});
```

## Using driver adapters [#using-driver-adapters]

Instead of Prisma's built-in driver, you can use JavaScript database drivers via [driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers#driver-adapters):

**Local SQLite with `better-sqlite3`:**

  

#### bun

```bash
bun add @prisma/adapter-better-sqlite3
```

#### pnpm

```bash
pnpm add @prisma/adapter-better-sqlite3
```

#### yarn

```bash
yarn add @prisma/adapter-better-sqlite3
```

#### npm

```bash
npm install @prisma/adapter-better-sqlite3
```

```ts
import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
import { PrismaClient } from "./generated/prisma";

const adapter = new PrismaBetterSqlite3({ url: "file:./prisma/dev.db" });
const prisma = new PrismaClient({ adapter });
```

**Turso with `@prisma/adapter-libsql`:**

  

#### bun

```bash
bun add @prisma/adapter-libsql
```

#### pnpm

```bash
pnpm add @prisma/adapter-libsql
```

#### yarn

```bash
yarn add @prisma/adapter-libsql
```

#### npm

```bash
npm install @prisma/adapter-libsql
```

```ts
import { PrismaLibSQL } from "@prisma/adapter-libsql";
import { PrismaClient } from "./generated/prisma";

const adapter = new PrismaLibSQL({
  url: process.env.TURSO_DATABASE_URL,
  authToken: process.env.TURSO_AUTH_TOKEN,
});
const prisma = new PrismaClient({ adapter });
```

**Cloudflare D1 with `@prisma/adapter-d1`:**

  

#### bun

```bash
bun add @prisma/adapter-d1
```

#### pnpm

```bash
pnpm add @prisma/adapter-d1
```

#### yarn

```bash
yarn add @prisma/adapter-d1
```

#### npm

```bash
npm install @prisma/adapter-d1
```

```ts
import { PrismaD1 } from "@prisma/adapter-d1";
import { PrismaClient } from "./generated/prisma";

const adapter = new PrismaD1(env.DB); // D1 binding in Workers
const prisma = new PrismaClient({ adapter });
```

## Supported variants [#supported-variants]

### Local SQLite [#local-sqlite]

Standard SQLite database files (`.db`). Connection URL format: `file:./path/to/database.db`

* Use `prisma migrate dev` for schema changes
* Store database file anywhere in your filesystem
* Suited to development and small applications

### Turso (libSQL) [#turso-libsql]

Edge-hosted, distributed SQLite-compatible database.

* Connection URL format: `libsql://[hostname]`
* Requires authentication token
* Supports embedded replicas for faster local reads
* Use local SQLite file + Turso CLI for migrations (see [Turso docs](https://docs.turso.tech/))

**Key differences:**

* Remote access over HTTP
* Replication and automated backups
* Schema changes via `prisma migrate diff` + Turso CLI

### Cloudflare D1 [#cloudflare-d1]

Serverless SQLite database for Cloudflare Workers.

* Automatic read-replication across regions
* Schema changes via Wrangler CLI + `prisma migrate diff`
* Local (`.wrangler/state`) and remote versions available

**Key differences:**

* No transaction support currently
* Migrations via Wrangler: `wrangler d1 migrations apply`
* Deploy with Cloudflare Workers

## Type mappings [#type-mappings]

| Prisma ORM | SQLite    |
| ---------- | --------- |
| `String`   | `TEXT`    |
| `Boolean`  | `BOOLEAN` |
| `Int`      | `INTEGER` |
| `BigInt`   | `INTEGER` |
| `Float`    | `REAL`    |
| `Decimal`  | `DECIMAL` |
| `DateTime` | `NUMERIC` |
| `Json`     | `JSONB`   |
| `Bytes`    | `BLOB`    |
| `Enum`     | `TEXT`    |

> [!NOTE]
> SQLite stores booleans as `0` (false) or `1` (true). Learn more about [SQLite type affinity](https://www.sqlite.org/datatype3.html#boolean).

## Common considerations [#common-considerations]

**Timestamp format with driver adapters:**

Configure how `DateTime` values are stored:

```ts
const adapter = new PrismaBetterSqlite3(
  { url: "file:./dev.db" },
  { timestampFormat: "unixepoch-ms" } // For backward compatibility
);
```

* **ISO 8601 (default)**: Best for new projects
* **`unixepoch-ms`**: Required for migrating from Prisma's native driver

**Enum validation:**

SQLite doesn't enforce enum values at the database level. Invalid values will cause Prisma Client queries to fail at runtime.

**Integer overflow:**

Prisma ORM validates that numbers fit within integer boundaries. If a value exceeds limits, you'll get a P2023 error.

## Related pages

- [`Database drivers`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers): Learn how Prisma connects to your database using driver adapters
- [`MongoDB`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb): How Prisma ORM connects to MongoDB databases
- [`MySQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql): Use Prisma ORM with MySQL databases including self-hosted MySQL/MariaDB and serverless PlanetScale
- [`PostgreSQL`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql): Use Prisma ORM with PostgreSQL databases including self-hosted, serverless (Neon, Supabase), and CockroachDB
- [`SQL Server`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server): Use Prisma ORM with Microsoft SQL Server databases

# Drizzle (Prisma ORM v7) (/docs/orm/v7/more/comparisons/prisma-and-drizzle)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how Prisma ORM compares to Drizzle

Location: ORM > v7 > More > Comparisons > Drizzle

Prisma and Drizzle take different approaches to working with databases. While Drizzle appeals to developers who prefer writing queries close to SQL, Prisma is designed to support teams building and maintaining production applications—where clarity, collaboration, and long-term maintainability matter.

While both libraries solve similar problems, they work in very different ways and have individual pros and cons. Which one to choose will depend on the needs of your project and the exact tradeoffs that are important for it.

## Drizzle vs Prisma ORM [#drizzle-vs-prisma-orm]

**Drizzle** is a traditional SQL query builder that lets you compose SQL queries with JavaScript/TypeScript functions. It can be used to query a database or run migrations. Drizzle also offers a Queries API, which offers a higher level abstraction from SQL and can be used to read nested relations. Drizzle schema is defined in TypeScript files, which are used to generate SQL migrations and are then executed against a database.

**Prisma ORM** mitigates many problems of traditional ORMs, such as bloated model instances, mixing business with storage logic, lack of type-safety or unpredictable queries caused e.g. by lazy loading. It uses the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) to define application models in a declarative way. Prisma Migrate then allows the generation of SQL migrations from the Prisma schema and executes them against the database. CRUD queries are provided by Prisma Client, a lightweight and entirely type-safe database client for Node.js and TypeScript.

## Prisma: Built for Teams [#prisma-built-for-teams]

Prisma is designed to help teams ship faster—especially when not everyone is a SQL expert.

* **No SQL bottlenecks**: With Prisma, you don’t need deep SQL knowledge to be productive. Your entire team can contribute to backend code—without relying on one person to write raw queries or debug database logic.
* **Shared mental model**: Prisma’s schema is human-readable and easy to reason about. It provides a single, consistent view of your application’s data model.
* **Easier code reviews**: Schema changes and data access patterns are transparent and consistent, making it easier for reviewers to understand and approve backend changes.
* **Predictable workflows**: Prisma automates migration generation, client typing, and query construction—so your team doesn’t have to.

Drizzle can be great in the hands of a single developer who knows SQL or prefers learning it. But once you have a team, Prisma removes the friction and knowledge risk that slows you down.

## Type safety [#type-safety]

Drizzle is not *fully* type safe. As quoted on this [comparison study](https://github.com/thetutlage/meta/discussions/8) done by a 3rd party, "Drizzle gives the impression of type-safety. However, only the query results have type information. You can write invalid queries with Drizzle."

With Prisma, you get *full* type safety thanks to the generated types. This means, less potential for errors when writing code and collaborating with team members.

## Prisma Schema as a Single Source of Truth [#prisma-schema-as-a-single-source-of-truth]

With Prisma, your data model lives in a single file: schema.prisma.

* **It’s explicit**: No need to infer types or decipher SQL-generating functions—your schema is right there.
* **It’s readable**: Even non-technical teammates can understand your models and relationships.
* **It powers everything**: Migrations, TypeScript types, autocompletion, ERD generation, and more all come from your schema.

In contrast, Drizzle’s schema is built via TypeScript code, which makes it harder to visualize your full data model, increases cognitive load, and can lead to inconsistencies in how models are defined across the codebase. Read more in [the Prisma Schema Language blog post](https://www.prisma.io/blog/prisma-schema-language-the-best-way-to-define-your-data) about why we are bullish on PSL (Prisma Schema Language).

To see your schema as an ERD, run `npx prisma generate && npx prisma-erd-generator`.

## API design & Level of abstraction [#api-design--level-of-abstraction]

Drizzle and Prisma ORM operate on different levels of abstraction. Drizzle's philosophy is "If you know SQL, you know Drizzle ORM". It mirrors SQL in its API while Prisma Client provides a higher-level abstraction that was designed with the common tasks of application developers in mind. Prisma ORM's API design heavily leans on the idea of [making the right thing easy](https://jason.energy/right-thing-easy-thing/).

While Prisma Client operates on a higher level of abstraction, you are able to drop down to [raw SQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql) at any time. However, full use of Prisma ORM and development of your application does not require SQL knowledge. Prisma ORM's goal is a query syntax that feels familiar to application developers and reduces the SQL you need to write by hand. You can learn more about this here: [Why Prisma](https://www.prisma.io/docs/orm/v7#why-prisma-orm).

For the few queries that are unable to be expressed in the Prisma Client API, Prisma ORM also offers [TypedSQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql) which provides a more familiar and type-safe experience by directly utilizing `.sql` files. Your existing SQL tooling and workflow can work alongside Prisma Client to handle any level of abstraction desired.

While fully typed SQL queries are available in Prisma ORM with TypedSQL, the following sections examine a few examples of how the Prisma and Drizzle APIs differ and what the rationale of Prisma ORM's API design is in these cases.

### Data modeling [#data-modeling]

Prisma models are defined in the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview), while Drizzle uses TypeScript functions for table definitions. These functions are then exported and used in queries.

Prisma generates a lightweight database client that exposes a tailored and fully type-safe API to read and write data for the models that are defined in the Prisma schema, following the DataMapper ORM pattern.

Prisma ORM's data modeling language is declarative and short to read. When modeling data in VS Code, the [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) adds autocompletion, quick fixes, and jump to definition. On the other hand, Drizzle's use of TypeScript means that you can lean on the power of TypeScript for additional flexibility (via reused code, for example).

```prisma
model User {
  id    Int     @id @default(autoincrement())
  name  String?
  email String  @unique
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  authorId  Int?
  author    User?   @relation(fields: [authorId], references: [id])
}
```

```ts
import { boolean, integer, pgTable, serial, text, uniqueIndex, varchar } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: serial("id").primaryKey(),
  name: varchar("name", { length: 256 }),
  email: varchar("email", { length: 256 }).unique(),
});

export const posts = pgTable("posts", {
  id: serial("id").primaryKey(),
  title: varchar("title", { length: 256 }).notNull(),
  content: text("content"),
  published: boolean("published"),
  authorId: integer("author_id").references(() => users.id),
});
```

### Migrations [#migrations]

Migrations work similarly between Drizzle and Prisma ORM. Both tools follow the approach of generating SQL files based on the provided model definitions and provide a CLI to execute them against the database. The SQL files can be modified before the migrations are executed so that any custom database operation can be performed with either migration system.

### Querying [#querying]

Plain queries are natural to construct in both Drizzle and Prisma ORM. Using Drizzle's Queries API, the two approaches are very similar:

```ts
// find all users
const allUsers = await prisma.user.findMany();

// find a single user
const user = await prisma.user.findFirst({
  where: { id: 27 },
});

// find a unique user
const user = await prisma.user.findUnique({
  where: { email: "nilu@prisma.io" },
});
```

```ts
import { eq } from "drizzle-orm";

// find all users
const allUsers = await db.query.users.findMany();

// find a single user
const user = await db.query.users.findFirst({
  where: eq(users.id, 1),
});

// find a unique post
const user = await db.query.users.findFirst({
  where: eq(users.email, "nilu@prisma.io"),
});
```

When performing a mutation, a `create`, `update`, or `delete`, the Drizzle Queries API is not available. In these cases, you will need to use Drizzle's SQL-like APIs:

```ts
// create a user
const user = await prisma.user.create({
  data: {
    name: "Nilu",
    email: "nilu@prisma.io",
  },
});

// update a user
const user = await prisma.user.update({
  where: { email: "nilu@prisma.io" },
  data: { name: "Another Nilu" },
});

// delete a user
const deletedUser = await prisma.user.delete({
  where: { email: "nilu@prisma.io" },
});
```

```ts
// create a user
const user = await db.insert(users).values({
  name: "Nilu",
  email: "nilu@prisma.io",
});

// update a user
const user = await db
  .update(users)
  .set({ name: "Another Nilu" })
  .where(eq(users.email, "nilu@prisma.io"))
  .returning();

// delete a user
const deletedUser = await db.delete(users).where(eq(users.email, "nilu@prisma.io")).returning();
```

### Relations [#relations]

Working with records that are connected via foreign keys can become very complex in SQL. Prisma ORM's concept of [virtual relation field](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields) enables an intuitive and convenient way for application developers to work with related data. Some benefits of Prisma ORM's approach are:

* traversing relationships via the fluent API ([Fluent API](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#fluent-api))
* nested writes that enable updating/creating connected records ([Nested writes](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-writes))
* applying filters on related records ([Relation filters](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-filters))
* type-safe querying of nested data without writing the underlying SQL ([Nested reads](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-reads))
* creating nested TypeScript typings based on models and their relations ([Type safety Overview](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety))
* intuitive modeling of relations in the data model via relation fields ([Relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations))
* implicit handling of relation tables (also sometimes called JOIN, link, pivot or junction tables) ([Implicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations))

```ts
const posts = await prisma.post.findMany({
  include: {
    author: true,
  },
});
```

```ts
const posts = await db.query.posts.findMany({
  with: {
    author: true,
  },
});
```

### Filtering [#filtering]

Drizzle exposes the underlying filter and conditional operators for a given SQL dialect. Prisma ORM on the other hand, provides a more [generic set of operators](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting#combining-operators) that are intuitive to use.

A good example of how the filtering APIs of both Drizzle and Prisma ORM differ is by looking at `string` filters. While Drizzle provides filters for `like` and `ilike`, Prisma ORM provides more specific operators that developers can use, e.g.: `contains`, `startsWith` and `endsWith`.

```ts
// case sensitive filter
const posts = await prisma.post.findMany({
  where: {
    title: "Hello World",
  },
});

// case insensitive filter
const posts = await prisma.post.findMany({
  where: {
    title: "Hello World",
    mode: "insensitive",
  },
});
```

```ts
// case sensitive filter
const posts = await db.select().from(posts).where(like(posts.title, "Hello World"));

// case insensitive filter
const posts = await db.select().from(posts).where(ilike(posts.title, "Hello World"));
```

```ts
const posts = await prisma.post.findMany({
  where: {
    title: {
      contains: "Hello World",
    },
  },
});
```

```ts
const posts = await db.select().from(posts).where(ilike(posts.title, "%Hello World%"));
```

```ts
const posts = await prisma.post.findMany({
  where: {
    title: {
      startsWith: "Hello World",
    },
  },
});
```

```ts
const posts = await db.select().from(posts).where(ilike(posts.title, "Hello World%"));
```

```ts
const posts = await prisma.post.findMany({
  where: {
    title: {
      endsWith: "Hello World",
    },
  },
});
```

```ts
const posts = await db.select().from(posts).where(ilike(posts.title, "%Hello World"));
```

### Observability [#observability]

Both Drizzle and Prisma ORM have the ability to log queries and the underlying SQL generated.

## Safer Changes and Fewer Bugs [#safer-changes-and-fewer-bugs]

Prisma minimizes the risk of human error when working with your database.

* **Renaming a field**: Prisma updates the schema, the database, and the generated client, so all three stay in sync.
* **Changing a relationship**: Prisma generates a migration and the generated types flag any code that no longer matches.

## Batteries-Included Ecosystem [#batteries-included-ecosystem]

Both Drizzle and Prisma ORM have cases where users want to do something not directly supported by the library. Drizzle relies on the expressiveness of SQL to avoid these cases, while Prisma ORM has [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions) to allow any user to add additional behaviors to their instance of Prisma Client. These extensions are also shareable, meaning teams can develop them for use across their projects or even for use by other teams.

While Drizzle is a relatively new product, Prisma ORM was [released in 2021](https://www.prisma.io/blog/how-prisma-orm-became-the-most-downloaded-orm-for-node-js) and is well established in the JavaScript/TypeScript space. It has proven value and many companies trust [Prisma ORM in production](https://www.prisma.io/showcase).

Prisma ORM is also included as the data layer tool of choice in many meta-frameworks and development platforms like [Amplication](https://amplication.com/), [Wasp](https://wasp.sh/), [RedwoodJS](https://rwsdk.com/), [KeystoneJS](https://keystonejs.com/), [Remix](https://remix.run/) and the [t3 stack](https://create.t3.gg/).

Thanks to its maturity, Prisma's community has developed a [plethora of useful tools](https://www.prisma.io/ecosystem) that helps with various Prisma workflows. Here are a few highlights:

* [`prisma-erd-generator`](https://github.com/keonik/prisma-erd-generator#prisma-entity-relationship-diagram-generator): Visualizes the Prisma schema as an entity-relationship-diagram (ERD).
* [`prisma-zod-generator`](https://github.com/omar-dulaimi/prisma-zod-generator): Generates [Zod](https://github.com/colinhacks/zod) schemas from the Prisma schema.
* [`bridg`](https://github.com/bridg-db/bridg): Let's you access your database from the frontend using Prisma Client.
* [`jest-prisma`](https://github.com/Quramy/jest-prisma): Environment for Prisma integrated testing with [Jest](https://jestjs.io/).
* [`prisma-pothos-types`](https://github.com/hayes/pothos/tree/main/packages/plugin-prisma): Creates GraphQL types based on Prisma models when using [GraphQL Pothos](https://github.com/hayes/pothos/tree/main).
* [`prisma-trpc-generator`](https://github.com/omar-dulaimi/prisma-trpc-generator): Creates [tRPC](https://trpc.io/) routers from your Prisma schema.
* [`@cerbos/orm-prisma`](https://github.com/cerbos/query-plan-adapters/tree/main/prisma): Filter data based on authorization policies from [Cerbos](https://www.cerbos.dev).

Beyond the ORM itself, Prisma includes:

* Prisma Schema → migrations, types, and documentation
* Prisma Client → auto-completed, fully type-safe queries
* Prisma Studio → a [GUI](https://prisma.io/studio) to inspect and edit data
* Native integrations → PlanetScale, Vercel, Cloudflare D1, Neon, and more

## Database support [#database-support]

Both Drizzle and Prisma ORM support multiple and different kinds of databases. Drizzle achieves this support through driver implementations created by Drizzle, which integrate with existing third-party database drivers.

Prisma ORM has begun adding support for third-party database drivers. Prisma also defaults connections to TLS, which improves security.

Additionally, Prisma ORM supports CockroachDB, Microsoft SQL Server, and MongoDB, which Drizzle does not currently support. Prisma ORM also offers the [relation mode](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode) that allows Prisma ORM to emulate foreign key constraints for those database engines that do not support it. Drizzle currently supports Cloudflare D1, `bun:sqlite`, and SQLite via HTTP Proxy, which Prisma ORM currently does not.

## Benchmarks [#benchmarks]

We understand that performance is a key consideration when selecting an ORM. To compare performance of various ORMs, you can use the open-source [database latency benchmark tool](https://pris.ly/benchmark) hosted by Vercel. This tool allows you to evaluate the latency and throughput of various ORMs under different workloads and configurations. By running the benchmarks against the databases or database providers you are considering, you can get a clear picture of their relative performance characteristics to help make an informed decision.

Alternatively, you can also review findings on the [benchmark tool](https://benchmarks.prisma.io) that we have built that compares popular TypeScript ORMs, including Drizzle. This benchmark is open source and aims to be a fair comparison of database query latencies across database providers and ORM libraries in the Node.js and TypeScript ecosystem.

## Conclusion [#conclusion]

Yes, we are biased, but this is also what we have heard from our users and customers:

* "We switched from Drizzle to Prisma because schema drift was killing us. Prisma just works."
* "I onboarded a junior dev in 2 hours thanks to Prisma’s schema. With Drizzle, it would’ve taken days."
* "I trust Prisma to keep our database sane. No one on our team needs to be a Postgres expert."
* "The pace of updates and new features from the Prisma team has been nothing short of outstanding."

Both Drizzle ORM and Prisma ORM are tools for data access and migrations. Drizzle is focused on being a thin wrapper around a SQL-like syntax while Prisma is focused on a convenient and expressive API. Other important differences include Prisma ORM's support of MSSQL and MongoDB, support for additional features via [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions), additional cloud products, and a larger ecosystem of community tools.

On the other hand, for teams that are a mix of developers (front-end, back-end, and full-stack) that have varying levels of experience with databases, Prisma ORM offers an approach to data access and schema management that does not require every team member to know SQL.

## Related pages

- [`Mongoose`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-mongoose): Learn how Prisma ORM compares to Mongoose
- [`Sequelize`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-sequelize): Learn how Prisma ORM compares to Sequelize
- [`TypeORM`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-typeorm): Learn how Prisma compares to TypeORM

# Mongoose (Prisma ORM v7) (/docs/orm/v7/more/comparisons/prisma-and-mongoose)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how Prisma ORM compares to Mongoose

Location: ORM > v7 > More > Comparisons > Mongoose

This page compares the Prisma ORM and [Mongoose](https://mongoosejs.com/docs/guide.html) APIs. If you want to learn how to migrate from Mongoose to Prisma, check out this [guide](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-mongoose).

## Fetching single objects [#fetching-single-objects]

**Prisma ORM**

```ts
const user = await prisma.user.findUnique({
  where: {
    id: 1,
  },
});
```

**Mongoose**

```ts
const result = await User.findById(1);
```

## Fetching selected scalars of single objects [#fetching-selected-scalars-of-single-objects]

**Prisma ORM**

```ts
const user = await prisma.user.findUnique({
  where: {
    id: 1,
  },
  select: {
    name: true,
  },
});
```

**Mongoose**

```ts
const user = await User.findById(1).select(["name"]);
```

## Fetching relations [#fetching-relations]

**Prisma ORM**

  

#### Using include

```ts
const userWithPost = await prisma.user.findUnique({
  where: {
    id: 2,
  },
  include: {
    post: true,
  },
})
```

#### Fluent API

```ts
const userWithPost = await prisma.user
  .findUnique({
    where: {
      id: 2,
    },
  })
  .post()
```

**Mongoose**

```ts
const userWithPost = await User.findById(2).populate("post");
```

## Filtering for concrete values [#filtering-for-concrete-values]

**Prisma ORM**

```ts
const posts = await prisma.post.findMany({
  where: {
    title: {
      contains: "Hello World",
    },
  },
});
```

**Mongoose**

```ts
const posts = await Post.find({
  title: "Hello World",
});
```

## Other filter criteria [#other-filter-criteria]

**Prisma ORM**

Prisma ORM generates many [additional filters](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting) that are commonly used in application development.

**Mongoose**

Mongoose exposes the [MongoDB query selectors](https://www.mongodb.com/docs/manual/reference/mql/query-predicates/logical/) as filter criteria.

## Relation filters [#relation-filters]

**Prisma ORM**

Prisma ORM lets you filter a list based on a criteria that applies not only to the models of the list being retrieved, but to a *relation* of that model.

For example, the following query returns users with one or more posts with "Hello" in the title:

```ts
const posts = await prisma.user.findMany({
  where: {
    Post: {
      some: {
        title: {
          contains: "Hello",
        },
      },
    },
  },
});
```

**Mongoose**

Mongoose doesn't offer a dedicated API for relation filters. You can get similar functionality by adding an additional step to filter the results returned by the query.

## Pagination [#pagination]

**Prisma ORM**

Cursor-style pagination:

```ts
const page = prisma.post.findMany({
  before: {
    id: 242,
  },
  last: 20,
});
```

Offset pagination:

```ts
const cc = prisma.post.findMany({
  skip: 200,
  first: 20,
});
```

**Mongoose**

```ts
const posts = await Post.find({
  skip: 200,
  limit: 20,
});
```

## Creating objects [#creating-objects]

**Prisma ORM**

```ts
const user = await prisma.user.create({
  data: {
    name: "Alice",
    email: "alice@prisma.io",
  },
});
```

**Mongoose**

  

#### Using create

```ts
const user = await User.create({
  name: 'Alice',
  email: 'alice@prisma.io',
})
```

#### Using save

```ts
const user = new User({
  name: 'Alice',
  email: 'alice@prisma.io',
})
await user.save()
```

## Updating objects [#updating-objects]

**Prisma ORM**

```ts
const user = await prisma.user.update({
  data: {
    name: "Alicia",
  },
  where: {
    id: 2,
  },
});
```

**Mongoose**

  

#### Using findOneAndUpdate

```ts
const updatedUser = await User.findOneAndUpdate(
  { _id: 2 },
  {
    $set: {
      name: 'Alicia',
    },
  }
)
```

#### Using save

```ts
user.name = 'Alicia'
await user.save()
```

## Deleting objects [#deleting-objects]

**Prisma ORM**

```ts
const user = prisma.user.delete({
  where: {
    id: 10,
  },
});
```

**Mongoose**

```ts
await User.deleteOne({ _id: 10 });
```

## Batch deletes [#batch-deletes]

**Prisma ORM**

```ts
const users = await prisma.user.deleteMany({
  where: {
    id: {
      in: [1, 2, 6, 6, 22, 21, 25],
    },
  },
});
```

**Mongoose**

```ts
await User.deleteMany({ id: { $in: [1, 2, 6, 6, 22, 21, 25] } });
```

## Related pages

- [`Drizzle`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-drizzle): Learn how Prisma ORM compares to Drizzle
- [`Sequelize`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-sequelize): Learn how Prisma ORM compares to Sequelize
- [`TypeORM`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-typeorm): Learn how Prisma compares to TypeORM

# Sequelize (Prisma ORM v7) (/docs/orm/v7/more/comparisons/prisma-and-sequelize)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how Prisma ORM compares to Sequelize

Location: ORM > v7 > More > Comparisons > Sequelize

This page compares the Prisma ORM and [Sequelize](https://sequelize.org/docs/v6/) APIs.

## Sequelize vs Prisma ORM [#sequelize-vs-prisma-orm]

While Prisma ORM and Sequelize solve similar problems, they work in very different ways.

**Sequelize** is a traditional ORM which maps *tables* to *model classes*. Instances of the model classes then provide an interface for CRUD queries to an application at runtime.

**Prisma ORM** is a new kind of ORM that mitigates many problems of traditional ORMs, such as bloated model instances, mixing business with storage logic, lack of type-safety or unpredictable queries caused e.g. by lazy loading.

It uses the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) to define application models in a declarative way. Prisma Migrate then allows generating SQL migrations from the Prisma schema and executes them against the database. CRUD queries are provided by Prisma Client, a lightweight and entirely type-safe database client for Node.js and TypeScript.

## API comparison [#api-comparison]

### Fetching single objects [#fetching-single-objects]

**Prisma ORM**

```ts
const user = await prisma.user.findUnique({
  where: {
    id: 1,
  },
});
```

**Sequelize**

```ts
const user = await User.findByPk(id);
```

### Fetching selected scalars of single objects [#fetching-selected-scalars-of-single-objects]

**Prisma ORM**

```ts
const user = await prisma.user.findUnique({
  where: {
    id: 1,
  },
  select: {
    name: true,
  },
});
```

**Sequelize**

```ts
const user = await User.findByPk(1, { attributes: ["name"], raw: true });
```

> [!NOTE]
> Use the `raw: true` query option to return plain JavaScript objects.

### Fetching relations [#fetching-relations]

**Prisma ORM**

  

#### Using include

```ts
const posts = await prisma.user.findUnique({
  where: {
    id: 2,
  },
  include: {
    post: true,
  },
});
```

#### Fluent API

```ts
const posts = await prisma.user
  .findUnique({
    where: {
      id: 2,
    },
  })
  .post();
```

> **Note**: `select` returns a `user` object that includes a `post` array, whereas the fluent API only returns a `post` array.

**Sequelize**

```ts
const user = await User.findByPk(id, {
  include: [
    {
      model: Post,
    },
  ],
});
```

> [!NOTE]
> Use `model: Post as "Post"` if you used an alias to define the relationship between `User` and `Post` - for example: `User.hasMany(Post, { as: "Post", foreignKey: "authorId" });`

### Filtering for concrete values [#filtering-for-concrete-values]

**Prisma ORM**

```ts
const posts = await prisma.post.findMany({
  where: {
    title: {
      contains: "Hello",
    },
  },
});
```

**Sequelize**

```ts
const post = await Post.findAll({
  raw: true,
  where: {
    title: {
      [Op.like]: "%Hello%",
    },
  },
});
```

### Other filter criteria [#other-filter-criteria]

**Prisma ORM**

Prisma ORM generates many [additional filters](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting) that are commonly used in application development.

**Sequelize**

Sequelize has an [extensive set of operators](https://sequelize.org/docs/v6/core-concepts/model-querying-basics/#operators).

### Relation filters [#relation-filters]

**Prisma ORM**

Prisma ORM lets you filter a list based on a criteria that applies not only to the models of the list being retrieved, but to a *relation* of that model.

For example, the following query returns users with one or more posts with "Hello" in the title:

```ts
const posts = await prisma.user.findMany({
  where: {
    Post: {
      some: {
        title: {
          contains: "Hello",
        },
      },
    },
  },
});
```

**Sequelize**

Sequelize [doesn't offer a dedicated API for relation filters](https://github.com/sequelize/sequelize/issues/10943). You can get similar functionality by sending a raw SQL query to the database.

### Pagination [#pagination]

**Prisma ORM**

Cursor-style pagination:

```ts
const page = await prisma.post.findMany({
  before: {
    id: 242,
  },
  last: 20,
});
```

Offset pagination:

```ts
const cc = await prisma.post.findMany({
  skip: 200,
  first: 20,
});
```

**Sequelize**

Cursor pagination:

```ts
const posts = await Post.findAll({
  limit: 20,
  where: {
    id: {
      [Op.gt]: 242,
    },
  },
});
```

> **Note**: Sequelize use the [Sequelize operators](https://sequelize.org/docs/v6/core-concepts/model-querying-basics/#operators) to perform cursor pagination.

Offset pagination:

```ts
const posts = await Post.findAll({
  offset: 5,
  limit: 10,
});
```

### Creating objects [#creating-objects]

**Prisma ORM**

```ts
const user = await prisma.user.create({
  data: {
    email: "alice@prisma.io",
  },
});
```

**Sequelize**

  

#### Using save

```ts
const user = User.build({
  name: 'Alice',
  email: 'alice@prisma,io',
})
await user.save()
```

#### Using create

```ts
const user = await User.create({
  name: 'Alice',
  email: 'alice@prisma,io',
})
```

### Updating objects [#updating-objects]

**Prisma ORM**

```ts
const user = await prisma.user.update({
  data: {
    name: "Alicia",
  },
  where: {
    id: 2,
  },
});
```

**Sequelize**

  

#### Using save

```ts
user.name = 'James'
user.email = ' alice@prisma.com'
await user.save()
```

#### Using update

```ts
await User.update({
  name: 'James',
  email: 'james@prisma.io',
})
```

### Deleting objects [#deleting-objects]

**Prisma ORM**

```ts
const user = await prisma.user.delete({
  where: {
    id: 10,
  },
});
```

**Sequelize**

```ts
await user.destroy();
```

### Batch updates [#batch-updates]

**Prisma ORM**

```ts
const user = await prisma.user.updateMany({
  data: {
    name: "Published author!",
  },
  where: {
    email: {
      contains: "prisma.io",
    },
  },
});
```

**Sequelize**

```ts
const updatedUsers = await User.update({
  { role: "Admin" },
  where: {
    email: {
      [Op.like]: "%@prisma.io"
    }
  },
})
```

### Batch deletes [#batch-deletes]

**Prisma ORM**

```ts
const users = await prisma.user.deleteMany({
  where: {
    id: {
      in: [1, 2, 6, 6, 22, 21, 25],
    },
  },
});
```

**Sequelize**

```ts
await User.destroy({
  where: {
    id: {
      [Op.in]: [id1, id2, id3],
    },
  },
});
```

### Transactions [#transactions]

**Prisma ORM**

```ts
const user = await prisma.user.create({
  data: {
    email: "bob.rufus@prisma.io",
    name: "Bob Rufus",
    Post: {
      create: [{ title: "Working at Prisma" }, { title: "All about databases" }],
    },
  },
});
```

**Sequelize**

  

#### Manual

```ts
return sequelize.$transaction(async (t) => {
  const user = await User.create(
    {
      name: 'Alice',
      email: 'alice@prisma,io',
    },
    {
      transaction: t,
    }
  )
  const post1 = await Post.create(
    {
      title: 'Join us for GraphQL Conf in 2019',
    },
    {
      transaction: t,
    }
  )
  const post2 = await Post.create(
    {
      title: 'Subscribe to GraphQL Weekly for GraphQL news',
    },
    {
      transaction: t,
    }
  )
  await user.setPosts([post1, post2])
})
```

#### Automatic

```ts
return sequelize.$transaction(async (transaction) => {
  try {
    const user = await User.create({
      name: 'Alice',
      email: 'alice@prisma,io',
    })
    const post1 = await Post.create({
      title: 'Join us for GraphQL Conf in 2019',
    })
    const post2 = await Post.create({
      title: 'Subscribe to GraphQL Weekly for GraphQL news',
    })
    await user.setPosts([post1, post2])
  } catch (e) {
    return transaction.rollback()
  }
})
```

## Related pages

- [`Drizzle`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-drizzle): Learn how Prisma ORM compares to Drizzle
- [`Mongoose`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-mongoose): Learn how Prisma ORM compares to Mongoose
- [`TypeORM`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-typeorm): Learn how Prisma compares to TypeORM

# TypeORM (Prisma ORM v7) (/docs/orm/v7/more/comparisons/prisma-and-typeorm)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how Prisma compares to TypeORM

Location: ORM > v7 > More > Comparisons > TypeORM

This page compares Prisma ORM and [TypeORM](https://typeorm.io/). If you want to learn how to migrate from TypeORM to Prisma ORM, check out this [guide](https://www.prisma.io/docs/guides/switch-to-prisma-orm/from-sql-orms).

## TypeORM vs Prisma ORM [#typeorm-vs-prisma-orm]

While Prisma ORM and TypeORM solve similar problems, they work in very different ways.

**TypeORM** is a traditional ORM which maps *tables* to *model classes*. These model classes can be used to generate SQL migrations. Instances of the model classes then provide an interface for CRUD queries to an application at runtime.

**Prisma ORM** is a new kind of ORM that mitigates many problems of traditional ORMs, such as bloated model instances, mixing business with storage logic, lack of type-safety or unpredictable queries caused e.g. by lazy loading.

It uses the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) to define application models in a declarative way. Prisma Migrate then allows generating SQL migrations from the Prisma schema and executes them against the database. CRUD queries are provided by Prisma Client, a lightweight and entirely type-safe database client for Node.js and TypeScript.

## API design & Level of abstraction [#api-design--level-of-abstraction]

TypeORM and Prisma ORM operate on different levels of abstraction. TypeORM is closer to mirroring SQL in its API while Prisma Client provides a higher-level abstraction that was carefully designed with the common tasks of application developers in mind. Prisma ORM's API design heavily leans on the idea of [making the right thing easy](https://jason.energy/right-thing-easy-thing/).

While Prisma Client operates at a higher level of abstraction, it lets you drop down to [raw SQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries) at any time if your use case requires it.

The following sections examine a few examples for how Prisma ORM's and TypeORM's APIs differ in certain scenarios and what the rationale of Prisma ORM's API design is in these cases.

### Filtering [#filtering]

TypeORM primarily leans on SQL operators for filtering lists or records, e.g. with the `find` method. Prisma ORM on the other hand, provides a more [generic set of operators](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting#combining-operators) that are intuitive to use. It should also be noted that, as explained in the type-safety section [below](#filtering-1), TypeORM loses type-safety in filter queries in many scenarios.

A good example of how the filtering APIs of both TypeORM and Prisma ORM differ is by looking at `string` filters. While TypeORM primarily provides the filter based on the `ILike` operator which comes directly from SQL, Prisma ORM provides more specific operators that developers can use, e.g.: `contains`, `startsWith` and `endsWith`.

```ts
const posts = await prisma.post.findMany({
  where: {
    title: "Hello World",
  },
});
```

```ts
const posts = await postRepository.find({
  where: {
    title: ILike("Hello World"),
  },
});
```

```ts
const posts = await prisma.post.findMany({
  where: {
    title: { contains: "Hello World" },
  },
});
```

```ts
const posts = await postRepository.find({
  where: {
    title: ILike("%Hello World%"),
  },
});
```

```ts
const posts = await prisma.post.findMany({
  where: {
    title: { startsWith: "Hello World" },
  },
});
```

```ts
const posts = await postRepository.find({
  where: {
    title: ILike("Hello World%"),
  },
});
```

```ts
const posts = await prisma.post.findMany({
  where: {
    title: { endsWith: "Hello World" },
  },
});
```

```ts
const posts = await postRepository.find({
  where: {
    title: ILike("%Hello World"),
  },
});
```

### Pagination [#pagination]

TypeORM only offers limit-offset pagination while Prisma ORM provides dedicated APIs for both limit-offset and cursor-based pagination. You can learn more about both approaches in the [Pagination](https://www.prisma.io/docs/orm/v7/prisma-client/queries/pagination) section of the docs or in the API comparison [below](#pagination-1).

### Relations [#relations]

Working with records that are connected via foreign keys can become very complex in SQL. Prisma ORM's concept of [virtual relation field](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields) enables an intuitive and convenient way for application developers to work with related data. Some benefits of Prisma ORM's approach are:

* traversing relationships via the fluent API ([Fluent API](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#fluent-api))
* nested writes that enable updating/creating connected records ([Nested writes](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-writes))
* applying filters on related records ([Relation filters](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-filters))
* type-safe querying of nested data without writing JOINs ([Nested reads](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-reads))
* creating nested TypeScript typings based on models and their relations ([Type safety Overview](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety))
* intuitive modeling of relations in the data model via relation fields ([Relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations))
* implicit handling of relation tables (also sometimes called JOIN, link, pivot or junction tables) ([Implicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations))

### Data modeling and migrations [#data-modeling-and-migrations]

Prisma models are defined in the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) while TypeORM uses classes and experimental TypeScript decorators for model definitions. With the Active Record ORM pattern, TypeORM's approach often leads to complex model instances that are becoming hard to maintain as an application grows.

Prisma ORM on the other hand generates a lightweight database client that exposes a tailored and fully type-safe API to read and write data for the models that are defined in the Prisma schema, following the DataMapper ORM pattern rather than Active Record.

Prisma ORM's data modeling language is declarative and short to read. When modeling data in VS Code, the Prisma VS Code extension adds autocompletion, quick fixes, and jump to definition.

```prisma
model User {
  id    Int     @id @default(autoincrement())
  name  String?
  email String  @unique
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  authorId  Int?
  author    User?   @relation(fields: [authorId], references: [id])
}
```

```ts
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToOne } from "typeorm";

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ nullable: true })
  name: string;

  @Column({ unique: true })
  email: string;

  @OneToMany((type) => Post, (post) => post.author)
  posts: Post[];
}

@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column({ nullable: true })
  content: string;

  @Column({ default: false })
  published: boolean;

  @ManyToOne((type) => User, (user) => user.posts)
  author: User;
}
```

Migrations work in similar fashions in TypeORM and Prisma ORM. Both tools follow the approach of generating SQL files based on the provided model definitions and provide a CLI to execute them against the database. The SQL files can be modified before the migrations are executed so that any custom database operation can be performed with either migration system.

## Type safety [#type-safety]

TypeORM has been one of the first ORMs in the Node.js ecosystem to fully embrace TypeScript and has done a great job in enabling developers to get a certain level of type safety for their database queries.

However, there are numerous situations where the type safety guarantees of TypeORM fall short. The following sections describe the scenarios where Prisma ORM can provide stronger guarantees for the types of query results.

### Selecting fields [#selecting-fields]

This section explains the differences in type safety when selecting a subset of a model's fields in a query.

#### TypeORM [#typeorm]

TypeORM provides a `select` option for its [`find`](https://typeorm.io/find-options) methods (e.g. `find`, `findByIds`, `findOne`, ...), for example:

  

#### find with select

```ts
const postRepository = getManager().getRepository(Post);
const publishedPosts: Post[] = await postRepository.find({
  where: { published: true },
  select: ["id", "title"],
});
```

#### Model

```ts
@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column({ nullable: true })
  content: string;

  @Column({ default: false })
  published: boolean;

  @ManyToOne((type) => User, (user) => user.posts)
  author: User;
}
```

While each object in the returned `publishedPosts` array only carries the selected `id` and `title` properties at runtime, the TypeScript compiler doesn't have any knowledge of this. It will allow you to access any other properties defined on the `Post` entity after the query, for example:

```ts
const post = publishedPosts[0];

// The TypeScript compiler has no issue with this
if (post.content.length > 0) {
  console.log(`This post has some content.`);
}
```

This code will result in an error at runtime:

```
TypeError: Cannot read property 'length' of undefined
```

The TypeScript compiler only sees the `Post` type of the returned objects, but it doesn't know about the fields that these objects *actually* carry at runtime. It therefore can't protect you from accessing fields that have not been retrieved in the database query, resulting in a runtime error.

#### Prisma ORM [#prisma-orm]

Prisma Client can guarantee full type safety in the same situation and protects you from accessing fields that were not retrieved from the database.

Consider the same example with a Prisma Client query:

  

#### findMany with select

```ts
const publishedPosts = await prisma.post.findMany({
  where: { published: true },
  select: {
    id: true,
    title: true,
  },
});
const post = publishedPosts[0];

// The TypeScript compiler will not allow this
if (post.content.length > 0) {
  console.log(`This post has some content.`);
}
```

#### Model

```prisma
model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  authorId  Int?
  author    User?   @relation(fields: [authorId], references: [id])
}
```

In this case, the TypeScript compiler will throw the following error already at compile-time:

```
[ERROR] 14:03:39 ⨯ Unable to compile TypeScript:
src/index.ts:36:12 - error TS2339: Property 'content' does not exist on type '{ id: number; title: string; }'.

42   if (post.content.length > 0) {
```

This is because Prisma Client generates the return type for its queries *on the fly*. In this case, `publishedPosts` is typed as follows:

```ts
const publishedPosts: {
  id: number;
  title: string;
}[];
```

It therefore is impossible for you to accidentally access a property on a model that has not been retrieved in a query.

### Loading relations [#loading-relations]

This section explains the differences in type safety when loading relations of a model in a query. In traditional ORMs, this is sometimes called *eager loading*.

#### TypeORM [#typeorm-1]

TypeORM allows eagerly loading relations from the database via the `relations` option that can be passed to its [`find`](https://typeorm.io/find-options) methods.

Consider this example:

  

#### find with relations

```ts
const postRepository = getManager().getRepository(Post);
const publishedPosts: Post[] = await postRepository.find({
  where: { published: true },
  relations: ["author"],
});
```

#### Models

```ts
@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column({ nullable: true })
  content: string;

  @Column({ default: false })
  published: boolean;

  @ManyToOne((type) => User, (user) => user.posts)
  author: User;
}
```

```ts
@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ nullable: true })
  name: string;

  @Column({ unique: true })
  email: string;

  @OneToMany((type) => Post, (post) => post.author)
  posts: Post[];
}
```

Unlike with `select`, TypeORM does *not* provide autocompletion, nor any type-safety for the strings that are passed to the `relations` option. This means, the TypeScript compiler is not able to catch any typos that are made when querying these relations. For example, it would allow for the following query:

```ts
const publishedPosts: Post[] = await postRepository.find({
  where: { published: true },
  // this query would lead to a runtime error because of a typo
  relations: ["authors"],
});
```

This subtle typo would now lead to the following runtime error:

```
UnhandledPromiseRejectionWarning: Error: Relation "authors" was not found; please check if it is correct and really exists in your entity.
```

#### Prisma ORM [#prisma-orm-1]

Prisma ORM protects you from mistakes like this and thus eliminates a whole class of errors that can occur in your application at runtime. When using `include` to load a relation in a Prisma Client query, you can not only take advantage of autocompletion to specify the query, but the result of the query will also be properly typed:

  

#### find with relations

```ts
const publishedPosts = await prisma.post.findMany({
  where: { published: true },
  include: { author: true },
});
```

#### Models

```ts
model User {
  id      Int      @id @default(autoincrement())
  name    String?
  email   String   @unique
  posts   Post[]
}

model Post {
  id                Int                @id @default(autoincrement())
  title             String
  content           String?
  published         Boolean            @default(false)
  authorId          Int?
  author            User?              @relation(fields: [authorId], references: [id])
}
```

Again, the type of `publishedPosts` is generated on the fly and looks as follows:

```ts
const publishedPosts: (Post & {
  author: User;
})[];
```

For reference, this is what the `User` and `Post` types look like that Prisma Client generates for your Prisma models:

  

#### User

```ts
// Generated by Prisma ORM
export type User = {
  id: number;
  name: string | null;
  email: string;
};
```

#### Post

```ts
// Generated by Prisma ORM
export type Post = {
  id: number;
  title: string;
  content: string | null;
  published: boolean;
  authorId: number | null;
};
```

### Filtering [#filtering-1]

This section explains the differences in type safety when filtering a list of records using `where`.

#### TypeORM [#typeorm-2]

TypeORM allows passing a `where` option to its [`find`](https://typeorm.io/find-options) methods to filter the list of returned records according to specific criteria. These criteria can be defined with respect to a model's properties.

##### Losing type-safety using operators [#losing-type-safety-using-operators]

Consider this example:

  

#### find with select

```ts
const postRepository = getManager().getRepository(Post);
const publishedPosts: Post[] = await postRepository.find({
  where: {
    published: true,
    title: ILike("Hello World"),
    views: MoreThan(0),
  },
});
```

#### Model

```ts
@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column({ nullable: true })
  content: string;

  @Column({ nullable: true })
  views: number;

  @Column({ default: false })
  published: boolean;

  @ManyToOne((type) => User, (user) => user.posts)
  author: User;
}
```

This code runs properly and produces a valid query at runtime. However, the `where` option is not really type-safe in various different scenarios. When using a `FindOperator` like `ILike` or `MoreThan` that only work for specific types (`ILike` works for strings, `MoreThan` for numbers), you're losing the guarantee of providing the correct type for the model's field.

For example, you can provide a string to the `MoreThan` operator. The TypeScript compiler will not complain and your application will only fail at runtime:

```ts
const postRepository = getManager().getRepository(Post);
const publishedPosts: Post[] = await postRepository.find({
  where: {
    published: true,
    title: ILike("Hello World"),
    views: MoreThan("test"),
  },
});
```

The code above results in a runtime error that the TypeScript compiler doesn't catch for you:

```
error: error: invalid input syntax for type integer: "test"
```

##### Specifying non-existing properties [#specifying-non-existing-properties]

Also note that the TypeScript compiler allows you to specify properties on the `where` option that don't exist on your models – again resulting in runtime errors:

```ts
const publishedPosts: Post[] = await postRepository.find({
  where: {
    published: true,
    title: ILike("Hello World"),
    viewCount: 1,
  },
});
```

In this case, your application again fails at runtime with the following error:

```
EntityColumnNotFound: No entity column "viewCount" was found.
```

#### Prisma ORM [#prisma-orm-2]

Both filtering scenarios that are problematic with TypeORM in terms of type-safety are covered by Prisma ORM in a fully type-safe way.

##### Type-safe usage of operators [#type-safe-usage-of-operators]

With Prisma ORM, the TypeScript compiler enforces the correct usage of an operator per field:

```ts
const publishedPosts = await prisma.post.findMany({
  where: {
    published: true,
    title: { contains: "Hello World" },
    views: { gt: 0 },
  },
});
```

It would not be allowed to specify the same problematic query shown above with Prisma Client:

```ts
const publishedPosts = await prisma.post.findMany({
  where: {
    published: true,
    title: { contains: "Hello World" },
    views: { gt: "test" }, // Caught by the TypeScript compiler
  },
});
```

The TypeScript compiler would catch this and throw the following error to protect you from a runtime failure of the app:

```
[ERROR] 16:13:50 ⨯ Unable to compile TypeScript:
src/index.ts:39:5 - error TS2322: Type '{ gt: string; }' is not assignable to type 'number | IntNullableFilter'.
  Type '{ gt: string; }' is not assignable to type 'IntNullableFilter'.
    Types of property 'gt' are incompatible.
      Type 'string' is not assignable to type 'number'.

42     views: { gt: "test" }
```

##### Type-safe definition of filters as model properties [#type-safe-definition-of-filters-as-model-properties]

With TypeORM, you are able to specify a property on the `where` option that doesn't map to a model's field. In the above example, filtering for `viewCount` therefore led to a runtime error because the field actually is called `views`.

With Prisma ORM, the TypeScript compiler will not allow to reference any properties inside of `where` that don't exist on the model:

```ts
const publishedPosts = await prisma.post.findMany({
  where: {
    published: true,
    title: { contains: "Hello World" },
    viewCount: { gt: 0 }, // Caught by the TypeScript compiler
  },
});
```

Again, the TypeScript compiler complains with the following message to protect you from your own mistakes:

```ts
[ERROR] 16:16:16 ⨯ Unable to compile TypeScript:
src/index.ts:39:5 - error TS2322: Type '{ published: boolean; title: { contains: string; }; viewCount: { gt: number; }; }' is not assignable to type 'PostWhereInput'.
  Object literal may only specify known properties, and 'viewCount' does not exist in type 'PostWhereInput'.

42     viewCount: { gt: 0 }
```

### Creating new records [#creating-new-records]

This section explains the differences in type safety when creating new records.

#### TypeORM [#typeorm-3]

With TypeORM, there are two main ways to create new records in the database: `insert` and `save`. Both methods allow developers to submit data that can lead to runtime errors when *required* fields are not provided.

Consider this example:

  

#### Create with save

```ts
const userRepository = getManager().getRepository(User);
const newUser = new User();
newUser.name = "Alice";
userRepository.save(newUser);
```

#### Create with insert

```ts
const userRepository = getManager().getRepository(User);
userRepository.insert({
  name: "Alice",
});
```

#### Model

```ts
@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ nullable: true })
  name: string;

  @Column({ unique: true })
  email: string;

  @OneToMany((type) => Post, (post) => post.author)
  posts: Post[];
}
```

No matter if you're using `save` or `insert` for record creation with TypeORM, you will get the following runtime error if you forget to provide the value for a required field:

```
QueryFailedError: null value in column "email" of relation "user" violates not-null constraint
```

The `email` field is defined as required on the `User` entity (which is enforced by a `NOT NULL` constraint in the database).

### Prisma ORM [#prisma-orm-3]

Prisma ORM protects you from these kind of mistakes by enforcing that you submit values for *all* required fields of a model.

For example, the following attempt to create a new `User` where the required `email` field is missing would be caught by the TypeScript compiler:

  

#### Create with create

```ts
const newUser = await prisma.user.create({
  data: {
    name: "Alice",
  },
});
```

#### Model

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

It would lead to the following compile-time error:

```
[ERROR] 10:39:07 ⨯ Unable to compile TypeScript:
src/index.ts:39:5 - error TS2741: Property 'email' is missing in type '{ name: string; }' but required in type 'UserCreateInput'.
```

## API comparison [#api-comparison]

### Fetching single objects [#fetching-single-objects]

**Prisma ORM**

```ts
const user = await prisma.user.findUnique({
  where: {
    id: 1,
  },
});
```

**TypeORM**

```ts
const userRepository = getRepository(User);
const user = await userRepository.findOne(id);
```

### Fetching selected scalars of single objects [#fetching-selected-scalars-of-single-objects]

**Prisma ORM**

```ts
const user = await prisma.user.findUnique({
  where: {
    id: 1,
  },
  select: {
    name: true,
  },
});
```

**TypeORM**

```ts
const userRepository = getRepository(User);
const user = await userRepository.findOne(id, {
  select: ["id", "email"],
});
```

### Fetching relations [#fetching-relations]

**Prisma ORM**

  

#### Using include

```ts
const posts = await prisma.user.findUnique({
  where: {
    id: 2,
  },
  include: {
    post: true,
  },
});
```

#### Fluent API

```ts
const posts = await prisma.user
  .findUnique({
    where: {
      id: 2,
    },
  })
  .post();
```

> **Note**: `select` return a `user` object that includes a `post` array, whereas the fluent API only returns a `post` array.

**TypeORM**

  

#### Using relations

```ts
const userRepository = getRepository(User);
const user = await userRepository.findOne(id, {
  relations: ["posts"],
});
```

#### Using JOIN

```ts
const userRepository = getRepository(User);
const user = await userRepository.findOne(id, {
  join: {
    alias: "user",
    leftJoinAndSelect: {
      posts: "user.posts",
    },
  },
});
```

#### Using eager relations

```ts
const userRepository = getRepository(User);
const user = await userRepository.findOne(id);
```

### Filtering for concrete values [#filtering-for-concrete-values]

**Prisma ORM**

```ts
const posts = await prisma.post.findMany({
  where: {
    title: {
      contains: "Hello",
    },
  },
});
```

**TypeORM**

```ts
const userRepository = getRepository(User);
const users = await userRepository.find({
  where: {
    name: "Alice",
  },
});
```

### Other filter criteria [#other-filter-criteria]

**Prisma ORM**

Prisma ORM generates many [additional filters](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting) that are commonly used in application development.

**TypeORM**

TypeORM provides [built-in operators](https://typeorm.io/find-options#advanced-options) that can be used to create more complex comparisons

### Relation filters [#relation-filters]

**Prisma ORM**

Prisma ORM lets you filter a list based on a criteria that applies not only to the models of the list being retrieved, but to a *relation* of that model.

For example, the following query returns users with one or more posts with "Hello" in the title:

```ts
const posts = await prisma.user.findMany({
  where: {
    Post: {
      some: {
        title: {
          contains: "Hello",
        },
      },
    },
  },
});
```

**TypeORM**

TypeORM doesn't offer a dedicated API for relation filters. You can get similar functionality by using the `QueryBuilder` or writing the queries by hand.

### Pagination [#pagination-1]

**Prisma ORM**

Cursor-style pagination:

```ts
const page = await prisma.post.findMany({
  before: {
    id: 242,
  },
  last: 20,
});
```

Offset pagination:

```ts
const cc = await prisma.post.findMany({
  skip: 200,
  first: 20,
});
```

**TypeORM**

```ts
const postRepository = getRepository(Post);
const posts = await postRepository.find({
  skip: 5,
  take: 10,
});
```

### Creating objects [#creating-objects]

**Prisma ORM**

```ts
const user = await prisma.user.create({
  data: {
    email: "alice@prisma.io",
  },
});
```

**TypeORM**

  

#### Using save

```ts
const user = new User();
user.name = "Alice";
user.email = "alice@prisma.io";
await user.save();
```

#### Using create

```ts
const userRepository = getRepository(User);
const user = await userRepository.create({
  name: "Alice",
  email: "alice@prisma.io",
});
await user.save();
```

#### Using insert

```ts
const userRepository = getRepository(User);
await userRepository.insert({
  name: "Alice",
  email: "alice@prisma.io",
});
```

### Updating objects [#updating-objects]

**Prisma ORM**

```ts
const user = await prisma.user.update({
  data: {
    name: "Alicia",
  },
  where: {
    id: 2,
  },
});
```

**TypeORM**

```ts
const userRepository = getRepository(User);
const updatedUser = await userRepository.update(id, {
  name: "James",
  email: "james@prisma.io",
});
```

### Deleting objects [#deleting-objects]

**Prisma ORM**

```ts
const deletedUser = await prisma.user.delete({
  where: {
    id: 10,
  },
});
```

**TypeORM**

  

#### Using delete

```ts
const userRepository = getRepository(User);
await userRepository.delete(id);
```

#### Using remove

```ts
const userRepository = getRepository(User);
const deletedUser = await userRepository.remove(user);
```

### Batch updates [#batch-updates]

**Prisma ORM**

```ts
const user = await prisma.user.updateMany({
  data: {
    name: "Published author!",
  },
  where: {
    Post: {
      some: {
        published: true,
      },
    },
  },
});
```

**TypeORM**

You can use the [query builder to update entities in your database](https://typeorm.io/update-query-builder).

### Batch deletes [#batch-deletes]

**Prisma ORM**

```ts
const users = await prisma.user.deleteMany({
  where: {
    id: {
      in: [1, 2, 6, 6, 22, 21, 25],
    },
  },
});
```

**TypeORM**

  

#### Using delete

```ts
const userRepository = getRepository(User);
await userRepository.delete([id1, id2, id3]);
```

#### Using remove

```ts
const userRepository = getRepository(User);
const deleteUsers = await userRepository.remove([user1, user2, user3]);
```

### Transactions [#transactions]

**Prisma ORM**

```ts
const user = await prisma.user.create({
  data: {
    email: "bob.rufus@prisma.io",
    name: "Bob Rufus",
    Post: {
      create: [{ title: "Working at Prisma" }, { title: "All about databases" }],
    },
  },
});
```

**TypeORM**

```ts
await getConnection().$transaction(async (transactionalEntityManager) => {
  const user = getRepository(User).create({
    name: "Bob",
    email: "bob@prisma.io",
  });
  const post1 = getRepository(Post).create({
    title: "Join us for GraphQL Conf in 2019",
  });
  const post2 = getRepository(Post).create({
    title: "Subscribe to GraphQL Weekly for GraphQL news",
  });
  user.posts = [post1, post2];
  await transactionalEntityManager.save(post1);
  await transactionalEntityManager.save(post2);
  await transactionalEntityManager.save(user);
});
```

## Related pages

- [`Drizzle`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-drizzle): Learn how Prisma ORM compares to Drizzle
- [`Mongoose`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-mongoose): Learn how Prisma ORM compares to Mongoose
- [`Sequelize`](https://www.prisma.io/docs/orm/v7/more/comparisons/prisma-and-sequelize): Learn how Prisma ORM compares to Sequelize

# Editor setup (Prisma ORM v7) (/docs/orm/v7/more/dev-environment/editor-setup)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to configure your editor and IDEs for syntax highlighting, autocompletion, and formatting with Prisma ORM

Location: ORM > v7 > More > Dev environment > Editor setup

This page describes how to configure your editor for syntax highlighting, autocompletion, and formatting of Prisma schema files.

If you don't see your editor here, please [open a feature request](https://github.com/prisma/orm/issues/new?assignees=\&labels=\&template=feature_request.md\&title=")" and ask for dedicated support for your editor (e.g. for syntax highlighting and auto-formatting).

## VS Code extension [#vs-code-extension]

You can install the official [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma). It adds extra capabilities to VS Code when developing applications with Prisma ORM:

* Syntax highlighting of `schema.prisma`
* Linting
  * Diagnostic tools are used to surface errors and warnings in your schema file as you type.
* Code Completion
  * Completion results appear for symbols as you type.
  * You can trigger this manually with the `Ctrl+Space` shortcut.
* Documentation help
  * Documentation of a completion result pops up as completion results are provided.
* Quick info on hover
  * Documentation Comments (`///`) of models and enums appear anywhere you hover over their usages.
* Go to Definition
  * Jump to or peek a model or enum's declaration.
* Formatting
  * Format code either manually or on save (if configured).
    * To automatically format on save, add the following to your `settings.json` file:
      ```json
      "editor.formatOnSave": true
      ```
    * To enable formatting in combination with `prettier`, add the following to your `settings.json` file:or use the [Prettier plugin for Prisma](https://github.com/umidbekk/prettier-plugin-prisma)
      ```json
      "[prisma]": {
        "editor.defaultFormatter": "Prisma.prisma"
      },
      ```
* Rename
  * Rename models, enums, fields and enum values
    * Click into the model or enum, press `F2` and then type the new desired name and press `Enter`
    * All usages will be renamed
    * Automatically applies `@map` or `@@map` on the schema
* Quick-fixes
  * Quickly fix typos in model and enum names
  * Create new models and enums with a single click

> [!NOTE]
> If you're using VS Code, you can use [VS Code agent mode](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode) to enter prompts such as “create Postgres database” or “apply schema migration” directly in the chat. The VS code agent handles all underlying Prisma CLI invocations and API calls automatically. See our [VS Code Agent documentation](https://www.prisma.io/docs/guides/postgres/vscode#agent-mode) for more details.

## Community projects [#community-projects]

> **Note**: Community projects are not maintained or officially supported by Prisma and some features may by out of sync. Use at your own discretion.

### Emacs [#emacs]

* [emacs-prisma-mode](https://github.com/pimeys/emacs-prisma-mode) provides syntax highlighting of the Prisma Schema Language and uses the Prisma Language Server.

### Vim [#vim]

* [vim-prisma](https://github.com/prisma/vim-prisma) provides file detection and syntax highlighting of the Prisma Schema Language.

### neovim [#neovim]

* [coc-prisma](https://github.com/pantharshit00/coc-prisma) implements the Prisma Language Server.

### JetBrains IDE [#jetbrains-ide]

* [Prisma ORM](https://plugins.jetbrains.com/plugin/20686-prisma-orm) Provided by JetBrains. This plugin provides PSL grammar, syntax highlighting, LSP, and more.

### Sublime Text [#sublime-text]

* [Prisma](https://packagecontrol.io/packages/Prisma) - For Sublime Text 3 & 4 - Provides syntax highlighting for the Prisma Schema Language. ([Source Code](https://github.com/Sublime-Instincts/PrismaHighlight/))
* [LSP-prisma](https://packagecontrol.io/packages/LSP-prisma) - For Sublime Text 4 - Language Server helper package for Prisma schema files that uses Prisma's Language Server to provide linting, error checking, formatting, autocompletion, renaming etc. Note: It requires the Prisma package to be installed. ([Source Code](https://github.com/Sublime-Instincts/LSP-prisma))

### nova [#nova]

* [nova](https://extensions.panic.com/extensions/robb-j/robb-j.Prisma/) provides syntax highlighting of the Prisma Schema Language and uses the Prisma Language Server.

### Helix [#helix]

* [Helix](https://helix-editor.com/) (from version 22.08) provides syntax highlighting of the Prisma Schema Language and uses the Prisma Language Server.

### CLI autocomplete [#cli-autocomplete]

#### inshellisense [#inshellisense]

You can get IDE-style autocompletion for Prisma CLI using [`inshellisense`](https://github.com/microsoft/inshellisense/tree/main). It supports: bash, zsh, fish, pwsh, powershell (Windows Powershell).

To install, run:

  

#### bun

```bash
bun add --global @microsoft/inshellisense
```

#### pnpm

```bash
pnpm add -g @microsoft/inshellisense
```

#### yarn

```bash
yarn global add @microsoft/inshellisense
```

#### npm

```bash
npm install -g @microsoft/inshellisense
```

## Related pages

- [`Environment variables`](https://www.prisma.io/docs/orm/v7/more/dev-environment/environment-variables): Learn how to manage environment variables in your Prisma ORM project

# Environment variables (Prisma ORM v7) (/docs/orm/v7/more/dev-environment/environment-variables)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to manage environment variables in your Prisma ORM project

Location: ORM > v7 > More > Dev environment > Environment variables

An environment variable is a key value pair of string data that is stored on your machine's local environment. Refer to our [Environment variables reference documentation](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference) for specific details.

Typically the name of the variable is uppercase, this is then followed by an equals sign then the value of the variable:

```text
MY_VALUE=prisma
```

The environment variable belongs to the environment where a process is running. Any program can read and create these environment variables. They are a cheap and effective way to store simple information.

> [!NOTE]
> With Prisma ORM v6.4.0, we released the `prisma.config.ts` file. This file allows you to manage your environment variables and settings in a more flexible way. [View our reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference) for more information.

## How Prisma ORM can use environment variables [#how-prisma-orm-can-use-environment-variables]

Prisma ORM always reads environment variables from the system's environment.

When you initialize Prisma ORM in your project with `prisma init`, it creates a convenience `.env` file for you to set your [`connection url`](https://www.prisma.io/docs/orm/v7/reference/connection-urls) as an environment variable. When you use Prisma CLI or Prisma Client, the `.env` file content and the variables defined in it are added to the [`process.env` object](https://nodejs.org/api/process.html#processenv), where Prisma ORM can read it and use it.

### Using an `.env` file [#using-an-env-file]

> [!WARNING]
> **Do not commit your `.env` files into version control**!

The Prisma CLI looks for `.env` files, in order, in the following locations:

1. In the root folder of your project (`./.env`)
2. From the same folder as the schema specified by the `--schema` argument
3. From the same folder as the schema taken from `"prisma": {"schema": "/path/to/schema.prisma"}` in `package.json`
4. From the `./prisma` folder

If a `.env` file is located in step 1., but additional, clashing `.env` variables are located in steps 2. - 4., the CLI will throw an error. For example, if you specify a `DATABASE_URL` variable in two different `.env` files, you will get the following error:

```
Error: There is a conflict between env vars in .env and prisma/.env
Conflicting env vars:
  DATABASE_URL

We suggest to move the contents of prisma/.env to .env to consolidate your env vars.
```

The following table describes where the Prisma CLI looks for the `.env` file:

| **Command**                                     | **schema location**                                                          | **`.env` file locations checked, in order**               |
| :---------------------------------------------- | :--------------------------------------------------------------------------- | :-------------------------------------------------------- |
| `prisma [command]`                              | `./prisma/schema.prisma`                                                     | `./.env`<br />`./prisma/.env`                             |
| `prisma [command] --schema=./a/b/schema.prisma` | `./a/b/schema.prisma`                                                        | `./.env`<br />`./a/b/.env`<br />`./prisma/.env`           |
| `prisma [command]`                              | `"prisma": {"schema": "/path/to/schema.prisma"}`                             | `.env`<br /> `./path/to/schema/.env`<br />`./prisma/.env` |
| `prisma [command]`                              | No schema (for example, when running `prisma db pull` in an empty directory) | `./.env`<br />`./prisma/.env`                             |

Any environment variables defined in that `.env` file will automatically be loaded when running a Prisma CLI command.

> [!NOTE]
> To use more than one `.env` file, see [Using multiple `.env` files](#using-multiple-env-files) for how to set them up in your application.

Refer to the `dotenv` documentation for information about [what happens if an environment variable is defined in two places](https://www.npmjs.com/package/dotenv#what-happens-to-environment-variables-that-were-already-set).

#### Expanding variables with `.env` files [#expanding-variables-with-env-files]

Variables stored in `.env` files can be expanded using the format specified by [dotenv-expand](https://github.com/motdotla/dotenv-expand).

```text title=".env"
DATABASE_URL=postgresql://test:test@localhost:5432/test
DATABASE_URL_WITH_SCHEMA=${DATABASE_URL}?schema=public
```

Additionally, you can use environment variables in the expansion that are set *outside* of the `.env` file. For example a database URL that is set on a PaaS like Heroku or similar:

```bash
# environment variable already set in the environment of the system
export DATABASE_URL=postgresql://test:test@localhost:5432/test
```

```text title=".env"
DATABASE_URL_WITH_SCHEMA=${DATABASE_URL}?schema=foo
```

This will make the environment variable `DATABASE_URL_WITH_SCHEMA` with value `postgresql://test:test@localhost:5432/test?schema=foo` available for Prisma ORM.

### Using environment variables in your code [#using-environment-variables-in-your-code]

If you want environment variables to be evaluated at runtime, you need to load them manually in your application code (for example, by using [`dotenv`](https://github.com/motdotla/dotenv)):

```ts
import * as dotenv from "dotenv";

dotenv.config(); // Load the environment variables
console.log(`The connection URL is ${process.env.DATABASE_URL}`);
```

If you are using a custom file name for your environment variables, you can configure `dotenv` to use that filename:

```ts
import * as dotenv from "dotenv";

var envFile = path.resolve(join(__dirname, "myenv.env"));
dotenv.config({ path: envFile }); // Load the environment variables
console.log(`The connection URL is ${process.env.DATABASE_URL}`);
```

If you need variable expansion across environment files, you can additionally use [`dotenv-expand`](https://github.com/motdotla/dotenv-expand):

```ts
import * as dotenv from "dotenv";
const dotenvExpand = require("dotenv-expand");

var envFile = path.resolve(join(__dirname, "myenv.env"));
var mySqlEnv = dotenv.config({ path: envFile });
dotenvExpand.expand(mySqlEnv);
```

If you are using multiple `.env` files, you can reference an environment file in your project's code depending on the environment you are running in.

```ts
import { config } from "dotenv";

const envFile = process.env.NODE_ENV === "development" ? ".env.development" : ".env.production";
config({ path: envFile });
```

### Manually set environment variables [#manually-set-environment-variables]

Because Prisma ORM reads from the system's environment when looking for environment variables, it's possible to skip using `.env` completely and create them manually on your local system.

> [!NOTE]
> The following examples will use setting the `DATABASE_URL` environment variable which is often used for the database connection URL.

#### Manually set an environment variable on a Mac/Linux system [#manually-set-an-environment-variable-on-a-maclinux-system]

From a terminal on a Unix machine (Mac/Linux), you export the variable as a key value pair.

```bash
export DATABASE_URL=postgresql://test:test@localhost:5432/test?schema=public
```

Then check that it has been successfully set using `printenv`:

```bash
printenv DATABASE_URL
```

```text no-copy
postgresql://test:test@localhost:5432/test?schema=public
```

#### Manually set an environment variable on a Windows system [#manually-set-an-environment-variable-on-a-windows-system]

The following examples illustrate how to set the environment variable (for the current user) using both Command Prompt (`cmd.exe`) and PowerShell, depending on your preference.

  

#### Command Prompt

```bash
set "DATABASE_URL=postgresql://test:test@localhost:5432/test?schema=public"
```

#### PowerShell

```bash
[Environment]::SetEnvironmentVariable("DATABASE_URL", "postgresql://test:test@localhost:5432/test?schema=public")
```

Then check that it has been successfully set:

  

#### Command Prompt

```bash
set DATABASE_URL
```

#### PowerShell

```bash
Get-ChildItem Env:DATABASE_URL
```

### Using multiple `.env` files [#using-multiple-env-files]

There is a risk that your production database could be deleted if you store different connection URLs to each of your environments within a single `.env` file.

One solution is to have multiple `.env` files which each represent different environments. In practice, this means you create a file for each of your environments:

* `.env.development`
* `.env.sample`

Then using a package like [`dotenv-cli`](https://www.npmjs.com/package/dotenv-cli), you can load the correct connection URL for the environment you are working in.

> [!NOTE]
> For our purposes, it is assumed you have a dedicated development database that you use while developing your application.

1. Rename your `.env` file to `.env.development`

```text title=".env.development"
DATABASE_URL="postgresql://prisma:prisma@localhost:5433/dev"
```

2. Create a new `.env.sample` file and change the database name to `sample` (or your preferred name)

```text title=".env.sample"
DATABASE_URL="postgresql://prisma:prisma@localhost:5433/sample"
```

3. Install [`dotenv-cli`](https://www.npmjs.com/package/dotenv-cli)

In order for Prisma ORM and Jest to know which `.env` file to use, alter your `package.json` scripts to include and call the `dotenv` package and specify which file to use depending on what commands you are running and in which environment you want them to run.

> [!NOTE]
> Any top-level script that is running the tests and migrations needs the `dotenv` command before it. This makes sure that the env variables from `.env.sample` are passed to all commands, including Jest.

#### Running migrations on different environments [#running-migrations-on-different-environments]

You can use the [`dotenv-cli`](https://www.npmjs.com/package/dotenv-cli) package to specify which environment file Prisma ORM should use when running a migration.

The below script uses `dotenv-cli` to pass the `.env.sample` environment file (which holds a `DATABASE_URL` connection string) to the Prisma ORM migration script.

#### Migration script [#migration-script]

```json title="package.json"
  "scripts": {
    "migrate:postgres": "dotenv -e .env.sample -- npx prisma migrate deploy",
  },
```

#### Running tests on different environments [#running-tests-on-different-environments]

When running tests, we advise you to [mock Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/testing/unit-testing#mocking-prisma-client). In doing so, you need to tell Jest which environment it should use when running its tests.

By default, Prisma Client will use the environment specified in the default `.env` file located at the project's root.

If you have created a separate `.env.sample` file to specify your testing database, then this environment will need to be passed to Jest.

The below script uses `dotenv-cli` to pass the `.env.sample` environment file (which holds a `DATABASE_URL` connection string) to Jest.

```json title="package.json"
  "scripts": {
    "test": "dotenv -e .env.sample -- jest -i"
  },
```

## Related pages

- [`Editor setup`](https://www.prisma.io/docs/orm/v7/more/dev-environment/editor-setup): Learn how to configure your editor and IDEs for syntax highlighting, autocompletion, and formatting with Prisma ORM

# Dev environment (Prisma ORM v7) (/docs/orm/v7/more/dev-environment)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Set up your local Prisma ORM development environment, including editor tooling and environment variables.

Location: ORM > v7 > More > Dev environment

These guides cover the local development environment around Prisma ORM: editor setup, configuration ergonomics, and environment variable management.

## Start here [#start-here]

* [Environment variables](https://www.prisma.io/docs/orm/v7/more/dev-environment/environment-variables)
* [Editor setup](https://www.prisma.io/docs/orm/v7/more/dev-environment/editor-setup)

## Related pages [#related-pages]

* [Prisma schema overview](https://www.prisma.io/docs/orm/v7/prisma-schema/overview)
* [Prisma CLI](https://www.prisma.io/docs/cli/v7)
* [Prisma Config reference](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)

## Related pages

- [`Best practices`](https://www.prisma.io/docs/orm/v7/more/best-practices): Learn production-ready patterns for schema design, query optimization, type safety, security, and deployment with Prisma ORM.
- [`ORM releases and maturity levels`](https://www.prisma.io/docs/orm/v7/more/releases): Learn about the release process, versioning, and maturity of Prisma ORM components and how to deal with breaking changes that might happen throughout releases

# Bundler issues (Prisma ORM v7) (/docs/orm/v7/more/troubleshooting/bundler-issues)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Solve ENOENT package error with vercel/pkg and other bundlers

Location: ORM > v7 > More > Troubleshooting > Bundler issues

## Problem with vercel/pkg [#problem-with-vercelpkg]

If you use [vercel/pkg](https://github.com/vercel/pkg) to package your Node.js project, you might encounter an `ENOENT` error like:

```
spawn /snapshot/enoent-problem/node_modules/.prisma/client/query-engine-debian-openssl-1.1.x ENOENT
```

## Solution [#solution]

Add your Prisma query engine binary path to the `pkg/assets` section of your `package.json` file:

```json
{
  "pkg": {
    "assets": ["node_modules/.prisma/client/*.node"]
  }
}
```

See [this Github issue](https://github.com/prisma/orm/issues/8449) for further discussion.

## Related pages

- [`Check constraints`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/check-constraints): Learn how to configure CHECK constraints for data validation with Prisma ORM and PostgreSQL
- [`GraphQL autocompletion`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/graphql-autocompletion): Get autocompletion for Prisma Client queries in GraphQL resolvers with plain JavaScript
- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/many-to-many-relations): Learn how to model, query, and convert many-to-many relations with Prisma ORM
- [`Next.js`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nextjs): Best practices and troubleshooting for using Prisma ORM with Next.js applications
- [`Nuxt`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nuxt): Learn how to integrate Prisma ORM with your Nuxt application

# Check constraints (Prisma ORM v7) (/docs/orm/v7/more/troubleshooting/check-constraints)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to configure CHECK constraints for data validation with Prisma ORM and PostgreSQL

Location: ORM > v7 > More > Troubleshooting > Check constraints

This page explains how to configure [check constraints](https://www.postgresql.org/docs/9.4/ddl-constraints.html#DDL-CONSTRAINTS-CHECK-CONSTRAINTS) in a PostgreSQL database. A check constraint is a condition that must be satisfied before a value can be saved to a table - for example, the discounted price of a product must always be less than the original price.

Check constraints can be added when you create the table (using `CREATE TABLE`) or to a table that already exists (using `ALTER TABLE`).

## Prerequisites [#prerequisites]

* A [PostgreSQL](https://www.postgresql.org/) database server running
* The [`psql`](https://www.postgresql.org/docs/13/app-psql.html) command line client
* [Node.js](https://nodejs.org/) installed

## Single column check constraint [#single-column-check-constraint]

Create a table with a check constraint on a single column:

```sql
CREATE TABLE "public"."product" (
  price NUMERIC CONSTRAINT price_value_check CHECK (price > 0.01 AND price <> 1240.00)
);
ALTER TABLE "public"."product"
  ADD COLUMN "productid" serial,
  ADD PRIMARY KEY ("productid");
```

This ensures the price is never less than 0.01 and never equal to 1240.00.

## Multi-column check constraint [#multi-column-check-constraint]

Create a table with a check constraint that compares values of two columns:

```sql
CREATE TABLE "public"."anotherproduct" (
  reducedprice NUMERIC CONSTRAINT reduced_price_check CHECK (price > reducedprice),
  price NUMERIC
);
ALTER TABLE "public"."anotherproduct"
  ADD COLUMN "productid" serial,
  ADD PRIMARY KEY ("productid");
```

This ensures `reducedprice` is always less than `price`.

## Multiple check constraints [#multiple-check-constraints]

```sql
CREATE TABLE "public"."secondtolastproduct" (
  reducedprice NUMERIC CONSTRAINT reduced_price_check CHECK (price > reducedprice),
  price NUMERIC,
  tags TEXT[] CONSTRAINT tags_contains_product CHECK ('product' = ANY(tags))
);
ALTER TABLE "public"."secondtolastproduct"
  ADD COLUMN "productid" serial,
  ADD PRIMARY KEY ("productid");
```

## Adding check constraints to existing tables [#adding-check-constraints-to-existing-tables]

```sql
CREATE TABLE "public"."lastproduct" (
  category TEXT
);

ALTER TABLE "public"."lastproduct"
  ADD CONSTRAINT "category_not_clothing" CHECK (category <> 'clothing');
```

## Using with Prisma ORM [#using-with-prisma-orm]

After introspection, your Prisma schema will include the models but the check constraints are enforced at the database level:

```prisma
model product {
  price     Float?
  productid Int    @id
}

model anotherproduct {
  price        Float?
  productid    Int    @id
  reducedprice Float?
}
```

Generate Prisma Client and test:

```js
const { PrismaClient } = require("../prisma/generated/client");

const prisma = new PrismaClient();

async function main() {
  // This will fail due to the check constraint
  const newProduct = await prisma.product.create({
    data: {
      price: 0.0, // violates price > 0.01
    },
  });
}

main();
```

The script throws an error indicating the `price_check_value` check constraint was not met:

```
Error: new row for relation "product" violates check constraint "price_value_check"
```

Check constraints are resolved in alphabetical order, and only the first constraint to fail appears in the error message.

## Related pages

- [`Bundler issues`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/bundler-issues): Solve ENOENT package error with vercel/pkg and other bundlers
- [`GraphQL autocompletion`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/graphql-autocompletion): Get autocompletion for Prisma Client queries in GraphQL resolvers with plain JavaScript
- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/many-to-many-relations): Learn how to model, query, and convert many-to-many relations with Prisma ORM
- [`Next.js`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nextjs): Best practices and troubleshooting for using Prisma ORM with Next.js applications
- [`Nuxt`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nuxt): Learn how to integrate Prisma ORM with your Nuxt application

# GraphQL autocompletion (Prisma ORM v7) (/docs/orm/v7/more/troubleshooting/graphql-autocompletion)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Get autocompletion for Prisma Client queries in GraphQL resolvers with plain JavaScript

Location: ORM > v7 > More > Troubleshooting > GraphQL autocompletion

When using GraphQL with TypeScript, you get autocompletion for the Prisma Client instance in your GraphQL resolvers because the `context` object can be typed. In plain JavaScript, this needs a little more effort.

## Problem [#problem]

In a resolver like this:

```js
filterPosts: (parent, args, ctx) => {
  return ctx.prisma.post.findMany({
    where: {
      OR: [
        { title: { contains: args.searchString } },
        { content: { contains: args.searchString } },
      ],
    },
  });
};
```

VS Code doesn't know the type of the `context` object so it can't provide any intellisense.

## Solution [#solution]

Add a [JSDoc](https://jsdoc.app/) comment named `typedef` to "import" the correct type:

```js
// Add this to the top of the file
/**
 * @typedef { import("../prisma/generated/client").PrismaClient } Prisma
 */
```

Then type your resolver arguments:

```js
/**
 * @param {any} parent
 * @param {{ searchString: string }} args
 * @param {{ prisma: Prisma }} ctx
 */
filterPosts: (parent, args, ctx) => {
  return ctx.prisma.post.findMany({
    where: {
      OR: [
        { title: { contains: args.searchString } },
        { content: { contains: args.searchString } },
      ],
    },
  });
};
```

This tells VS Code that `context` has a property named `prisma` with type `Prisma`, enabling autocompletion.

## Complete example [#complete-example]

```js
/**
 * @typedef { import("../prisma/generated/client").PrismaClient } Prisma
 * @typedef { import("../prisma/generated/client").UserCreateArgs } UserCreateArgs
 */

const { makeExecutableSchema } = require("graphql-tools");

const resolvers = {
  Query: {
    /**
     * @param {any} parent
     * @param {any} args
     * @param {{ prisma: Prisma }} ctx
     */
    feed: (parent, args, ctx) => {
      return ctx.prisma.post.findMany({
        where: { published: true },
      });
    },
    /**
     * @param {any} parent
     * @param {{ searchString: string }} args
     * @param {{ prisma: Prisma }} ctx
     */
    filterPosts: (parent, args, ctx) => {
      return ctx.prisma.post.findMany({
        where: {
          OR: [
            { title: { contains: args.searchString } },
            { content: { contains: args.searchString } },
          ],
        },
      });
    },
  },
};
```

## Related pages

- [`Bundler issues`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/bundler-issues): Solve ENOENT package error with vercel/pkg and other bundlers
- [`Check constraints`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/check-constraints): Learn how to configure CHECK constraints for data validation with Prisma ORM and PostgreSQL
- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/many-to-many-relations): Learn how to model, query, and convert many-to-many relations with Prisma ORM
- [`Next.js`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nextjs): Best practices and troubleshooting for using Prisma ORM with Next.js applications
- [`Nuxt`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nuxt): Learn how to integrate Prisma ORM with your Nuxt application

# Many-to-many relations (Prisma ORM v7) (/docs/orm/v7/more/troubleshooting/many-to-many-relations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to model, query, and convert many-to-many relations with Prisma ORM

Location: ORM > v7 > More > Troubleshooting > Many-to-many relations

Modeling and querying many-to-many relations in relational databases can be challenging. This guide shows how to work with [implicit](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations) and [explicit](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#explicit-many-to-many-relations) many-to-many relations, and how to convert between them.

## Implicit relations [#implicit-relations]

Implicit many-to-many relations let Prisma ORM handle the [relation table](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#relation-table-conventions) internally:

```prisma
model Post {
  id    Int    @id @default(autoincrement())
  title String
  tags  Tag[]
}

model Tag {
  id    Int    @id @default(autoincrement())
  name  String @unique
  posts Post[]
}
```

### Creating records [#creating-records]

```ts
await prisma.post.create({
  data: {
    title: "Types of relations",
    tags: { create: [{ name: "dev" }, { name: "prisma" }] },
  },
});
```

### Querying with relations [#querying-with-relations]

```ts
await prisma.post.findMany({
  include: { tags: true },
});
```

Result:

```json
[
  {
    "id": 1,
    "title": "Types of relations",
    "tags": [
      { "id": 1, "name": "dev" },
      { "id": 2, "name": "prisma" }
    ]
  }
]
```

### Connecting and creating tags simultaneously [#connecting-and-creating-tags-simultaneously]

```ts
await prisma.post.update({
  where: { id: 1 },
  data: {
    title: "Prisma is awesome!",
    tags: { set: [{ id: 1 }, { id: 2 }], create: { name: "typescript" } },
  },
});
```

## Explicit relations [#explicit-relations]

Explicit relations are needed when you need to store extra fields in the relation table or when [introspecting](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) an existing database:

```prisma
model Post {
  id    Int        @id @default(autoincrement())
  title String
  tags  PostTags[]
}

model PostTags {
  id     Int   @id @default(autoincrement())
  post   Post? @relation(fields: [postId], references: [id])
  tag    Tag?  @relation(fields: [tagId], references: [id])
  postId Int?
  tagId  Int?

  @@index([postId, tagId])
}

model Tag {
  id    Int        @id @default(autoincrement())
  name  String     @unique
  posts PostTags[]
}
```

### Creating records with explicit relations [#creating-records-with-explicit-relations]

```ts
await prisma.post.create({
  data: {
    title: "Types of relations",
    tags: {
      create: [{ tag: { create: { name: "dev" } } }, { tag: { create: { name: "prisma" } } }],
    },
  },
});
```

### Querying with explicit relations [#querying-with-explicit-relations]

```ts
await prisma.post.findMany({
  include: { tags: { include: { tag: true } } },
});
```

### Mapping the response [#mapping-the-response]

To get a cleaner response similar to implicit relations:

```ts
const result = posts.map((post) => {
  return { ...post, tags: post.tags.map((tag) => tag.tag) };
});
```

## Converting implicit to explicit relations [#converting-implicit-to-explicit-relations]

Sometimes you need to transition from implicit to explicit relations, for example to add metadata like timestamps to the relation.

### Step 1: Add the explicit relation model [#step-1-add-the-explicit-relation-model]

Keep the implicit relation while adding the new model:

```prisma
model User {
  id        Int        @id @default(autoincrement())
  name      String
  posts     Post[]
  userPosts UserPost[]
}

model Post {
  id        Int        @id @default(autoincrement())
  title     String
  authors   User[]
  userPosts UserPost[]
}

model UserPost {
  id        Int       @id @default(autoincrement())
  userId    Int
  postId    Int
  user      User      @relation(fields: [userId], references: [id])
  post      Post      @relation(fields: [postId], references: [id])
  createdAt DateTime  @default(now())

  @@unique([userId, postId])
}
```

Run the migration:

  

#### bun

```bash
bunx prisma migrate dev --name "added explicit relation"
```

#### pnpm

```bash
pnpm prisma migrate dev --name "added explicit relation"
```

#### yarn

```bash
yarn prisma migrate dev --name "added explicit relation"
```

#### npm

```bash
npx prisma migrate dev --name "added explicit relation"
```

### Step 2: Migrate existing data [#step-2-migrate-existing-data]

```typescript
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient();

async function main() {
  const users = await prisma.user.findMany({
    include: { posts: true },
  });

  for (const user of users) {
    for (const post of user.posts) {
      await prisma.userPost.create({
        data: {
          userId: user.id,
          postId: post.id,
        },
      });
    }
  }

  console.log("Data migration completed.");
}

main()
  .catch((e) => {
    throw e;
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```

### Step 3: Remove implicit relation columns [#step-3-remove-implicit-relation-columns]

After migrating the data, remove the implicit relation columns:

```prisma
model User {
  id        Int        @id @default(autoincrement())
  name      String
  userPosts UserPost[]
}

model Post {
  id        Int        @id @default(autoincrement())
  title     String
  userPosts UserPost[]
}
```

Run the migration:

  

#### bun

```bash
bunx prisma migrate dev --name "removed implicit relation"
```

#### pnpm

```bash
pnpm prisma migrate dev --name "removed implicit relation"
```

#### yarn

```bash
yarn prisma migrate dev --name "removed implicit relation"
```

#### npm

```bash
npx prisma migrate dev --name "removed implicit relation"
```

This will drop the implicit table `_PostToUser`.

## Related pages

- [`Bundler issues`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/bundler-issues): Solve ENOENT package error with vercel/pkg and other bundlers
- [`Check constraints`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/check-constraints): Learn how to configure CHECK constraints for data validation with Prisma ORM and PostgreSQL
- [`GraphQL autocompletion`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/graphql-autocompletion): Get autocompletion for Prisma Client queries in GraphQL resolvers with plain JavaScript
- [`Next.js`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nextjs): Best practices and troubleshooting for using Prisma ORM with Next.js applications
- [`Nuxt`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nuxt): Learn how to integrate Prisma ORM with your Nuxt application

# Next.js (Prisma ORM v7) (/docs/orm/v7/more/troubleshooting/nextjs)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Best practices and troubleshooting for using Prisma ORM with Next.js applications

Location: ORM > v7 > More > Troubleshooting > Next.js

This guide covers best practices, common issues, and solutions for using Prisma ORM in Next.js applications.

## Best practices for using Prisma Client in development [#best-practices-for-using-prisma-client-in-development]

### Avoid multiple Prisma Client instances [#avoid-multiple-prisma-client-instances]

When developing a Next.js application, one common issue is accidentally creating multiple instances of the Prisma Client. This often occurs due to Next.js's hot-reloading feature in development.

#### Why this happens [#why-this-happens]

Next.js's hot-reloading feature reloads modules frequently to reflect code changes instantly. However, this can lead to multiple instances of Prisma Client being created, which consumes resources and might cause unexpected behavior.

#### Recommended solution [#recommended-solution]

To avoid this, create a single Prisma Client instance by using a global variable:

```typescript
// lib/prisma.ts
import { PrismaClient } from "../prisma/generated/client";

const globalForPrisma = global as unknown as { prisma: PrismaClient };

export const prisma = globalForPrisma.prisma || new PrismaClient();

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
```

Using this approach ensures that only one instance of Prisma Client exists, even during hot-reloading in development.

## Setting Up Prisma ORM in a Monorepo [#setting-up-prisma-orm-in-a-monorepo]

### Challenges of using Prisma ORM in monorepos [#challenges-of-using-prisma-orm-in-monorepos]

Monorepos allow multiple projects to share code and dependencies, making them a popular choice. However, using Prisma ORM in a monorepo can present challenges related to dependency resolution and schema management.

#### Key issues [#key-issues]

1. **Dependency Resolution**: Multiple packages in a monorepo might lead to conflicts if they use different version of Prisma ORM.
2. **Schema Centralization**: Managing a single Prisma Schema across multiple projects can be complex.

#### Best practices for monorepo integration [#best-practices-for-monorepo-integration]

* **Centralize the Prisma Schema**: Place the `schema.prisma` file in a shared package, such as `@myorg/db`, to ensure consistency.
* **Use a custom output directory for generated client**: Define a [custom output directory](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#fields-for-prisma-client-provider) for the generated Prisma Client to maintain consistency across packages.
* **Install dependencies in the root**: To prevent version conflicts, install Prisma ORM at the root of the monorepo.
* **Use NPM Scripts for Generation**:

  ```json
  {
    "scripts": {
      "prisma:generate": "prisma generate --schema=./packages/db/schema.prisma"
    }
  }
  ```

## Dynamic usage of Prisma Client in Next.js [#dynamic-usage-of-prisma-client-in-nextjs]

### Handling dynamic scenarios [#handling-dynamic-scenarios]

Dynamic use cases, such as working with tenant-specific databases, require additional consideration when using Prisma ORM with Next.js.

#### Problem [#problem]

Each tenant might have its own database, necessitating the creation of separate Prisma Clients at runtime. This can be complex in Next.js due to its hybrid rendering model.

#### Solution [#solution]

Use a factory function to dynamically create Prisma Clients based on tenant-specific configurations:

```typescript
// lib/prismaDynamic.ts
import { PrismaClient } from "../prisma/generated/client";

type TenantConfig = {
  databaseUrl: string;
};

export function createPrismaClient(config: TenantConfig): PrismaClient {
  return new PrismaClient({
    datasources: {
      db: {
        url: config.databaseUrl,
      },
    },
  });
}
```

Ensure that you manage the lifecycle of dynamically created Prisma Clients to avoid resource exhaustion.

## Vercel build dependency caching [#vercel-build-dependency-caching]

### Problem [#problem-1]

If you deploy an application using Prisma ORM to [Vercel](https://vercel.com/), you may run into the following error message on deployment:

```
Prisma has detected that this project was built on Vercel, which caches dependencies.
This leads to an outdated Prisma Client because Prisma's auto-generation isn't triggered.
To fix this, make sure to run the `prisma generate` command during the build process.

Learn how: https://pris.ly/d/vercel-build
```

This occurs because Vercel caches the dependencies of your project until one of those dependencies changes. Prisma ORM uses a `postinstall` hook to generate Prisma Client when dependencies are installed. Because Vercel uses cached modules, this `postinstall` hook never gets run in subsequent deployments after the initial deployment.

### Solution [#solution-1]

This issue can be solved by explicitly generating Prisma Client on every deployment. Running `prisma generate` before each deployment will ensure Prisma Client is up-to-date.

#### Option 1: Custom `postinstall` script (Recommended) [#option-1-custom-postinstall-script-recommended]

Within the `scripts` section of your project's `package.json` file, add `prisma generate` to the `postinstall` script:

```json
{
  "scripts": {
    "postinstall": "prisma generate"
  }
}
```

#### Option 2: Add to build script [#option-2-add-to-build-script]

Prepend `prisma generate` to your build command:

```json
{
  "scripts": {
    "build": "prisma generate && <actual-build-command>"
  }
}
```

#### Option 3: Vercel UI build settings [#option-3-vercel-ui-build-settings]

Within your project's dashboard, go to **Settings** > **General** > **Build & Development Settings** and prepend `prisma generate` to the Build Command field.

## Netlify build dependency caching [#netlify-build-dependency-caching]

### Problem [#problem-2]

If you deploy an application using Prisma ORM to [Netlify](https://www.netlify.com/), you may encounter a similar caching error:

```
Prisma has detected that this project was built on Netlify, which caches dependencies.
This leads to an outdated Prisma Client because Prisma's auto-generation isn't triggered.
To fix this, make sure to run the `prisma generate` command during the build process.

Learn how: https://pris.ly/d/netlify-build
```

### Solution [#solution-2]

The same solutions apply as for Vercel:

#### Option 1: Custom `postinstall` script (Recommended) [#option-1-custom-postinstall-script-recommended-1]

```json
{
  "scripts": {
    "postinstall": "prisma generate"
  }
}
```

#### Option 2: Add to build script [#option-2-add-to-build-script-1]

```json
{
  "scripts": {
    "build": "prisma generate && <actual-build-command>"
  }
}
```

#### Option 3: Netlify UI build settings [#option-3-netlify-ui-build-settings]

Within your project's dashboard, go to **Site Settings** > **Build & deploy** > **Continuous deployment** > **Build settings** and prepend `prisma generate` to the Build command field.

## Related pages

- [`Bundler issues`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/bundler-issues): Solve ENOENT package error with vercel/pkg and other bundlers
- [`Check constraints`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/check-constraints): Learn how to configure CHECK constraints for data validation with Prisma ORM and PostgreSQL
- [`GraphQL autocompletion`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/graphql-autocompletion): Get autocompletion for Prisma Client queries in GraphQL resolvers with plain JavaScript
- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/many-to-many-relations): Learn how to model, query, and convert many-to-many relations with Prisma ORM
- [`Nuxt`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nuxt): Learn how to integrate Prisma ORM with your Nuxt application

# Nuxt (Prisma ORM v7) (/docs/orm/v7/more/troubleshooting/nuxt)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to integrate Prisma ORM with your Nuxt application

Location: ORM > v7 > More > Troubleshooting > Nuxt

> [!WARNING]
> The `@prisma/nuxt` module is deprecated and no longer recommended. Please follow our [Nuxt guide](https://www.prisma.io/docs/guides/v7/frameworks/nuxt) for the recommended approach to integrating Prisma ORM with your Nuxt application.

## Related pages

- [`Bundler issues`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/bundler-issues): Solve ENOENT package error with vercel/pkg and other bundlers
- [`Check constraints`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/check-constraints): Learn how to configure CHECK constraints for data validation with Prisma ORM and PostgreSQL
- [`GraphQL autocompletion`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/graphql-autocompletion): Get autocompletion for Prisma Client queries in GraphQL resolvers with plain JavaScript
- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/many-to-many-relations): Learn how to model, query, and convert many-to-many relations with Prisma ORM
- [`Next.js`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nextjs): Best practices and troubleshooting for using Prisma ORM with Next.js applications

# Raw SQL comparisons (Prisma ORM v7) (/docs/orm/v7/more/troubleshooting/raw-sql-comparisons)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Compare columns of the same table with raw queries in Prisma ORM

Location: ORM > v7 > More > Troubleshooting > Raw SQL comparisons

Comparing different columns from the same table is a common scenario. This page shows how to achieve this using raw queries for Prisma ORM versions prior to 4.3.0.

> [!WARNING]
> From version 4.3.0, you do not need to use raw queries to compare columns in the same table. You can use the `<model>.fields` property to [compare the columns](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#compare-columns-in-the-same-table).

## Comparing numeric values [#comparing-numeric-values]

Example: retrieving posts that have more comments than likes.

```prisma
model Post {
  id            Int      @id @default(autoincrement())
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt
  title         String
  content       String?
  published     Boolean  @default(false)
  author        User     @relation(fields: [authorId], references: [id])
  authorId      Int
  likesCount    Int
  commentsCount Int
}
```

### PostgreSQL / CockroachDB [#postgresql--cockroachdb]

```js
const response =
  await prisma.$queryRaw`SELECT * FROM "public"."Post" WHERE "likesCount" < "commentsCount";`;
```

### MySQL [#mysql]

```js
const response =
  await prisma.$queryRaw`SELECT * FROM \`public\`.\`Post\` WHERE \`likesCount\` < \`commentsCount\`;`;
```

### SQLite [#sqlite]

```js
const response =
  await prisma.$queryRaw`SELECT * FROM "Post" WHERE "likesCount" < "commentsCount";`;
```

## Comparing date values [#comparing-date-values]

Example: get all projects completed after the due date.

```prisma
model Project {
  id            Int      @id @default(autoincrement())
  title         String
  author        User     @relation(fields: [authorId], references: [id])
  authorId      Int
  dueDate       DateTime
  completedDate DateTime
  createdAt     DateTime @default(now())
}
```

### PostgreSQL / CockroachDB [#postgresql--cockroachdb-1]

```js
const response =
  await prisma.$queryRaw`SELECT * FROM "public"."Project" WHERE "completedDate" > "dueDate";`;
```

### MySQL [#mysql-1]

```js
const response =
  await prisma.$queryRaw`SELECT * FROM \`public\`.\`Project\` WHERE \`completedDate\` > \`dueDate\`;`;
```

### SQLite [#sqlite-1]

```js
const response =
  await prisma.$queryRaw`SELECT * FROM "Project" WHERE "completedDate" > "dueDate";`;
```

## Related pages

- [`Bundler issues`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/bundler-issues): Solve ENOENT package error with vercel/pkg and other bundlers
- [`Check constraints`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/check-constraints): Learn how to configure CHECK constraints for data validation with Prisma ORM and PostgreSQL
- [`GraphQL autocompletion`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/graphql-autocompletion): Get autocompletion for Prisma Client queries in GraphQL resolvers with plain JavaScript
- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/many-to-many-relations): Learn how to model, query, and convert many-to-many relations with Prisma ORM
- [`Next.js`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nextjs): Best practices and troubleshooting for using Prisma ORM with Next.js applications

# TypeScript performance (Prisma ORM v7) (/docs/orm/v7/more/troubleshooting/typescript-performance)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Optimize TypeScript compilation performance when working with large Prisma schemas

Location: ORM > v7 > More > Troubleshooting > TypeScript performance

When working with large database schemas, changing how you reference the `PrismaClient` type can cut compile time and memory use substantially:

| Approach             | Types                     | Instantiations            | Memory                    | Compile Time              |
| -------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- |
| **Direct Reference** | 269,597                   | 2,772,929                 | 395MB                     | 1.86s                     |
| **typeof technique** | 222 (**99.9% reduction**) | 152 (**99.9% reduction**) | 147MB (**62% reduction**) | 0.41s (**78% reduction**) |

## Problem [#problem]

In enterprise applications with extensive database schemas, Prisma's generated types can become enormous. A schema with 50+ tables and deep relationships can lead to:

* Compilation times exceeding several minutes
* High memory usage during type checking
* IDE responsiveness degrading significantly
* CI/CD pipelines timing out on type checks

## Solution [#solution]

Use TypeScript's `typeof` operator instead of direct type references when defining function parameters that accept PrismaClient instances.

### Problematic approach for large schemas [#problematic-approach-for-large-schemas]

```typescript
import { PrismaClient } from "../prisma/generated/client";

const saveFn = async (prismaClient: PrismaClient) => {
  // Function implementation
};

const client = new PrismaClient();
await saveFn(client);
```

### Optimized approach with `typeof` [#optimized-approach-with-typeof]

```typescript
import { PrismaClient } from "../prisma/generated/client";

const saveFn = async (prismaClient: typeof client) => {
  // Function implementation
};

const client = new PrismaClient();
await saveFn(client);
```

## Why `typeof` is more efficient [#why-typeof-is-more-efficient]

The `typeof` operator creates a more efficient type resolution path:

1. **Type Query Reference**: `typeof client` performs a type query that obtains the widened type of the identifier expression, avoiding the need to re-expand the complex `PrismaClient` type definition
2. **Reduced Type Instantiation**: The compiler avoids expanding the entire Prisma type hierarchy for each type check (resulting in a 99.9% reduction in instantiations)
3. **Memory Efficiency**: Referencing an existing instance's inferred type requires significantly less memory than expanding complex conditional types and generics

## Conclusion [#conclusion]

When working with large Prisma schemas, prefer `typeof` type queries over direct references to `PrismaClient`. The 78% compilation time reduction shown here grows as the schema gets larger.

## Benchmark [#benchmark]

The complete benchmark code is available at:
[https://github.com/ToyB0x/ts-bench/pull/211](https://github.com/ToyB0x/ts-bench/pull/211)

## Related pages

- [`Bundler issues`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/bundler-issues): Solve ENOENT package error with vercel/pkg and other bundlers
- [`Check constraints`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/check-constraints): Learn how to configure CHECK constraints for data validation with Prisma ORM and PostgreSQL
- [`GraphQL autocompletion`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/graphql-autocompletion): Get autocompletion for Prisma Client queries in GraphQL resolvers with plain JavaScript
- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/many-to-many-relations): Learn how to model, query, and convert many-to-many relations with Prisma ORM
- [`Next.js`](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nextjs): Best practices and troubleshooting for using Prisma ORM with Next.js applications

# Add methods to Prisma Client (Prisma ORM v7) (/docs/orm/v7/prisma-client/client-extensions/client)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Extend the functionality of Prisma Client, client component

Location: ORM > v7 > Prisma Client > Client Extensions > Add methods to Prisma Client

You can use the `client` [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions) component to add top-level methods to Prisma Client.

## Extend Prisma Client [#extend-prisma-client]

Use the `$extends` [client-level method](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#client-methods) to create an *extended client*. An extended client is a variant of the standard Prisma Client that is wrapped by one or more extensions. Use the `client` extension component to add top-level methods to Prisma Client.

To add a top-level method to Prisma Client, use the following structure:

```ts
const prisma = new PrismaClient().$extends({
  client?: { ... }
})
```

### Example [#example]

The following example uses the `client` component to add two methods to Prisma Client:

* `$log` outputs a message.
* `$totalQueries` returns the number of queries executed by the current client instance.

```ts
let total = 0;
const prisma = new PrismaClient().$extends({
  client: {
    $log: (s: string) => console.log(s),
    async $totalQueries() {
      return total;
    },
  },
  query: {
    $allModels: {
      async $allOperations({ query, args }) {
        total += 1;
        return query(args);
      },
    },
  },
});

async function main() {
  prisma.$log("Hello world");
  const totalQueries = await prisma.$totalQueries();
  console.log(totalQueries);
}
```

## Related pages

- [`Add custom fields and methods to query results`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/result): Extend the functionality of Prisma Client, result component
- [`Add custom methods to your models`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model): Extend the functionality of Prisma Client, model component
- [`Create custom Prisma Client queries`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query): Extend the functionality of Prisma Client, query component
- [`Shared packages & examples`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/extension-examples): Explore the Prisma Client extensions that have been built by Prisma and its community
- [`Shared Prisma Client extensions`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/shared-extensions): Share extensions or import shared extensions into your Prisma project

# Shared packages & examples (Prisma ORM v7) (/docs/orm/v7/prisma-client/client-extensions/extension-examples)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Explore the Prisma Client extensions that have been built by Prisma and its community

Location: ORM > v7 > Prisma Client > Client Extensions > Shared packages & examples

## Extensions made by Prisma [#extensions-made-by-prisma]

The following is a list of extensions we've built at Prisma:

| Extension                                                                              | Description                                |
| :------------------------------------------------------------------------------------- | :----------------------------------------- |
| [`@prisma/extension-read-replicas`](https://github.com/prisma/extension-read-replicas) | Adds read replica support to Prisma Client |

## Extensions made by Prisma's community [#extensions-made-by-prismas-community]

The following is a list of extensions created by the community. If you want to create your own package, refer to the [Shared Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/shared-extensions) documentation.

| Extension                                                                                      | Description                                                                                                           |
| :--------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| [`prisma-extension-supabase-rls`](https://github.com/dthyresson/prisma-extension-supabase-rls) | Adds support for Supabase Row Level Security with Prisma                                                              |
| [`prisma-extension-bark`](https://github.com/adamjkb/bark)                                     | Implements the Materialized Path pattern that allows you to easily create and interact with tree structures in Prisma |
| [`prisma-cursorstream`](https://github.com/etabits/prisma-cursorstream)                        | Adds cursor-based streaming                                                                                           |
| [`prisma-gpt`](https://github.com/aliyeysides/prisma-gpt)                                      | Lets you query your database using natural language                                                                   |
| [`prisma-extension-caching`](https://github.com/isaev-the-poetry/prisma-extension-caching)     | Adds the ability to cache complex queries                                                                             |
| [`prisma-extension-cache-manager`](https://github.com/random42/prisma-extension-cache-manager) | Caches model queries with any [cache-manager](https://www.npmjs.com/package/cache-manager) compatible cache           |
| [`prisma-extension-random`](https://github.com/nkeil/prisma-extension-random)                  | Lets you query for random rows in your database                                                                       |
| [`prisma-paginate`](https://github.com/sandrewTx08/prisma-paginate)                            | Adds support for paginating read queries                                                                              |
| [`prisma-extension-streamdal`](https://github.com/streamdal/prisma-extension-streamdal)        | Adds support for Code-Native data pipelines using Streamdal                                                           |
| [`prisma-rbac`](https://github.com/multipliedtwice/prisma-rbac)                                | Adds customizable role-based access control                                                                           |
| [`prisma-extension-redis`](https://github.com/yxx4c/prisma-extension-redis)                    | Extensive Prisma extension designed for efficient caching and cache invalidation using Redis and Dragonfly Databases  |
| [`prisma-cache-extension`](https://github.com/Shikhar97/prisma-cache)                          | Prisma extension for caching and invalidating cache with Redis(other Storage options to be supported)                 |
| [`prisma-extension-casl`](https://github.com/dennemark/prisma-extension-casl)                  | Prisma client extension that utilizes CASL to enforce authorization logic on most simple and nested queries.          |
| [`prisma-emitter-extension`](https://github.com/feggaa/prisma-emitter-extension)               | Prisma extension for emit events on CRUD operations based on configurable listeners.                                  |
| [`prisma-prefixed-ids`](https://github.com/pureartisan/prisma-prefixed-ids)                    | Automatically generates prefixed IDs for models, with configurable per-model prefixes and ID generation               |

If you have built an extension and would like to see it featured, feel free to add it to the list by opening a pull request.

## Examples [#examples]

> [!NOTE]
> The following example extensions are provided as examples only, and without warranty. They are supposed to show how Prisma Client extensions can be created using approaches documented here. We recommend using these examples as a source of inspiration for building your own extensions.

| Example                                                                                                                          | Description                                                                                                   |
| :------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ |
| [`audit-log-context`](https://github.com/prisma/prisma-client-extensions/tree/main/audit-log-context)                            | Provides the current user's ID as context to Postgres audit log triggers                                      |
| [`callback-free-itx`](https://github.com/prisma/prisma-client-extensions/tree/main/callback-free-itx)                            | Adds a method to start interactive transactions without callbacks                                             |
| [`computed-fields`](https://github.com/prisma/prisma-client-extensions/tree/main/computed-fields)                                | Adds virtual / computed fields to result objects                                                              |
| [`input-transformation`](https://github.com/prisma/prisma-client-extensions/tree/main/input-transformation)                      | Transforms the input arguments passed to Prisma Client queries to filter the result set                       |
| [`input-validation`](https://github.com/prisma/prisma-client-extensions/tree/main/input-validation)                              | Runs custom validation logic on input arguments passed to mutation methods                                    |
| [`instance-methods`](https://github.com/prisma/prisma-client-extensions/tree/main/instance-methods)                              | Adds Active Record-like methods like `save()` and `delete()` to result objects                                |
| [`json-field-types`](https://github.com/prisma/prisma-client-extensions/tree/main/json-field-types)                              | Uses strongly-typed runtime parsing for data stored in JSON columns                                           |
| [`model-filters`](https://github.com/prisma/prisma-client-extensions/tree/main/model-filters)                                    | Adds reusable filters that can composed into complex `where` conditions for a model                           |
| [`obfuscated-fields`](https://github.com/prisma/prisma-client-extensions/tree/main/obfuscated-fields)                            | Prevents sensitive data (e.g. `password` fields) from being included in results                               |
| [`query-logging`](https://github.com/prisma/prisma-client-extensions/tree/main/query-logging)                                    | Wraps Prisma Client queries with simple query timing and logging                                              |
| [`readonly-client`](https://github.com/prisma/prisma-client-extensions/tree/main/readonly-client)                                | Creates a client that only allows read operations                                                             |
| [`retry-transactions`](https://github.com/prisma/prisma-client-extensions/tree/main/retry-transactions)                          | Adds a retry mechanism to transactions with exponential backoff and jitter                                    |
| [`row-level-security`](https://github.com/prisma/prisma-client-extensions/tree/main/row-level-security)                          | Uses Postgres row-level security policies to isolate data a multi-tenant application                          |
| [`static-methods`](https://github.com/prisma/prisma-client-extensions/tree/main/static-methods)                                  | Adds custom query methods to Prisma Client models                                                             |
| [`transformed-fields`](https://github.com/prisma/prisma-client-extensions/tree/main/transformed-fields)                          | Demonstrates how to use result extensions to transform query results and add i18n to an app                   |
| [`exists-method`](https://github.com/prisma/prisma-client-extensions/tree/main/exists-fn)                                        | Demonstrates how to add an `exists` method to all your models                                                 |
| [`update-delete-ignore-not-found `](https://github.com/prisma/prisma-client-extensions/tree/main/update-delete-ignore-not-found) | Demonstrates how to add the `updateIgnoreOnNotFound` and `deleteIgnoreOnNotFound` methods to all your models. |

## Going further [#going-further]

* Learn more about [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions).

## Related pages

- [`Add custom fields and methods to query results`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/result): Extend the functionality of Prisma Client, result component
- [`Add custom methods to your models`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model): Extend the functionality of Prisma Client, model component
- [`Add methods to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/client): Extend the functionality of Prisma Client, client component
- [`Create custom Prisma Client queries`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query): Extend the functionality of Prisma Client, query component
- [`Shared Prisma Client extensions`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/shared-extensions): Share extensions or import shared extensions into your Prisma project

# What are Client Extensions (Prisma ORM v7) (/docs/orm/v7/prisma-client/client-extensions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Extend the functionality of Prisma Client

Location: ORM > v7 > Prisma Client > What are Client Extensions

You can use Prisma Client extensions to add functionality to your models, result objects, and queries, or to add client-level methods.

> [!NOTE]
> Using Prisma 8?
> 
> Prisma 8 replaces Client extensions with [extensions](https://www.prisma.io/docs/orm/extensions) that add database capabilities and [middleware](https://www.prisma.io/docs/orm/middleware/how-middleware-works) that wraps every query. Browse both in the [extension directory](https://www.prisma.io/extensions).

You can create an extension with one or more of the following component types:

* `model`: [add custom methods or fields to your models](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model)
* `client`: [add client-level methods to Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/client)
* `query`: [create custom Prisma Client queries](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query)
* `result`: [add custom fields to your query results](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/result)

For example, you might create an extension that uses the `model` and `client` component types.

## About Prisma Client extensions [#about-prisma-client-extensions]

When you use a Prisma Client extension, you create an *extended client*. An extended client is a lightweight variant of the standard Prisma Client that is wrapped by one or more extensions. The standard client is not mutated. You can add as many extended clients as you want to your project. [Learn more about extended clients](#extended-clients).

You can associate a single extension, or multiple extensions, with an extended client. [Learn more about multiple extensions](#multiple-extensions).

You can [share your Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/shared-extensions) with other Prisma ORM users, and [import Prisma Client extensions developed by other users](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/shared-extensions#install-a-shared-packaged-extension) into your Prisma ORM project.

### Extended clients [#extended-clients]

Extended clients interact with each other, and with the standard client, as follows:

* Each extended client operates independently in an isolated instance.
* Extended clients cannot conflict with each other, or with the standard client.
* All extended clients and the standard client share the same connection pool.

> **Note**: The author of an extension can modify this behavior since they're able to run arbitrary code as part of an extension. For example, an extension might actually create an entirely new `PrismaClient` instance (including its own query engine and connection pool). Be sure to check the documentation of the extension you're using to learn about any specific behavior it might implement.

### Example use cases for extended clients [#example-use-cases-for-extended-clients]

Because extended clients operate in isolated instances, they can be a good way to do the following, for example:

* Implement row-level security (RLS), where each HTTP request has its own client with its own RLS extension, customized with session data. This can keep each user entirely separate, each in a separate client.
* Add a `user.current()` method for the `User` model to get the currently logged-in user.
* Enable more verbose logging for requests if a debug cookie is set.
* Attach a unique request id to all logs so that you can correlate them later, for example to help you analyze the operations that Prisma Client carries out.
* Remove a `delete` method from models unless the application calls the admin endpoint and the user has the necessary privileges.

## Add an extension to Prisma Client [#add-an-extension-to-prisma-client]

You can create an extension using two primary ways:

* Use the client-level [`$extends`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#client-methods) method

  ```ts
  const prisma = new PrismaClient().$extends({
    name: 'signUp', // Optional: name appears in error logs
    model: {        // This is a `model` component
      user: { ... } // The extension logic for the `user` model goes inside the curly braces
    },
  })
  ```

* Use the `Prisma.defineExtension` method to define an extension and assign it to a variable, and then pass the extension to the client-level `$extends` method

  ```ts
  import { Prisma } from '@prisma/client'

  // Define the extension
  const myExtension = Prisma.defineExtension({
    name: 'signUp', // Optional: name appears in error logs
    model: {        // This is a `model` component
      user: { ... } // The extension logic for the `user` model goes inside the curly braces
    },
  })

  // Pass the extension to a Prisma Client instance
  const prisma = new PrismaClient().$extends(myExtension)
  ```

  > [!NOTE]
> This pattern is useful for when you would like to separate extensions into multiple files or directories within a project.

The above examples use the [`model` extension component](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model) to extend the `User` model.

In your `$extends` method, use the appropriate extension component or components ([`model`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model), [`client`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/client), [`result`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/result) or [`query`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query)).

## Name an extension for error logs [#name-an-extension-for-error-logs]

You can name your extensions to help identify them in error logs. To do so, use the optional field `name`. For example:

```ts
const prisma = new PrismaClient().$extends({
  name: `signUp`,  // (Optional) Extension name
  model: {
    user: { ... }
 },
})
```

## Multiple extensions [#multiple-extensions]

You can associate an extension with an [extended client](#about-prisma-client-extensions) in one of two ways:

* You can associate it with an extended client on its own, or
* You can combine the extension with other extensions and associate all of these extensions with an extended client. The functionality from these combined extensions applies to the same extended client.
  Note: [Combined extensions can conflict](#conflicts-in-combined-extensions).

You can combine the two approaches above. For example, you might associate one extension with its own extended client and associate two other extensions with another extended client. [Learn more about how client instances interact](#extended-clients).

### Apply multiple extensions to an extended client [#apply-multiple-extensions-to-an-extended-client]

In the following example, suppose that you have two extensions, `extensionA` and `extensionB`. There are two ways to combine these.

#### Option 1: Declare the new client in one line [#option-1-declare-the-new-client-in-one-line]

With this option, you apply both extensions to a new client in one line of code.

```ts
// First of all, store your original Prisma Client in a variable as usual
const prisma = new PrismaClient();

// Declare an extended client that has an extensionA and extensionB
const prismaAB = prisma.$extends(extensionA).$extends(extensionB);
```

You can then refer to `prismaAB` in your code, for example `prismaAB.myExtensionMethod()`.

#### Option 2: Declare multiple extended clients [#option-2-declare-multiple-extended-clients]

The advantage of this option is that you can call any of the extended clients separately.

```ts
// First of all, store your original Prisma Client in a variable as usual
const prisma = new PrismaClient();

// Declare an extended client that has extensionA applied
const prismaA = prisma.$extends(extensionA);

// Declare an extended client that has extensionB applied
const prismaB = prisma.$extends(extensionB);

// Declare an extended client that is a combination of clientA and clientB
const prismaAB = prismaA.$extends(extensionB);
```

In your code, you can call any of these clients separately, for example `prismaA.myExtensionMethod()`, `prismaB.myExtensionMethod()`, or `prismaAB.myExtensionMethod()`.

### Conflicts in combined extensions [#conflicts-in-combined-extensions]

When you combine two or more extensions into a single extended client, then the *last* extension that you declare takes precedence in any conflict. In the example in option 1 above, suppose there is a method called `myExtensionMethod()` defined in `extensionA` and a method called `myExtensionMethod()` in `extensionB`. When you call `prismaAB.myExtensionMethod()`, then Prisma Client uses `myExtensionMethod()` as defined in `extensionB`.

### Middleware chaining with query extensions [#middleware-chaining-with-query-extensions]

Chain [`query`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query) extensions to compose middleware. Extensions execute in the order they are declared, first in, first out:

```ts
import { PrismaClient } from "./generated/prisma";

const prisma = new PrismaClient()
  // Extension 1: Logging - measures query execution time
  .$extends({
    query: {
      $allModels: {
        async $allOperations({ model, operation, args, query }) {
          const start = Date.now();
          const result = await query(args);
          console.log(`[LOGGING] ${model}.${operation}: ${Date.now() - start}ms`);
          return result;
        },
      },
    },
  })
  // Extension 2: Audit - logs write operations
  .$extends({
    query: {
      $allModels: {
        async $allOperations({ model, operation, args, query }) {
          if (["create", "update", "delete"].includes(operation)) {
            console.log(`[AUDIT] ${operation} on ${model}:`, JSON.stringify(args));
          }
          return query(args);
        },
      },
    },
  });
```

## Type of an extended client [#type-of-an-extended-client]

You can infer the type of an extended Prisma Client instance using the [`typeof`](https://www.typescriptlang.org/docs/handbook/2/typeof-types.html) utility as follows:

```ts
const extendedPrismaClient = new PrismaClient().$extends({
  /** extension */
});

type ExtendedPrismaClient = typeof extendedPrismaClient;
```

If you're using Prisma Client as a singleton, you can get the type of the extended Prisma Client instance using the `typeof` and [`ReturnType`](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype) utilities as follows:

```ts
function getExtendedClient() {
  return new PrismaClient().$extends({
    /* extension */
  });
}

type ExtendedPrismaClient = ReturnType<typeof getExtendedClient>;
```

## Extending model types with `Prisma.Result` [#extending-model-types-with-prismaresult]

You can use the `Prisma.Result` type utility to extend model types to include properties added via client extensions. This allows you to infer the type of the extended model, including the extended properties.

### Example [#example]

The following example demonstrates how to use `Prisma.Result` to extend the `User` model type to include a `__typename` property added via a client extension.

```ts
import { PrismaClient, Prisma } from "@prisma/client";

const prisma = new PrismaClient().$extends({
  result: {
    user: {
      __typename: {
        needs: {},
        compute() {
          return "User";
        },
      },
    },
  },
});

type ExtendedUser = Prisma.Result<typeof prisma.user, { select: { id: true } }, "findFirstOrThrow">;

async function main() {
  const user: ExtendedUser = await prisma.user.findFirstOrThrow({
    select: {
      id: true,
      __typename: true,
    },
  });

  console.log(user.__typename); // Output: 'User'
}

main();
```

The `Prisma.Result` type utility is used to infer the type of the extended `User` model, including the `__typename` property added via the client extension.

## Limitations [#limitations]

### Usage of client-level methods in extended clients [#usage-of-client-level-methods-in-extended-clients]

[Client-level methods](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#client-methods) do not necessarily exist on extended clients. For these clients you will need to first check for existence before using.

```ts
const xPrisma = new PrismaClient().$extends(...);

if (xPrisma.$connect) {
  xPrisma.$connect()
}
```

### Usage with nested operations [#usage-with-nested-operations]

The `query` extension type does not support nested read and write operations.

## Related pages

- [`Fields & types`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types): Learn how to use about special fields and types with Prisma Client
- [`Type safety Overview`](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety): Prisma Client provides full type safety for queries, even for partial queries or included relations. This page explains how to leverage the generated types and utilities
- [`Write your own SQL`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql): Learn how to use raw SQL queries in Prisma Client

# Add custom methods to your models (Prisma ORM v7) (/docs/orm/v7/prisma-client/client-extensions/model)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Extend the functionality of Prisma Client, model component

Location: ORM > v7 > Prisma Client > Client Extensions > Add custom methods to your models

You can use the `model` [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions) component type to add custom methods to your models.

Possible uses for the `model` component include the following:

* New operations to operate alongside existing Prisma Client operations, such as `findMany`
* Encapsulated business logic
* Repetitive operations
* Model-specific utilities

## Add a custom method [#add-a-custom-method]

Use the `$extends` [client-level method](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#client-methods) to create an *extended client*. An extended client is a variant of the standard Prisma Client that is wrapped by one or more extensions. Use the `model` extension component to add methods to models in your schema.

### Add a custom method to a specific model [#add-a-custom-method-to-a-specific-model]

To extend a specific model in your schema, use the following structure. This example adds a method to the `user` model.

```ts
const prisma = new PrismaClient().$extends({
  name?: '<name>',  // (optional) names the extension for error logs
  model?: {
    user: { ... }   // in this case, we extend the `user` model
  },
});
```

#### Example [#example]

The following example adds a method called `signUp` to the `user` model. This method creates a new user with the specified email address:

```ts
const prisma = new PrismaClient().$extends({
  model: {
    user: {
      async signUp(email: string) {
        await prisma.user.create({ data: { email } });
      },
    },
  },
});
```

You would call `signUp` in your application as follows:

```ts
const user = await prisma.user.signUp("john@prisma.io");
```

### Add a custom method to all models in your schema [#add-a-custom-method-to-all-models-in-your-schema]

To extend *all* models in your schema, use the following structure:

```ts
const prisma = new PrismaClient().$extends({
  name?: '<name>', // `name` is an optional field that you can use to name the extension for error logs
  model?: {
    $allModels: { ... }
  },
})
```

#### Example [#example-1]

The following example adds an `exists` method to all models.

```ts
const prisma = new PrismaClient().$extends({
  model: {
    $allModels: {
      async exists<T>(this: T, where: Prisma.Args<T, "findFirst">["where"]): Promise<boolean> {
        // Get the current model at runtime
        const context = Prisma.getExtensionContext(this);

        const result = await (context as any).findFirst({ where });
        return result !== null;
      },
    },
  },
});
```

You would call `exists` in your application as follows:

```ts
// `exists` method available on all models
await prisma.user.exists({ name: "Alice" });
await prisma.post.exists({
  OR: [{ title: { contains: "Prisma" } }, { content: { contains: "Prisma" } }],
});
```

## Call a custom method from another custom method [#call-a-custom-method-from-another-custom-method]

You can call a custom method from another custom method, if the two methods are declared on the same model. For example, you can call a custom method on the `user` model from another custom method on the `user` model. It does not matter if the two methods are declared in the same extension or in different extensions.

To do so, use `Prisma.getExtensionContext(this).methodName`. Note that you cannot use `prisma.user.methodName`. This is because `prisma` is not extended yet, and therefore does not contain the new method.

For example:

```ts
const prisma = new PrismaClient().$extends({
  model: {
    user: {
      firstMethod() {
        ...
      },
      secondMethod() {
          Prisma.getExtensionContext(this).firstMethod()
      }
    }
  }
})
```

## Get the current model name at runtime [#get-the-current-model-name-at-runtime]

You can get the name of the current model at runtime with `Prisma.getExtensionContext(this).$name`. You might use this to write out the model name to a log, to send the name to another service, or to branch your code based on the model.

For example:

```ts
// `context` refers to the current model
const context = Prisma.getExtensionContext(this);

// `context.$name` returns the name of the current model
console.log(context.$name);

// Usage
await (context as any).findFirst({ args });
```

Refer to [Add a custom method to all models in your schema](#example-1) for a concrete example for retrieving the current model name at runtime.

## Advanced type safety: type utilities for defining generic extensions [#advanced-type-safety-type-utilities-for-defining-generic-extensions]

You can improve the type-safety of `model` components in your shared extensions with [type utilities](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/type-utilities).

## Related pages

- [`Add custom fields and methods to query results`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/result): Extend the functionality of Prisma Client, result component
- [`Add methods to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/client): Extend the functionality of Prisma Client, client component
- [`Create custom Prisma Client queries`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query): Extend the functionality of Prisma Client, query component
- [`Shared packages & examples`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/extension-examples): Explore the Prisma Client extensions that have been built by Prisma and its community
- [`Shared Prisma Client extensions`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/shared-extensions): Share extensions or import shared extensions into your Prisma project

# Create custom Prisma Client queries (Prisma ORM v7) (/docs/orm/v7/prisma-client/client-extensions/query)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Extend the functionality of Prisma Client, query component

Location: ORM > v7 > Prisma Client > Client Extensions > Create custom Prisma Client queries

You can use the `query` [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions) component type to hook into the query life-cycle and modify an incoming query or its result.

You can use Prisma Client extensions `query` component to create independent clients with customized behavior. You can bind one client to a specific filter or user, and another client to another filter or user. For example, you might do this to get [user isolation](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions#extended-clients) in a row-level security (RLS) extension. The `query` extension component provides end-to-end type safety for all your custom queries.

## Extend Prisma Client query operations [#extend-prisma-client-query-operations]

Use the `$extends` [client-level method](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#client-methods) to create an [extended client](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions#about-prisma-client-extensions). An extended client is a variant of the standard Prisma Client that is wrapped by one or more extensions.

Use the `query` extension component to modify queries. You can modify a custom query in the following:

* [A specific operation in a specific model](#modify-a-specific-operation-in-a-specific-model)
* [A specific operation in all models of your schema](#modify-a-specific-operation-in-all-models-of-your-schema)
* [All Prisma Client operations](#modify-all-prisma-client-operations)
* [All operations in a specific model](#modify-all-operations-in-a-specific-model)
* [All operations in all models of your schema](#modify-all-operations-in-all-models-of-your-schema)
* [A specific top-level raw query operation](#modify-a-top-level-raw-query-operation)

To create a custom query, use the following structure:

```ts
const prisma = new PrismaClient().$extends({
  name?: 'name',
  query?: {
    user: { ... } // in this case, we add a query to the `user` model
  },
});
```

The properties are as follows:

* `name`: (optional) specifies a name for the extension that appears in error logs.
* `query`: defines a custom query.

### Modify a specific operation in a specific model [#modify-a-specific-operation-in-a-specific-model]

The `query` object can contain functions that map to the names of the [Prisma Client operations](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#model-queries), such as `findUnique()`, `findFirst`, `findMany`, `count`, and `create`. The following example modifies `user.findMany` to a use a customized query that finds only users who are older than 18 years:

```ts
const prisma = new PrismaClient().$extends({
  query: {
    user: {
      async findMany({ model, operation, args, query }) {
        // take incoming `where` and set `age`
        args.where = { ...args.where, age: { gt: 18 } };

        return query(args);
      },
    },
  },
});

await prisma.user.findMany(); // returns users whose age is greater than 18
```

In the above example, a call to `prisma.user.findMany` triggers `query.user.findMany`. Each callback receives a type-safe `{ model, operation, args, query }` object that describes the query. This object has the following properties:

* `model`: the name of the containing model for the query that we want to extend.

  In the above example, the `model` is a string of type `"User"`.

* `operation`: the name of the operation being extended and executed.

  In the above example, the `operation` is a string of type `"findMany"`.

* `args`: the specific query input information to be extended.

  This is a type-safe object that you can mutate before the query happens. You can mutate any of the properties in `args`. Exception: you cannot mutate `include` or `select` because that would change the expected output type and break type safety.

* `query`: a promise for the result of the query.
  * You can use `await` and then mutate the result of this promise, because its value is type-safe. TypeScript catches any unsafe mutations on the object.

### Modify a specific operation in all models of your schema [#modify-a-specific-operation-in-all-models-of-your-schema]

To extend the queries in all the models of your schema, use `$allModels` instead of a specific model name. For example:

```ts
const prisma = new PrismaClient().$extends({
  query: {
    $allModels: {
      async findMany({ model, operation, args, query }) {
        // set `take` and fill with the rest of `args`
        args = { ...args, take: 100 };

        return query(args);
      },
    },
  },
});
```

### Modify all operations in a specific model [#modify-all-operations-in-a-specific-model]

Use `$allOperations` to extend all operations in a specific model.

For example, the following code applies a custom query to all operations on the `user` model:

```ts
const prisma = new PrismaClient().$extends({
  query: {
    user: {
      $allOperations({ model, operation, args, query }) {
        /* your custom logic here */
        return query(args);
      },
    },
  },
});
```

### Modify all Prisma Client operations [#modify-all-prisma-client-operations]

Use the `$allOperations` method to modify all query methods present in Prisma Client. The `$allOperations` can be used on both model operations and raw queries.

You can modify all methods as follows:

```ts
const prisma = new PrismaClient().$extends({
  query: {
    $allOperations({ model, operation, args, query }) {
      /* your custom logic for modifying all Prisma Client operations here */
      return query(args);
    },
  },
});
```

In the event a [raw query](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries) is invoked, the `model` argument passed to the callback will be `undefined`.

For example, you can use the `$allOperations` method to log queries as follows:

```ts
const prisma = new PrismaClient().$extends({
  query: {
    async $allOperations({ operation, model, args, query }) {
      const start = performance.now();
      const result = await query(args);
      const end = performance.now();
      const time = end - start;
      console.log(
        util.inspect(
          { model, operation, args, time },
          { showHidden: false, depth: null, colors: true },
        ),
      );
      return result;
    },
  },
});
```

### Modify all operations in all models of your schema [#modify-all-operations-in-all-models-of-your-schema]

Use `$allModels` and `$allOperations` to extend all operations in all models of your schema.

To apply a custom query to all operations on all models of your schema:

```ts
const prisma = new PrismaClient().$extends({
  query: {
    $allModels: {
      $allOperations({ model, operation, args, query }) {
        /* your custom logic for modifying all operations on all models here */
        return query(args);
      },
    },
  },
});
```

### Modify a top-level raw query operation [#modify-a-top-level-raw-query-operation]

To apply custom behavior to a specific top-level raw query operation, use the name of a top-level raw query function instead of a model name:

  

#### Relational databases

```ts copy 
const prisma = new PrismaClient().$extends({
  query: {
    $queryRaw({ args, query, operation }) {
      // handle $queryRaw operation
      return query(args);
    },
    $executeRaw({ args, query, operation }) {
      // handle $executeRaw operation
      return query(args);
    },
    $queryRawUnsafe({ args, query, operation }) {
      // handle $queryRawUnsafe operation
      return query(args);
    },
    $executeRawUnsafe({ args, query, operation }) {
      // handle $executeRawUnsafe operation
      return query(args);
    },
  },
});
```

#### MongoDB

```ts copy 
const prisma = new PrismaClient().$extends({
  query: {
    $runCommandRaw({ args, query, operation }) {
      // handle $runCommandRaw operation
      return query(args);
    },
  },
});
```

### Mutate the result of a query [#mutate-the-result-of-a-query]

You can use `await` and then mutate the result of the `query` promise.

```ts
const prisma = new PrismaClient().$extends({
  query: {
    user: {
      async findFirst({ model, operation, args, query }) {
        const user = await query(args);

        if (user.password !== undefined) {
          user.password = "******";
        }

        return user;
      },
    },
  },
});
```

> [!NOTE]
> We include the above example to show that this is possible. However, for performance reasons we recommend that you use the [`result` component type](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/result) to override existing fields. The `result` component type usually gives better performance in this situation because it computes only on access. The `query` component type computes after query execution.

## Wrap a query into a batch transaction [#wrap-a-query-into-a-batch-transaction]

You can wrap your extended queries into a [batch transaction](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions). For example, you can use this to enact row-level security (RLS).

The following example extends `findFirst` so that it runs in a batch transaction.

```ts
const transactionExtension = Prisma.defineExtension((prisma) =>
  prisma.$extends({
    query: {
      user: {
        // Get the input `args` and a callback to `query`
        async findFirst({ args, query, operation }) {
          const [result] = await prisma.$transaction([query(args)]); // wrap the query in a batch transaction, and destructure the result to return an array
          return result; // return the first result found in the array
        },
      },
    },
  }),
);
const prisma = new PrismaClient().$extends(transactionExtension);
```

## Related pages

- [`Add custom fields and methods to query results`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/result): Extend the functionality of Prisma Client, result component
- [`Add custom methods to your models`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model): Extend the functionality of Prisma Client, model component
- [`Add methods to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/client): Extend the functionality of Prisma Client, client component
- [`Shared packages & examples`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/extension-examples): Explore the Prisma Client extensions that have been built by Prisma and its community
- [`Shared Prisma Client extensions`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/shared-extensions): Share extensions or import shared extensions into your Prisma project

# Add custom fields and methods to query results (Prisma ORM v7) (/docs/orm/v7/prisma-client/client-extensions/result)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Extend the functionality of Prisma Client, result component

Location: ORM > v7 > Prisma Client > Client Extensions > Add custom fields and methods to query results

You can use the `result` [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions) component type to add custom fields and methods to query results.

Use the `$extends` [client-level method](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#client-methods) to create an *extended client*. An extended client is a variant of the standard Prisma Client that is wrapped by one or more extensions.

To add a custom [field](#add-a-custom-field-to-query-results) or [method](#add-a-custom-method-to-the-result-object) to query results, use the following structure. In this example, we add the custom field `myComputedField` to the result of a `user` model query.

```ts
const prisma = new PrismaClient().$extends({
  name?: 'name',
  result?: {
    user: {                   // in this case, we extend the `user` model
      myComputedField: {      // the name of the new computed field
        needs: { ... },
        compute() { ... }
      },
    },
  },
});
```

The parameters are as follows:

* `name`: (optional) specifies a name for the extension that appears in error logs.
* `result`: defines new fields and methods to the query results.
* `needs`: an object which describes the dependencies of the result field.
* `compute`: a method that defines how the virtual field is computed when it is accessed.

## Add a custom field to query results [#add-a-custom-field-to-query-results]

You can use the `result` extension component to add fields to query results. These fields are computed at runtime and are type-safe.

In the following example, we add a new virtual field called `fullName` to the `user` model.

```ts
const prisma = new PrismaClient().$extends({
  result: {
    user: {
      fullName: {
        // the dependencies
        needs: { firstName: true, lastName: true },
        compute(user) {
          // the computation logic
          return `${user.firstName} ${user.lastName}`;
        },
      },
    },
  },
});

const user = await prisma.user.findFirst();

// return the user's full name, such as "John Doe"
console.log(user.fullName);
```

In above example, the input `user` of `compute` is automatically typed according to the object defined in `needs`. `firstName` and `lastName` are of type `string`, because they are specified in `needs`. If they are not specified in `needs`, then they cannot be accessed.

## Re-use a computed field in another computed field [#re-use-a-computed-field-in-another-computed-field]

The following example computes a user's title and full name in a type-safe way. `titleFullName` is a computed field that reuses the `fullName` computed field.

```ts
const prisma = new PrismaClient()
  .$extends({
    result: {
      user: {
        fullName: {
          needs: { firstName: true, lastName: true },
          compute(user) {
            return `${user.firstName} ${user.lastName}`;
          },
        },
      },
    },
  })
  .$extends({
    result: {
      user: {
        titleFullName: {
          needs: { title: true, fullName: true },
          compute(user) {
            return `${user.title} (${user.fullName})`;
          },
        },
      },
    },
  });
```

### Considerations for fields [#considerations-for-fields]

* For performance reasons, Prisma Client computes results on access, not on retrieval.
* You can only create computed fields that are based on scalar fields.
* You can only use computed fields with `select` and you cannot aggregate them. For example:

  ```ts
  const user = await prisma.user.findFirst({
    select: { email: true },
  });
  console.log(user.fullName); // undefined
  ```

## Add a custom method to the result object [#add-a-custom-method-to-the-result-object]

You can use the `result` component to add methods to query results. The following example adds a new method, `save` to the result object.

```ts
const prisma = new PrismaClient().$extends({
  result: {
    user: {
      save: {
        needs: { id: true },
        compute(user) {
          return () => prisma.user.update({ where: { id: user.id }, data: user });
        },
      },
    },
  },
});

const user = await prisma.user.findUniqueOrThrow({ where: { id: someId } });
user.email = "mynewmail@mailservice.com";
await user.save();
```

## Using `omit` query option with `result` extension component [#using-omit-query-option-with-result-extension-component]

You can use the [`omit` (Preview) option](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#omit) with [custom fields](#add-a-custom-field-to-query-results) and fields needed by custom fields.

### `omit` fields needed by custom fields from query result [#omit-fields-needed-by-custom-fields-from-query-result]

If you `omit` a field that is a dependency of a custom field, it will still be read from the database even though it will not be included in the query result.

The following example omits the `password` field, which is a dependency of the custom field `sanitizedPassword`:

```ts
const xprisma = prisma.$extends({
  result: {
    user: {
      sanitizedPassword: {
        needs: { password: true },
        compute(user) {
          return sanitize(user.password);
        },
      },
    },
  },
});

const user = await xprisma.user.findFirstOrThrow({
  omit: {
    password: true,
  },
});
```

In this case, although `password` is omitted from the result, it will still be queried from the database because it is a dependency of the `sanitizedPassword` custom field.

### `omit` custom field and dependencies from query result [#omit-custom-field-and-dependencies-from-query-result]

To ensure omitted fields are not queried from the database at all, you must omit both the custom field and its dependencies.

The following example omits both the custom field `sanitizedPassword` and the dependent `password` field:

```ts
const xprisma = prisma.$extends({
  result: {
    user: {
      sanitizedPassword: {
        needs: { password: true },
        compute(user) {
          return sanitize(user.password);
        },
      },
    },
  },
});

const user = await xprisma.user.findFirstOrThrow({
  omit: {
    sanitizedPassword: true,
    password: true,
  },
});
```

In this case, omitting both `password` and `sanitizedPassword` will exclude both from the result as well as prevent the `password` field from being read from the database.

## Limitation [#limitation]

As of now, Prisma Client's result extension component does not support relation fields. This means that you cannot create custom fields or methods based on related models or fields in a relational relationship (e.g., user.posts, post.author). The needs parameter can only reference scalar fields within the same model. Follow [issue #20091 on GitHub](https://github.com/prisma/orm/issues/20091).

```ts
const prisma = new PrismaClient().$extends({
  result: {
    user: {
      postsCount: {
        needs: { posts: true }, // This will not work because posts is a relation field
        compute(user) {
          return user.posts.length; // Accessing a relation is not allowed
        },
      },
    },
  },
});
```

## Related pages

- [`Add custom methods to your models`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model): Extend the functionality of Prisma Client, model component
- [`Add methods to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/client): Extend the functionality of Prisma Client, client component
- [`Create custom Prisma Client queries`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query): Extend the functionality of Prisma Client, query component
- [`Shared packages & examples`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/extension-examples): Explore the Prisma Client extensions that have been built by Prisma and its community
- [`Shared Prisma Client extensions`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/shared-extensions): Share extensions or import shared extensions into your Prisma project

# Type utilities (Prisma ORM v7) (/docs/orm/v7/prisma-client/client-extensions/type-utilities)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Advanced type safety: improve type safety in your custom model methods

Location: ORM > v7 > Prisma Client > Client Extensions > Type utilities

Several type utilities exist within Prisma Client that can assist in the creation of highly type-safe extensions.

## Type Utilities [#type-utilities]

[Prisma Client type utilities](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety) are utilities available within your application and Prisma Client extensions and provide useful ways of constructing safe and extendable types for your extension.

The type utilities available are:

* `Exact<Input, Shape>`: Enforces strict type safety on `Input`. `Exact` makes sure that a generic type `Input` strictly complies with the type that you specify in `Shape`. It [narrows](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) `Input` down to the most precise types.
* `Args<Type, Operation>`: Retrieves the input arguments for any given model and operation. This is particularly useful for extension authors who want to do the following:
  * Re-use existing types to extend or modify them.
  * Benefit from the same auto-completion experience as on existing operations.
* `Result<Type, Arguments, Operation>`: Takes the input arguments and provides the result for a given model and operation. You would usually use this in conjunction with `Args`. As with `Args`, `Result` helps you to re-use existing types to extend or modify them.
* `Payload<Type, Operation>`: Retrieves the entire structure of the result, as scalars and relations objects for a given model and operation. For example, you can use this to determine which keys are scalars or objects at a type level.

The following example creates a new operation, `exists`, based on `findFirst`. It has all of the arguments that `findFirst`.

```ts
const prisma = new PrismaClient().$extends({
  model: {
    $allModels: {
      // Define a new `exists` operation on all models
      // T is a generic type that corresponds to the current model
      async exists<T>(
        // `this` refers to the current type, e.g. `prisma.user` at runtime
        this: T,

        // The `exists` function will use the `where` arguments from the current model, `T`, and the `findFirst` operation
        where: Prisma.Args<T, "findFirst">["where"],
      ): Promise<boolean> {
        // Retrieve the current model at runtime
        const context = Prisma.getExtensionContext(this);

        // Prisma Client query that retrieves data based
        const result = await (context as any).findFirst({ where });
        return result !== null;
      },
    },
  },
});

async function main() {
  const user = await prisma.user.exists({ name: "Alice" });
  const post = await prisma.post.exists({
    OR: [{ title: { contains: "Prisma" } }, { content: { contains: "Prisma" } }],
  });
}
```

## Add a custom property to a method [#add-a-custom-property-to-a-method]

The following example illustrates how you can add custom arguments, to a method in an extension:

```ts highlight=16
type CacheStrategy = {
  swr: number;
  ttl: number;
};

const prisma = new PrismaClient().$extends({
  model: {
    $allModels: {
      findMany<T, A>(
        this: T,
        args: Prisma.Exact<
          A,
          // For the `findMany` method, use the arguments from model `T` and the `findMany` method
          // and intersect it with `CacheStrategy` as part of `findMany` arguments
          Prisma.Args<T, "findMany"> & CacheStrategy
        >,
      ): Prisma.Result<T, A, "findMany"> {
        // method implementation with the cache strategy
      },
    },
  },
});

async function main() {
  await prisma.post.findMany({
    cacheStrategy: {
      ttl: 360,
      swr: 60,
    },
  });
}
```

This example is conceptual. You must implement and operate the cache used by the extension.

## Related pages

- [`Add custom fields and methods to query results`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/result): Extend the functionality of Prisma Client, result component
- [`Add custom methods to your models`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model): Extend the functionality of Prisma Client, model component
- [`Add methods to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/client): Extend the functionality of Prisma Client, client component
- [`Create custom Prisma Client queries`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query): Extend the functionality of Prisma Client, query component
- [`Shared packages & examples`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/extension-examples): Explore the Prisma Client extensions that have been built by Prisma and its community

# Debugging (Prisma ORM v7) (/docs/orm/v7/prisma-client/debugging-and-troubleshooting/debugging)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

This page explains how to enable debugging output for Prisma Client by setting the `DEBUG` environment variable

Location: ORM > v7 > Prisma Client > Debugging and Troubleshooting > Debugging

You can enable debugging output in Prisma Client and Prisma CLI via the [`DEBUG`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference#debug) environment variable. It accepts two namespaces to print debugging output:

* `prisma:engine`: Prints relevant debug messages happening in a Prisma ORM [engine](https://github.com/prisma/prisma-engines/)
* `prisma:client`: Prints relevant debug messages happening in the Prisma Client runtime
* `prisma*`: Prints all debug messages from Prisma Client or CLI
* `*`: Prints all debug messages

> [!NOTE]
> Prisma Client can be configured to log warnings, errors and information related to queries sent to the database. See [Configuring logging](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/logging) for more information.

## Setting the `DEBUG` environment variable [#setting-the-debug-environment-variable]

Here are examples for setting these debugging options in bash:

```bash
# enable only `prisma:engine`-level debugging output
export DEBUG="prisma:engine"

# enable only `prisma:client`-level debugging output
export DEBUG="prisma:client"

# enable both `prisma-client`- and `engine`-level debugging output
export DEBUG="prisma:client,prisma:engine"
```

To enable all `prisma` debugging options, set `DEBUG` to `prisma*`:

```bash
export DEBUG="prisma*"
```

On Windows, use `set` instead of `export`:

```bash
set DEBUG="prisma*"
```

To enable *all* debugging options, set `DEBUG` to `*`:

```bash
export DEBUG="*"
```

## Related pages

- [`Handling exceptions and errors`](https://www.prisma.io/docs/orm/v7/prisma-client/debugging-and-troubleshooting/handling-exceptions-and-errors): This page covers how to handle exceptions and errors

# Handling exceptions and errors (Prisma ORM v7) (/docs/orm/v7/prisma-client/debugging-and-troubleshooting/handling-exceptions-and-errors)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

This page covers how to handle exceptions and errors

Location: ORM > v7 > Prisma Client > Debugging and Troubleshooting > Handling exceptions and errors

In order to handle different types of errors you can use `instanceof` to check what the error is and handle it accordingly.

The following example tries to create a user with an already existing email record. This will throw an error because the `email` field has the `@unique` attribute applied to it.

```prisma title="schema.prisma"
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
}
```

Use the `Prisma` namespace to access the error type. The [error code](https://www.prisma.io/docs/orm/v7/reference/error-reference#error-codes) can then be checked and a message can be printed.

```ts
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient, Prisma } from "../generated/prisma/client";

const connectionString = `${process.env.DATABASE_URL}`;
const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

try {
  await client.user.create({ data: { email: "alreadyexisting@mail.com" } });
} catch (e) {
  if (e instanceof Prisma.PrismaClientKnownRequestError) {
    // The .code property can be accessed in a type-safe manner
    if (e.code === "P2002") {
      console.log(
        "There is a unique constraint violation, a new user cannot be created with this email",
      );
    }
  }
  throw e;
}
```

See [Errors reference](https://www.prisma.io/docs/orm/v7/reference/error-reference) for a detailed breakdown of the different error types and their codes.

## Related pages

- [`Debugging`](https://www.prisma.io/docs/orm/v7/prisma-client/debugging-and-troubleshooting/debugging): This page explains how to enable debugging output for Prisma Client by setting the `DEBUG` environment variable

# Caveats when deploying to AWS platforms (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/caveats-when-deploying-to-aws-platforms)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Known caveats when deploying to an AWS platform

Location: ORM > v7 > Prisma Client > Deployment > Caveats when deploying to AWS platforms

The following describes some caveats you might face when deploying to different AWS platforms.

## AWS RDS Proxy [#aws-rds-proxy]

Prisma ORM is compatible with AWS RDS Proxy. However, there is no benefit in using it for connection pooling with Prisma ORM due to the way RDS Proxy pins connections:

> "Your connections to the proxy can enter a state known as pinning. When a connection is pinned, each later transaction uses the same underlying database connection until the session ends. Other client connections also can't reuse that database connection until the session ends. The session ends when Prisma Client's connection is dropped." - [AWS RDS Proxy Docs](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-pinning.html)

[Prepared statements (of any size) or query statements greater than 16 KB cause RDS Proxy to pin the session.](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/rds-proxy-pinning.html) Because Prisma ORM uses prepared statements for all queries, you won't see any benefit when using RDS Proxy with Prisma ORM.

## AWS Elastic Beanstalk [#aws-elastic-beanstalk]

AWS Elastic Beanstalk is a PaaS-like deployment service that abstracts away infrastructure and allows you to deploy applications to AWS quickly.

When deploying an app using Prisma Client to AWS Elastic Beanstalk, Prisma ORM generates the Prisma Client code into `node_modules`. This is typically done in a `postinstall` hook defined in a `package.json`.

Because Beanstalk limits the ability to write to the filesystem in the `postinstall` hook, you need to create an [`.npmrc`](https://docs.npmjs.com/cli/v6/configuring-npm/npmrc/) file in the root of your project and add the following configuration:

```yaml title=".npmrc" showLineNumbers
unsafe-perm=true
```

Enabling `unsafe-perm` forces *npm* to run as *root*, avoiding the filesystem access problem, thereby allowing the `prisma generate` command in the `postinstall` hook to generate your code.

### Error: @prisma/client did not initialize yet [#error-prismaclient-did-not-initialize-yet]

This error happens because AWS Elastic Beanstalk doesn't install `devDependencies`, which means that it doesn't pick up the Prisma CLI. To remedy this you can either:

1. Add the `prisma` CLI package to your `dependencies` instead of the `devDependencies`. (Making sure to run `npm install` afterward to update the `package-lock.json`).
2. Or install your `devDependencies` on AWS Elastic Beanstalk instances. To do this you must set the AWS Elastic Beanstalk `NPM_USE_PRODUCTION` environment property to false.

## AWS RDS Postgres [#aws-rds-postgres]

When using Prisma ORM with AWS RDS Postgres, you may encounter connection issues or the following error during migration or runtime:

```bash
Error: P1010: User <username> was denied access on the database <database>
```

### Cause [#cause]

AWS RDS enforces SSL connections by default, and Prisma parses the database connection string with `rejectUnauthorized: true`, which requires a valid SSL certificate. If the certificate is not configured properly, Prisma cannot connect to the database.

### Solution [#solution]

To resolve this issue, update the `DATABASE_URL` environment variable to include the `sslmode=no-verify` option. This bypasses strict SSL certificate verification and allows Prisma to connect to the database. Update your `.env` file as follows:

```bash
DATABASE_URL=postgresql://<username>:<password>@<host>/<database>?sslmode=no-verify&schema=public
```

### Why This Works [#why-this-works]

The `sslmode=no-verify` setting passes `rejectUnauthorized: false` to the SSL configuration via the [pg-connection-string](https://github.com/brianc/node-postgres/blob/95d7e620ef8b51743b4cbca05dd3c3ce858ecea7/packages/pg-connection-string/README.md?plain=1#L71) package. This disables strict certificate validation, allowing Prisma to establish a connection with the RDS database.

### Note [#note]

While using `sslmode=no-verify` can be a quick fix, it bypasses SSL verification and might not meet security requirements for production environments. In such cases, ensure that a valid SSL certificate is properly configured.

## Related pages

- [`Deploy migrations from a local environment`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-migrations-from-a-local-environment): Learn how to deploy Node.js and TypeScript applications that are using Prisma Client locally
- [`Deploy Prisma ORM`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-prisma): Learn more about the different deployment paradigms for Node.js applications and how they affect deploying an application using Prisma Client
- [`Deploying database changes with Prisma Migrate`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-database-changes-with-prisma-migrate): Learn how to deploy database changes with Prisma Migrate

# Deploying database changes with Prisma Migrate (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/deploy-database-changes-with-prisma-migrate)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy database changes with Prisma Migrate

Location: ORM > v7 > Prisma Client > Deployment > Deploying database changes with Prisma Migrate

To apply pending migrations to staging, testing, or production environments, run the `migrate deploy` command as part of your CI/CD pipeline:

  

#### bun

```bash
bunx prisma migrate deploy
```

#### pnpm

```bash
pnpm prisma migrate deploy
```

#### yarn

```bash
yarn prisma migrate deploy
```

#### npm

```bash
npx prisma migrate deploy
```

> [!NOTE]
> This guide **does not apply for MongoDB**.<br />
> Instead of `migrate deploy`, [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) is used for [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

Exactly when to run `prisma migrate deploy` depends on your platform. For example, a simplified [Heroku](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-heroku) workflow includes:

1. Ensuring the `./prisma/migration` folder is in source control
2. Running `prisma migrate deploy` during the [release phase](https://devcenter.heroku.com/articles/release-phase)

Ideally, `migrate deploy` should be part of an automated CI/CD pipeline, and we do not generally recommend running this command locally to deploy changes to a production database (for example, by temporarily changing the `DATABASE_URL` environment variable). It is not generally considered good practice to store the production database URL locally.

Beware that in order to run the `prisma migrate deploy` command, you need access to the `prisma` dependency that is typically added to the `devDependencies`. Some platforms like Vercel, prune development dependencies during the build, thereby preventing you from calling the command. This can be worked around by making the `prisma` a production dependency, by moving it to `dependencies` in your `package.json`.
For more information about the `migrate deploy` command, see:

* [`migrate deploy` reference](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-deploy)
* [How `migrate deploy` works](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production#production-and-testing-environments)
* [Production troubleshooting](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing)

## Deploying database changes using GitHub Actions [#deploying-database-changes-using-github-actions]

As part of your CI/CD, you can run `prisma migrate deploy` as part of your pipeline to apply pending migrations to your production database.

Here is an example action that will run your migrations against your database:

```yaml title="deploy.yml" highlight=17-20 showLineNumbers
name: Deploy
on:
  push:
    paths:
      - prisma/migrations/** # [!code highlight]
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo
        uses: actions/checkout@v3
      - name: Setup Node
        uses: actions/setup-node@v3
      - name: Install dependencies
        run: npm ci
      - name: Apply all pending migrations to the database
        run: npx prisma migrate deploy
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
```

The highlighted line shows that this action will only run if there is a change in the `prisma/migrations` directory, so `npx prisma migrate deploy` will only run when migrations are updated.

Ensure you have the `DATABASE_URL` variable [set as a secret in your repository](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions), without quotes around the connection string.

## Pre-deploy migration safety checks [#pre-deploy-migration-safety-checks]

Before running `prisma migrate deploy`, you can analyze your migration SQL files for potentially dangerous patterns using a migration safety tool like [pgfence](https://www.prisma.io/docs/guides/integrations/pgfence). pgfence detects operations that acquire heavy locks (such as `CREATE INDEX` without `CONCURRENTLY` or `ALTER COLUMN TYPE`), reports risk levels, and provides safe rewrite recipes.

To add pgfence as a pre-deploy step in your GitHub Actions workflow:

```yaml
- name: Run migration safety check
  run: npx @flvmnt/pgfence analyze --ci --max-risk medium prisma/migrations/**/migration.sql

- name: Apply all pending migrations to the database
  run: npx prisma migrate deploy
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
```

For a full setup guide, see the [pgfence integration guide](https://www.prisma.io/docs/guides/integrations/pgfence).

## Related pages

- [`Caveats when deploying to AWS platforms`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/caveats-when-deploying-to-aws-platforms): Known caveats when deploying to an AWS platform
- [`Deploy migrations from a local environment`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-migrations-from-a-local-environment): Learn how to deploy Node.js and TypeScript applications that are using Prisma Client locally
- [`Deploy Prisma ORM`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-prisma): Learn more about the different deployment paradigms for Node.js applications and how they affect deploying an application using Prisma Client

# Deploy migrations from a local environment (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/deploy-migrations-from-a-local-environment)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy Node.js and TypeScript applications that are using Prisma Client locally

Location: ORM > v7 > Prisma Client > Deployment > Deploy migrations from a local environment

There are two scenarios where you might consider deploying migrations directly from a local environment to a production environment.

* You have a local CI/CD pipeline
* You are [baselining](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining) a production environment

This page outlines some examples of how you can do that and **why we would generally not recommend it**.

## Local CI/CD pipeline [#local-cicd-pipeline]

If you do not have an automated CI/CD process, you can technically deploy new migrations from your local environment to production in the following ways:

1. Make sure your migration history is up to date. You can do this through running `prisma migrate dev`, which will generate a migration history from the latest changes made.
2. Swap your local connection URL for your production connection URL

```bash title=".env"
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/my_local_database" # [!code --]

DATABASE_URL="postgresql://johndoe:randompassword@prod-db.example.com:5432/my_production_database" # [!code ++]
```

3. Run `prisma migrate deploy`

**⛔  We strongly discourage this solution due to the following reasons**

* You risk exposing your production database connection URL to version control.
* You may accidentally use your production connection URL instead and in turn **override or delete your production database**.

**✅ We recommend setting up an automated CI/CD pipeline**

The pipeline should handle deployment to staging and production environments, and use `migrate deploy` in a pipeline step. See the [deployment guides](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-database-changes-with-prisma-migrate) for examples.

## Baselining a production database [#baselining-a-production-database]

When you add Prisma Migrate to an **existing database**, you must [baseline](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining) the production database. Baselining is performed **once**, and can be done from a local instance.

![Baselining production from local with Prisma ORM](https://www.prisma.io/img/orm/baseline-production-from-local.png)

## Related pages

- [`Caveats when deploying to AWS platforms`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/caveats-when-deploying-to-aws-platforms): Known caveats when deploying to an AWS platform
- [`Deploy Prisma ORM`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-prisma): Learn more about the different deployment paradigms for Node.js applications and how they affect deploying an application using Prisma Client
- [`Deploying database changes with Prisma Migrate`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-database-changes-with-prisma-migrate): Learn how to deploy database changes with Prisma Migrate

# Deploy Prisma ORM (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/deploy-prisma)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn more about the different deployment paradigms for Node.js applications and how they affect deploying an application using Prisma Client

Location: ORM > v7 > Prisma Client > Deployment > Deploy Prisma ORM

Projects using Prisma Client can be deployed to many cloud platforms. Platforms differ in how they run your code, and that difference affects how you deploy an application that uses Prisma Client. This page describes the three deployment paradigms.

## Deployment paradigms [#deployment-paradigms]

Each paradigm has different tradeoffs that affect the performance, scalability, and operational costs of your application.

Moreover, the user traffic pattern of your application is also an important factor to consider. For example, any application with consistent user traffic may be better suited for a [continuously running paradigm](#traditional-servers), whereas an application with sudden spikes may be better suited to [serverless](#serverless-functions).

### Traditional servers [#traditional-servers]

Your application is [traditionally deployed](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-heroku) if a Node.js process is continuously running and handles multiple requests at the same time. Your application could be deployed to a Platform-as-a-Service (PaaS) like [Heroku](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-heroku), [Koyeb](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-koyeb), or [Render](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-render); as a Docker container to Kubernetes; or as a Node.js process on a virtual machine or bare metal server.

See also: [Connection management in long-running processes](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections#long-running-processes)

### Serverless Functions [#serverless-functions]

Your application is [serverless](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-vercel) if the Node.js processes of your application (or subsets of it broken into functions) are started as requests come in, and each function only handles one request at a time. Your application would most likely be deployed to a Function-as-a-Service (FaaS) offering, such as [AWS Lambda](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-aws-lambda) or [Azure Functions](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-azure-functions)

Serverless environments have the concept of warm starts, which means that for subsequent invocations of the same function, it may use an already existing container that has the allocated processes, memory, file system (`/tmp` is writable on AWS Lambda), and even DB connection still available.

Typically, any piece of code [outside the handler](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) remains initialized.

See also: [Connection management in serverless environments](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections#serverless-environments-faas)

### Edge Functions [#edge-functions]

Your application is [edge deployed](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/overview) if your application is [serverless](#serverless-functions) and the functions are distributed across one or more regions close to the user.

Typically, edge environments also have a different runtime than a traditional or serverless environment, leading to common APIs being unavailable.

## Related pages

- [`Caveats when deploying to AWS platforms`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/caveats-when-deploying-to-aws-platforms): Known caveats when deploying to an AWS platform
- [`Deploy migrations from a local environment`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-migrations-from-a-local-environment): Learn how to deploy Node.js and TypeScript applications that are using Prisma Client locally
- [`Deploying database changes with Prisma Migrate`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-database-changes-with-prisma-migrate): Learn how to deploy database changes with Prisma Migrate

# Logging (Prisma ORM v7) (/docs/orm/v7/prisma-client/observability-and-logging/logging)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to configure Prisma Client to log the raw SQL queries it sends to the database and other information

Location: ORM > v7 > Prisma Client > Observability and Logging > Logging

Use the `PrismaClient` [`log`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#log) parameter to configure [log levels](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#log-levels) , including warnings, errors, and information about the queries sent to the database.

Prisma Client supports two types of logging:

* Logging to [stdout](https://en.wikipedia.org/wiki/Standard_streams) (default)
* Event-based logging (use [`$on()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#on) method to [subscribe to events](#event-based-logging))

> [!NOTE]
> You can also use the `DEBUG` environment variable to enable debugging output in Prisma Client. See [Debugging](https://www.prisma.io/docs/orm/v7/prisma-client/debugging-and-troubleshooting/debugging) for more information.

> [!NOTE]
> If you want a detailed insight into your Prisma Client's performance at the level of individual operations, see [Tracing](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/opentelemetry-tracing).

## Log to stdout [#log-to-stdout]

The simplest way to print *all* log levels to stdout is to pass in an array `LogLevel` objects:

```ts
const prisma = new PrismaClient({
  log: ["query", "info", "warn", "error"],
});
```

This is the short form of passing in an array of `LogDefinition` objects where the value of `emit` is always `stdout`:

```ts
const prisma = new PrismaClient({
  log: [
    {
      emit: "stdout",
      level: "query",
    },
    {
      emit: "stdout",
      level: "error",
    },
    {
      emit: "stdout",
      level: "info",
    },
    {
      emit: "stdout",
      level: "warn",
    },
  ],
});
```

## Event-based logging [#event-based-logging]

To use event-based logging:

1. Set `emit` to `event` for a specific log level, such as query
2. Use the `$on()` method to subscribe to the event

The following example subscribes to all `query` events and write the `duration` and `query` to console:

  

#### Relational databases

```ts highlight=4,5,22-26;normal 
const prisma = new PrismaClient({
  log: [
    {
      emit: "event",
      level: "query",
    },
    {
      emit: "stdout",
      level: "error",
    },
    {
      emit: "stdout",
      level: "info",
    },
    {
      emit: "stdout",
      level: "warn",
    },
  ],
});

prisma.$on("query", (e) => {
  console.log("Query: " + e.query);
  console.log("Params: " + e.params);
  console.log("Duration: " + e.duration + "ms");
});
```

```sql
Query: SELECT "public"."User"."id", "public"."User"."email", "public"."User"."name" FROM "public"."User" WHERE 1=1 OFFSET $1
Params: [0]
Duration: 3ms
Query: SELECT "public"."Post"."id", "public"."Post"."title", "public"."Post"."authorId" FROM "public"."Post" WHERE "public"."Post"."authorId" IN ($1,$2,$3,$4) OFFSET $5
Params: [2, 7, 18, 29]
Duration: 2ms
```

  

#### MongoDB

```ts highlight=4,5,22-25;normal 
const prisma = new PrismaClient({
  log: [
    {
      emit: "event",
      level: "query",
    },
    {
      emit: "stdout",
      level: "error",
    },
    {
      emit: "stdout",
      level: "info",
    },
    {
      emit: "stdout",
      level: "warn",
    },
  ],
});

prisma.$on("query", (e) => {
  console.log("Query: " + e.query);
});
```

```bash
Query: db.User.aggregate([ { $project: { _id: 1, email: 1, name: 1, }, }, ])
Query: db.Post.aggregate([ { $match: { userId: { $in: [ "622f0bbbdf635a42016ee325", ], }, }, }, { $project: { _id: 1, slug: 1, title: 1, body: 1, userId: 1, }, }, ])
```

The exact [event (`e`) type and the properties available](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#event-types) depends on the log level.

## Related pages

- [`OpenTelemetry tracing`](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/opentelemetry-tracing): Diagnose application performance with detailed traces of each query
- [`SQL comments`](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/sql-comments): Add metadata to your SQL queries as comments for improved observability, debugging, and tracing

# OpenTelemetry tracing (Prisma ORM v7) (/docs/orm/v7/prisma-client/observability-and-logging/opentelemetry-tracing)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Diagnose application performance with detailed traces of each query

Location: ORM > v7 > Prisma Client > Observability and Logging > OpenTelemetry tracing

Tracing provides a detailed log of the activity that Prisma Client carries out, at an operation level, including the time taken to execute each query. It helps you analyze your application's performance and identify bottlenecks. Tracing is fully compliant with [OpenTelemetry](https://opentelemetry.io/), so you can use it as part of your end-to-end application tracing system.

> [!NOTE]
> Tracing gives you a highly detailed, operation-level insight into your Prisma ORM project.

> [!NOTE]
> Correlate database queries with traces
> 
> You can add the `traceparent` header to your SQL queries as comments using the [`@prisma/sqlcommenter-trace-context`](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/sql-comments#trace-context) plugin. This enables correlation between distributed traces and database queries in your monitoring tools.

## About tracing [#about-tracing]

When you enable tracing, Prisma Client outputs the following:

* One trace for each operation (e.g. findMany) that Prisma Client makes.
* In each trace, one or more [spans](https://opentelemetry.io/docs/specs/otel/trace/api/#span). Each span represents the length of time that one stage of the operation takes, such as serialization, or a database query. Spans are represented in a tree structure, where child spans indicate that execution is happening within a larger parent span.

The number and type of spans in a trace depends on the type of operation the trace covers, but an example is as follows:

![Example Prisma Client trace structure showing parent and child spans for a database operation (serialization, query engine, database query).](https://www.prisma.io/img/orm/prisma-client/observability-and-logging/trace-diagram.png)

You can [send tracing output to the console](#send-tracing-output-to-the-console), or analyze it in any OpenTelemetry-compatible tracing system, such as [Jaeger](https://www.jaegertracing.io/), [Honeycomb](https://www.honeycomb.io/distributed-tracing) and [Datadog](https://www.datadoghq.com/). On this page, we give an example of how to send tracing output to Jaeger, which you can [run locally](#visualize-traces-with-jaeger).

## Trace output [#trace-output]

For each trace, Prisma Client outputs a series of spans. The number and type of these spans depends on the Prisma Client operation. A typical Prisma trace has the following spans:

* `prisma:client:operation`: Represents the entire Prisma Client operation, from Prisma Client to the database and back. It contains details such as the model and method called by Prisma Client. Depending on the Prisma operation, it contains one or more of the following spans:
  * `prisma:client:connect`: Represents how long it takes for Prisma Client to connect to the database.
  * `prisma:client:serialize`: Represents how long it takes to validate and transform a Prisma Client operation into a query for the query engine.
  * `prisma:engine:query`: Represents how long a query takes in the query engine.
    * `prisma:engine:connection`: Represents how long it takes for Prisma Client to get a database connection.
    * `prisma:engine:db_query`: Represents the database query that was executed against the database. It includes the query in the tags, and how long the query took to run.
    * `prisma:engine:serialize`: Represents how long it takes to transform a raw response from the database into a typed result.
    * `prisma:engine:response_json_serialization`: Represents how long it takes to serialize the database query result into a JSON response to the Prisma Client.

For example, given the following Prisma Client code:

```ts
prisma.user.findMany({
  where: {
    email: email,
  },
  include: {
    posts: true,
  },
});
```

The trace is structured as follows:

* `prisma:client:operation`
  * `prisma:client:serialize`
  * `prisma:engine:query`
    * `prisma:engine:connection`
    * `prisma:engine:db_query`: details of the first SQL query or command...
    * `prisma:engine:db_query`: ...details of the next SQL query or command...
    * `prisma:engine:serialize`
    * `prisma:engine:response_json_serialization`

## Considerations and prerequisites [#considerations-and-prerequisites]

If your application sends a large number of spans to a [collector](https://opentelemetry.io/docs/collector/), this can have a significant performance impact. For information on how to minimize this impact, see [Reducing performance impact](#reduce-performance-impact).

To use tracing, you must do the following:

1. [Install the appropriate dependencies](#step-1-install-prisma-orm-dependencies).
2. [Install OpenTelemetry packages](#step-2-install-opentelemetry-packages).
3. [Register tracing in your application](#step-3-register-tracing-in-your-application).

## Get started with tracing in Prisma ORM [#get-started-with-tracing-in-prisma-orm]

This section explains how to install and register tracing in your application.

### Step 1. Install Prisma ORM dependencies [#step-1-install-prisma-orm-dependencies]

Install the `prisma`, `@prisma/client`, and `@prisma/instrumentation` npm packages. You will also need to install the `@opentelemetry/api` package as it's a peer dependency.

  

#### bun

```bash
bun add prisma@prev --dev
bun add @prisma/client@7
bun add @prisma/instrumentation@latest
bun add @opentelemetry/api@latest
```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
pnpm add @prisma/client@7
pnpm add @prisma/instrumentation@latest
pnpm add @opentelemetry/api@latest
```

#### yarn

```bash
yarn add prisma@prev --dev
yarn add @prisma/client@7
yarn add @prisma/instrumentation@latest
yarn add @opentelemetry/api@latest
```

#### npm

```bash
npm install prisma@prev --save-dev
npm install @prisma/client@7 --save
npm install @prisma/instrumentation@latest --save
npm install @opentelemetry/api@latest --save
```

**Tracing on previous versions of Prisma ORM**

Tracing was added in version `4.2.0` of Prisma ORM as a Preview feature. For versions of Prisma ORM between `4.2.0` and `6.1.0`, you need to enable the `tracing` Preview feature in your Prisma schema file.

```prisma
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["tracing"]
}
```

### Step 2: Install OpenTelemetry packages [#step-2-install-opentelemetry-packages]

Now install the appropriate OpenTelemetry packages, as follows:

  

#### bun

```bash
bun add @opentelemetry/semantic-conventions \
  @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/sdk-trace-base \
  @opentelemetry/sdk-trace-node \
  @opentelemetry/resources
```

#### pnpm

```bash
pnpm add @opentelemetry/semantic-conventions \
  @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/sdk-trace-base \
  @opentelemetry/sdk-trace-node \
  @opentelemetry/resources
```

#### yarn

```bash
yarn add @opentelemetry/semantic-conventions \
  @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/sdk-trace-base \
  @opentelemetry/sdk-trace-node \
  @opentelemetry/resources
```

#### npm

```bash
npm install @opentelemetry/semantic-conventions \
  @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/sdk-trace-base \
  @opentelemetry/sdk-trace-node \
  @opentelemetry/resources
```

### Step 3: Register tracing in your application [#step-3-register-tracing-in-your-application]

The following code provides two examples of configuring OpenTelemetry tracing in Prisma:

1. Using `@opentelemetry/sdk-trace-node` (existing example), which gives fine-grained control over tracing setup.
2. Using `@opentelemetry/sdk-node`, which offers a simpler configuration and follows OpenTelemetry's JavaScript getting started guide.

#### Option 1: Using `@opentelemetry/sdk-trace-node` [#option-1-using-opentelemetrysdk-trace-node]

This setup gives you fine-grained control over instrumentation and tracing. You need to customize this configuration for your specific application. This approach is concise and easier for users who need a quick setup for sending traces to OTLP-compatible backends, such as Honeycomb, Jaeger, or Datadog.

```ts
// Imports
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from "@opentelemetry/semantic-conventions";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { PrismaInstrumentation, registerInstrumentations } from "@prisma/instrumentation";
import { resourceFromAttributes } from "@opentelemetry/resources";

// Configure the trace provider
const provider = new NodeTracerProvider({
  resource: resourceFromAttributes({
    [ATTR_SERVICE_NAME]: "example application", // Replace with your service name
    [ATTR_SERVICE_VERSION]: "0.0.1", // Replace with your service version
  }),
  spanProcessors: [
    // Configure how spans are processed and exported. In this case, we're sending spans
    // as we receive them to an OTLP-compatible collector (e.g., Jaeger).
    new SimpleSpanProcessor(new OTLPTraceExporter()),
  ],
});

// Register your auto-instrumentors
registerInstrumentations({
  tracerProvider: provider,
  instrumentations: [new PrismaInstrumentation()],
});

// Register the provider globally
provider.register();
```

This approach provides maximum flexibility but may involve additional configuration steps.

#### Option 2: Using `@opentelemetry/sdk-node` [#option-2-using-opentelemetrysdk-node]

The `NodeSDK` class bundles common OpenTelemetry defaults into a single configuration.

```ts
// Imports
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
import { NodeSDK } from "@opentelemetry/sdk-node";
import { PrismaInstrumentation } from "@prisma/instrumentation";

// Configure the OTLP trace exporter
const traceExporter = new OTLPTraceExporter({
  url: "https://api.honeycomb.io/v1/traces", // Replace with your collector's endpoint
  headers: {
    "x-honeycomb-team": "HONEYCOMB_API_KEY", // Replace with your Honeycomb API key or collector auth header
  },
});

// Initialize the NodeSDK
const sdk = new NodeSDK({
  serviceName: "my-service-name", // Replace with your service name
  traceExporter,
  instrumentations: [new PrismaInstrumentation()],
});

// Start the SDK
sdk.start();

// Handle graceful shutdown
process.on("SIGTERM", async () => {
  try {
    await sdk.shutdown();
    console.log("Tracing shut down successfully");
  } catch (err) {
    console.error("Error shutting down tracing", err);
  } finally {
    process.exit(0);
  }
});
```

Choose the `NodeSDK` approach if:

* You are starting with OpenTelemetry and want a simplified setup.
* You need to quickly integrate tracing with minimal boilerplate.
* You are using an OTLP-compatible tracing backend like Honeycomb, Jaeger, or Datadog.

Choose the `NodeTracerProvider` approach if:

* You need detailed control over how spans are created, processed, and exported.
* You are using custom span processors or exporters.
* Your application requires specific instrumentation or sampling strategies.

OpenTelemetry is highly configurable. You can customize the resource attributes, what components gets instrumented, how spans are processed, and where spans are sent.

You can find a complete example that includes metrics in [this sample application](https://github.com/garrensmith/prisma-metrics-sample).

## Tracing how-tos [#tracing-how-tos]

### Visualize traces with Jaeger [#visualize-traces-with-jaeger]

[Jaeger](https://www.jaegertracing.io/) is a free and open source OpenTelemetry collector and dashboard that you can use to visualize your traces.

The following screenshot shows an example trace visualization:

![Jaeger UI](https://www.prisma.io/img/orm/prisma-client/observability-and-logging/jaeger.png)

To run Jaeger locally, use the following [Docker](https://www.docker.com/) command:

```console
docker run --rm --name jaeger -d -e COLLECTOR_OTLP_ENABLED=true -p 16686:16686 -p 4318:4318 jaegertracing/all-in-one:latest
```

You'll now find the tracing dashboard available at `http://localhost:16686/`. When you use your application with tracing enabled, you'll start to see traces in this dashboard.

### Send tracing output to the console [#send-tracing-output-to-the-console]

The following example sends output tracing to the console with `ConsoleSpanExporter` from `@opentelemetry/sdk-trace-base`.

```ts
// Imports
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from "@opentelemetry/semantic-conventions";
import { ConsoleSpanExporter, SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { AsyncHooksContextManager } from "@opentelemetry/context-async-hooks";
import * as api from "@opentelemetry/api";
import { PrismaInstrumentation, registerInstrumentations } from "@prisma/instrumentation";
import { resourceFromAttributes } from "@opentelemetry/resources";

// Export the tracing
export function otelSetup() {
  const contextManager = new AsyncHooksContextManager().enable();

  api.context.setGlobalContextManager(contextManager);

  //Configure the console exporter
  const consoleExporter = new ConsoleSpanExporter();

  // Configure the trace provider
  const provider = new NodeTracerProvider({
    resource: resourceFromAttributes({
      [ATTR_SERVICE_NAME]: "example application", // Replace with your service name
      [ATTR_SERVICE_VERSION]: "0.0.1", // Replace with your service version
    }),
    spanProcessors: [
      // Configure how spans are processed and exported. In this case, we're sending spans
      // as we receive them to the console
      new SimpleSpanProcessor(consoleExporter),
    ],
  });

  // Register your auto-instrumentors
  registerInstrumentations({
    tracerProvider: provider,
    instrumentations: [new PrismaInstrumentation()],
  });

  // Register the provider
  provider.register();
}
```

### Trace interactive transactions [#trace-interactive-transactions]

When you perform an interactive transaction, you'll see the following span in addition to the [standard spans](#trace-output):

* `prisma:client:transaction`: A [root span](https://opentelemetry.io/docs/concepts/observability-primer/#distributed-traces) that wraps the `prisma` span.

As an example, take the following Prisma schema:

```prisma title="schema.prisma" showLineNumbers
generator client {
  provider        = "prisma-client"
  output          = "./generated"
}

datasource db {
  provider = "postgresql"
}

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

model Audit {
  id     Int    @id
  table  String
  action String
}
```

Given the following interactive transaction:

```ts
await prisma.$transaction(async (tx) => {
  const user = await tx.user.create({
    data: {
      email: email,
    },
  });

  await tx.audit.create({
    data: {
      table: "user",
      action: "create",
      id: user.id,
    },
  });

  return user;
});
```

The trace is structured as follows:

* `prisma:client:transaction`
* `prisma:client:connect`
* `prisma:engine:itx_runner`
  * `prisma:engine:connection`
  * `prisma:engine:db_query`
  * `prisma:engine:itx_query_builder`
    * `prisma:engine:db_query`
    * `prisma:engine:db_query`
    * `prisma:engine:serialize`
  * `prisma:engine:itx_query_builder`
    * `prisma:engine:db_query`
    * `prisma:engine:db_query`
    * `prisma:engine:serialize`
* `prisma:client:operation`
  * `prisma:client:serialize`
* `prisma:client:operation`
  * `prisma:client:serialize`

### Add more instrumentation [#add-more-instrumentation]

OpenTelemetry lets you add more instrumentation with minimal changes to your application code.

For example, to add HTTP and [ExpressJS](https://expressjs.com/) tracing, add the following instrumentations to your OpenTelemetry configuration. These instrumentations add spans for the full request-response lifecycle. These spans show you how long your HTTP requests take.

```js
// Imports
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";

// Register your auto-instrumentors
registerInstrumentations({
  tracerProvider: provider,
  instrumentations: [
    new HttpInstrumentation(),
    new ExpressInstrumentation(),
    new PrismaInstrumentation(),
  ],
});
```

For a full list of available instrumentation, take a look at the [OpenTelemetry Registry](https://opentelemetry.io/ecosystem/registry/?language=js\&component=instrumentation).

### Customize resource attributes [#customize-resource-attributes]

You can adjust how your application's traces are grouped by changing the resource attributes to be more specific to your application:

```js
const provider = new NodeTracerProvider({
  resource: new Resource({
    [ATTR_SERVICE_NAME]: "weblog",
    [ATTR_SERVICE_VERSION]: "1.0.0",
  }),
});
```

There is an ongoing effort to standardize common resource attributes. Whenever possible, it's a good idea to follow the [standard attribute names](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/trace.md).

### Reduce performance impact [#reduce-performance-impact]

If your application sends a large number of spans to a collector, this can have a significant performance impact. You can use the following approaches to reduce this impact:

* [Use the BatchSpanProcessor](#send-traces-in-batches-using-the-batchspanprocessor)
* [Send fewer spans to the collector](#send-fewer-spans-to-the-collector-with-sampling)

#### Send traces in batches using the `BatchSpanProcessor` [#send-traces-in-batches-using-the-batchspanprocessor]

In a production environment, you can use OpenTelemetry's `BatchSpanProcessor` to send the spans to a collector in batches rather than one at a time. However, during development and testing, you might not want to send spans in batches. In this situation, you might prefer to use the `SimpleSpanProcessor`.

You can configure your tracing configuration to use the appropriate span processor, depending on the environment, as follows:

```ts
import { SimpleSpanProcessor, BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";

const spanProcessors = [];
if (process.env.NODE_ENV === "production") {
  spanProcessors.push(new BatchSpanProcessor(otlpTraceExporter));
} else {
  spanProcessors.push(new SimpleSpanProcessor(otlpTraceExporter));
}

const provider = new NodeTracerProvider({
  spanProcessors,
  // ...other configurations
});
```

#### Send fewer spans to the collector with sampling [#send-fewer-spans-to-the-collector-with-sampling]

Another way to reduce the performance impact is to [use probability sampling](https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling/) to send fewer spans to the collector. This reduces the collection cost of tracing but still gives a good representation of what is happening in your application.

An example implementation looks like this:

```ts highlight=3,7;add
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from "@opentelemetry/semantic-conventions";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { TraceIdRatioBasedSampler } from "@opentelemetry/core";
import { resourceFromAttributes } from "@opentelemetry/resources";

const provider = new NodeTracerProvider({
  sampler: new TraceIdRatioBasedSampler(0.1), // [!code ++]
  resource: resourceFromAttributes({
    // we can define some metadata about the trace resource
    [ATTR_SERVICE_NAME]: "test-tracing-service",
    [ATTR_SERVICE_VERSION]: "1.0.0",
  }),
});
```

## Troubleshoot tracing [#troubleshoot-tracing]

### My traces aren't showing up [#my-traces-arent-showing-up]

The order in which you set up tracing matters. In your application, ensure that you register tracing and instrumentation before you import any instrumented dependencies. For example:

```ts
import { registerTracing } from "./tracing";

registerTracing({
  name: "tracing-example",
  version: "0.0.1",
});

// You must import any dependencies after you register tracing.
import { PrismaClient } from "../prisma/generated/client";
import async from "express-async-handler";
import express from "express";
```

## Related pages

- [`Logging`](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/logging): Learn how to configure Prisma Client to log the raw SQL queries it sends to the database and other information
- [`SQL comments`](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/sql-comments): Add metadata to your SQL queries as comments for improved observability, debugging, and tracing

# SQL comments (Prisma ORM v7) (/docs/orm/v7/prisma-client/observability-and-logging/sql-comments)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Add metadata to your SQL queries as comments for improved observability, debugging, and tracing

Location: ORM > v7 > Prisma Client > Observability and Logging > SQL comments

SQL comments allow you to append metadata to your database queries, making it easier to correlate queries with application context. Prisma ORM supports the [sqlcommenter format](https://google.github.io/sqlcommenter/) developed by Google, which is widely supported by database monitoring tools.

SQL comments are useful for:

* **Observability**: Correlate database queries with application traces using `traceparent`
* **Query insights**: Tag queries with metadata for analysis in database monitoring tools
* **Debugging**: Add custom context to queries for easier troubleshooting

## Installation [#installation]

Install one or more first-party plugins depending on your use case:

  

#### bun

```bash
bun add @prisma/sqlcommenter-query-tags
bun add @prisma/sqlcommenter-trace-context
```

#### pnpm

```bash
pnpm add @prisma/sqlcommenter-query-tags
pnpm add @prisma/sqlcommenter-trace-context
```

#### yarn

```bash
yarn add @prisma/sqlcommenter-query-tags
yarn add @prisma/sqlcommenter-trace-context
```

#### npm

```bash
npm install @prisma/sqlcommenter-query-tags
npm install @prisma/sqlcommenter-trace-context
```

Install the core SQL commenter types package to create your own plugin:

  

#### bun

```bash
bun add @prisma/sqlcommenter
```

#### pnpm

```bash
pnpm add @prisma/sqlcommenter
```

#### yarn

```bash
yarn add @prisma/sqlcommenter
```

#### npm

```bash
npm install @prisma/sqlcommenter
```

## Basic usage [#basic-usage]

Pass an array of SQL commenter plugins to the `comments` option when creating a `PrismaClient` instance:

```ts
import { PrismaClient } from "../prisma/generated/client";
import { PrismaPg } from "@prisma/adapter-pg";
import { queryTags } from "@prisma/sqlcommenter-query-tags";
import { traceContext } from "@prisma/sqlcommenter-trace-context";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });

const prisma = new PrismaClient({
  adapter,
  comments: [queryTags(), traceContext()],
});
```

With this configuration, your SQL queries will include metadata as comments:

```sql
SELECT "id", "name" FROM "User" /*application='my-app',traceparent='00-abc123...-01'*/
```

## First-party plugins [#first-party-plugins]

Prisma provides two official SQL commenter plugins:

### Query tags [#query-tags]

The `@prisma/sqlcommenter-query-tags` package allows you to add arbitrary tags to queries within an async context using `AsyncLocalStorage`.

```ts
import { queryTags, withQueryTags } from "@prisma/sqlcommenter-query-tags";
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient({
  adapter,
  comments: [queryTags()],
});

// Wrap your queries to add tags
const users = await withQueryTags({ route: "/api/users", requestId: "abc-123" }, () =>
  prisma.user.findMany(),
);
```

The resulting SQL includes the tags as comments:

```sql
SELECT ... FROM "User" /*requestId='abc-123',route='/api/users'*/
```

#### Multiple queries in one scope [#multiple-queries-in-one-scope]

All queries within the callback share the same tags:

```ts
const result = await withQueryTags({ traceId: "trace-456" }, async () => {
  const users = await prisma.user.findMany();
  const posts = await prisma.post.findMany();
  return { users, posts };
});
```

#### Nested scopes with tag replacement [#nested-scopes-with-tag-replacement]

By default, nested `withQueryTags` calls replace the outer tags entirely:

```ts
await withQueryTags({ requestId: "req-123" }, async () => {
  // Queries here have: requestId='req-123'

  await withQueryTags({ userId: "user-456" }, async () => {
    // Queries here only have: userId='user-456'
    // requestId is NOT included
    await prisma.user.findMany();
  });
});
```

#### Nested scopes with tag merging [#nested-scopes-with-tag-merging]

Use `withMergedQueryTags` to merge tags with the outer scope:

```ts
import { withQueryTags, withMergedQueryTags } from "@prisma/sqlcommenter-query-tags";

await withQueryTags({ requestId: "req-123", source: "api" }, async () => {
  await withMergedQueryTags({ userId: "user-456", source: "handler" }, async () => {
    // Queries here have: requestId='req-123', userId='user-456', source='handler'
    await prisma.user.findMany();
  });
});
```

You can also remove tags in nested scopes by setting them to `undefined`:

```ts
await withQueryTags({ requestId: "req-123", debug: "true" }, async () => {
  await withMergedQueryTags({ userId: "user-456", debug: undefined }, async () => {
    // Queries here have: requestId='req-123', userId='user-456'
    // debug is removed
    await prisma.user.findMany();
  });
});
```

### Trace context [#trace-context]

The `@prisma/sqlcommenter-trace-context` package adds W3C Trace Context (`traceparent`) headers to your queries, enabling correlation between distributed traces and database queries.

```ts
import { traceContext } from "@prisma/sqlcommenter-trace-context";
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient({
  adapter,
  comments: [traceContext()],
});
```

When tracing is enabled and the current span is sampled, queries include the `traceparent`:

```sql
SELECT * FROM "User" /*traceparent='00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01'*/
```

> [!NOTE]
> The trace context plugin requires [`@prisma/instrumentation`](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/opentelemetry-tracing) to be configured. The `traceparent` is only added when tracing is active and the span is sampled.

The `traceparent` header follows the [W3C Trace Context](https://www.w3.org/TR/trace-context/) specification:

```
{version}-{trace-id}-{parent-id}-{trace-flags}
```

Where:

* `version`: Always `00` for the current spec
* `trace-id`: 32 hexadecimal characters representing the trace ID
* `parent-id`: 16 hexadecimal characters representing the parent span ID
* `trace-flags`: 2 hexadecimal characters; `01` indicates sampled

## Creating custom plugins [#creating-custom-plugins]

You can create your own SQL commenter plugins to add custom metadata to queries.

### Plugin structure [#plugin-structure]

A SQL commenter plugin is a function that receives query context and returns key-value pairs:

```ts
import type { SqlCommenterPlugin, SqlCommenterContext } from "@prisma/sqlcommenter";

const myPlugin: SqlCommenterPlugin = (context: SqlCommenterContext) => {
  return {
    application: "my-app",
    version: "1.0.0",
  };
};
```

### Using custom plugins [#using-custom-plugins]

Pass your custom plugins to the `comments` option:

```ts
const prisma = new PrismaClient({
  adapter,
  comments: [myPlugin],
});
```

### Conditional keys [#conditional-keys]

Return `undefined` for keys you want to exclude from the comment. Keys with `undefined` values are automatically filtered out:

```ts
const conditionalPlugin: SqlCommenterPlugin = (context) => ({
  model: context.query.modelName, // undefined for raw queries, automatically omitted
  action: context.query.action,
});
```

### Query context [#query-context]

Plugins receive a `SqlCommenterContext` object containing information about the query:

```ts
interface SqlCommenterContext {
  query: SqlCommenterQueryInfo;
  sql?: string;
}
```

The `query` property provides information about the Prisma operation:

| Property    | Type                                                   | Description                                                            |
| ----------- | ------------------------------------------------------ | ---------------------------------------------------------------------- |
| `type`      | `'single'` \| `'compacted'`                            | Whether this is a single query or a batched query                      |
| `modelName` | `string` \| `undefined`                                | The model being queried (e.g., `"User"`). Undefined for raw queries.   |
| `action`    | `string`                                               | The Prisma operation (e.g., `"findMany"`, `"createOne"`, `"queryRaw"`) |
| `query`     | `unknown` (single) or `queries: unknown[]` (compacted) | The full query object(s). Structure is not part of the public API.     |

The `sql` property is the raw SQL query generated from this Prisma query. It is always available when `PrismaClient` connects to the database and renders SQL queries directly. When using Prisma Accelerate, SQL rendering happens on Accelerate side and the raw SQL strings are not available when SQL commenter plugins are executed on the `PrismaClient` side.

#### Single vs. compacted queries [#single-vs-compacted-queries]

* **Single queries** (`type: 'single'`): A single Prisma query is being executed
* **Compacted queries** (`type: 'compacted'`): Multiple queries have been batched into a single SQL statement (e.g., automatic `findUnique` batching)

### Example: Application metadata [#example-application-metadata]

```ts
import type { SqlCommenterPlugin } from "@prisma/sqlcommenter";

const applicationTags: SqlCommenterPlugin = (context) => ({
  application: "my-service",
  environment: process.env.NODE_ENV ?? "development",
  operation: context.query.action,
  model: context.query.modelName,
});
```

### Example: Async context propagation [#example-async-context-propagation]

Use `AsyncLocalStorage` to propagate context through your application:

```ts
import { AsyncLocalStorage } from "node:async_hooks";
import type { SqlCommenterPlugin } from "@prisma/sqlcommenter";

interface RequestContext {
  route: string;
  userId?: string;
}

const requestStorage = new AsyncLocalStorage<RequestContext>();

const requestContextPlugin: SqlCommenterPlugin = () => {
  const context = requestStorage.getStore();
  return {
    route: context?.route,
    userId: context?.userId,
  };
};

// Usage in a request handler
requestStorage.run({ route: "/api/users", userId: "user-123" }, async () => {
  await prisma.user.findMany();
});
```

### Combining multiple plugins [#combining-multiple-plugins]

Plugins are called in array order, and their outputs are merged. Later plugins can override keys from earlier plugins:

```ts
import type { SqlCommenterPlugin } from "@prisma/sqlcommenter";
import { queryTags } from "@prisma/sqlcommenter-query-tags";
import { traceContext } from "@prisma/sqlcommenter-trace-context";

const appPlugin: SqlCommenterPlugin = () => ({
  application: "my-app",
  version: "1.0.0",
});

const prisma = new PrismaClient({
  adapter,
  comments: [appPlugin, queryTags(), traceContext()],
});
```

## Framework integration [#framework-integration]

### Hono [#hono]

Hono's middleware properly awaits downstream handlers:

```ts
import { createMiddleware } from "hono/factory";
import { withQueryTags } from "@prisma/sqlcommenter-query-tags";

app.use(
  createMiddleware(async (c, next) => {
    await withQueryTags(
      {
        route: c.req.path,
        method: c.req.method,
        requestId: c.req.header("x-request-id") ?? crypto.randomUUID(),
      },
      () => next(),
    );
  }),
);
```

### Koa [#koa]

Koa's middleware properly awaits downstream handlers:

```ts
import { withQueryTags } from "@prisma/sqlcommenter-query-tags";

app.use(async (ctx, next) => {
  await withQueryTags(
    {
      route: ctx.path,
      method: ctx.method,
      requestId: ctx.get("x-request-id") || crypto.randomUUID(),
    },
    () => next(),
  );
});
```

### Fastify [#fastify]

Wrap individual route handlers:

```ts
import { withQueryTags } from "@prisma/sqlcommenter-query-tags";

fastify.get("/users", (request, reply) => {
  return withQueryTags(
    {
      route: "/users",
      method: "GET",
      requestId: request.id,
    },
    () => prisma.user.findMany(),
  );
});
```

### Express [#express]

Express middleware uses callbacks, so wrap route handlers directly:

```ts
import { withQueryTags } from "@prisma/sqlcommenter-query-tags";

app.get("/users", (req, res, next) => {
  withQueryTags(
    {
      route: req.path,
      method: req.method,
      requestId: req.header("x-request-id") ?? crypto.randomUUID(),
    },
    () => prisma.user.findMany(),
  )
    .then((users) => res.json(users))
    .catch(next);
});
```

### NestJS [#nestjs]

Use an interceptor to wrap handler execution:

```ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from "@nestjs/common";
import { Observable, from, lastValueFrom } from "rxjs";
import { withQueryTags } from "@prisma/sqlcommenter-query-tags";

@Injectable()
export class QueryTagsInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
    const request = context.switchToHttp().getRequest<Request>();
    return from(
      withQueryTags(
        {
          route: request.url,
          method: request.method,
          requestId: request.headers.get("x-request-id") ?? crypto.randomUUID(),
        },
        () => lastValueFrom(next.handle()),
      ),
    );
  }
}

// Apply globally in main.ts
app.useGlobalInterceptors(new QueryTagsInterceptor());
```

## Output format [#output-format]

Plugin outputs are merged, sorted alphabetically by key, URL-encoded, and formatted according to the [sqlcommenter specification](https://google.github.io/sqlcommenter/spec/):

```sql
SELECT "id", "name" FROM "User" /*application='my-app',environment='production',model='User'*/
```

Key behaviors:

* Plugins are called synchronously in array order
* Later plugins override earlier ones if they return the same key
* Keys with `undefined` values are filtered out (they do not remove keys set by earlier plugins)
* Keys and values are URL-encoded per the sqlcommenter spec
* Single quotes in values are escaped as `\'`
* Comments are appended to the end of SQL queries

## API reference [#api-reference]

### `SqlCommenterTags` [#sqlcommentertags]

```ts
type SqlCommenterTags = { readonly [key: string]: string | undefined };
```

Key-value pairs to add as SQL comments. Keys with `undefined` values are automatically filtered out.

### `SqlCommenterPlugin` [#sqlcommenterplugin]

```ts
interface SqlCommenterPlugin {
  (context: SqlCommenterContext): SqlCommenterTags;
}
```

A function that receives query context and returns key-value pairs. Return an empty object to add no comments for a particular query.

### `SqlCommenterContext` [#sqlcommentercontext]

```ts
interface SqlCommenterContext {
  query: SqlCommenterQueryInfo;
  sql?: string;
}
```

Context provided to plugins containing information about the query.

* **`query`**: Information about the Prisma query being executed. See [`SqlCommenterQueryInfo`](#sqlcommenterqueryinfo).
* **`sql`**: The SQL query being executed. It is only available when using driver adapters but not when using Accelerate.

### `SqlCommenterQueryInfo` [#sqlcommenterqueryinfo]

```ts
type SqlCommenterQueryInfo =
  | ({ type: "single" } & SqlCommenterSingleQueryInfo)
  | ({ type: "compacted" } & SqlCommenterCompactedQueryInfo);
```

Information about the query or queries being executed.

### `SqlCommenterSingleQueryInfo` [#sqlcommentersinglequeryinfo]

```ts
interface SqlCommenterSingleQueryInfo {
  modelName?: string;
  action: string;
  query: unknown;
}
```

Information about a single Prisma query.

### `SqlCommenterCompactedQueryInfo` [#sqlcommentercompactedqueryinfo]

```ts
interface SqlCommenterCompactedQueryInfo {
  modelName?: string;
  action: string;
  queries: unknown[];
}
```

Information about a compacted batch query.

## Related pages

- [`Logging`](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/logging): Learn how to configure Prisma Client to log the raw SQL queries it sends to the database and other information
- [`OpenTelemetry tracing`](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/opentelemetry-tracing): Diagnose application performance with detailed traces of each query

# Aggregation, grouping, and summarizing (Prisma ORM v7) (/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Use Prisma Client to aggregate, group by, count, and select distinct.

Location: ORM > v7 > Prisma Client > Queries > Aggregation, grouping, and summarizing

Prisma Client allows you to count records, aggregate number fields, and select distinct field values.

## Aggregate [#aggregate]

Prisma Client allows you to [`aggregate`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#aggregate) on the **number** fields (such as `Int` and `Float`) of a model. The following query returns the average age of all users:

```ts
const aggregations = await prisma.user.aggregate({
  _avg: { age: true },
});

console.log('Average age:' + aggregations._avg.age);
```

You can combine aggregation with filtering and ordering. For example, the following query returns the average age of users:

* Ordered by `age` ascending
* Where `email` contains `prisma.io`
* Limited to the 10 users

```ts
const aggregations = await prisma.user.aggregate({
  _avg: { age: true },
  where: {
    email: {
      contains: 'prisma.io',
    },
  },
  orderBy: { age: 'asc' },
  take: 10,
});

console.log('Average age:' + aggregations._avg.age);
```

### Aggregate values are nullable [#aggregate-values-are-nullable]

Aggregations on **nullable fields** can return a `number` or `null`. This excludes `count`, which always returns 0 if no records are found.

Consider the following query, where `age` is nullable in the schema:

```ts
const aggregations = await prisma.user.aggregate({
  _avg: { age: true },
  _count: { age: true },
});
```

```json
{
  "_avg": { "age": null },
  "_count": { "age": 9 }
}
```

The query returns `{ _avg: { age: null } }` in either of the following scenarios:

* There are no users
* The value of every user's `age` field is `null`

This allows you to differentiate between the true aggregate value (which could be zero) and no data.

## Group by [#group-by]

Prisma Client's [`groupBy()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#groupby) allows you to **group records** by one or more field values - such as `country`, or `country` and `city` and **perform aggregations** on each group, such as finding the average age of people living in a particular city.

The following example groups all users by the `country` field and returns the total number of profile views for each country:

```ts
const groupUsers = await prisma.user.groupBy({
  by: ['country'],
  _sum: { profileViews: true },
});
```

```json
[
  { country: 'Germany', _sum: { profileViews: 126 } },
  { country: 'Sweden', _sum: { profileViews: 0 } },
];
```

If you have a single element in the `by` option, you can use the following shorthand syntax to express your query:

```ts
const groupUsers = await prisma.user.groupBy({
  by: 'country',
});
```

### `groupBy()` and filtering [#groupby-and-filtering]

`groupBy()` supports two levels of filtering: `where` and `having`.

#### Filter records with `where` [#filter-records-with-where]

Use `where` to filter all records **before grouping**. The following example groups users by country and sums profile views, but only includes users where the email address contains `prisma.io`:

```ts
const groupUsers = await prisma.user.groupBy({
  by: ['country'],
  where: {
    // [!code highlight]
    email: {
      // [!code highlight]
      contains: 'prisma.io', // [!code highlight]
    }, // [!code highlight]
  }, // [!code highlight]
  _sum: {
    profileViews: true,
  },
});
```

#### Filter groups with `having` [#filter-groups-with-having]

Use `having` to filter **entire groups** by an aggregate value such as the sum or average of a field, not individual records - for example, only return groups where the *average* `profileViews` is greater than 100:

```ts
const groupUsers = await prisma.user.groupBy({
  by: ['country'],
  where: {
    email: {
      contains: 'prisma.io',
    },
  },
  _sum: { profileViews: true, },
  having: {
    // [!code highlight]
    profileViews: {
      // [!code highlight]
      _avg: {
        // [!code highlight]
        gt: 100, // [!code highlight]
      }, // [!code highlight]
    }, // [!code highlight]
  }, // [!code highlight]
});
```

##### Use case for `having` [#use-case-for-having]

The primary use case for `having` is to filter on aggregations. We recommend that you use `where` to reduce the size of your data set as far as possible *before* grouping, because doing so ✔ reduces the number of records the database has to return and ✔ makes use of indices.

For example, the following query groups all users that are *not* from Sweden or Ghana:

```ts
const fd = await prisma.user.groupBy({
  by: ['country'],
  where: {
    country: {
      // [!code highlight]
      notIn: ['Sweden', 'Ghana'], // [!code highlight]
    }, // [!code highlight]
  },
  _sum: {
    profileViews: true,
  },
  having: {
    profileViews: {
      _min: {
        gte: 10,
      },
    },
  },
});
```

The following query technically achieves the same result, but excludes users from Ghana *after* grouping. This does not confer any benefit and is not recommended practice.

```ts
const groupUsers = await prisma.user.groupBy({
  by: ['country'],
  where: {
    country: {
      // [!code highlight]
      not: 'Sweden', // [!code highlight]
    }, // [!code highlight]
  },
  _sum: {
    profileViews: true,
  },
  having: {
    country: {
      // [!code highlight]
      not: 'Ghana', // [!code highlight]
    }, // [!code highlight]
    profileViews: {
      _min: {
        gte: 10,
      },
    },
  },
});
```

> **Note**: Within `having`, you can only filter on aggregate values *or* fields available in `by`.

### `groupBy()` and ordering [#groupby-and-ordering]

The following constraints apply when you combine `groupBy()` and `orderBy`:

* You can `orderBy` fields that are present in `by`
* You can `orderBy` aggregate (Preview in 2.21.0 and later)
* If you use `skip` and/or `take` with `groupBy()`, you must also include `orderBy` in the query

#### Order by aggregate group [#order-by-aggregate-group]

You can **order by aggregate group**. The following example sorts each `city` group by the number of users in that group (largest group first):

```ts
const groupBy = await prisma.user.groupBy({
  by: ['city'],
  _count: {
    city: true,
  },
  orderBy: {
    _count: {
      city: 'desc',
    },
  },
});
```

```json
[
  { city: 'Berlin', count: { city: 3 } },
  { city: 'Paris', count: { city: 2 } },
  { city: 'Amsterdam', count: { city: 1 } },
];
```

#### Order by field [#order-by-field]

The following query orders groups by country, skips the first two groups, and returns the 3rd and 4th group:

```ts
const groupBy = await prisma.user.groupBy({
  by: ['country'],
  _sum: {
    profileViews: true,
  },
  orderBy: {
    country: 'desc',
  },
  skip: 2,
  take: 2,
});
```

### `groupBy()` FAQ [#groupby-faq]

#### Can I use `select` with `groupBy()`? [#can-i-use-select-with-groupby]

You cannot use `select` with `groupBy()`. However, all fields included in `by` are automatically returned.

#### What is the difference between using `where` and `having` with `groupBy()`? [#what-is-the-difference-between-using-where-and-having-with-groupby]

`where` filters all records before grouping, and `having` filters entire groups and supports filtering on an aggregate field value, such as the average or sum of a particular field in that group.

#### What is the difference between `groupBy()` and `distinct`? [#what-is-the-difference-between-groupby-and-distinct]

Both `distinct` and `groupBy()` group records by one or more unique field values. `groupBy()` allows you to aggregate data within each group - for example, return the average number of views on posts from Denmark - whereas distinct does not.

## Count [#count]

### Count records [#count-records]

Use [`count()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#count) to count the number of records or non-`null` field values. The following example query counts all users:

```ts
const userCount = await prisma.user.count();
```

### Count relations [#count-relations]

To return a count of relations (for example, a user's post count), use the `_count` parameter with a nested `select` as shown:

```ts
const usersWithCount = await prisma.user.findMany({
  include: {
    _count: {
      select: { posts: true },
    },
  },
});
```

```json
{ id: 1, _count: { posts: 3 } },
{ id: 2, _count: { posts: 2 } },
{ id: 3, _count: { posts: 2 } },
{ id: 4, _count: { posts: 0 } },
{ id: 5, _count: { posts: 0 } }
```

The `_count` parameter:

* Can be used inside a top-level `include` *or* `select`
* Can be used with any query that returns records (including `delete`, `update`, and `findFirst`)
* Can return [multiple relation counts](#return-multiple-relation-counts)
* Can [filter relation counts](#filter-the-relation-count) (from version 4.3.0)

#### Return a relations count with `include` [#return-a-relations-count-with-include]

The following query includes each user's post count in the results:

```ts
const usersWithCount = await prisma.user.findMany({
  include: {
    _count: {
      select: { posts: true },
    },
  },
});
```

```json
{ id: 1, _count: { posts: 3 } },
{ id: 2, _count: { posts: 2 } },
{ id: 3, _count: { posts: 2 } },
{ id: 4, _count: { posts: 0 } },
{ id: 5, _count: { posts: 0 } }
```

#### Return a relations count with `select` [#return-a-relations-count-with-select]

The following query uses `select` to return each user's post count *and no other fields*:

```ts
const usersWithCount = await prisma.user.findMany({
  select: {
    _count: {
      select: { posts: true },
    },
  },
});
```

```json
{
  _count: {
    posts: 3;
  }
}
```

#### Return multiple relation counts [#return-multiple-relation-counts]

The following query returns a count of each user's `posts` and `recipes` and no other fields:

```ts
const usersWithCount = await prisma.user.findMany({
  select: {
    _count: {
      select: {
        posts: true,
        recipes: true,
      },
    },
  },
});
```

```json
{
  "_count": {
    "posts": 3,
    "recipes": 9
  }
}
```

#### Filter the relation count [#filter-the-relation-count]

Use `where` to filter the fields returned by the `_count` output type. You can do this on [scalar fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#scalar-fields) and [relation fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#relation-fields).

For example, the following query returns all user posts with the title "Hello!":

```ts
// Count all user posts with the title "Hello!"
await prisma.user.findMany({
  select: {
    _count: {
      select: {
        posts: { where: { title: 'Hello!' } },
      },
    },
  },
});
```

The following query finds all user posts with comments from an author named "Alice":

```ts
// Count all user posts that have comments
// whose author is named "Alice"
await prisma.user.findMany({
  select: {
    _count: {
      select: {
        posts: {
          where: { comments: { some: { author: { is: { name: 'Alice' } } } } },
        },
      },
    },
  },
});
```

### Count non-`null` field values [#count-non-null-field-values]

In [2.15.0](https://github.com/prisma/orm/releases/2.15.0) and later, you can count all records as well as all instances of non-`null` field values. The following query returns a count of:

* All `User` records (`_all`)
* All non-`null` `name` values (not distinct values, just values that are not `null`)

```ts
const userCount = await prisma.user.count({
  select: {
    _all: true, // Count all records
    name: true, // Count all non-null field values
  },
});
```

```json
{ "_all": 30, "name": 10 }
```

### Filtered count [#filtered-count]

`count` supports filtering. The following example query counts all users with more than 100 profile views:

```ts
const userCount = await prisma.user.count({
  where: {
    profileViews: {
      gte: 100,
    },
  },
});
```

The following example query counts a particular user's posts:

```ts
const postCount = await prisma.post.count({
  where: {
    authorId: 29,
  },
});
```

## Select distinct [#select-distinct]

Prisma Client allows you to filter duplicate rows from a Prisma Query response to a [`findMany`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#findmany) query using [`distinct`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#distinct) . `distinct` is often used in combination with [`select`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#select) to identify certain unique combinations of values in the rows of your table.

The following example returns all fields for all `User` records with distinct `name` field values:

```ts
const result = await prisma.user.findMany({
  where: {},
  distinct: ['name'],
});
```

The following example returns distinct `role` field values (for example, `ADMIN` and `USER`):

```ts
const distinctRoles = await prisma.user.findMany({
  distinct: ['role'],
  select: {
    role: true,
  },
});
```

```json
[
  { role: 'USER', },
  { role: 'ADMIN', },
];
```

### `distinct` under the hood [#distinct-under-the-hood]

Prisma Client's `distinct` option does not use SQL `SELECT DISTINCT`. Instead, `distinct` uses:

* A `SELECT` query
* In-memory post-processing to select distinct

It was designed in this way in order to &#x2A;*support `select` and `include`** as part of `distinct` queries.

The following example selects distinct on `gameId` and `playerId`, ordered by `score`, in order to return **each player's highest score per game**. The query uses `include` and `select` to include additional data:

* Select `score` (field on `Play`)
* Select related player name (relation between `Play` and `User`)
* Select related game name (relation between `Play` and `Game`)

**Expand for sample schema**

```prisma title="schema.prisma"
model User {
  id   Int     @id @default(autoincrement())
  name String?
  play Play[]
}

model Game {
  id   Int     @id @default(autoincrement())
  name String?
  play Play[]
}

model Play {
  id       Int   @id @default(autoincrement())
  score    Int?  @default(0)
  playerId Int?
  player   User? @relation(fields: [playerId], references: [id])
  gameId   Int?
  game     Game? @relation(fields: [gameId], references: [id])
}
```

```ts
const distinctScores = await prisma.play.findMany({
  distinct: ['playerId', 'gameId'],
  orderBy: {
    score: 'desc',
  },
  select: {
    score: true,
    game: {
      select: {
        name: true,
      },
    },
    player: {
      select: {
        name: true,
      },
    },
  },
});
```

```json
[
  {
    "score": 900,
    "game": { "name": "Pacman" },
    "player": { "name": "Bert Bobberton" }
  },
  {
    "score": 400,
    "game": { "name": "Pacman" },
    "player": { "name": "Nellie Bobberton" }
  }
]
```

Without `select` and `distinct`, the query would return:

```json
[
  {
    "gameId": 2,
    "playerId": 5
  },
  {
    "gameId": 2,
    "playerId": 10
  }
]
```

## Related pages

- [`CRUD`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud): Learn how to perform create, read, update, and delete operations
- [`Excluding fields`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/excluding-fields): Learn how to exclude fields from Prisma Client results with the omit option.
- [`Filtering and sorting`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting): Learn how to filter Prisma Client queries with where and sort results with orderBy.
- [`Full-text search`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search): Learn how to search text fields with Prisma Client using your database's native full-text search support.
- [`Pagination`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/pagination): Learn how to paginate Prisma Client query results with offset pagination and cursor-based pagination.

# CRUD (Prisma ORM v7) (/docs/orm/v7/prisma-client/queries/crud)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to perform create, read, update, and delete operations

Location: ORM > v7 > Prisma Client > Queries > CRUD

This page describes how to perform CRUD operations with Prisma Client:

* [Create](#create) - Insert records
* [Read](#read) - Query records
* [Update](#update) - Modify records
* [Delete](#delete) - Remove records

See the [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference) for detailed method documentation.

## Create [#create]

### Create a single record [#create-a-single-record]

```ts
const user = await prisma.user.create({
  data: {
    email: "elsa@prisma.io",
    name: "Elsa Prisma",
  },
});
```

## Where to go next [#where-to-go-next]

* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference) if you need the full method and option surface
* [Relation queries](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) if your CRUD workflow needs nested writes or relational reads
* [Prisma Migrate getting started](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started) if you're still evolving the database schema behind these queries
* [Quickstart with Prisma Postgres](https://www.prisma.io/docs/v7/prisma-orm/quickstart/prisma-postgres) if you want a managed database to try these examples against quickly

The `id` is auto-generated. Your schema determines which fields are mandatory.

### Create multiple records [#create-multiple-records]

```ts
const createMany = await prisma.user.createMany({
  data: [
    { name: "Bob", email: "bob@prisma.io" },
    { name: "Yewande", email: "yewande@prisma.io" },
  ],
  skipDuplicates: true, // Skip records with duplicate unique fields
});
// Returns: { count: 2 }
```

> [!NOTE]
> `skipDuplicates` is not supported on MongoDB, SQLServer, or SQLite.

### Create and return multiple records [#create-and-return-multiple-records]

Supported by PostgreSQL, CockroachDB, and SQLite.

```ts
const users = await prisma.user.createManyAndReturn({
  data: [
    { name: "Alice", email: "alice@prisma.io" },
    { name: "Bob", email: "bob@prisma.io" },
  ],
});
```

See [Nested writes](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-writes) for creating records with relations.

## Read [#read]

### Get record by ID or unique field [#get-record-by-id-or-unique-field]

```ts
// By unique field
const user = await prisma.user.findUnique({
  where: { email: "elsa@prisma.io" },
});

// By ID
const user = await prisma.user.findUnique({
  where: { id: 99 },
});
```

### Get all records [#get-all-records]

```ts
const users = await prisma.user.findMany();
```

### Get first matching record [#get-first-matching-record]

```ts
const user = await prisma.user.findFirst({
  where: { posts: { some: { likes: { gt: 100 } } } },
  orderBy: { id: "desc" },
});
```

### Filter records [#filter-records]

```ts
// Single field filter
const users = await prisma.user.findMany({
  where: { email: { endsWith: "prisma.io" } },
});

// Multiple conditions with OR/AND
const users = await prisma.user.findMany({
  where: {
    OR: [{ name: { startsWith: "E" } }, { AND: { profileViews: { gt: 0 }, role: "ADMIN" } }],
  },
});

// Filter by related records
const users = await prisma.user.findMany({
  where: {
    email: { endsWith: "prisma.io" },
    posts: { some: { published: false } },
  },
});
```

See [Filtering and sorting](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting) for more examples.

### Select fields [#select-fields]

```ts
const user = await prisma.user.findUnique({
  where: { email: "emma@prisma.io" },
  select: { email: true, name: true },
});
// Returns: { email: 'emma@prisma.io', name: "Emma" }
```

### Include related records [#include-related-records]

```ts
const users = await prisma.user.findMany({
  where: { role: "ADMIN" },
  include: { posts: true },
});
```

See [Select fields](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields) and [Relation queries](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) for more.

## Update [#update]

### Update a single record [#update-a-single-record]

```ts
const updateUser = await prisma.user.update({
  where: { email: "viola@prisma.io" },
  data: { name: "Viola the Magnificent" },
});
```

### Update multiple records [#update-multiple-records]

```ts
const updateUsers = await prisma.user.updateMany({
  where: { email: { contains: "prisma.io" } },
  data: { role: "ADMIN" },
});
// Returns: { count: 19 }
```

### Update and return multiple records [#update-and-return-multiple-records]

Supported by PostgreSQL, CockroachDB, and SQLite.

```ts
const users = await prisma.user.updateManyAndReturn({
  where: { email: { contains: "prisma.io" } },
  data: { role: "ADMIN" },
});
```

### Upsert (update or create) [#upsert-update-or-create]

```ts
const upsertUser = await prisma.user.upsert({
  where: { email: "viola@prisma.io" },
  update: { name: "Viola the Magnificent" },
  create: { email: "viola@prisma.io", name: "Viola the Magnificent" },
});
```

> [!NOTE]
> To emulate `findOrCreate()`, use `upsert()` with an empty `update` parameter.

### Atomic number operations [#atomic-number-operations]

```ts
await prisma.post.updateMany({
  data: {
    views: { increment: 1 },
    likes: { increment: 1 },
  },
});
```

See [Relation queries](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries) for connecting and disconnecting related records.

## Delete [#delete]

### Delete a single record [#delete-a-single-record]

The following query uses [`delete()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#delete) to delete a single `User` record:

```ts
const deleteUser = await prisma.user.delete({
  where: {
    email: "bert@prisma.io",
  },
});
```

Attempting to delete a user with one or more posts result in an error, as every `Post` requires an author - see [cascading deletes](#cascading-deletes-deleting-related-records).

### Delete multiple records [#delete-multiple-records]

The following query uses [`deleteMany()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#deletemany) to delete all `User` records where `email` contains `prisma.io`:

```ts
const deleteUsers = await prisma.user.deleteMany({
  where: {
    email: {
      contains: "prisma.io",
    },
  },
});
```

Attempting to delete a user with one or more posts result in an error, as every `Post` requires an author - see [cascading deletes](#cascading-deletes-deleting-related-records).

### Delete all records [#delete-all-records]

The following query uses [`deleteMany()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#deletemany) to delete all `User` records:

```ts
const deleteUsers = await prisma.user.deleteMany({});
```

Be aware that this query will fail if the user has any related records (such as posts). In this case, you need to [delete the related records first](#cascading-deletes-deleting-related-records).

### Cascading deletes (deleting related records) [#cascading-deletes-deleting-related-records]

> [!NOTE]
> You can configure cascading deletes using [referential actions](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions).

The following query uses [`delete()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#delete) to delete a single `User` record:

```ts
const deleteUser = await prisma.user.delete({
  where: {
    email: "bert@prisma.io",
  },
});
```

However, the example schema includes a **required relation** between `Post` and `User`, which means that you cannot delete a user with posts:

```
The change you are trying to make would violate the required relation 'PostToUser' between the `Post` and `User` models.
```

To resolve this error, you can:

* Make the relation optional:

  ```prisma highlight=3,4;add|5,6;delete
  model Post {
    id       Int   @id @default(autoincrement())
    author   User? @relation(fields: [authorId], references: [id]) // [!code ++]
    authorId Int? // [!code ++]
    author   User  @relation(fields: [authorId], references: [id]) // [!code --]
    authorId Int // [!code --]
  }
  ```

* Change the author of the posts to another user before deleting the user.

* Delete a user and all their posts with two separate queries in a transaction (all queries must succeed):

  ```ts
  const deletePosts = prisma.post.deleteMany({
    where: {
      authorId: 7,
    },
  });

  const deleteUser = prisma.user.delete({
    where: {
      id: 7,
    },
  });

  const transaction = await prisma.$transaction([deletePosts, deleteUser]);
  ```

### Delete all records from all tables [#delete-all-records-from-all-tables]

Sometimes you want to remove all data from all tables but keep the actual tables. This can be particularly useful in a development environment and whilst testing.

The following shows how to delete all records from all tables with Prisma Client and with Prisma Migrate.

#### Deleting all data with `deleteMany()` [#deleting-all-data-with-deletemany]

When you know the order in which your tables should be deleted, you can use the [`deleteMany`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#deletemany) function. This is executed synchronously in a [`$transaction`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions) and can be used with all types of databases.

```ts
const deletePosts = prisma.post.deleteMany();
const deleteProfile = prisma.profile.deleteMany();
const deleteUsers = prisma.user.deleteMany();

// The transaction runs synchronously so deleteUsers must run last.
await prisma.$transaction([deleteProfile, deletePosts, deleteUsers]);
```

✅ **Pros**:

* Works well when you know the structure of your schema ahead of time
* Synchronously deletes each tables data

❌ **Cons**:

* When working with relational databases, this function doesn't scale as well as having a more generic solution which looks up and `TRUNCATE`s your tables regardless of their relational constraints. Note that this scaling issue does not apply when using the MongoDB connector.

> **Note**: The `$transaction` performs a cascading delete on each models table so they have to be called in order.

#### Deleting all data with raw SQL / `TRUNCATE` [#deleting-all-data-with-raw-sql--truncate]

If you are comfortable working with raw SQL, you can perform a `TRUNCATE` query on a table using [`$executeRawUnsafe`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#executerawunsafe).

In the following examples, the first tab shows how to perform a `TRUNCATE` on a Postgres database by using a `$queryRaw` look up that maps over the table and `TRUNCATES` all tables in a single query.

The second tab shows performing the same function but with a MySQL database. In this instance the constraints must be removed before the `TRUNCATE` can be executed, before being reinstated once finished. The whole process is run as a `$transaction`

  

#### PostgreSQL

```ts
const tablenames = await prisma.$queryRaw<
  Array<{ tablename: string }>
>`SELECT tablename FROM pg_tables WHERE schemaname='public'`;

const tables = tablenames
  .map(({ tablename }) => tablename)
  .filter((name) => name !== "_prisma_migrations")
  .map((name) => `"public"."${name}"`)
  .join(", ");

try {
  await prisma.$executeRawUnsafe(`TRUNCATE TABLE ${tables} CASCADE;`);
} catch (error) {
  console.log({ error });
}
```

#### MySQL

```ts
const transactions: PrismaPromise<any>[] = [];
transactions.push(prisma.$executeRaw`SET FOREIGN_KEY_CHECKS = 0;`);

const tablenames = await prisma.$queryRaw<
  Array<{ TABLE_NAME: string }>
>`SELECT TABLE_NAME from information_schema.TABLES WHERE TABLE_SCHEMA = 'tests';`;

for (const { TABLE_NAME } of tablenames) {
  if (TABLE_NAME !== "_prisma_migrations") {
    try {
      transactions.push(prisma.$executeRawUnsafe(`TRUNCATE ${TABLE_NAME};`));
    } catch (error) {
      console.log({ error });
    }
  }
}

transactions.push(prisma.$executeRaw`SET FOREIGN_KEY_CHECKS = 1;`);

try {
  await prisma.$transaction(transactions);
} catch (error) {
  console.log({ error });
}
```

✅ **Pros**:

* Scalable
* Very fast

❌ **Cons**:

* Can't undo the operation
* Using reserved SQL key words as tables names can cause issues when trying to run a raw query

#### Deleting all records with Prisma Migrate [#deleting-all-records-with-prisma-migrate]

If you use Prisma Migrate, you can use `migrate reset`, this will:

1. Drop the database
2. Create a new database
3. Apply migrations
4. Seed the database with data

## Advanced query examples [#advanced-query-examples]

### Create a deeply nested tree of records [#create-a-deeply-nested-tree-of-records]

* A single `User`
* Two new, related `Post` records
* Connect or create `Category` per post

```ts
const u = await prisma.user.create({
  include: {
    posts: {
      include: {
        categories: true,
      },
    },
  },
  data: {
    email: "emma@prisma.io",
    posts: {
      create: [
        {
          title: "My first post",
          categories: {
            connectOrCreate: [
              {
                create: { name: "Introductions" },
                where: {
                  name: "Introductions",
                },
              },
              {
                create: { name: "Social" },
                where: {
                  name: "Social",
                },
              },
            ],
          },
        },
        {
          title: "How to make cookies",
          categories: {
            connectOrCreate: [
              {
                create: { name: "Social" },
                where: {
                  name: "Social",
                },
              },
              {
                create: { name: "Cooking" },
                where: {
                  name: "Cooking",
                },
              },
            ],
          },
        },
      ],
    },
  },
});
```

## Related pages

- [`Aggregation, grouping, and summarizing`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing): Use Prisma Client to aggregate, group by, count, and select distinct.
- [`Excluding fields`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/excluding-fields): Learn how to exclude fields from Prisma Client results with the omit option.
- [`Filtering and sorting`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting): Learn how to filter Prisma Client queries with where and sort results with orderBy.
- [`Full-text search`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search): Learn how to search text fields with Prisma Client using your database's native full-text search support.
- [`Pagination`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/pagination): Learn how to paginate Prisma Client query results with offset pagination and cursor-based pagination.

# Excluding fields (Prisma ORM v7) (/docs/orm/v7/prisma-client/queries/excluding-fields)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to exclude fields from Prisma Client results with the omit option.

Location: ORM > v7 > Prisma Client > Queries > Excluding fields

Use `omit` when you want Prisma Client to return the normal result shape except for a few specific fields.

## Omit a field for one query [#omit-a-field-for-one-query]

```ts
const user = await prisma.user.findUnique({
  where: { id: 1 },
  omit: {
    password: true,
  },
});
```

## Omit fields globally [#omit-fields-globally]

You can also configure `omit` on the client itself:

```ts
const prisma = new PrismaClient({
  omit: {
    user: {
      password: true,
    },
  },
});
```

## When to use omit vs select [#when-to-use-omit-vs-select]

* Use [`select`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields) when you want to return only a small subset of fields.
* Use `omit` when the default result is mostly correct and you only want to remove a few sensitive or noisy fields.

## Related pages [#related-pages]

* [Select fields](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields)
* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#omit)

## Related pages

- [`Aggregation, grouping, and summarizing`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing): Use Prisma Client to aggregate, group by, count, and select distinct.
- [`CRUD`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud): Learn how to perform create, read, update, and delete operations
- [`Filtering and sorting`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting): Learn how to filter Prisma Client queries with where and sort results with orderBy.
- [`Full-text search`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search): Learn how to search text fields with Prisma Client using your database's native full-text search support.
- [`Pagination`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/pagination): Learn how to paginate Prisma Client query results with offset pagination and cursor-based pagination.

# Filtering and sorting (Prisma ORM v7) (/docs/orm/v7/prisma-client/queries/filtering-and-sorting)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to filter Prisma Client queries with where and sort results with orderBy.

Location: ORM > v7 > Prisma Client > Queries > Filtering and sorting

Prisma Client lets you narrow results with `where` and order them with `orderBy`.

## Filtering with where [#filtering-with-where]

Use `where` to match records by field values:

```ts
const users = await prisma.user.findMany({
  where: {
    email: {
      endsWith: "prisma.io",
    },
  },
});
```

## Combining operators [#combining-operators]

You can compose filters with operators such as `OR`, `AND`, and `NOT`:

```ts
const users = await prisma.user.findMany({
  where: {
    OR: [
      { email: { endsWith: "gmail.com" } },
      { email: { endsWith: "company.com" } },
    ],
    NOT: {
      email: {
        endsWith: "admin.company.com",
      },
    },
  },
});
```

## Filter on related records [#filter-on-related-records]

Relation filters let you match records based on related data:

```ts
const users = await prisma.user.findMany({
  where: {
    posts: {
      some: {
        published: true,
      },
    },
  },
});
```

For more relation-specific patterns, see [Relation queries](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries).

## Sort results with orderBy [#sort-results-with-orderby]

Use `orderBy` to control result ordering:

```ts
const posts = await prisma.post.findMany({
  orderBy: {
    title: "asc",
  },
});
```

You can also combine filtering and sorting:

```ts
const posts = await prisma.post.findMany({
  where: {
    published: true,
  },
  orderBy: {
    createdAt: "desc",
  },
});
```

## Case-insensitive filtering [#case-insensitive-filtering]

Case sensitivity depends on your database provider and collation settings. For PostgreSQL, Prisma Client also supports specific case-insensitive filter modes on supported operators. See the [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#mode) for details.

## Sort by relation [#sort-by-relation]

You can sort by properties on related records when the query shape supports it. For example, you might order posts by their author's name or users by related aggregates.

## Sort by relevance (PostgreSQL and MySQL) [#sort-by-relevance-postgresql-and-mysql]

On supported databases, Prisma Client can sort search results by relevance using `_relevance`. This is especially useful when combined with [full-text search](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search).

## Sort with null records first or last [#sort-with-null-records-first-or-last]

Prisma Client supports explicit null ordering on supported databases so you can keep incomplete values grouped at the beginning or end of a result set.

## Related pages [#related-pages]

* [Pagination](https://www.prisma.io/docs/orm/v7/prisma-client/queries/pagination)
* [Select fields](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields)
* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#filter-conditions-and-operators)

## Related pages

- [`Aggregation, grouping, and summarizing`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing): Use Prisma Client to aggregate, group by, count, and select distinct.
- [`CRUD`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud): Learn how to perform create, read, update, and delete operations
- [`Excluding fields`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/excluding-fields): Learn how to exclude fields from Prisma Client results with the omit option.
- [`Full-text search`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search): Learn how to search text fields with Prisma Client using your database's native full-text search support.
- [`Pagination`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/pagination): Learn how to paginate Prisma Client query results with offset pagination and cursor-based pagination.

# Full-text search (Prisma ORM v7) (/docs/orm/v7/prisma-client/queries/full-text-search)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to search text fields with Prisma Client using your database's native full-text search support.

Location: ORM > v7 > Prisma Client > Queries > Full-text search

Prisma Client supports full-text search for MySQL and for PostgreSQL with the `fullTextSearchPostgres` preview feature.

## Enabling full-text search for PostgreSQL [#enabling-full-text-search-for-postgresql]

Add the preview flag to your generator and re-generate Prisma Client:

```prisma title="schema.prisma"
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["fullTextSearchPostgres"]
}
```

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## Search within a text field [#search-within-a-text-field]

```ts
const posts = await prisma.post.findMany({
  where: {
    body: {
      search: "cat | dog",
    },
  },
});
```

## Sort by relevance [#sort-by-relevance]

Prisma Client also supports relevance-based ordering on supported databases:

```ts
const posts = await prisma.post.findMany({
  orderBy: {
    _relevance: {
      fields: ["title"],
      search: "database",
      sort: "desc",
    },
  },
});
```

## Related pages [#related-pages]

* [Filtering and sorting](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting)
* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#search)
* [Preview features](https://www.prisma.io/docs/orm/v7/reference/preview-features/client-preview-features)

## Related pages

- [`Aggregation, grouping, and summarizing`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing): Use Prisma Client to aggregate, group by, count, and select distinct.
- [`CRUD`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud): Learn how to perform create, read, update, and delete operations
- [`Excluding fields`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/excluding-fields): Learn how to exclude fields from Prisma Client results with the omit option.
- [`Filtering and sorting`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting): Learn how to filter Prisma Client queries with where and sort results with orderBy.
- [`Pagination`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/pagination): Learn how to paginate Prisma Client query results with offset pagination and cursor-based pagination.

# Pagination (Prisma ORM v7) (/docs/orm/v7/prisma-client/queries/pagination)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to paginate Prisma Client query results with offset pagination and cursor-based pagination.

Location: ORM > v7 > Prisma Client > Queries > Pagination

Prisma Client supports both offset pagination and cursor-based pagination.

## Offset pagination [#offset-pagination]

Use `skip` and `take` when you need page numbers or shallow navigation through a result set:

```ts
const posts = await prisma.post.findMany({
  skip: 20,
  take: 10,
});
```

Offset pagination is straightforward, but it becomes more expensive as the offset grows.

## Cursor-based pagination [#cursor-based-pagination]

Use `cursor` and `take` when you want stable, scalable pagination for feeds, timelines, or large datasets:

```ts
const firstPage = await prisma.post.findMany({
  take: 10,
  orderBy: {
    id: "asc",
  },
});

const lastPost = firstPage[firstPage.length - 1];

const nextPage = lastPost
  ? await prisma.post.findMany({
      take: 10,
      skip: 1,
      cursor: {
        id: lastPost.id,
      },
      orderBy: {
        id: "asc",
      },
    })
  : [];
```

## Which approach to choose [#which-approach-to-choose]

* Use offset pagination when users need to jump directly to a numbered page.
* Use cursor-based pagination when you care more about performance and consistency as the dataset grows.

## Related pages [#related-pages]

* [Filtering and sorting](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting)
* [Query Insights](https://www.prisma.io/docs/query-insights)
* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference)

## Related pages

- [`Aggregation, grouping, and summarizing`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing): Use Prisma Client to aggregate, group by, count, and select distinct.
- [`CRUD`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud): Learn how to perform create, read, update, and delete operations
- [`Excluding fields`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/excluding-fields): Learn how to exclude fields from Prisma Client results with the omit option.
- [`Filtering and sorting`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting): Learn how to filter Prisma Client queries with where and sort results with orderBy.
- [`Full-text search`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search): Learn how to search text fields with Prisma Client using your database's native full-text search support.

# Relation queries (Prisma ORM v7) (/docs/orm/v7/prisma-client/queries/relation-queries)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma Client provides convenient queries for working with relations, such as a fluent API, nested writes (transactions), nested reads and relation filters

Location: ORM > v7 > Prisma Client > Queries > Relation queries

A key feature of Prisma Client is the ability to query [relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations) between two or more models. Relation queries include:

* [Nested reads](#nested-reads) (sometimes referred to as *eager loading*) via [`select`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#select) and [`include`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#include)
* [Nested writes](#nested-writes) with [transactional](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions) guarantees
* [Filtering on related records](#relation-filters)

Prisma Client also has a [fluent API for traversing relations](#fluent-api).

## Nested reads [#nested-reads]

Nested reads allow you to read related data from multiple tables in your database - such as a user and that user's posts. You can:

* Use [`include`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#include) to include related records, such as a user's posts or profile, in the query response.
* Use a nested [`select`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#select) to include specific fields from a related record. You can also nest `select` inside an `include`.

### Relation load strategies (Preview) [#relation-load-strategies-preview]

You can decide on a per-query-level *how* you want Prisma Client to execute a relation query (i.e. what *load strategy* should be applied) via the `relationLoadStrategy` option for PostgreSQL databases.

Because the `relationLoadStrategy` option is currently in Preview, you need to enable it via the `relationJoins` preview feature flag in your Prisma schema file:

```prisma title="schema.prisma" showLineNumbers
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["relationJoins"]
}
```

After adding this flag, you need to run `prisma generate` again to re-generate Prisma Client. The `relationJoins` feature is currently available on PostgreSQL, CockroachDB and MySQL.

Prisma Client supports two load strategies for relations:

* `join` (default): Uses a database-level `LATERAL JOIN` (PostgreSQL) or correlated subqueries (MySQL) and fetches all data with a single query to the database.
* `query`: Sends multiple queries to the database (one per table) and joins them on the application level.

Another important difference between these two options is that the `join` strategy uses JSON aggregation on the database level. That means that it creates the JSON structures returned by Prisma Client already in the database which saves computation resources on the application level.

#### Examples [#examples]

You can use the `relationLoadStrategy` option on the top-level in any query that supports `include` or `select`.

Here is an example with `include`:

```ts
const users = await prisma.user.findMany({
  relationLoadStrategy: "join", // or 'query'
  include: {
    posts: true,
  },
});
```

And here is another example with `select`:

```ts
const users = await prisma.user.findMany({
  relationLoadStrategy: "join", // or 'query'
  select: {
    posts: true,
  },
});
```

#### When to use each load strategy [#when-to-use-each-load-strategy]

* The `join` strategy (default) will be more effective in most scenarios. On PostgreSQL, it uses a combination of `LATERAL JOINs` and JSON aggregation to reduce redundancy in result sets and delegate the work of transforming the query results into the expected JSON structures on the database server. On MySQL, it uses correlated subqueries to fetch the results with a single query.
* There may be edge cases where `query` could be more performant depending on the characteristics of the dataset and query. We recommend that you profile your database queries to identify these situations.
* Use `query` if you want to save resources on the database server and do heavy-lifting of merging and transforming data in the application server which might be easier to scale.

### Include a relation [#include-a-relation]

The following example returns a single user and that user's posts:

```ts
const user = await prisma.user.findFirst({
  include: {
    posts: true,
  },
});
```

```json
{
  id: 19,
  name: null,
  email: 'emma@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: [],
  posts: [
    {
      id: 20,
      title: 'My first post',
      published: true,
      authorId: 19,
      comments: null,
      views: 0,
      likes: 0
    },
    {
      id: 21,
      title: 'How to make cookies',
      published: true,
      authorId: 19,
      comments: null,
      views: 0,
      likes: 0
    }
  ]
}
```

### Include all fields for a specific relation [#include-all-fields-for-a-specific-relation]

The following example returns a post and its author:

```ts
const post = await prisma.post.findFirst({
  include: {
    author: true,
  },
});
```

```json
{
  id: 17,
  title: 'How to make cookies',
  published: true,
  authorId: 16,
  comments: null,
  views: 0,
  likes: 0,
  author: {
    id: 16,
    name: null,
    email: 'orla@prisma.io',
    profileViews: 0,
    role: 'USER',
    coinflips: [],
  },
}
```

### Include deeply nested relations [#include-deeply-nested-relations]

You can nest `include` options to include relations of relations. The following example returns a user's posts, and each post's categories:

```ts
const user = await prisma.user.findFirst({
  include: {
    posts: {
      include: {
        categories: true,
      },
    },
  },
});
```

```json
{
    "id": 40,
    "name": "Yvette",
    "email": "yvette@prisma.io",
    "profileViews": 0,
    "role": "USER",
    "coinflips": [],
    "testing": [],
    "city": null,
    "country": "Sweden",
    "posts": [
        {
            "id": 66,
            "title": "How to make an omelette",
            "published": true,
            "authorId": 40,
            "comments": null,
            "views": 0,
            "likes": 0,
            "categories": [
                {
                    "id": 3,
                    "name": "Easy cooking"
                }
            ]
        },
        {
            "id": 67,
            "title": "How to eat an omelette",
            "published": true,
            "authorId": 40,
            "comments": null,
            "views": 0,
            "likes": 0,
            "categories": []
        }
    ]
}
```

### Select specific fields of included relations [#select-specific-fields-of-included-relations]

You can use a nested `select` to choose a subset of fields of relations to return. For example, the following query returns the user's `name` and the `title` of each related post:

```ts
const user = await prisma.user.findFirst({
  select: {
    name: true,
    posts: {
      select: {
        title: true,
      },
    },
  },
});
```

```json
{
  name: "Elsa",
  posts: [ { title: 'My first post' }, { title: 'How to make cookies' } ]
}
```

You can also nest a `select` inside an `include` - the following example returns *all* `User` fields and the `title` field of each post:

```ts
const user = await prisma.user.findFirst({
  include: {
    posts: {
      select: {
        title: true,
      },
    },
  },
});
```

```json
{
  "id": 1,
  "name": null,
  "email": "martina@prisma.io",
  "profileViews": 0,
  "role": "USER",
  "coinflips": [],
  "posts": [
    { "title": "How to grow salad" },
    { "title": "How to ride a horse" }
  ]
}
```

Note that you **cannot** use `select` and `include` *on the same level*. This means that if you choose to `include` a user's post and `select` each post's title, you cannot `select` only the users' `email`:

```ts
// The following query returns an exception
const user = await prisma.user.findFirst({
  select: { // This won't work! // [!code --]
    email:  true
  }
  include: { // This won't work! // [!code --]
    posts: {
      select: {
        title: true
      }
    }
  },
})
```

```text no-copy
Invalid `prisma.user.findUnique()` invocation:

{
  where: {
    id: 19
  },
  select: {
  ~~~~~~
    email: true
  },
  include: {
  ~~~~~~~
    posts: {
      select: {
        title: true
      }
    }
  }
}

Please either use `include` or `select`, but not both at the same time.
```

Instead, use nested `select` options:

```ts
const user = await prisma.user.findFirst({
  select: {
    // This will work!
    email: true,
    posts: {
      select: {
        title: true,
      },
    },
  },
});
```

## Relation count [#relation-count]

In [3.0.1](https://github.com/prisma/orm/releases/3.0.1) and later, you can [`include` or `select` a count of relations](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#count-relations) alongside fields - for example, a user's post count.

```ts
const relationCount = await prisma.user.findMany({
  include: {
    _count: {
      select: { posts: true },
    },
  },
});
```

```text no-copy
{ id: 1, _count: { posts: 3 } },
{ id: 2, _count: { posts: 2 } },
{ id: 3, _count: { posts: 2 } },
{ id: 4, _count: { posts: 0 } },
{ id: 5, _count: { posts: 0 } }
```

## Filter a list of relations [#filter-a-list-of-relations]

When you use `select` or `include` to return a subset of the related data, you can **filter and sort the list of relations** inside the `select` or `include`.

For example, the following query returns list of titles of the unpublished posts associated with the user:

```ts
const result = await prisma.user.findFirst({
  select: {
    posts: {
      where: {
        published: false,
      },
      orderBy: {
        title: "asc",
      },
      select: {
        title: true,
      },
    },
  },
});
```

You can also write the same query using `include` as follows:

```ts
const result = await prisma.user.findFirst({
  include: {
    posts: {
      where: {
        published: false,
      },
      orderBy: {
        title: "asc",
      },
    },
  },
});
```

## Nested writes [#nested-writes]

A nested write allows you to write **relational data** to your database in **a single transaction**.

Nested writes:

* Provide **transactional guarantees** for creating, updating or deleting data across multiple tables in a single Prisma Client query. If any part of the query fails (for example, creating a user succeeds but creating posts fails), Prisma Client rolls back all changes.
* Support any level of nesting supported by the data model.
* Are available for [relation fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields) when using the model's create or update query. The following section shows the nested write options that are available per query.

### Create a related record [#create-a-related-record]

You can create a record and one or more related records at the same time. The following query creates a `User` record and two related `Post` records:

```ts
const result = await prisma.user.create({
  data: {
    email: "elsa@prisma.io",
    name: "Elsa Prisma",
    posts: {
      // [!code highlight]
      create: [{ title: "How to make an omelette" }, { title: "How to eat an omelette" }], // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true, // Include all posts in the returned object
  },
});
```

```json
{
  id: 29,
  name: 'Elsa',
  email: 'elsa@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: [],
  posts: [
    {
      id: 22,
      title: 'How to make an omelette',
      published: true,
      authorId: 29,
      comments: null,
      views: 0,
      likes: 0
    },
    {
      id: 23,
      title: 'How to eat an omelette',
      published: true,
      authorId: 29,
      comments: null,
      views: 0,
      likes: 0
    }
  ]
}
```

### Create a single record and multiple related records [#create-a-single-record-and-multiple-related-records]

There are two ways to create or update a single record and multiple related records - for example, a user with multiple posts:

* Use a nested [`create`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#create) query
* Use a nested [`createMany`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#nested-createmany-options) query

In most cases, a nested `create` will be preferable unless the [`skipDuplicates` query option](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#nested-createmany-options) is required. Here's a quick table describing the differences between the two options:

| Feature                               | `create` | `createMany` | Notes                                                                                                                                                                                           |
| :------------------------------------ | :------- | :----------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Supports nesting additional relations | ✔        | ✘ \*         | For example, you can create a user, several posts, and several comments per post in one query.<br />\* You can manually set a foreign key in a has-one relation - for example: `{ authorId: 9}` |
| Supports 1-n relations                | ✔        | ✔            | For example, you can create a user and multiple posts (one user has many posts)                                                                                                                 |
| Supports m-n relations                | ✔        | ✘            | For example, you can create a post and several categories (one post can have many categories, and one category can have many posts)                                                             |
| Supports skipping duplicate records   | ✘        | ✔            | Use `skipDuplicates` query option.                                                                                                                                                              |

#### Using nested `create` [#using-nested-create]

The following query uses nested [`create`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#create) to create:

* One user
* Two posts
* One post category

The example also uses a nested `include` to include all posts and post categories in the returned data.

```ts
const result = await prisma.user.create({
  data: {
    email: "yvette@prisma.io",
    name: "Yvette",
    posts: {
      // [!code highlight]
      create: [
        // [!code highlight]
        {
          // [!code highlight]
          title: "How to make an omelette", // [!code highlight]
          categories: {
            // [!code highlight]
            create: {
              // [!code highlight]
              name: "Easy cooking", // [!code highlight]
            }, // [!code highlight]
          }, // [!code highlight]
        }, // [!code highlight]
        { title: "How to eat an omelette" }, // [!code highlight]
      ], // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    // Include posts
    posts: {
      include: {
        categories: true, // Include post categories
      },
    },
  },
});
```

```json
{
    "id": 40,
    "name": "Yvette",
    "email": "yvette@prisma.io",
    "profileViews": 0,
    "role": "USER",
    "coinflips": [],
    "testing": [],
    "city": null,
    "country": "Sweden",
    "posts": [
        {
            "id": 66,
            "title": "How to make an omelette",
            "published": true,
            "authorId": 40,
            "comments": null,
            "views": 0,
            "likes": 0,
            "categories": [
                {
                    "id": 3,
                    "name": "Easy cooking"
                }
            ]
        },
        {
            "id": 67,
            "title": "How to eat an omelette",
            "published": true,
            "authorId": 40,
            "comments": null,
            "views": 0,
            "likes": 0,
            "categories": []
        }
    ]
}
```

Here's a visual representation of how a nested create operation can write to several tables in the database as once:

![Diagram showing how a nested create operation writes to multiple database tables (User, Post, Category) in a single transaction.](https://www.prisma.io/img/orm/nested-create.png)

#### Using nested `createMany` [#using-nested-createmany]

The following query uses a nested [`createMany`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#createmany) to create:

* One user
* Two posts

The example also uses a nested `include` to include all posts in the returned data.

```ts
const result = await prisma.user.create({
  data: {
    email: "saanvi@prisma.io",
    posts: {
      // [!code highlight]
      createMany: {
        // [!code highlight]
        data: [{ title: "My first post" }, { title: "My second post" }], // [!code highlight]
      }, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

```json
{
    "id": 43,
    "name": null,
    "email": "saanvi@prisma.io",
    "profileViews": 0,
    "role": "USER",
    "coinflips": [],
    "testing": [],
    "city": null,
    "country": "India",
    "posts": [
        {
            "id": 70,
            "title": "My first post",
            "published": true,
            "authorId": 43,
            "comments": null,
            "views": 0,
            "likes": 0
        },
        {
            "id": 71,
            "title": "My second post",
            "published": true,
            "authorId": 43,
            "comments": null,
            "views": 0,
            "likes": 0
        }
    ]
}
```

Note that it is **not possible** to nest an additional `create` or `createMany` inside the highlighted query, which means that you cannot create a user, posts, and post categories at the same time.

As a workaround, you can send a query to create the records that will be connected first, and then create the actual records. For example:

```ts
const categories = await prisma.category.createManyAndReturn({
  data: [{ name: "Fun" }, { name: "Technology" }, { name: "Sports" }],
  select: {
    id: true,
  },
});

const posts = await prisma.post.createManyAndReturn({
  data: [
    {
      title: "Funniest moments in 2024",
      categoryId: categories.find((category) => category.name === "Fun")!.id,
    },
    {
      title: "Linux or macOS — what's better?",
      categoryId: categories.find((category) => category.name === "Technology")!.id,
    },
    {
      title: "Who will win the next soccer championship?",
      categoryId: categories.find((category) => category.name === "Sports")!.id,
    },
  ],
});
```

If you want to create *all* records in a single database query, consider using a [`$transaction`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#the-transaction-api) or [type-safe, raw SQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql).

### Create multiple records and multiple related records [#create-multiple-records-and-multiple-related-records]

You cannot access relations in a `createMany()` or `createManyAndReturn()` query, which means that you cannot create multiple users and multiple posts in a single nested write. The following is **not** possible:

```ts
const createMany = await prisma.user.createMany({
  data: [
    {
      name: "Yewande",
      email: "yewande@prisma.io",
      posts: {
        // [!code --]
        // Not possible to create posts! // [!code --]
      }, // [!code --]
    },
    {
      name: "Noor",
      email: "noor@prisma.io",
      posts: {
        // [!code --]
        // Not possible to create posts! // [!code --]
      }, // [!code --]
    },
  ],
});
```

### Connect multiple records [#connect-multiple-records]

The following query creates ([`create`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#create) ) a new `User` record and connects that record ([`connect`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#connect) ) to three existing posts:

```ts
const result = await prisma.user.create({
  data: {
    email: "vlad@prisma.io",
    posts: {
      // [!code highlight]
      connect: [{ id: 8 }, { id: 9 }, { id: 10 }], // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true, // Include all posts in the returned object
  },
});
```

```json
{
  id: 27,
  name: null,
  email: 'vlad@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: [],
  posts: [
    {
      id: 10,
      title: 'An existing post',
      published: true,
      authorId: 27,
      comments: {},
      views: 0,
      likes: 0
    }
  ]
}
```

> [!NOTE]
> Note
> 
> Prisma Client throws an exception if any of the post records cannot be found: `connect: [{ id: 8 }, { id: 9 }, { id: 10 }]`

### Connect a single record [#connect-a-single-record]

You can [`connect`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#connect) an existing record to a new or existing user. The following query connects an existing post (`id: 11`) to an existing user (`id: 9`)

```ts
const result = await prisma.user.update({
  where: {
    id: 9,
  },
  data: {
    posts: {
      // [!code highlight]
      connect: {
        // [!code highlight]
        id: 11, // [!code highlight]
      }, // [!code highlight]
    },
  },
  include: {
    posts: true,
  },
});
```

### Connect *or* create a record [#connect-or-create-a-record]

If a related record may or may not already exist, use [`connectOrCreate`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#connectorcreate) to connect the related record:

* Connect a `User` with the email address `viola@prisma.io` *or*
* Create a new `User` with the email address `viola@prisma.io` if the user does not already exist

```ts
const result = await prisma.post.create({
  data: {
    title: "How to make croissants",
    author: {
      // [!code highlight]
      connectOrCreate: {
        // [!code highlight]
        where: {
          // [!code highlight]
          email: "viola@prisma.io", // [!code highlight]
        }, // [!code highlight]
        create: {
          // [!code highlight]
          email: "viola@prisma.io", // [!code highlight]
          name: "Viola", // [!code highlight]
        }, // [!code highlight]
      }, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    author: true,
  },
});
```

```json
{
  id: 26,
  title: 'How to make croissants',
  published: true,
  authorId: 43,
  views: 0,
  likes: 0,
  author: {
    id: 43,
    name: 'Viola',
    email: 'viola@prisma.io',
    profileViews: 0,
    role: 'USER',
    coinflips: []
  }
}
```

### Disconnect a related record [#disconnect-a-related-record]

To `disconnect` one out of a list of records (for example, a specific blog post) provide the ID or unique identifier of the record(s) to disconnect:

```ts
const result = await prisma.user.update({
  where: {
    id: 16,
  },
  data: {
    posts: {
      // [!code highlight]
      disconnect: [{ id: 12 }, { id: 19 }], // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

```json
{
  id: 16,
  name: null,
  email: 'orla@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: [],
  posts: []
}
```

To `disconnect` *one* record (for example, a post's author), use `disconnect: true`:

```ts
const result = await prisma.post.update({
  where: {
    id: 23,
  },
  data: {
    author: {
      // [!code highlight]
      disconnect: true, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    author: true,
  },
});
```

```json
{
  id: 23,
  title: 'How to eat an omelette',
  published: true,
  authorId: null,
  comments: null,
  views: 0,
  likes: 0,
  author: null
}
```

### Disconnect all related records [#disconnect-all-related-records]

To [`disconnect`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#disconnect) *all* related records in a one-to-many relation (a user has many posts), `set` the relation to an empty list as shown:

```ts
const result = await prisma.user.update({
  where: {
    id: 16,
  },
  data: {
    posts: {
      // [!code highlight]
      set: [], // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

```json
{
  id: 16,
  name: null,
  email: 'orla@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: [],
  posts: []
}
```

### Delete all related records [#delete-all-related-records]

Delete all related `Post` records:

```ts
const result = await prisma.user.update({
  where: {
    id: 11,
  },
  data: {
    posts: {
      // [!code highlight]
      deleteMany: {}, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

### Delete specific related records [#delete-specific-related-records]

Update a user by deleting all unpublished posts:

```ts
const result = await prisma.user.update({
  where: {
    id: 11,
  },
  data: {
    posts: {
      // [!code highlight]
      deleteMany: {
        // [!code highlight]
        published: false, // [!code highlight]
      }, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

Update a user by deleting specific posts:

```ts
const result = await prisma.user.update({
  where: {
    id: 6,
  },
  data: {
    posts: {
      // [!code highlight]
      deleteMany: [{ id: 7 }], // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

### Update all related records (or filter) [#update-all-related-records-or-filter]

You can use a nested `updateMany` to update *all* related records for a particular user. The following query unpublishes all posts for a specific user:

```ts
const result = await prisma.user.update({
  where: {
    id: 6,
  },
  data: {
    posts: {
      // [!code highlight]
      updateMany: {
        // [!code highlight]
        where: {
          // [!code highlight]
          published: true, // [!code highlight]
        }, // [!code highlight]
        data: {
          // [!code highlight]
          published: false, // [!code highlight]
        }, // [!code highlight]
      }, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

### Update a specific related record [#update-a-specific-related-record]

```ts
const result = await prisma.user.update({
  where: {
    id: 6,
  },
  data: {
    posts: {
      // [!code highlight]
      update: {
        // [!code highlight]
        where: {
          // [!code highlight]
          id: 9, // [!code highlight]
        }, // [!code highlight]
        data: {
          // [!code highlight]
          title: "My updated title", // [!code highlight]
        }, // [!code highlight]
      }, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

### Update *or* create a related record [#update-or-create-a-related-record]

The following query uses a nested `upsert` to update `"bob@prisma.io"` if that user exists, or create the user if they do not exist:

```ts
const result = await prisma.post.update({
  where: {
    id: 6,
  },
  data: {
    author: {
      // [!code highlight]
      upsert: {
        // [!code highlight]
        create: {
          // [!code highlight]
          email: "bob@prisma.io", // [!code highlight]
          name: "Bob the New User", // [!code highlight]
        }, // [!code highlight]
        update: {
          // [!code highlight]
          email: "bob@prisma.io", // [!code highlight]
          name: "Bob the existing user", // [!code highlight]
        }, // [!code highlight]
      }, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    author: true,
  },
});
```

### Add new related records to an existing record [#add-new-related-records-to-an-existing-record]

You can nest `create` or `createMany` inside an `update` to add new related records to an existing record. The following query adds two posts to a user with an `id` of 9:

```ts
const result = await prisma.user.update({
  where: {
    id: 9,
  },
  data: {
    posts: {
      // [!code highlight]
      createMany: {
        // [!code highlight]
        data: [{ title: "My first post" }, { title: "My second post" }], // [!code highlight]
      }, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

## Relation filters [#relation-filters]

### Filter on "-to-many" relations [#filter-on--to-many-relations]

Prisma Client provides the [`some`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#some), [`every`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#every), and [`none`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#none) options to filter records by the properties of related records on the "-to-many" side of the relation. For example, filtering users based on properties of their posts.

For example:

| Requirement                                                                       | Query option to use                 |
| --------------------------------------------------------------------------------- | ----------------------------------- |
| "I want a list of every `User` that has *at least one* unpublished `Post` record" | `some` posts are unpublished        |
| "I want a list of every `User` that has *no* unpublished `Post` records"          | `none` of the posts are unpublished |
| "I want a list of every `User` that has *only* unpublished `Post` records"        | `every` post is unpublished         |

For example, the following query returns `User` that meet the following criteria:

* No posts with more than 100 views
* All posts have less than, or equal to 50 likes

```ts
const users = await prisma.user.findMany({
  where: {
    posts: {
      // [!code highlight]
      none: {
        // [!code highlight]
        views: {
          // [!code highlight]
          gt: 100, // [!code highlight]
        }, // [!code highlight]
      }, // [!code highlight]
      every: {
        // [!code highlight]
        likes: {
          // [!code highlight]
          lte: 50, // [!code highlight]
        }, // [!code highlight]
      }, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

### Filter on "-to-one" relations [#filter-on--to-one-relations]

Prisma Client provides the [`is`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#is) and [`isNot`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#isnot) options to filter records by the properties of related records on the "-to-one" side of the relation. For example, filtering posts based on properties of their author.

For example, the following query returns `Post` records that meet the following criteria:

* Author's name is not Bob
* Author is older than 40

```ts
const users = await prisma.post.findMany({
  where: {
    author: {
      // [!code highlight]
      isNot: {
        // [!code highlight]
        name: "Bob", // [!code highlight]
      }, // [!code highlight]
      is: {
        // [!code highlight]
        age: {
          // [!code highlight]
          gt: 40, // [!code highlight]
        }, // [!code highlight]
      }, // [!code highlight]
    }, // [!code highlight]
  }, // [!code highlight]
  include: {
    author: true,
  },
});
```

### Filter on absence of "-to-many" records [#filter-on-absence-of--to-many-records]

For example, the following query uses `none` to return all users that have zero posts:

```ts
const usersWithZeroPosts = await prisma.user.findMany({
  where: {
    posts: {
      // [!code highlight]
      none: {}, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

### Filter on absence of "-to-one" relations [#filter-on-absence-of--to-one-relations]

The following query returns all posts that don't have an author relation:

```js
const postsWithNoAuthor = await prisma.post.findMany({
  where: {
    author: null, // or author: { } // [!code highlight]
  },
  include: {
    author: true,
  },
});
```

### Filter on presence of related records [#filter-on-presence-of-related-records]

The following query returns all users with at least one post:

```ts
const usersWithSomePosts = await prisma.user.findMany({
  where: {
    posts: {
      // [!code highlight]
      some: {}, // [!code highlight]
    }, // [!code highlight]
  },
  include: {
    posts: true,
  },
});
```

## Fluent API [#fluent-api]

The fluent API lets you *fluently* traverse the [relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations) of your models via function calls. Note that the *last* function call determines the return type of the entire query (the respective type annotations are added in the code snippets below to make that explicit).

This query returns all `Post` records by a specific `User`:

```ts
const postsByUser: Post[] = await prisma.user
  .findUnique({ where: { email: "alice@prisma.io" } })
  .posts();
```

This is equivalent to the following `findMany` query:

```ts
const postsByUser = await prisma.post.findMany({
  where: {
    author: {
      email: "alice@prisma.io",
    },
  },
});
```

The main difference between the queries is that the fluent API call is translated into two separate database queries while the other one only generates a single query (see this [GitHub issue](https://github.com/prisma/orm/issues/1984))

This request returns all categories by a specific post:

```ts
const categoriesOfPost: Category[] = await prisma.post
  .findUnique({ where: { id: 1 } })
  .categories();
```

Note that you can chain as many queries as you like. In this example, the chaining starts at `Profile` and goes over `User` to `Post`:

```ts
const posts: Post[] = await prisma.profile
  .findUnique({ where: { id: 1 } })
  .user()
  .posts();
```

The only requirement for chaining is that the previous function call must return only a *single object* (e.g. as returned by a `findUnique` query or a "to-one relation" like `profile.user()`).

The following query is **not possible** because `findMany` does not return a single object but a *list*:

```ts
// This query is illegal
const posts = await prisma.user.findMany().posts();
```

## Related pages

- [`Aggregation, grouping, and summarizing`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing): Use Prisma Client to aggregate, group by, count, and select distinct.
- [`CRUD`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud): Learn how to perform create, read, update, and delete operations
- [`Excluding fields`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/excluding-fields): Learn how to exclude fields from Prisma Client results with the omit option.
- [`Filtering and sorting`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting): Learn how to filter Prisma Client queries with where and sort results with orderBy.
- [`Full-text search`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search): Learn how to search text fields with Prisma Client using your database's native full-text search support.

# Select fields (Prisma ORM v7) (/docs/orm/v7/prisma-client/queries/select-fields)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to return only the fields and relations you need with select and include in Prisma Client.

Location: ORM > v7 > Prisma Client > Queries > Select fields

By default, Prisma Client returns all scalar fields for a model and no relations. Use `select` and `include` to make the result smaller, clearer, and more intentional.

## Return the default fields [#return-the-default-fields]

If you do not pass `select`, `include`, or `omit`, Prisma Client returns all scalar fields for the model and excludes relations from the result.

## Select specific fields [#select-specific-fields]

Use `select` when you only need a few scalar fields:

```ts
const user = await prisma.user.findFirst({
  select: {
    email: true,
    name: true,
  },
});
```

## Return nested objects by selecting relation fields [#return-nested-objects-by-selecting-relation-fields]

Use `include` when you want related records alongside the main result:

```ts
const user = await prisma.user.findFirst({
  include: {
    posts: true,
  },
});
```

## Nest selections [#nest-selections]

You can combine both patterns to keep relation payloads focused:

```ts
const user = await prisma.user.findFirst({
  select: {
    email: true,
    posts: {
      select: {
        title: true,
        published: true,
      },
    },
  },
});
```

## Omit fields instead of selecting everything manually [#omit-fields-instead-of-selecting-everything-manually]

If you mostly want the default result but need to exclude a few fields, see [Excluding fields](https://www.prisma.io/docs/orm/v7/prisma-client/queries/excluding-fields).

## Related pages [#related-pages]

* [Relation queries](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries)
* [Filtering and sorting](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting)
* [Prisma Client API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#select)

## Related pages

- [`Aggregation, grouping, and summarizing`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing): Use Prisma Client to aggregate, group by, count, and select distinct.
- [`CRUD`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud): Learn how to perform create, read, update, and delete operations
- [`Excluding fields`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/excluding-fields): Learn how to exclude fields from Prisma Client results with the omit option.
- [`Filtering and sorting`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting): Learn how to filter Prisma Client queries with where and sort results with orderBy.
- [`Full-text search`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search): Learn how to search text fields with Prisma Client using your database's native full-text search support.

# Transactions and batch queries (Prisma ORM v7) (/docs/orm/v7/prisma-client/queries/transactions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

This page explains the transactions API of Prisma Client

Location: ORM > v7 > Prisma Client > Queries > Transactions and batch queries

A database transaction is a sequence of read/write operations guaranteed to succeed or fail as a whole (ACID properties: Atomic, Consistent, Isolated, Durable).

Prisma Client supports transactions in several ways:

| Scenario            | Technique                                |
| :------------------ | :--------------------------------------- |
| Dependent writes    | Nested writes                            |
| Independent writes  | `$transaction([])` API, Batch operations |
| Read, modify, write | Interactive transactions                 |

## Nested writes [#nested-writes]

A [nested write](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-writes) performs multiple operations on related records in a single transaction:

```ts
// Create user with posts in a single transaction
const user = await prisma.user.create({
  data: {
    email: "alice@prisma.io",
    posts: {
      create: [{ title: "Post 1" }, { title: "Post 2" }],
    },
  },
});
```

## Batch operations [#batch-operations]

These bulk operations run as transactions:

* `createMany()` / `createManyAndReturn()`
* `updateMany()` / `updateManyAndReturn()`
* `deleteMany()`

## The `$transaction` API [#the-transaction-api]

### Sequential operations [#sequential-operations]

Pass an array of queries to execute sequentially in a transaction:

```ts
const [posts, totalPosts] = await prisma.$transaction([
  prisma.post.findMany({ where: { title: { contains: "prisma" } } }),
  prisma.post.count(),
]);
```

With options:

```ts
await prisma.$transaction(
  [prisma.resource.deleteMany({ where: { name: "name" } }), prisma.resource.createMany({ data })],
  { isolationLevel: Prisma.TransactionIsolationLevel.Serializable },
);
```

### Interactive transactions [#interactive-transactions]

For complex logic between queries, use interactive transactions:

```ts
const result = await prisma.$transaction(async (tx) => {
  const sender = await tx.account.update({
    data: { balance: { decrement: 100 } },
    where: { email: "alice@prisma.io" },
  });

  if (sender.balance < 0) {
    throw new Error("Insufficient funds");
  }

  return await tx.account.update({
    data: { balance: { increment: 100 } },
    where: { email: "bob@prisma.io" },
  });
});
```

> [!WARNING]
> Keep transactions short. Long-running transactions hurt performance and can cause deadlocks.

**Options:**

```ts
await prisma.$transaction(
  async (tx) => {
    /* ... */
  },
  {
    maxWait: 5000, // Max wait to acquire transaction (default: 2000ms)
    timeout: 10000, // Max transaction run time (default: 5000ms)
    isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
  },
);
```

### Transaction isolation level [#transaction-isolation-level]

> [!NOTE]
> This feature is not available on MongoDB, because MongoDB does not support isolation levels.

You can set the transaction [isolation level](https://www.prisma.io/dataguide/intro/database-glossary#isolation-levels) for transactions.

#### Set the isolation level [#set-the-isolation-level]

To set the transaction isolation level, use the `isolationLevel` option in the second parameter of the API.

For sequential operations:

```ts
await prisma.$transaction(
  [
    // Prisma Client operations running in a transaction...
  ],
  {
    isolationLevel: Prisma.TransactionIsolationLevel.Serializable, // optional, default defined by database configuration
  },
);
```

For an interactive transaction:

```jsx
await prisma.$transaction(
  async (prisma) => {
    // Code running in a transaction...
  },
  {
    isolationLevel: Prisma.TransactionIsolationLevel.Serializable, // optional, default defined by database configuration
    maxWait: 5000, // default: 2000
    timeout: 10000, // default: 5000
  },
);
```

#### Supported isolation levels [#supported-isolation-levels]

Prisma Client supports the following isolation levels if they are available in the underlying database:

* `ReadUncommitted`
* `ReadCommitted`
* `RepeatableRead`
* `Snapshot`
* `Serializable`

The isolation levels available for each database connector are as follows:

| Database    | `ReadUncommitted` | `ReadCommitted` | `RepeatableRead` | `Snapshot` | `Serializable` |
| ----------- | ----------------- | --------------- | ---------------- | ---------- | -------------- |
| PostgreSQL  | ✔️                | ✔️              | ✔️               | No         | ✔️             |
| MySQL       | ✔️                | ✔️              | ✔️               | No         | ✔️             |
| SQL Server  | ✔️                | ✔️              | ✔️               | ✔️         | ✔️             |
| CockroachDB | No                | No              | No               | No         | ✔️             |
| SQLite      | No                | No              | No               | No         | ✔️             |

By default, Prisma Client sets the isolation level to the value currently configured in your database.

The isolation levels configured by default in each database are as follows:

| Database    | Default          |
| ----------- | ---------------- |
| PostgreSQL  | `ReadCommitted`  |
| MySQL       | `RepeatableRead` |
| SQL Server  | `ReadCommitted`  |
| CockroachDB | `Serializable`   |
| SQLite      | `Serializable`   |

#### Database-specific information on isolation levels [#database-specific-information-on-isolation-levels]

See the following resources:

* [Transaction isolation levels in PostgreSQL](https://www.postgresql.org/docs/9.3/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-ISOLATION)
* [Transaction isolation levels in Microsoft SQL Server](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql?view=sql-server-ver15)
* [Transaction isolation levels in MySQL](https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html)

CockroachDB and SQLite only support the `Serializable` isolation level.

### Transaction timing issues [#transaction-timing-issues]

> [!NOTE]
> * The solution in this section does not apply to MongoDB, because MongoDB does not support [isolation levels](https://www.prisma.io/dataguide/intro/database-glossary#isolation-levels).
> * The timing issues discussed in this section do not apply to CockroachDB and SQLite, because these databases only support the highest `Serializable` isolation level.

When two or more transactions run concurrently in certain [isolation levels](https://www.prisma.io/dataguide/intro/database-glossary#isolation-levels), timing issues can cause write conflicts or deadlocks, such as the violation of unique constraints. For example, consider the following sequence of events where Transaction A and Transaction B both attempt to execute a `deleteMany` and a `createMany` operation:

1. Transaction B: `createMany` operation creates a new set of rows.
2. Transaction B: The application commits transaction B.
3. Transaction A: `createMany` operation.
4. Transaction A: The application commits transaction A. The new rows conflict with the rows that transaction B added at step 2.

This conflict can occur at the isolation level `ReadCommitted`, which is the default isolation level in PostgreSQL and Microsoft SQL Server. To avoid this problem, you can set a higher isolation level (`RepeatableRead` or `Serializable`). You can set the isolation level on a transaction. This overrides your database isolation level for that transaction.

To avoid transaction write conflicts and deadlocks on a transaction:

1. On your transaction, use the `isolationLevel` parameter to `Prisma.TransactionIsolationLevel.Serializable`.

   This ensures that your application commits multiple concurrent or parallel transactions as if they were run serially. When a transaction fails due to a write conflict or deadlock, Prisma Client returns a [P2034 error](https://www.prisma.io/docs/orm/v7/reference/error-reference#p2034).

2. In your application code, add a retry around your transaction to handle any P2034 errors, as shown in this example:

   ```ts
   import { Prisma, PrismaClient } from "../prisma/generated/client";

   const prisma = new PrismaClient();
   async function main() {
     const MAX_RETRIES = 5;
     let retries = 0;

     let result;
     while (retries < MAX_RETRIES) {
       try {
         result = await prisma.$transaction(
           [
             prisma.user.deleteMany({
               where: {
                 /** args */
               },
             }),
             prisma.post.createMany({
               data: {
                 /** args */
               },
             }),
           ],
           {
             isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
           },
         );
         break;
       } catch (error) {
         if (error.code === "P2034") {
           retries++;
           continue;
         }
         throw error;
       }
     }
   }
   ```

### Using `$transaction` within `Promise.all()` [#using-transaction-within-promiseall]

If you wrap a `$transaction` inside a call to `Promise.all()`, the queries inside the transaction will be executed *serially* (i.e. one after another):

```ts
await prisma.$transaction(async (prisma) => {
  await Promise.all([
    prisma.user.findMany(),
    prisma.user.findMany(),
    prisma.user.findMany(),
    prisma.user.findMany(),
    prisma.user.findMany(),
    prisma.user.findMany(),
    prisma.user.findMany(),
    prisma.user.findMany(),
    prisma.user.findMany(),
    prisma.user.findMany(),
  ]);
});
```

This may be counterintuitive because `Promise.all()` usually *parallelizes* the calls passed into it.

The reason for this behaviour is that:

* One transaction means that all queries inside it have to be run on the same connection.
* A database connection can only ever execute one query at a time.
* As one query blocks the connection while it is doing its work, putting a transaction into `Promise.all` effectively means that queries should be ran one after another.

## Dependent writes [#dependent-writes]

Writes are **dependent** when operations rely on the result of a preceding operation (e.g., using a database-generated ID).

### Nested writes for dependent operations [#nested-writes-for-dependent-operations]

Use nested writes when you need to create related records atomically:

```ts
const team = await prisma.team.create({
  data: {
    name: "Aurora Adventures",
    members: {
      create: { email: "alice@prisma.io" },
    },
  },
});
```

If any operation fails, Prisma Client rolls back the entire transaction.

> [!NOTE]
> The `$transaction([])` API cannot pass IDs between operations - use nested writes when you need the generated ID from one record to create another.

## Independent writes [#independent-writes]

Writes are **independent** if they don't rely on the result of a previous operation. Use these for:

* Updating the status of multiple orders to "Dispatched"
* Marking a list of emails as "Read"

### Bulk operations [#bulk-operations]

```ts
const updateUsers = await prisma.user.updateMany({
  where: { email: { contains: "prisma.io" } },
  data: { role: "ADMIN" },
});
```

### Using `$transaction([])` for independent writes [#using-transaction-for-independent-writes]

```ts
const [deleteResult, createResult] = await prisma.$transaction([
  prisma.post.deleteMany({ where: { authorId: 7 } }),
  prisma.user.delete({ where: { id: 7 } }),
]);
```

### Scenario: Pre-computed IDs and the `$transaction([])` API [#scenario-pre-computed-ids-and-the-transaction-api]

If you pre-compute IDs (e.g., using UUIDs), you can use either nested writes or `$transaction([])` since both operations know the ID upfront.

#### When to use bulk operations [#when-to-use-bulk-operations]

Consider bulk operations as a solution if:

* ✔ You want to update a batch of the *same type* of record, like a batch of emails

#### Scenario: Marking emails as read [#scenario-marking-emails-as-read]

You are building a service like gmail.com, and your customer wants a &#x2A;*"Mark as read"** feature that allows users to mark all emails as read. Each update to the status of an email is an independent write because the emails do not depend on one another - for example, the "Happy Birthday! 🍰" email from your aunt is unrelated to the promotional email from IKEA.

In the following schema, a `User` can have many received emails (a one-to-many relationship):

```ts
model User {
  id    Int       @id @default(autoincrement())
  email           String @unique
  receivedEmails  Email[] // Many emails
}

model Email {
  id      Int     @id @default(autoincrement())
  user    User    @relation(fields: [userId], references: [id])
  userId  Int
  subject String
  body    String
  unread  Boolean
}
```

Based on this schema, you can use `updateMany` to mark all unread emails as read:

```ts
await prisma.email.updateMany({
  where: {
    user: {
      id: 10,
    },
    unread: true,
  },
  data: {
    unread: false,
  },
});
```

#### Can I use nested writes with bulk operations? [#can-i-use-nested-writes-with-bulk-operations]

No - neither `updateMany` nor `deleteMany` currently supports nested writes. For example, you cannot delete multiple teams and all of their members (a cascading delete):

```ts highlight=8;delete
await prisma.team.deleteMany({
  where: {
    id: {
      in: [2, 99, 2, 11],
    },
  },
  data: {
    members: {}, // Cannot access members here // [!code --]
  },
});
```

#### Can I use bulk operations with the `$transaction([])` API? [#can-i-use-bulk-operations-with-the-transaction-api]

Yes. For example, you can include multiple `deleteMany` operations inside a `$transaction([])`.

### `$transaction([])` API [#transaction-api]

The `$transaction([])` API is generic solution to independent writes that allows you to run multiple operations as a single, atomic operation - if any operation fails, Prisma Client rolls back the entire transaction.

Its also worth noting that operations are executed according to the order they are placed in the transaction.

```ts
await prisma.$transaction([iRunFirst, iRunSecond, iRunThird]);
```

> **Note**: Using a query in a transaction does not influence the order of operations in the query itself.

As Prisma Client evolves, use cases for the `$transaction([])` API will increasingly be replaced by more specialized bulk operations (such as `createMany`) and nested writes.

#### When to use the `$transaction([])` API [#when-to-use-the-transaction-api]

Consider the `$transaction([])` API if:

* ✔ You want to update a batch that includes different types of records, such as emails and users. The records do not need to be related in any way.
* ✔ You want to batch raw SQL queries (`$executeRaw`) - for example, for features that Prisma Client does not yet support.

#### Scenario: Privacy legislation [#scenario-privacy-legislation]

GDPR and other privacy legislation give users the right to request that an organization deletes all of their personal data. In the following example schema, a `User` can have many posts and private messages:

```prisma
model User {
  id              Int              @id @default(autoincrement())
  posts           Post[]
  privateMessages PrivateMessage[]
}

model Post {
  id      Int    @id @default(autoincrement())
  user    User   @relation(fields: [userId], references: [id])
  userId  Int
  title   String
  content String
}

model PrivateMessage {
  id      Int    @id @default(autoincrement())
  user    User   @relation(fields: [userId], references: [id])
  userId  Int
  message String
}
```

If a user invokes the right to be forgotten, we must delete three records: the user record, private messages, and posts. It is critical that *all* delete operations succeed together or not at all, which makes this a use case for a transaction. However, using a single bulk operation like `deleteMany` is not possible in this scenario because we need to delete across three models. Instead, we can use the `$transaction([])` API to run three operations together - two `deleteMany` and one `delete`:

```ts
const id = 9; // User to be deleted

const deletePosts = prisma.post.deleteMany({
  where: {
    userId: id,
  },
});

const deleteMessages = prisma.privateMessage.deleteMany({
  where: {
    userId: id,
  },
});

const deleteUser = prisma.user.delete({
  where: {
    id: id,
  },
});

await prisma.$transaction([deletePosts, deleteMessages, deleteUser]); // Operations succeed or fail together
```

#### Scenario: Pre-computed IDs and the `$transaction([])` API [#scenario-pre-computed-ids-and-the-transaction-api-1]

Dependent writes are not supported by the `$transaction([])` API - if operation A relies on the ID generated by operation B, use [nested writes](#nested-writes). However, if you *pre-computed* IDs (for example, by generating GUIDs), your writes become independent. Consider the sign-up flow from the nested writes example:

```ts
await prisma.team.create({
  data: {
    name: "Aurora Adventures",
    members: {
      create: {
        email: "alice@prisma.io",
      },
    },
  },
});
```

Instead of auto-generating IDs, change the `id` fields of `Team` and `User` to a `String` (if you do not provide a value, a UUID is generated automatically). This example uses UUIDs:

```prisma highlight=2,9;delete|3,10;add
model Team {
  id      Int    @id @default(autoincrement()) // [!code --]
  id      String @id @default(uuid()) // [!code ++]
  name    String
  members User[]
}

model User {
  id    Int    @id @default(autoincrement()) // [!code --]
  id    String @id @default(uuid()) // [!code ++]
  email String @unique
  teams Team[]
}
```

Refactor the sign-up flow example to use the `$transaction([])` API instead of nested writes:

```ts
import { v4 } from "uuid";

const teamID = v4();
const userID = v4();

await prisma.$transaction([
  prisma.user.create({
    data: {
      id: userID,
      email: "alice@prisma.io",
      team: {
        id: teamID,
      },
    },
  }),
  prisma.team.create({
    data: {
      id: teamID,
      name: "Aurora Adventures",
    },
  }),
]);
```

Technically you can still use nested writes with pre-computed APIs if you prefer that syntax:

```ts
import { v4 } from "uuid";

const teamID = v4();
const userID = v4();

await prisma.team.create({
  data: {
    id: teamID,
    name: "Aurora Adventures",
    members: {
      create: {
        id: userID,
        email: "alice@prisma.io",
        team: {
          id: teamID,
        },
      },
    },
  },
});
```

There's no compelling reason to switch to manually generated IDs and the `$transaction([])` API if you are already using auto-generated IDs and nested writes.

## Read, modify, write [#read-modify-write]

In some cases you may need to perform custom logic as part of an atomic operation - also known as the [read-modify-write pattern](https://en.wikipedia.org/wiki/Read%E2%80%93modify%E2%80%93write). The following is an example of the read-modify-write pattern:

* Read a value from the database
* Run some logic to manipulate that value (for example, contacting an external API)
* Write the value back to the database

All operations should **succeed or fail together** without making unwanted changes to the database, but you do not necessarily need to use an actual database transaction. This section of the guide describes two ways to work with Prisma Client and the read-modify-write pattern:

* Designing idempotent APIs
* Optimistic concurrency control

### Idempotent APIs [#idempotent-apis]

Idempotency is the ability to run the same logic with the same parameters multiple times with the same result: the **effect on the database** is the same whether you run the logic once or one thousand times. For example:

* **NOT IDEMPOTENT**: Upsert (update-or-insert) a user in the database with email address `"letoya@prisma.io"`. The `User` table **does not** enforce unique email addresses. The effect on the database is different if you run the logic once (one user created) or ten times (ten users created).
* **IDEMPOTENT**: Upsert (update-or-insert) a user in the database with the email address `"letoya@prisma.io"`. The `User` table **does** enforce unique email addresses. The effect on the database is the same if you run the logic once (one user created) or ten times (existing user is updated with the same input).

Idempotency is something you can and should actively design into your application wherever possible.

#### When to design an idempotent API [#when-to-design-an-idempotent-api]

* ✔ You need to be able to retry the same logic without creating unwanted side-effects in the databases

#### Scenario: Upgrading a Slack team [#scenario-upgrading-a-slack-team]

You are creating an upgrade flow for Slack that allows teams to unlock paid features. Teams can choose between different plans and pay per user, per month. You use Stripe as your payment gateway, and extend your `Team` model to store a `stripeCustomerId`. Subscriptions are managed in Stripe.

```prisma highlight=5;normal
model Team {
  id               Int     @id @default(autoincrement())
  name             String
  User             User[]
  stripeCustomerId String? // [!code highlight]
}
```

The upgrade flow looks like this:

1. Count the number of users
2. Create a subscription in Stripe that includes the number of users
3. Associate the team with the Stripe customer ID to unlock paid features

```ts
const teamId = 9;
const planId = "plan_id";

// Count team members
const numTeammates = await prisma.user.count({
  where: {
    teams: {
      some: {
        id: teamId,
      },
    },
  },
});

// Create a customer in Stripe for plan-9454549
const customer = await stripe.customers.create({
  externalId: teamId,
  plan: planId,
  quantity: numTeammates,
});

// Update the team with the customer id to indicate that they are a customer
// and support querying this customer in Stripe from our application code.
await prisma.team.update({
  data: {
    customerId: customer.id,
  },
  where: {
    id: teamId,
  },
});
```

This example has a problem: you can only run the logic *once*. Consider the following scenario:

1. Stripe creates a new customer and subscription, and returns a customer ID
2. Updating the team **fails** - the team is not marked as a customer in the Slack database
3. The customer is charged by Stripe, but paid features are not unlocked in Slack because the team lacks a valid `customerId`
4. Running the same code again either:
   * Results in an error because the team (defined by `externalId`) already exists - Stripe never returns a customer ID
   * If `externalId` is not subject to a unique constraint, Stripe creates yet another subscription (**not idempotent**)

You cannot re-run this code in case of an error and you cannot change to another plan without being charged twice.

The following refactor (highlighted) introduces a mechanism that checks if a subscription already exists, and either creates the description or updates the existing subscription (which will remain unchanged if the input is identical):

```ts highlight=12-27;normal
// Calculate the number of users times the cost per user
const numTeammates = await prisma.user.count({
  where: {
    teams: {
      some: {
        id: teamId,
      },
    },
  },
});

// Find customer in Stripe // [!code highlight]
let customer = await stripe.customers.get({ externalId: teamID }); // [!code highlight]

if (customer) {
  // [!code highlight]
  // If team already exists, update // [!code highlight]
  customer = await stripe.customers.update({
    // [!code highlight]
    externalId: teamId, // [!code highlight]
    plan: "plan_id", // [!code highlight]
    quantity: numTeammates, // [!code highlight]
  });
} else {
  customer = await stripe.customers.create({
    // If team does not exist, create customer
    externalId: teamId,
    plan: "plan_id",
    quantity: numTeammates,
  });
}

// Update the team with the customer id to indicate that they are a customer
// and support querying this customer in Stripe from our application code.
await prisma.team.update({
  data: {
    customerId: customer.id,
  },
  where: {
    id: teamId,
  },
});
```

You can now retry the same logic multiple times with the same input without adverse effect. To further enhance this example, you can introduce a mechanism whereby the subscription is cancelled or temporarily deactivated if the update does not succeed after a set number of attempts.

### Optimistic concurrency control [#optimistic-concurrency-control]

Optimistic concurrency control (OCC) is a model for handling concurrent operations on a single entity that does not rely on 🔒 locking. Instead, we **optimistically** assume that a record will remain unchanged in between reading and writing, and use a concurrency token (a timestamp or version field) to detect changes to a record.

If a ❌ conflict occurs (someone else has changed the record since you read it), you cancel the transaction. Depending on your scenario, you can then:

* Re-try the transaction (book another cinema seat)
* Throw an error (alert the user that they are about to overwrite changes made by someone else)

This section describes how to build your own optimistic concurrency control. See also: Plans for [application-level optimistic concurrency control on GitHub](https://github.com/prisma/orm/issues/4988)

#### When to use optimistic concurrency control [#when-to-use-optimistic-concurrency-control]

* ✔ You anticipate a high number of concurrent requests (multiple people booking cinema seats)
* ✔ You anticipate that conflicts between those concurrent requests will be rare

Avoiding locks in an application with a high number of concurrent requests makes the application more resilient to load and more scalable overall. Although locking is not inherently bad, locking in a high concurrency environment can lead to unintended consequences - even if you are locking individual rows, and only for a short amount of time. For more information, see:

* [Why ROWLOCK Hints Can Make Queries Slower and Blocking Worse in SQL Server](https://kendralittle.com/2016/02/04/why-rowlock-hints-can-make-queries-slower-and-blocking-worse-in-sql-server/)

#### Scenario: Reserving a seat at the cinema [#scenario-reserving-a-seat-at-the-cinema]

You are creating a booking system for a cinema. Each movie has a set number of seats. The following schema models movies and seats:

```ts
model Seat {
  id        Int   @id @default(autoincrement())
  userId    Int?
  claimedBy User? @relation(fields: [userId], references: [id])
  movieId   Int
  movie     Movie @relation(fields: [movieId], references: [id])
}

model Movie {
  id    Int    @id     @default(autoincrement())
  name  String @unique
  seats Seat[]
}
```

The following sample code finds the first available seat and assigns that seat to a user:

```ts
const movieName = "Hidden Figures";

// Find first available seat
const availableSeat = await prisma.seat.findFirst({
  where: {
    movie: {
      name: movieName,
    },
    claimedBy: null,
  },
});

// Throw an error if no seats are available
if (!availableSeat) {
  throw new Error(`Oh no! ${movieName} is all booked.`);
}

// Claim the seat
await prisma.seat.update({
  data: {
    claimedBy: userId,
  },
  where: {
    id: availableSeat.id,
  },
});
```

However, this code suffers from the "double-booking problem" - it is possible for two people to book the same seats:

1. Seat 3A returned to Sorcha (`findFirst`)
2. Seat 3A returned to Ellen (`findFirst`)
3. Seat 3A claimed by Sorcha (`update`)
4. Seat 3A claimed by Ellen (`update` - overwrites Sorcha's claim)

Even though Sorcha has successfully booked the seat, the system ultimately stores Ellen's claim. To solve this problem with optimistic concurrency control, add a `version` field to the seat:

```prisma highlight=7;normal
model Seat {
  id        Int   @id @default(autoincrement())
  userId    Int?
  claimedBy User? @relation(fields: [userId], references: [id])
  movieId   Int
  movie     Movie @relation(fields: [movieId], references: [id])
  version   Int // [!code highlight]
}
```

Next, adjust the code to check the `version` field before updating:

```ts highlight=19-38;normal
const userEmail = "alice@prisma.io";
const movieName = "Hidden Figures";

// Find the first available seat
// availableSeat.version might be 0
const availableSeat = await client.seat.findFirst({
  where: {
    Movie: {
      name: movieName,
    },
    claimedBy: null,
  },
});

if (!availableSeat) {
  throw new Error(`Oh no! ${movieName} is all booked.`);
}

// Only mark the seat as claimed if the availableSeat.version // [!code highlight]
// matches the version we're updating. Additionally, increment the // [!code highlight]
// version when we perform this update so all other clients trying // [!code highlight]
// to book this same seat will have an outdated version. // [!code highlight]
const seats = await client.seat.updateMany({
  // [!code highlight]
  data: {
    // [!code highlight]
    claimedBy: userEmail, // [!code highlight]
    version: {
      // [!code highlight]
      increment: 1, // [!code highlight]
    }, // [!code highlight]
  }, // [!code highlight]
  where: {
    // [!code highlight]
    id: availableSeat.id, // [!code highlight]
    version: availableSeat.version, // This version field is the key; only claim seat if in-memory version matches database version, indicating that the field has not been updated // [!code highlight]
  }, // [!code highlight]
}); // [!code highlight]

if (seats.count === 0) {
  // [!code highlight]
  throw new Error(`That seat is already booked! Please try again.`); // [!code highlight]
} // [!code highlight]
```

It is now impossible for two people to book the same seat:

1. Seat 3A returned to Sorcha (`version` is 0)
2. Seat 3A returned to Ellen (`version` is 0)
3. Seat 3A claimed by Sorcha (`version` is incremented to 1, booking succeeds)
4. Seat 3A claimed by Ellen (in-memory `version` (0) does not match database `version` (1) - booking does not succeed)

### Interactive transactions [#interactive-transactions-1]

If you have an existing application, it can be a significant undertaking to refactor your application to use optimistic concurrency control. Interactive Transactions offers a useful escape hatch for cases like this.

To create an interactive transaction, pass an async function into [$transaction](#transaction-api).

The first argument passed into this async function is an instance of the Prisma Client. Below, we will call this instance `tx`. Any Prisma Client call invoked on this `tx` instance is encapsulated into the transaction.

In the example below, Alice and Bob each have $100 in their account. If they try to send more money than they have, the transfer is rejected.

The expected outcome would be for Alice to make 1 transfer for $100 and the other transfer would be rejected. This would result in Alice having $0 and Bob having $200.

```ts
import { PrismaClient } from "../prisma/generated/client";
const prisma = new PrismaClient();

async function transfer(from: string, to: string, amount: number) {
  return await prisma.$transaction(async (tx) => {
    // 1. Decrement amount from the sender.
    const sender = await tx.account.update({
      data: {
        balance: {
          decrement: amount,
        },
      },
      where: {
        email: from,
      },
    });

    // 2. Verify that the sender's balance didn't go below zero.
    if (sender.balance < 0) {
      throw new Error(`${from} doesn't have enough to send ${amount}`);
    }

    // 3. Increment the recipient's balance by amount
    const recipient = tx.account.update({
      data: {
        balance: {
          increment: amount,
        },
      },
      where: {
        email: to,
      },
    });

    return recipient;
  });
}

async function main() {
  // This transfer is successful
  await transfer("alice@prisma.io", "bob@prisma.io", 100);
  // This transfer fails because Alice doesn't have enough funds in her account
  await transfer("alice@prisma.io", "bob@prisma.io", 100);
}

main();
```

In the example above, both `update` queries run within a database transaction. When the application reaches the end of the function, the transaction is **committed** to the database.

If the application encounters an error along the way, the async function will throw an exception and automatically **rollback** the transaction.

You can learn more about interactive transactions in this [section](#interactive-transactions).

> [!WARNING]
> **Use interactive transactions with caution**. Keeping transactions
> open for a long time hurts database performance and can even cause deadlocks.
> Try to avoid performing network requests and executing slow queries inside your
> transaction functions. Keep each transaction as short as possible.

## Conclusion [#conclusion]

Prisma Client supports multiple ways of handling transactions, either directly through the API or by supporting your ability to introduce optimistic concurrency control and idempotency into your application. If you feel like you have use cases in your application that are not covered by any of the suggested options, please open a [GitHub issue](https://github.com/prisma/orm/issues/new/choose) to start a discussion.

## Related pages

- [`Aggregation, grouping, and summarizing`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing): Use Prisma Client to aggregate, group by, count, and select distinct.
- [`CRUD`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud): Learn how to perform create, read, update, and delete operations
- [`Excluding fields`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/excluding-fields): Learn how to exclude fields from Prisma Client results with the omit option.
- [`Filtering and sorting`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/filtering-and-sorting): Learn how to filter Prisma Client queries with where and sort results with orderBy.
- [`Full-text search`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/full-text-search): Learn how to search text fields with Prisma Client using your database's native full-text search support.

# Custom model and field names (Prisma ORM v7) (/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how you can decouple the naming of Prisma models from database tables to improve the ergonomics of the generated Prisma Client API

Location: ORM > v7 > Prisma Client > Setup and Configuration > Custom model and field names

The Prisma Client API is generated based on the models in your [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview). Models are *typically* 1:1 mappings of your database tables.

In some cases, especially when using [introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection), it might be useful to *decouple* the naming of database tables and columns from the names that are used in your Prisma Client API. This can be done via the [`@map` and `@@map`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#mapping-model-names-to-tables-or-collections) attributes in your Prisma schema.

You can use `@map` and `@@map` to rename MongoDB fields and collections respectively. This page uses a relational database example.

## Example: Relational database [#example-relational-database]

Assume you have a PostgreSQL relational database schema looking similar to this:

```sql
CREATE TABLE users (
	user_id SERIAL PRIMARY KEY NOT NULL,
	name VARCHAR(256),
	email VARCHAR(256) UNIQUE NOT NULL
);
CREATE TABLE posts (
	post_id SERIAL PRIMARY KEY NOT NULL,
	created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
	title VARCHAR(256) NOT NULL,
	content TEXT,
	author_id INTEGER REFERENCES users(user_id)
);
CREATE TABLE profiles (
	profile_id SERIAL PRIMARY KEY NOT NULL,
	bio TEXT,
	user_id INTEGER NOT NULL UNIQUE REFERENCES users(user_id)
);
CREATE TABLE categories (
	category_id SERIAL PRIMARY KEY NOT NULL,
	name VARCHAR(256)
);
CREATE TABLE post_in_categories (
	post_id INTEGER NOT NULL REFERENCES posts(post_id),
	category_id INTEGER NOT NULL REFERENCES categories(category_id)
);
CREATE UNIQUE INDEX post_id_category_id_unique ON post_in_categories(post_id int4_ops,category_id int4_ops);
```

When introspecting a database with that schema, you'll get a Prisma schema looking similar to this:

```prisma
model categories {
  category_id        Int                  @id @default(autoincrement())
  name               String?              @db.VarChar(256)
  post_in_categories post_in_categories[]
}

model post_in_categories {
  post_id     Int
  category_id Int
  categories  categories @relation(fields: [category_id], references: [category_id], onDelete: NoAction, onUpdate: NoAction)
  posts       posts      @relation(fields: [post_id], references: [post_id], onDelete: NoAction, onUpdate: NoAction)

  @@unique([post_id, category_id], map: "post_id_category_id_unique")
}

model posts {
  post_id            Int                  @id @default(autoincrement())
  created_at         DateTime?            @default(now()) @db.Timestamptz(6)
  title              String               @db.VarChar(256)
  content            String?
  author_id          Int?
  users              users?               @relation(fields: [author_id], references: [user_id], onDelete: NoAction, onUpdate: NoAction)
  post_in_categories post_in_categories[]
}

model profiles {
  profile_id Int     @id @default(autoincrement())
  bio        String?
  user_id    Int     @unique
  users      users   @relation(fields: [user_id], references: [user_id], onDelete: NoAction, onUpdate: NoAction)
}

model users {
  user_id  Int       @id @default(autoincrement())
  name     String?   @db.VarChar(256)
  email    String    @unique @db.VarChar(256)
  posts    posts[]
  profiles profiles?
}
```

There are a few "issues" with this Prisma schema when the Prisma Client API is generated:

**Adhering to Prisma ORM's naming conventions**

Prisma ORM has a [naming convention](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#naming-conventions) of **camelCasing** and using the **singular form** for Prisma models. If these naming conventions are not met, the Prisma schema can become harder to interpret and the generated Prisma Client API will feel less natural. Consider the following, generated model:

```prisma
model users {
  user_id  Int       @id @default(autoincrement())
  name     String?   @db.VarChar(256)
  email    String    @unique @db.VarChar(256)
  posts    posts[]
  profiles profiles?
}
```

Although `profiles` refers to a 1:1 relation, its type is currently called `profiles` in plural, suggesting that there might be many `profiles` in this relation. With Prisma ORM conventions, the models and fields were *ideally* named as follows:

```prisma
model User {
  user_id Int      @id @default(autoincrement())
  name    String?  @db.VarChar(256)
  email   String   @unique @db.VarChar(256)
  posts   Post[]
  profile Profile?
}
```

Because these fields are "Prisma ORM-level" [relation fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields) that do not manifest you can manually rename them in your Prisma schema.

**Naming of annotated relation fields**

Foreign keys are represented as a combination of a [annotated relation fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields) and its corresponding relation scalar field in the Prisma schema. Here's how all the relations from the SQL schema are currently represented:

```prisma
model categories {
  category_id        Int                  @id @default(autoincrement())
  name               String?              @db.VarChar(256)
  post_in_categories post_in_categories[] // virtual relation field
}

model post_in_categories {
  post_id     Int // relation scalar field
  category_id Int // relation scalar field
  categories  categories @relation(fields: [category_id], references: [category_id], onDelete: NoAction, onUpdate: NoAction) // virtual relation field
  posts       posts      @relation(fields: [post_id], references: [post_id], onDelete: NoAction, onUpdate: NoAction)

  @@unique([post_id, category_id], map: "post_id_category_id_unique")
}

model posts {
  post_id            Int                  @id @default(autoincrement())
  created_at         DateTime?            @default(now()) @db.Timestamptz(6)
  title              String               @db.VarChar(256)
  content            String?
  author_id          Int?
  users              users?               @relation(fields: [author_id], references: [user_id], onDelete: NoAction, onUpdate: NoAction)
  post_in_categories post_in_categories[]
}

model profiles {
  profile_id Int     @id @default(autoincrement())
  bio        String?
  user_id    Int     @unique
  users      users   @relation(fields: [user_id], references: [user_id], onDelete: NoAction, onUpdate: NoAction)
}

model users {
  user_id  Int       @id @default(autoincrement())
  name     String?   @db.VarChar(256)
  email    String    @unique @db.VarChar(256)
  posts    posts[]
  profiles profiles?
}
```

## Using @map and @@map to rename fields and models in the Prisma Client API [#using-map-and-map-to-rename-fields-and-models-in-the-prisma-client-api]

You can "rename" fields and models that are used in Prisma Client by mapping them to the "original" names in the database using the `@map` and `@@map` attributes. For the example above, you could e.g. annotate your models as follows.

*After* you introspected your database with `prisma db pull`, you can manually adjust the resulting Prisma schema as follows:

```prisma
model Category {
  id                 Int                @id @default(autoincrement()) @map("category_id")
  name               String?            @db.VarChar(256)
  post_in_categories PostInCategories[]

  @@map("categories")
}

model PostInCategories {
  post_id     Int
  category_id Int
  categories  Category @relation(fields: [category_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
  posts       Post     @relation(fields: [post_id], references: [id], onDelete: NoAction, onUpdate: NoAction)

  @@unique([post_id, category_id], map: "post_id_category_id_unique")
  @@map("post_in_categories")
}

model Post {
  id                 Int                @id @default(autoincrement()) @map("post_id")
  created_at         DateTime?          @default(now()) @db.Timestamptz(6)
  title              String             @db.VarChar(256)
  content            String?
  author_id          Int?
  users              User?              @relation(fields: [author_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
  post_in_categories PostInCategories[]

  @@map("posts")
}

model Profile {
  id      Int     @id @default(autoincrement()) @map("profile_id")
  bio     String?
  user_id Int     @unique
  users   User    @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction)

  @@map("profiles")
}

model User {
  id       Int      @id @default(autoincrement()) @map("user_id")
  name     String?  @db.VarChar(256)
  email    String   @unique @db.VarChar(256)
  posts    Post[]
  profiles Profile?

  @@map("users")
}
```

With these changes, you're now adhering to Prisma ORM's naming conventions and the generated Prisma Client API feels more "natural":

```ts
// Nested writes
const profile = await prisma.profile.create({
  data: {
    bio: "Hello World",
    users: {
      create: {
        name: "Alice",
        email: "alice@prisma.io",
      },
    },
  },
});

// Fluent API
const userByProfile = await prisma.profile
  .findUnique({
    where: { id: 1 },
  })
  .users();
```

> [!NOTE]
> `prisma db pull` preserves the custom names you defined via `@map` and `@@map` in your Prisma schema on re-introspecting your database.

## Renaming relation fields [#renaming-relation-fields]

Prisma ORM-level [relation fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields) (sometimes referred to as "virtual relation fields") only exist in the Prisma schema, but do not actually manifest in the underlying database. You can therefore name these fields whatever you want.

Consider the following example of an ambiguous relation in a SQL database:

```sql
CREATE TABLE "User" (
    id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
    id SERIAL PRIMARY KEY,
    "author" integer NOT NULL,
    "favoritedBy" INTEGER,
    FOREIGN KEY ("author") REFERENCES "User"(id),
    FOREIGN KEY ("favoritedBy") REFERENCES "User"(id)
);
```

Prisma ORM's introspection will output the following Prisma schema:

```prisma
model Post {
  id                          Int   @id @default(autoincrement())
  author                      Int
  favoritedBy                 Int?
  User_Post_authorToUser      User  @relation("Post_authorToUser", fields: [author], references: [id], onDelete: NoAction, onUpdate: NoAction)
  User_Post_favoritedByToUser User? @relation("Post_favoritedByToUser", fields: [favoritedBy], references: [id], onDelete: NoAction, onUpdate: NoAction)
}

model User {
  id                          Int    @id @default(autoincrement())
  Post_Post_authorToUser      Post[] @relation("Post_authorToUser")
  Post_Post_favoritedByToUser Post[] @relation("Post_favoritedByToUser")
}
```

Because the names of the virtual relation fields `Post_Post_authorToUser` and `Post_Post_favoritedByToUser` are based on the generated relation names, they don't look very friendly in the Prisma Client API. In that case, you can rename the relation fields. For example:

```prisma highlight=11-12;edit
model Post {
  id                          Int   @id @default(autoincrement())
  author                      Int
  favoritedBy                 Int?
  User_Post_authorToUser      User  @relation("Post_authorToUser", fields: [author], references: [id], onDelete: NoAction, onUpdate: NoAction)
  User_Post_favoritedByToUser User? @relation("Post_favoritedByToUser", fields: [favoritedBy], references: [id], onDelete: NoAction, onUpdate: NoAction)
}

model User {
  id             Int    @id @default(autoincrement())
  //edit-start
  writtenPosts   Post[] @relation("Post_authorToUser")
  favoritedPosts Post[] @relation("Post_favoritedByToUser")
  //edit-end
}
```

> [!NOTE]
> `prisma db pull` preserves custom relation fields defined in your Prisma schema on re-introspecting your database.

## Related pages

- [`Configuring error formatting`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/error-formatting): This page explains how to configure the formatting of errors when using Prisma Client
- [`Database connections`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections): Learn how to manage database connections and configure connection pools
- [`Database polyfills`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/database-polyfills): Prisma Client provides features that are not achievable with relational databases. These features are referred to as "polyfills" and explained on this page.
- [`Generating Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client): Learn when and how to run prisma generate, configure the generator output, and import the generated client in your app.
- [`Introduction to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction): Learn how to set up and configure Prisma Client in your project

# Database polyfills (Prisma ORM v7) (/docs/orm/v7/prisma-client/setup-and-configuration/database-polyfills)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma Client provides features that are not achievable with relational databases. These features are referred to as "polyfills" and explained on this page.

Location: ORM > v7 > Prisma Client > Setup and Configuration > Database polyfills

Prisma Client provides features that are typically either not achievable with particular databases or require extensions. These features are referred to as *polyfills*. For all databases, this includes:

* Initializing [ID](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-an-id-field) values with `cuid` and `uuid` values
* Using [`@updatedAt`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-attributes) to store the time when a record was last updated

For relational databases, this includes:

* [Implicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations)

For MongoDB, this includes:

* [Relations in general](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations) - foreign key relations between documents are not enforced in MongoDB

## Related pages

- [`Configuring error formatting`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/error-formatting): This page explains how to configure the formatting of errors when using Prisma Client
- [`Custom model and field names`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names): Learn how you can decouple the naming of Prisma models from database tables to improve the ergonomics of the generated Prisma Client API
- [`Database connections`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections): Learn how to manage database connections and configure connection pools
- [`Generating Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client): Learn when and how to run prisma generate, configure the generator output, and import the generated client in your app.
- [`Introduction to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction): Learn how to set up and configure Prisma Client in your project

# Configuring error formatting (Prisma ORM v7) (/docs/orm/v7/prisma-client/setup-and-configuration/error-formatting)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

This page explains how to configure the formatting of errors when using Prisma Client

Location: ORM > v7 > Prisma Client > Setup and Configuration > Configuring error formatting

By default, Prisma Client uses [ANSI escape characters](https://en.wikipedia.org/wiki/ANSI_escape_code) to pretty print the error stack and give recommendations on how to fix a problem. While this is very useful when using Prisma Client from the terminal, in contexts like a GraphQL API, you only want the minimal error without any additional formatting.

This page explains how error formatting can be configured with Prisma Client.

## Formatting levels [#formatting-levels]

There are 3 error formatting levels:

1. **Pretty Error** (default): Includes a full stack trace with colors, syntax highlighting of the code and extended error message with a possible solution for the problem.
2. **Colorless Error**: Same as pretty errors, just without colors.
3. **Minimal Error**: The raw error message.

In order to configure these different error formatting levels, there are two options:

* Setting the config options via environment variables
* Providing the config options to the `PrismaClient` constructor

## Formatting via environment variables [#formatting-via-environment-variables]

* [`NO_COLOR`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference#no_color): If this env var is provided, colors are stripped from the error messages. Therefore you end up with a **colorless error**. The `NO_COLOR` environment variable is a standard described in [the NO_COLOR specification](https://no-color.org/).
* `NODE_ENV=production`: If the env var `NODE_ENV` is set to `production`, only the **minimal error** will be printed. This allows for easier digestion of logs in production environments.

### Formatting via the `PrismaClient` constructor [#formatting-via-the-prismaclient-constructor]

Alternatively, use the `PrismaClient` [`errorFormat`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#errorformat) parameter to set the error format:

```ts
const prisma = new PrismaClient({
  errorFormat: "pretty",
});
```

## Related pages

- [`Custom model and field names`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names): Learn how you can decouple the naming of Prisma models from database tables to improve the ergonomics of the generated Prisma Client API
- [`Database connections`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections): Learn how to manage database connections and configure connection pools
- [`Database polyfills`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/database-polyfills): Prisma Client provides features that are not achievable with relational databases. These features are referred to as "polyfills" and explained on this page.
- [`Generating Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client): Learn when and how to run prisma generate, configure the generator output, and import the generated client in your app.
- [`Introduction to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction): Learn how to set up and configure Prisma Client in your project

# Generating Prisma Client (Prisma ORM v7) (/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn when and how to run prisma generate, configure the generator output, and import the generated client in your app.

Location: ORM > v7 > Prisma Client > Setup and Configuration > Generating Prisma Client

`prisma generate` creates Prisma Client from the models and generator configuration in your `schema.prisma` file.

## Define a generator [#define-a-generator]

In Prisma ORM v7, the `output` field is required:

```prisma title="schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "./generated"
}
```

## Generate the client [#generate-the-client]

Run the following command whenever you add models, change fields, or update generator settings:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

If you want the CLI-specific options such as `--watch` or `--generator`, see the [`prisma generate` command reference](https://www.prisma.io/docs/cli/v7/generate).

## Import the generated client [#import-the-generated-client]

Import Prisma Client from the output path you configured:

```ts
import { PrismaClient } from "./generated/client";

const prisma = new PrismaClient();
```

## When to run generate [#when-to-run-generate]

You should run `prisma generate` after:

* changing your Prisma schema
* updating generator configuration
* enabling features that affect the client API
* pulling schema changes from another branch or teammate

In many projects it also makes sense to run `prisma generate` in `postinstall` or before your production build so deployments always use a current client.

## Related pages [#related-pages]

* [Introduction to Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction)
* [Generators in the Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators)
* [Prisma CLI reference for generate](https://www.prisma.io/docs/cli/v7/generate)

## Related pages

- [`Configuring error formatting`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/error-formatting): This page explains how to configure the formatting of errors when using Prisma Client
- [`Custom model and field names`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names): Learn how you can decouple the naming of Prisma models from database tables to improve the ergonomics of the generated Prisma Client API
- [`Database connections`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections): Learn how to manage database connections and configure connection pools
- [`Database polyfills`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/database-polyfills): Prisma Client provides features that are not achievable with relational databases. These features are referred to as "polyfills" and explained on this page.
- [`Introduction to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction): Learn how to set up and configure Prisma Client in your project

# Introduction to Prisma Client (Prisma ORM v7) (/docs/orm/v7/prisma-client/setup-and-configuration/introduction)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to set up and configure Prisma Client in your project

Location: ORM > v7 > Prisma Client > Setup and Configuration > Introduction to Prisma Client

Prisma Client is an auto-generated and type-safe query builder that's *tailored&#x2A; to your data. To get started with Prisma Client, follow the &#x2A;*[Quickstart](https://www.prisma.io/docs/v7/prisma-orm/quickstart/sqlite)**.

[Quickstart (5 min)](https://www.prisma.io/docs/v7/prisma-orm/quickstart/sqlite)

## Prerequisites [#prerequisites]

In order to set up Prisma Client, you need a Prisma Config and a [Prisma schema file](https://www.prisma.io/docs/orm/v7/prisma-schema/overview):

  

#### Prisma Config

```ts title="prisma.config.ts" 
import 'dotenv/config';
import { defineConfig, env } from 'prisma/config';

export default defineConfig({
  schema: 'prisma/schema.prisma',
  datasource: {
    url: env('DATABASE_URL'),
  },
});
```

#### Prisma Schema

```prisma title="schema.prisma" 
datasource db {
  provider = "postgresql"
}

generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

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

## Installation [#installation]

[Install the Prisma CLI](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference), the Prisma Client library, and the [driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers) for your database:

  

#### PostgreSQL

  

  <CodeBlockTab value="bun">
    ```bash
    bun add prisma@prev --dev
    bun add @prisma/client@7 @prisma/adapter-pg pg
    ```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg
```

#### yarn

```bash
yarn add prisma@prev --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg
```

#### npm

```bash
npm install prisma@prev --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg
```
    
  </CodeBlockTab>

#### MySQL / MariaDB

  

  <CodeBlockTab value="bun">
    ```bash
    bun add prisma@prev --dev
    bun add @prisma/client@7 @prisma/adapter-mariadb mariadb
    ```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
pnpm add @prisma/client@7 @prisma/adapter-mariadb mariadb
```

#### yarn

```bash
yarn add prisma@prev --dev
yarn add @prisma/client@7 @prisma/adapter-mariadb mariadb
```

#### npm

```bash
npm install prisma@prev --save-dev
npm install @prisma/client@7 @prisma/adapter-mariadb mariadb
```
    
  </CodeBlockTab>

#### SQLite

  

  <CodeBlockTab value="bun">
    ```bash
    bun add prisma@prev --dev
    bun add @prisma/client@7 @prisma/adapter-better-sqlite3 better-sqlite3
    ```

#### pnpm

```bash
pnpm add prisma@prev --save-dev
pnpm add @prisma/client@7 @prisma/adapter-better-sqlite3 better-sqlite3
```

#### yarn

```bash
yarn add prisma@prev --dev
yarn add @prisma/client@7 @prisma/adapter-better-sqlite3 better-sqlite3
```

#### npm

```bash
npm install prisma@prev --save-dev
npm install @prisma/client@7 @prisma/adapter-better-sqlite3 better-sqlite3
```
    
  </CodeBlockTab>

> [!NOTE]
> Prisma 7 requires a [driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers) to connect to your database. Make sure your `package.json` includes `"type": "module"` for ESM support. See the [upgrade guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v7) for details.

## Generate the Client API [#generate-the-client-api]

Prisma Client is based on the models in Prisma Schema. To provide the correct types, you need generate the client code:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This will create a `generated` directory based on where you set the `output` to in the Prisma Schema. Any time your import Prisma Client, it will need to come from this generated client API.

## Importing Prisma Client [#importing-prisma-client]

With the client generated, import it along with your [driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers) and create a new instance:

  

#### PostgreSQL

```ts
import { PrismaClient } from "./path/to/generated/prisma";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

export const prisma = new PrismaClient({ adapter });
```

#### MySQL / MariaDB

```ts
import { PrismaClient } from "./path/to/generated/prisma";
import { PrismaMariaDb } from "@prisma/adapter-mariadb";

const adapter = new PrismaMariaDb({
  host: "localhost",
  user: "root",
  database: "mydb",
});

export const prisma = new PrismaClient({ adapter });
```

#### SQLite

```ts
import { PrismaClient } from "./path/to/generated/prisma";
import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";

const adapter = new PrismaBetterSqlite3({
  url: "file:./dev.db",
});

export const prisma = new PrismaClient({ adapter });
```

#### PostgreSQL (Edge)

```ts
import { PrismaClient } from "./path/to/generated/prisma/edge";
import { PrismaPostgresAdapter } from "@prisma/adapter-ppg";

const adapter = new PrismaPostgresAdapter({
  connectionString: process.env.DATABASE_URL!,
});

export const prisma = new PrismaClient({ adapter });
```

> [!WARNING]
> `PrismaClient` requires a driver adapter in Prisma 7. Calling `new PrismaClient()` without an `adapter` will result in an error.

Find out what [driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers) is needed for your database.

Your application should generally only create **one instance** of `PrismaClient`. How to achieve this depends on whether you are using Prisma ORM in a [long-running application](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections#prismaclient-in-long-running-applications) or in a [serverless environment](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections#prismaclient-in-serverless-environments).

Creating multiple instances of `PrismaClient` will create multiple connection pools and can hit the connection limit for your database. Too many connections may start to **slow down your database** and eventually lead to errors such as:

```bash
Error in connector: Error querying the database: db error: FATAL: sorry, too many clients already
   at PrismaClientFetcher.request
```

## Use Prisma Client to send queries to your database [#use-prisma-client-to-send-queries-to-your-database]

Once you have instantiated `PrismaClient`, you can start sending queries in your code:

```ts
// run inside `async` function
const newUser = await prisma.user.create({
  data: {
    name: "Alice",
    email: "alice@prisma.io",
  },
});

const users = await prisma.user.findMany();
```

## Evolving your application [#evolving-your-application]

Whenever you make changes to your database that are reflected in the Prisma schema, you need to manually re-generate Prisma Client to update the generated code in your output directory:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

## Related pages

- [`Configuring error formatting`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/error-formatting): This page explains how to configure the formatting of errors when using Prisma Client
- [`Custom model and field names`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names): Learn how you can decouple the naming of Prisma models from database tables to improve the ergonomics of the generated Prisma Client API
- [`Database connections`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections): Learn how to manage database connections and configure connection pools
- [`Database polyfills`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/database-polyfills): Prisma Client provides features that are not achievable with relational databases. These features are referred to as "polyfills" and explained on this page.
- [`Generating Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client): Learn when and how to run prisma generate, configure the generator output, and import the generated client in your app.

# Read replicas (Prisma ORM v7) (/docs/orm/v7/prisma-client/setup-and-configuration/read-replicas)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to set up and use read replicas with Prisma Client

Location: ORM > v7 > Prisma Client > Setup and Configuration > Read replicas

Read replicas enable you to distribute workloads across database replicas for high-traffic workloads. The [read replicas extension](https://github.com/prisma/extension-read-replicas), `@prisma/extension-read-replicas`, adds support for read-only database replicas to Prisma Client.

If you run into a bug or have feedback, create a GitHub issue in [the `prisma/extension-read-replicas` repository](https://github.com/prisma/extension-read-replicas/issues/new).

## Setup the read replicas extension [#setup-the-read-replicas-extension]

Install the extension:

  

#### bun

```bash
bun add @prisma/extension-read-replicas@latest
```

#### pnpm

```bash
pnpm add @prisma/extension-read-replicas@latest
```

#### yarn

```bash
yarn add @prisma/extension-read-replicas@latest
```

#### npm

```bash
npm install @prisma/extension-read-replicas@latest
```

Initialize the extension by extending your Prisma Client instance and provide the extension with full `PrismaClient` instances for your read replicas. The default approach is to use driver adapters:

```ts
import { readReplicas } from "@prisma/extension-read-replicas";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "./generated/prisma/client";

// Create main client with adapter
const mainAdapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

const mainClient = new PrismaClient({ adapter: mainAdapter });

// Create replica client with adapter
const replicaAdapter = new PrismaPg({
  connectionString: process.env.REPLICA_URL!,
});

const replicaClient = new PrismaClient({ adapter: replicaAdapter });

// Extend main client with read replicas
const prisma = mainClient.$extends(readReplicas({ replicas: [replicaClient] }));

// Query is run against the database replica
await prisma.post.findMany();

// Query is run against the primary database
await prisma.post.create({
  data: {
    /** */
  },
});
```

All read operations (e.g. `findMany`) are executed against the database replica. All write operations (e.g. `create`, `update`) and `$transaction` queries are executed against your primary database.

## Configure multiple database replicas [#configure-multiple-database-replicas]

The `replicas` property accepts an array of `PrismaClient` instances for all your database replicas:

```ts
import { readReplicas } from "@prisma/extension-read-replicas";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "./generated/prisma/client";

// Create main client
const mainAdapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});
const mainClient = new PrismaClient({ adapter: mainAdapter });

// Create multiple replica clients
const replicaAdapter1 = new PrismaPg({
  connectionString: process.env.DATABASE_URL_REPLICA_1!,
});
const replicaClient1 = new PrismaClient({ adapter: replicaAdapter1 });

const replicaAdapter2 = new PrismaPg({
  connectionString: process.env.DATABASE_URL_REPLICA_2!,
});
const replicaClient2 = new PrismaClient({ adapter: replicaAdapter2 });

// Configure multiple replicas
const prisma = mainClient.$extends(
  readReplicas({
    replicas: [replicaClient1, replicaClient2],
  }),
);
```

If you have more than one read replica configured, a database replica will be randomly selected to execute your query.

## Executing read operations against your primary database [#executing-read-operations-against-your-primary-database]

You can use the `$primary()` method to explicitly execute a read operation against your primary database:

```ts
const posts = await prisma.$primary().post.findMany();
```

## Executing operations against a database replica [#executing-operations-against-a-database-replica]

You can use the `$replica()` method to explicitly execute your query against a replica instead of your primary database:

```ts
const result = await prisma.$replica().user.findFirst(...)
```

## Related pages

- [`Configuring error formatting`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/error-formatting): This page explains how to configure the formatting of errors when using Prisma Client
- [`Custom model and field names`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names): Learn how you can decouple the naming of Prisma models from database tables to improve the ergonomics of the generated Prisma Client API
- [`Database connections`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections): Learn how to manage database connections and configure connection pools
- [`Database polyfills`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/database-polyfills): Prisma Client provides features that are not achievable with relational databases. These features are referred to as "polyfills" and explained on this page.
- [`Generating Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client): Learn when and how to run prisma generate, configure the generator output, and import the generated client in your app.

# Composite types (Prisma ORM v7) (/docs/orm/v7/prisma-client/special-fields-and-types/composite-types)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Work with composite types and embedded documents in MongoDB

Location: ORM > v7 > Prisma Client > Special Fields and Types > Composite types

> [!WARNING]
> Composite types are only available with MongoDB.

[Composite types](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models), known as [embedded documents](https://www.mongodb.com/docs/manual/data-modeling/#embedded-data) in MongoDB, allow you to embed records within other records.

This page explains how to:

* [find](#finding-records-that-contain-composite-types-with-find-and-findmany) records that contain composite types using `findFirst` and `findMany`
* [create](#creating-records-with-composite-types-using-create-and-createmany) new records with composite types using `create` and `createMany`
* [update](#changing-composite-types-within-update-and-updatemany) composite types within existing records using `update` and `updateMany`
* [delete](#deleting-records-that-contain-composite-types-with-delete-and-deletemany) records with composite types using `delete` and `deleteMany`

## Example schema [#example-schema]

We’ll use this schema for the examples that follow:

```prisma title="schema.prisma" showLineNumbers
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

model Product {
  id     String  @id @default(auto()) @map("_id") @db.ObjectId
  name   String  @unique
  price  Float
  colors Color[]
  sizes  Size[]
  photos Photo[]
  orders Order[]
}

model Order {
  id              String   @id @default(auto()) @map("_id") @db.ObjectId
  product         Product  @relation(fields: [productId], references: [id])
  color           Color
  size            Size
  shippingAddress Address
  billingAddress  Address?
  productId       String   @db.ObjectId
}

enum Color {
  Red
  Green
  Blue
}

enum Size {
  Small
  Medium
  Large
  XLarge
}

type Photo {
  height Int    @default(200)
  width  Int    @default(100)
  url    String
}

type Address {
  street String
  city   String
  zip    String
}
```

In this schema, the `Product` model has a `Photo[]` composite type, and the `Order` model has two composite `Address` types. The `shippingAddress` is required, but the `billingAddress` is optional.

## Considerations when using composite types [#considerations-when-using-composite-types]

There are currently some limitations when using composite types in Prisma Client:

* [`findUnique()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#findunique) can't filter on composite types
* [`aggregate`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#aggregate), [`groupBy()`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#group-by), [`count`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#count) don’t support composite operations

## Default values for required fields on composite types [#default-values-for-required-fields-on-composite-types]

When you carry out a database read on a composite type and all of the following conditions are true, Prisma Client inserts the default value into the result:

* A field on the composite type is [required](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#optional-and-mandatory-fields), and
* this field has a [default value](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-a-default-value), and
* this field is not present in the returned document or documents.

Note:

* This is the same behavior as with [model fields](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types).
* On read operations, Prisma Client inserts the default value into the result, but does not insert the default value into the database.

In our example schema, suppose that you add a required field to `photo`. This field, `bitDepth`, has a default value:

```prisma title="schema.prisma" highlight=4;add
...
type Photo {
  ...
  bitDepth Int @default(8) // [!code ++]
}

...
```

Suppose that you then run `npx prisma db push` to [update your database](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-push) and regenerate your Prisma Client with `npx prisma generate`. Then, you run the following application code:

```ts
console.dir(await prisma.product.findMany({}), { depth: Infinity });
```

The `bitDepth` field has no content because you have only just added this field, so the query returns the default value of `8`.

## Finding records that contain composite types with `find` and `findMany` [#finding-records-that-contain-composite-types-with-find-and-findmany]

Records can be filtered by a composite type within the `where` operation.

The following section describes the operations available for filtering by a single type or multiple types, and gives examples of each.

### Filtering for one composite type [#filtering-for-one-composite-type]

Use the `is`, `equals`, `isNot` and `isSet` operations to change a single composite type:

* `is&#x60;: Filter results by matching composite types. Requires one or more fields to be present &#x2A;(e.g. Filter orders by the street name on the shipping address)*
* `equals&#x60;: Filter results by matching composite types. Requires all fields to be present. &#x2A;(e.g. Filter orders by the full shipping address)*
* `isNot`: Filter results by non-matching composite types
* `isSet` : Filter optional fields to include only results that have been set (either set to a value, or explicitly set to `null`). Setting this filter to `true` will exclude `undefined` results that are not set at all.

For example, use `is` to filter for orders with a street name of `'555 Candy Cane Lane'`:

```ts
const orders = await prisma.order.findMany({
  where: {
    shippingAddress: {
      is: {
        street: "555 Candy Cane Lane",
      },
    },
  },
});
```

Use `equals` to filter for orders which match on all fields in the shipping address:

```ts
const orders = await prisma.order.findMany({
  where: {
    shippingAddress: {
      equals: {
        street: "555 Candy Cane Lane",
        city: "Wonderland",
        zip: "52337",
      },
    },
  },
});
```

You can also use a shorthand notation for this query, where you leave out the `equals`:

```ts
const orders = await prisma.order.findMany({
  where: {
    shippingAddress: {
      street: "555 Candy Cane Lane",
      city: "Wonderland",
      zip: "52337",
    },
  },
});
```

Use `isNot` to filter for orders that do not have a `zip` code of `'52337'`:

```ts
const orders = await prisma.order.findMany({
  where: {
    shippingAddress: {
      isNot: {
        zip: "52337",
      },
    },
  },
});
```

Use `isSet` to filter for orders where the optional `billingAddress` has been set (either to a value or to `null`):

```ts
const orders = await prisma.order.findMany({
  where: {
    billingAddress: {
      isSet: true,
    },
  },
});
```

### Filtering for many composite types [#filtering-for-many-composite-types]

Use the `equals`, `isEmpty`, `every`, `some` and `none` operations to filter for multiple composite types:

* `equals`: Checks exact equality of the list
* `isEmpty`: Checks if the list is empty
* `every`: Every item in the list must match the condition
* `some`: One or more of the items in the list must match the condition
* `none`: None of the items in the list can match the condition
* `isSet` : Filter optional fields to include only results that have been set (either set to a value, or explicitly set to `null`). Setting this filter to `true` will exclude `undefined` results that are not set at all.

For example, you can use `equals` to find products with a specific list of photos (all `url`, `height` and `width` fields must match):

```ts
const product = prisma.product.findMany({
  where: {
    photos: {
      equals: [
        {
          url: "1.jpg",
          height: 200,
          width: 100,
        },
        {
          url: "2.jpg",
          height: 200,
          width: 100,
        },
      ],
    },
  },
});
```

You can also use a shorthand notation for this query, where you leave out the `equals` and specify just the fields that you want to filter for:

```ts
const product = prisma.product.findMany({
  where: {
    photos: [
      {
        url: "1.jpg",
        height: 200,
        width: 100,
      },
      {
        url: "2.jpg",
        height: 200,
        width: 100,
      },
    ],
  },
});
```

Use `isEmpty` to filter for products with no photos:

```ts
const product = prisma.product.findMany({
  where: {
    photos: {
      isEmpty: true,
    },
  },
});
```

Use `some` to filter for products where one or more photos has a `url` of `"2.jpg"`:

```ts
const product = prisma.product.findFirst({
  where: {
    photos: {
      some: {
        url: "2.jpg",
      },
    },
  },
});
```

Use `none` to filter for products where no photos have a `url` of `"2.jpg"`:

```ts
const product = prisma.product.findFirst({
  where: {
    photos: {
      none: {
        url: "2.jpg",
      },
    },
  },
});
```

## Creating records with composite types using `create` and `createMany` [#creating-records-with-composite-types-using-create-and-createmany]

> [!NOTE]
> When you create a record with a composite type that has a unique constraint, note that MongoDB does not enforce unique values inside a record. Learn more about [duplicate values in unique fields of composite types](#duplicate-values-in-unique-fields-of-composite-types).

Composite types can be created within a `create` or `createMany` method using the `set` operation. For example, you can use `set` within `create` to create an `Address` composite type inside an `Order`:

```ts
const order = await prisma.order.create({
  data: {
    // Normal relation
    product: { connect: { id: "some-object-id" } },
    color: "Red",
    size: "Large",
    // Composite type
    shippingAddress: {
      set: {
        street: "1084 Candycane Lane",
        city: "Silverlake",
        zip: "84323",
      },
    },
  },
});
```

You can also use a shorthand notation where you leave out the `set` and specify just the fields that you want to create:

```ts
const order = await prisma.order.create({
  data: {
    // Normal relation
    product: { connect: { id: "some-object-id" } },
    color: "Red",
    size: "Large",
    // Composite type
    shippingAddress: {
      street: "1084 Candycane Lane",
      city: "Silverlake",
      zip: "84323",
    },
  },
});
```

For an optional type, like the `billingAddress`, you can also set the value to `null`:

```ts
const order = await prisma.order.create({
  data: {
    // Normal relation
    product: { connect: { id: "some-object-id" } },
    color: "Red",
    size: "Large",
    // Composite type
    shippingAddress: {
      street: "1084 Candycane Lane",
      city: "Silverlake",
      zip: "84323",
    },
    // Embedded optional type, set to null
    billingAddress: {
      set: null,
    },
  },
});
```

To model the case where an `product` contains a list of multiple `photos`, you can `set` multiple composite types at once:

```ts
const product = await prisma.product.create({
  data: {
    name: "Forest Runners",
    price: 59.99,
    colors: ["Red", "Green"],
    sizes: ["Small", "Medium", "Large"],
    // New composite type
    photos: {
      set: [
        { height: 100, width: 200, url: "1.jpg" },
        { height: 100, width: 200, url: "2.jpg" },
      ],
    },
  },
});
```

You can also use a shorthand notation where you leave out the `set` and specify just the fields that you want to create:

```ts
const product = await prisma.product.create({
  data: {
    name: "Forest Runners",
    price: 59.99,
    // Scalar lists that we already support
    colors: ["Red", "Green"],
    sizes: ["Small", "Medium", "Large"],
    // New composite type
    photos: [
      { height: 100, width: 200, url: "1.jpg" },
      { height: 100, width: 200, url: "2.jpg" },
    ],
  },
});
```

These operations also work within the `createMany` method. For example, you can create multiple `product`s which each contain a list of `photos`:

```ts
const product = await prisma.product.createMany({
  data: [
    {
      name: "Forest Runners",
      price: 59.99,
      colors: ["Red", "Green"],
      sizes: ["Small", "Medium", "Large"],
      photos: [
        { height: 100, width: 200, url: "1.jpg" },
        { height: 100, width: 200, url: "2.jpg" },
      ],
    },
    {
      name: "Alpine Blazers",
      price: 85.99,
      colors: ["Blue", "Red"],
      sizes: ["Large", "XLarge"],
      photos: [
        { height: 100, width: 200, url: "1.jpg" },
        { height: 150, width: 200, url: "4.jpg" },
        { height: 200, width: 200, url: "5.jpg" },
      ],
    },
  ],
});
```

## Changing composite types within `update` and `updateMany` [#changing-composite-types-within-update-and-updatemany]

> [!NOTE]
> When you update a record with a composite type that has a unique constraint, note that MongoDB does not enforce unique values inside a record. Learn more about [duplicate values in unique fields of composite types](#duplicate-values-in-unique-fields-of-composite-types).

Composite types can be set, updated or removed within an `update` or `updateMany` method. The following section describes the operations available for updating a single type or multiple types at once, and gives examples of each.

### Changing a single composite type [#changing-a-single-composite-type]

Use the `set`, `unset` `update` and `upsert` operations to change a single composite type:

* Use `set` to set a composite type, overriding any existing value
* Use `unset` to unset a composite type. Unlike `set: null`, `unset` removes the field entirely
* Use `update` to update a composite type
* Use `upsert` to `update` an existing composite type if it exists, and otherwise `set` the composite type

For example, use `update` to update a required `shippingAddress` with an `Address` composite type inside an `Order`:

```ts
const order = await prisma.order.update({
  where: {
    id: "some-object-id",
  },
  data: {
    shippingAddress: {
      // Update just the zip field
      update: {
        zip: "41232",
      },
    },
  },
});
```

For an optional embedded type, like the `billingAddress`, use `upsert` to create a new record if it does not exist, and update the record if it does:

```ts
const order = await prisma.order.update({
  where: {
    id: "some-object-id",
  },
  data: {
    billingAddress: {
      // Create the address if it doesn't exist,
      // otherwise update it
      upsert: {
        set: {
          street: "1084 Candycane Lane",
          city: "Silverlake",
          zip: "84323",
        },
        update: {
          zip: "84323",
        },
      },
    },
  },
});
```

You can also use the `unset` operation to remove an optional embedded type. The following example uses `unset` to remove the `billingAddress` from an `Order`:

```ts
const order = await prisma.order.update({
  where: {
    id: "some-object-id",
  },
  data: {
    billingAddress: {
      // Unset the billing address
      // Removes "billingAddress" field from order
      unset: true,
    },
  },
});
```

You can use [filters](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/composite-types#finding-records-that-contain-composite-types-with-find-and-findmany) within `updateMany` to update all records that match a composite type. The following example uses the `is` filter to match the street name from a shipping address on a list of orders:

```ts
const orders = await prisma.order.updateMany({
  where: {
    shippingAddress: {
      is: {
        street: "555 Candy Cane Lane",
      },
    },
  },
  data: {
    shippingAddress: {
      update: {
        street: "111 Candy Cane Drive",
      },
    },
  },
});
```

### Changing multiple composite types [#changing-multiple-composite-types]

Use the `set`, `push`, `updateMany` and `deleteMany` operations to change a list of composite types:

* `set`: Set an embedded list of composite types, overriding any existing list
* `push`: Push values to the end of an embedded list of composite types
* `updateMany`: Update many composite types at once
* `deleteMany`: Delete many composite types at once

For example, use `push` to add a new photo to the `photos` list:

```ts
const product = prisma.product.update({
  where: {
    id: "62de6d328a65d8fffdae2c18",
  },
  data: {
    photos: {
      // Push a photo to the end of the photos list
      push: [{ height: 100, width: 200, url: "1.jpg" }],
    },
  },
});
```

Use `updateMany` to update photos with a `url` of `1.jpg` or `2.png`:

```ts
const product = prisma.product.update({
  where: {
    id: "62de6d328a65d8fffdae2c18",
  },
  data: {
    photos: {
      updateMany: {
        where: {
          url: "1.jpg",
        },
        data: {
          url: "2.png",
        },
      },
    },
  },
});
```

The following example uses `deleteMany` to delete all photos with a `height` of 100:

```ts
const product = prisma.product.update({
  where: {
    id: "62de6d328a65d8fffdae2c18",
  },
  data: {
    photos: {
      deleteMany: {
        where: {
          height: 100,
        },
      },
    },
  },
});
```

## Upserting composite types with `upsert` [#upserting-composite-types-with-upsert]

> [!NOTE]
> When you create or update the values in a composite type that has a unique constraint, note that MongoDB does not enforce unique values inside a record. Learn more about [duplicate values in unique fields of composite types](#duplicate-values-in-unique-fields-of-composite-types).

To create or update a composite type, use the `upsert` method. You can use the same composite operations as the `create` and `update` methods above.

For example, use `upsert` to either create a new product or add a photo to an existing product:

```ts
const product = await prisma.product.upsert({
  where: {
    name: "Forest Runners",
  },
  create: {
    name: "Forest Runners",
    price: 59.99,
    colors: ["Red", "Green"],
    sizes: ["Small", "Medium", "Large"],
    photos: [
      { height: 100, width: 200, url: "1.jpg" },
      { height: 100, width: 200, url: "2.jpg" },
    ],
  },
  update: {
    photos: {
      push: { height: 300, width: 400, url: "3.jpg" },
    },
  },
});
```

## Deleting records that contain composite types with `delete` and `deleteMany` [#deleting-records-that-contain-composite-types-with-delete-and-deletemany]

To remove records which embed a composite type, use the `delete` or `deleteMany` methods. This will also remove the embedded composite type.

For example, use `deleteMany` to delete all products with a `size` of `"Small"`. This will also delete any embedded `photos`.

```ts
const deleteProduct = await prisma.product.deleteMany({
  where: {
    sizes: {
      equals: "Small",
    },
  },
});
```

You can also use [filters](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/composite-types#finding-records-that-contain-composite-types-with-find-and-findmany) to delete records that match a composite type. The example below uses the `some` filter to delete products that contain a certain photo:

```ts
const product = await prisma.product.deleteMany({
  where: {
    photos: {
      some: {
        url: "2.jpg",
      },
    },
  },
});
```

## Ordering composite types [#ordering-composite-types]

You can use the `orderBy` operation to sort results in ascending or descending order.

For example, the following command finds all orders and orders them by the city name in the shipping address, in ascending order:

```ts
const orders = await prisma.order.findMany({
  orderBy: {
    shippingAddress: {
      city: "asc",
    },
  },
});
```

## Duplicate values in unique fields of composite types [#duplicate-values-in-unique-fields-of-composite-types]

Be careful when you carry out any of the following operations on a record with a composite type that has a unique constraint. In this situation, MongoDB does not enforce unique values inside a record.

* When you create the record
* When you add data to the record
* When you update data in the record

If your schema has a composite type with a `@@unique` constraint, MongoDB prevents you from storing the same value for the constrained value in two or more of the records that contain this composite type. However, MongoDB does not prevent you from storing multiple copies of the same field value in a single record.

Note that you can [use Prisma ORM relations to work around this issue](#use-prisma-orm-relations-to-enforce-unique-values-in-a-record).

For example, in the following schema, `MailBox` has a composite type, `addresses`, which has a `@@unique` constraint on the `email` field.

```prisma
type Address {
  email String
}

model MailBox {
  name      String
  addresses Address[]

  @@unique([addresses.email])
}
```

The following code creates a record with two identical values in `address`. MongoDB does not throw an error in this situation, and it stores `alice@prisma.io` in `addresses` twice.

```ts
await prisma.MailBox.createMany({
  data: [
    {
      name: "Alice",
      addresses: {
        set: [
          {
            address: "alice@prisma.io", // Not unique
          },
          {
            address: "alice@prisma.io", // Not unique
          },
        ],
      },
    },
  ],
});
```

Note: MongoDB throws an error if you try to store the same value in two separate records. In our example above, if you try to store the email address `alice@prisma.io` for the user Alice and for the user Bob, MongoDB does not store the data and throws an error.

### Use Prisma ORM relations to enforce unique values in a record [#use-prisma-orm-relations-to-enforce-unique-values-in-a-record]

In the example above, MongoDB did not enforce the unique constraint on a nested address name. However, you can model your data differently to enforce unique values in a record. To do so, use Prisma ORM [relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations) to turn the composite type into a collection. Set a relationship to this collection and place a unique constraint on the field that you want to be unique.

In the following example, MongoDB enforces unique values in a record. There is a relation between `Mailbox` and the `Address` model. Also, the `name` field in the `Address` model has a unique constraint.

```prisma
model Address {
  id        String   @id @default(auto()) @map("_id") @db.ObjectId
  name      String
  mailbox   Mailbox? @relation(fields: [mailboxId], references: [id])
  mailboxId String?  @db.ObjectId

  @@unique([name])
}

model Mailbox {
  id        String    @id @default(auto()) @map("_id") @db.ObjectId
  name      String
  addresses Address[] @relation
}
```

```ts
await prisma.MailBox.create({
  data: {
    name: "Alice",
    addresses: {
      create: [
        { name: "alice@prisma.io" }, // Not unique
        { name: "alice@prisma.io" }, // Not unique
      ],
    },
  },
});
```

If you run the above code, MongoDB enforces the unique constraint. It does not allow your application to add two addresses with the name `alice@prisma.io`.

## Related pages

- [`Null and undefined`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/null-and-undefined): How Prisma Client handles null and undefined
- [`Working with compound IDs and unique constraints`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-composite-ids-and-constraints): How to read, write, and filter by compound IDs and unique constraints
- [`Working with Json fields`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-json-fields): How to read, write, and filter by Json fields
- [`Working with scalar lists`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-scalar-lists-arrays): How to read, write, and filter by scalar lists / arrays

# Fields & types (Prisma ORM v7) (/docs/orm/v7/prisma-client/special-fields-and-types)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use about special fields and types with Prisma Client

Location: ORM > v7 > Prisma Client > Fields & types

This section covers various special fields and types you can use with Prisma Client.

## Working with `Decimal` [#working-with-decimal]

`Decimal` fields are represented by the [`Decimal.js` library](https://mikemcl.github.io/decimal.js/). The following example demonstrates how to import and use `Prisma.Decimal`:

```ts
import { PrismaClient, Prisma } from "@prisma/client";

const newTypes = await prisma.sample.create({
  data: {
    cost: new Prisma.Decimal(24.454545),
  },
});
```

<br />

You can also perform arithmetic operations:

```ts
import { PrismaClient, Prisma } from "@prisma/client";

const newTypes = await prisma.sample.create({
  data: {
    cost: new Prisma.Decimal(24.454545).plus(1),
  },
});
```

`Prisma.Decimal` uses Decimal.js, see [Decimal.js docs](https://mikemcl.github.io/decimal.js) to learn more.

> [!WARNING]
> The use of the `Decimal` field [is not currently supported in MongoDB](https://github.com/prisma/orm/issues/12637).

## Working with `BigInt` [#working-with-bigint]

### Overview [#overview]

`BigInt` fields are represented by the [`BigInt` type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) (Node.js 10.4.0+ required). The following example demonstrates how to use the `BigInt` type:

```ts
import { PrismaClient, Prisma } from "@prisma/client";

const newTypes = await prisma.sample.create({
  data: {
    revenue: BigInt(534543543534),
  },
});
```

### Serializing `BigInt` [#serializing-bigint]

Prisma Client returns records as plain JavaScript objects. If you attempt to use `JSON.stringify` on an object that includes a `BigInt` field, you will see the following error:

```
Do not know how to serialize a BigInt
```

To work around this issue, use a customized implementation of `JSON.stringify`:

```js
JSON.stringify(
  this,
  (key, value) => (typeof value === "bigint" ? value.toString() : value), // return everything else unchanged
);
```

## Working with `Bytes` [#working-with-bytes]

`Bytes` fields are represented by the [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) type. The following example demonstrates how to use the `Uint8Array` type:

```ts
import { PrismaClient, Prisma } from "@prisma/client";

const newTypes = await prisma.sample.create({
  data: {
    myField: new Uint8Array([1, 2, 3, 4]),
  },
});
```

## Working with `DateTime` [#working-with-datetime]

> [!NOTE]
> There currently is a [bug](https://github.com/prisma/orm/issues/9516) that doesn't allow you to pass in `DateTime` values as strings and produces a runtime error when you do. `DateTime` values need to be passed as [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) objects (i.e. `new Date('2024-12-04')` instead of `'2024-12-04'`).

When creating records that have fields of type [`DateTime`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#datetime), Prisma Client accepts values as [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) objects adhering to the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard.

Consider the following schema:

```prisma
model User {
  id        Int       @id @default(autoincrement())
  birthDate DateTime?
}
```

Here are some examples for creating new records:

##### Jan 01, 1998; 00 h 00 min and 000 ms [#jan-01-1998-00-h-00-min-and-000-ms]

```ts
await prisma.user.create({
  data: {
    birthDate: new Date("1998"),
  },
});
```

##### Dec 01, 1998; 00 h 00 min and 000 ms [#dec-01-1998-00-h-00-min-and-000-ms]

```ts
await prisma.user.create({
  data: {
    birthDate: new Date("1998-12"),
  },
});
```

##### Dec 24, 1998; 00 h 00 min and 000 ms [#dec-24-1998-00-h-00-min-and-000-ms]

```ts
await prisma.user.create({
  data: {
    birthDate: new Date("1998-12-24"),
  },
});
```

##### Dec 24, 1998; 06 h 22 min 33s and 444 ms [#dec-24-1998-06-h-22-min-33s-and-444-ms]

```ts
await prisma.user.create({
  data: {
    birthDate: new Date("1998-12-24T06:22:33.444Z"),
  },
});
```

## Related pages

- [`Type safety Overview`](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety): Prisma Client provides full type safety for queries, even for partial queries or included relations. This page explains how to leverage the generated types and utilities
- [`What are Client Extensions`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions): Extend the functionality of Prisma Client
- [`Write your own SQL`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql): Learn how to use raw SQL queries in Prisma Client

# Null and undefined (Prisma ORM v7) (/docs/orm/v7/prisma-client/special-fields-and-types/null-and-undefined)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How Prisma Client handles null and undefined

Location: ORM > v7 > Prisma Client > Special Fields and Types > Null and undefined

> [!WARNING]
> In Prisma ORM, if `undefined` is passed as a value, it is not included in the generated query. This behavior can lead to unexpected results and data loss. We strongly recommend enabling the `strictUndefinedChecks` preview feature described below.
> 
> For documentation on the current behavior (without the `strictUndefinedChecks` Preview feature) see [current behavior](#current-behavior).

## Strict undefined checks (Preview feature) [#strict-undefined-checks-preview-feature]

The `strictUndefinedChecks` preview feature changes how Prisma Client handles `undefined` values, offering better protection against accidental data loss or unintended query behavior.

### Enabling strict undefined checks [#enabling-strict-undefined-checks]

To enable this feature, add the following to your Prisma schema:

```prisma
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["strictUndefinedChecks"]
}
```

### Using strict undefined checks [#using-strict-undefined-checks]

When this feature is enabled:

1. Explicitly setting a field to `undefined` in a query will cause a runtime error.
2. To skip a field in a query, use the new `Prisma.skip` symbol instead of `undefined`.

Example usage:

```typescript
// This will throw an error
prisma.user.create({
  data: {
    name: "Alice",
    email: undefined, // Error: Cannot explicitly use undefined here
  },
});

// Use `Prisma.skip` (a symbol provided by Prisma) to omit a field
prisma.user.create({
  data: {
    name: "Alice",
    email: Prisma.skip, // This field will be omitted from the query
  },
});
```

This change helps prevent accidental deletions or updates, such as:

```typescript
// Before: This would delete all users
prisma.user.deleteMany({
  where: {
    id: undefined
  }
})

// After: This will throw an error
Invalid \`prisma.user.deleteMany()\` invocation in
/client/tests/functional/strictUndefinedChecks/test.ts:0:0
  XX })
  XX
  XX test('throws on undefined input field', async () => {
→ XX   const result = prisma.user.deleteMany({
         where: {
           id: undefined
               ~~~~~~~~~
         }
       })
Invalid value for argument \`where\`: explicitly \`undefined\` values are not allowed."
```

### Migration path [#migration-path]

To migrate existing code:

```typescript
// Before
let optionalEmail: string | undefined;

prisma.user.create({
  data: {
    name: "Alice",
    email: optionalEmail,
  },
});

// After
prisma.user.create({
  data: {
    name: "Alice",
    email: optionalEmail ?? Prisma.skip, // [!code highlight]
  },
});
```

### `exactOptionalPropertyTypes` [#exactoptionalpropertytypes]

In addition to `strictUndefinedChecks`, we also recommend enabling the TypeScript compiler option `exactOptionalPropertyTypes`. This option enforces that optional properties must match exactly, which can help catch potential issues with `undefined` values in your code. While `strictUndefinedChecks` will raise runtime errors for invalid `undefined` usage, `exactOptionalPropertyTypes` will catch these issues during the build process.

Learn more about `exactOptionalPropertyTypes` in the [TypeScript documentation](https://www.typescriptlang.org/tsconfig/#exactOptionalPropertyTypes).

### Feedback [#feedback]

As always, we welcome your feedback on this feature. Please share your thoughts and suggestions in the [GitHub discussion for this Preview feature](https://github.com/prisma/orm/discussions/25271).

## current behavior [#current-behavior]

Prisma Client differentiates between `null` and `undefined`:

* `null` is a **value**
* `undefined` means **do nothing**

> [!NOTE]
> This is particularly important to account for in [a **Prisma ORM with GraphQL context**, where `null` and `undefined` are interchangeable](#null-and-undefined-in-a-graphql-resolver).

The data below represents a `User` table. This set of data will be used in all of the examples below:

| id | name    | email                                          |
| -- | ------- | ---------------------------------------------- |
| 1  | Nikolas | [nikolas@gmail.com](mailto\:nikolas@gmail.com) |
| 2  | Martin  | [martin@gmail.com](mailto\:martin@gmail.com)   |
| 3  | *empty* | [sabin@gmail.com](mailto\:sabin@gmail.com)     |
| 4  | Tyler   | [tyler@gmail.com](mailto\:tyler@gmail.com)     |

### `null` and `undefined` in queries that affect *many* records [#null-and-undefined-in-queries-that-affect-many-records]

This section will cover how `undefined` and `null` values affect the behavior of queries that interact with or create multiple records in a database.

#### Null [#null]

Consider the following Prisma Client query which searches for all users whose `name` value matches the provided `null` value:

```ts
const users = await prisma.user.findMany({
  where: {
    name: null,
  },
});
```

```json
[
  {
    "id": 3,
    "name": null,
    "email": "sabin@gmail.com"
  }
]
```

Because `null` was provided as the filter for the `name` column, Prisma Client will generate a query that searches for all records in the `User` table whose `name` column is *empty*.

#### Undefined [#undefined]

Now consider the scenario where you run the same query with `undefined` as the filter value on the `name` column:

```ts
const users = await prisma.user.findMany({
  where: {
    name: undefined,
  },
});
```

```json
[
  {
    "id": 1,
    "name": "Nikolas",
    "email": "nikolas@gmail.com"
  },
  {
    "id": 2,
    "name": "Martin",
    "email": "martin@gmail.com"
  },
  {
    "id": 3,
    "name": null,
    "email": "sabin@gmail.com"
  },
  {
    "id": 4,
    "name": "Tyler",
    "email": "tyler@gmail.com"
  }
]
```

Using `undefined` as a value in a filter essentially tells Prisma Client you have decided *not to define a filter* for that column.

An equivalent way to write the above query would be:

```ts
const users = await prisma.user.findMany();
```

This query will select every row from the `User` table.

> [!NOTE]
> Using `undefined` as the value of any key in a Prisma Client query's parameter object will cause Prisma ORM to act as if that key was not provided at all.

Although this section's examples focused on the `findMany` function, the same concepts apply to any function that can affect multiple records, such as `updateMany` and `deleteMany`.

### `null` and `undefined` in queries that affect *one* record [#null-and-undefined-in-queries-that-affect-one-record]

This section will cover how `undefined` and `null` values affect the behavior of queries that interact with or create a single record in a database.

> [!WARNING]
> `null` is not a valid filter value in a `findUnique()` query.

The query behavior when using `null` and `undefined` in the filter criteria of a query that affects a single record is very similar to the behaviors described in the previous section.

#### Null [#null-1]

Consider the following query where `null` is used to filter the `name` column:

```ts
const user = await prisma.user.findFirst({
  where: {
    name: null,
  },
});
```

```json
[
  {
    "id": 3,
    "name": null,
    "email": "sabin@gmail.com"
  }
]
```

Because `null` was used as the filter on the `name` column, Prisma Client will generate a query that searches for the first record in the `User` table whose `name` value is *empty*.

#### Undefined [#undefined-1]

If `undefined` is used as the filter value on the `name` column instead, *the query will act as if no filter criteria was passed to that column at all*.

Consider the query below:

```ts
const user = await prisma.user.findFirst({
  where: {
    name: undefined,
  },
});
```

```json
[
  {
    "id": 1,
    "name": "Nikolas",
    "email": "nikolas@gmail.com"
  }
]
```

In this scenario, the query will return the very first record in the database.

Another way to represent the above query is:

```ts
const user = await prisma.user.findFirst();
```

Although this section's examples focused on the `findFirst` function, the same concepts apply to any function that affects a single record.

### `null` and `undefined` in a GraphQL resolver [#null-and-undefined-in-a-graphql-resolver]

For this example, consider a database based on the following Prisma schema:

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

In the following GraphQL mutation that updates a user, both `authorEmail` and `name` accept `null`. From a GraphQL perspective, this means that fields are **optional**:

```ts
type Mutation {
  // Update author's email or name, or both - or neither!
  updateUser(id: Int!, authorEmail: String, authorName: String): User!
}
```

However, if you pass `null` values for `authorEmail` or `authorName` on to Prisma Client, the following will happen:

* If `args.authorEmail` is `null`, the query will **fail**. `email` does not accept `null`.
* If `args.authorName` is `null`, Prisma Client changes the value of `name` to `null`. This is probably not how you want an update to work.

```ts
updateUser: (parent, args, ctx: Context) => {
  return ctx.prisma.user.update({
    where: { id: Number(args.id) },
    data: {
      email: args.authorEmail, // email cannot be null // [!code highlight]
      name: args.authorName // name set to null - potentially unwanted behavior // [!code highlight]
    },
  })
},
```

Instead, set the value of `email` and `name` to `undefined` if the input value is `null`. Doing this is the same as not updating the field at all:

```ts
updateUser: (parent, args, ctx: Context) => {
  return ctx.prisma.user.update({
    where: { id: Number(args.id) },
    data: {
      email: args.authorEmail != null ? args.authorEmail : undefined, // If null, do nothing // [!code highlight]
      name: args.authorName != null ? args.authorName : undefined // If null, do nothing // [!code highlight]
    },
  })
},
```

### The effect of `null` and `undefined` on conditionals [#the-effect-of-null-and-undefined-on-conditionals]

There are some caveats to filtering with conditionals which might produce unexpected results. When filtering with conditionals you might expect one result but receive another given how Prisma Client treats nullable values.

The following table provides a high-level overview of how the different operators handle 0, 1 and `n` filters.

| Operator | 0 filters         | 1 filter               | n filters            |
| -------- | ----------------- | ---------------------- | -------------------- |
| `OR`     | return empty list | validate single filter | validate all filters |
| `AND`    | return all items  | validate single filter | validate all filters |
| `NOT`    | return all items  | validate single filter | validate all filters |

This example shows how an `undefined` parameter impacts the results returned by a query that uses the [`OR`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#or) operator.

```ts
interface FormData {
  name: string;
  email?: string;
}

const formData: FormData = {
  name: "Emelie",
};

const users = await prisma.user.findMany({
  where: {
    OR: [
      {
        email: {
          contains: formData.email,
        },
      },
    ],
  },
});

// returns: []
```

The query receives filters from a formData object, which includes an optional email property. In this instance, the value of the email property is `undefined`. When this query is run no data is returned.

This is in contrast to the [`AND`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#and) and [`NOT`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference) operators, which will both return all the users
if you pass in an `undefined` value.

> This is because passing an `undefined` value to an `AND` or `NOT` operator is the same
> as passing nothing at all, meaning the `findMany` query in the example will run without any filters and return all the users.

```ts
interface FormData {
  name: string;
  email?: string;
}

const formData: FormData = {
  name: "Emelie",
};

const users = await prisma.user.findMany({
  where: {
    AND: [
      {
        email: {
          contains: formData.email,
        },
      },
    ],
  },
});

// returns: { id: 1, email: 'ems@boop.com', name: 'Emelie' }

const users = await prisma.user.findMany({
  where: {
    NOT: [
      {
        email: {
          contains: formData.email,
        },
      },
    ],
  },
});

// returns: { id: 1, email: 'ems@boop.com', name: 'Emelie' }
```

## Related pages

- [`Composite types`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/composite-types): Work with composite types and embedded documents in MongoDB
- [`Working with compound IDs and unique constraints`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-composite-ids-and-constraints): How to read, write, and filter by compound IDs and unique constraints
- [`Working with Json fields`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-json-fields): How to read, write, and filter by Json fields
- [`Working with scalar lists`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-scalar-lists-arrays): How to read, write, and filter by scalar lists / arrays

# Working with compound IDs and unique constraints (Prisma ORM v7) (/docs/orm/v7/prisma-client/special-fields-and-types/working-with-composite-ids-and-constraints)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to read, write, and filter by compound IDs and unique constraints

Location: ORM > v7 > Prisma Client > Special Fields and Types > Working with compound IDs and unique constraints

Composite IDs and compound unique constraints can be defined in your Prisma schema using the [`@@id`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) and [`@@unique`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) attributes.

> [!WARNING]
> **MongoDB does not support `@@id`**<br />
> MongoDB does not support composite IDs, which means you cannot identify a model with a `@@id` attribute.

A composite ID or compound unique constraint uses the combined values of two fields as a primary key or identifier in your database table. In the following example, the `postId` field and `userId` field are used as a composite ID for a `Like` table:

```prisma highlight=22;normal
model User {
  id    Int    @id @default(autoincrement())
  name  String
  post  Post[]
  likes Like[]
}

model Post {
  id      Int    @id @default(autoincrement())
  content String
  User    User?  @relation(fields: [userId], references: [id])
  userId  Int?
  likes   Like[]
}

model Like {
  postId Int
  userId Int
  User   User @relation(fields: [userId], references: [id])
  Post   Post @relation(fields: [postId], references: [id])

  @@id([postId, userId]) // [!code highlight]
}
```

Querying for records from the `Like` table (e.g. using `prisma.like.findMany()`) would return objects that look as follows:

```json
{
  "postId": 1,
  "userId": 1
}
```

Although there are only two fields in the response, those two fields make up a compound ID named `postId_userId`.

You can also create a named compound ID or compound unique constraint by using the `@@id` or `@@unique` attributes' `name` field. For example:

```prisma highlight=7;normal
model Like {
  postId Int
  userId Int
  User   User @relation(fields: [userId], references: [id])
  Post   Post @relation(fields: [postId], references: [id])

  @@id(name: "likeId", [postId, userId]) // [!code highlight]
}
```

## Where you can use compound IDs and unique constraints [#where-you-can-use-compound-ids-and-unique-constraints]

Compound IDs and compound unique constraints can be used when working with *unique* data.

Below is a list of Prisma Client functions that accept a compound ID or compound unique constraint in the `where` filter of the query:

* `findUnique()`
* `findUniqueOrThrow`
* `delete`
* `update`
* `upsert`

A composite ID and a composite unique constraint is also usable when creating relational data with `connect` and `connectOrCreate`.

## Filtering records by a compound ID or unique constraint [#filtering-records-by-a-compound-id-or-unique-constraint]

Although your query results will not display a compound ID or unique constraint as a field, you can use these compound values to filter your queries for unique records:

```ts highlight=3-6;normal
const like = await prisma.like.findUnique({
  where: {
    likeId: {
      userId: 1,
      postId: 1,
    },
  },
});
```

> [!NOTE]
> Note composite ID and compound unique constraint keys are only available as filter options for *unique* queries such as `findUnique()` and `findUniqueOrThrow`. See the [section](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-composite-ids-and-constraints#where-you-can-use-compound-ids-and-unique-constraints) above for a list of places these fields may be used.

## Deleting records by a compound ID or unique constraint [#deleting-records-by-a-compound-id-or-unique-constraint]

A compound ID or compound unique constraint may be used in the `where` filter of a `delete` query:

```ts highlight=3-6;normal
const like = await prisma.like.delete({
  where: {
    likeId: {
      userId: 1,
      postId: 1,
    },
  },
});
```

## Updating and upserting records by a compound ID or unique constraint [#updating-and-upserting-records-by-a-compound-id-or-unique-constraint]

A compound ID or compound unique constraint may be used in the `where` filter of an `update` query:

```ts highlight=3-6;normal
const like = await prisma.like.update({
  where: {
    likeId: {
      userId: 1,
      postId: 1,
    },
  },
  data: {
    postId: 2,
  },
});
```

They may also be used in the `where` filter of an `upsert` query:

```ts highlight=3-6;normal
await prisma.like.upsert({
  where: {
    likeId: {
      userId: 1,
      postId: 1,
    },
  },
  update: {
    userId: 2,
  },
  create: {
    userId: 2,
    postId: 1,
  },
});
```

## Filtering relation queries by a compound ID or unique constraint [#filtering-relation-queries-by-a-compound-id-or-unique-constraint]

Compound IDs and compound unique constraint can also be used in the `connect` and `connectOrCreate` keys used when connecting records to create a relationship.

For example, consider this query:

```ts highlight=6-9;normal
await prisma.user.create({
  data: {
    name: "Alice",
    likes: {
      connect: {
        likeId: {
          postId: 1,
          userId: 2,
        },
      },
    },
  },
});
```

The `likeId` compound ID is used as the identifier in the `connect` object that is used to locate the `Like` table's record that will be linked to the new user: `"Alice"`.

Similarly, the `likeId` can be used in `connectOrCreate`'s `where` filter to attempt to locate an existing record in the `Like` table:

```ts highlight=10-13;normal
await prisma.user.create({
  data: {
    name: "Alice",
    likes: {
      connectOrCreate: {
        create: {
          postId: 1,
        },
        where: {
          likeId: {
            postId: 1,
            userId: 1,
          },
        },
      },
    },
  },
});
```

## Related pages

- [`Composite types`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/composite-types): Work with composite types and embedded documents in MongoDB
- [`Null and undefined`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/null-and-undefined): How Prisma Client handles null and undefined
- [`Working with Json fields`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-json-fields): How to read, write, and filter by Json fields
- [`Working with scalar lists`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-scalar-lists-arrays): How to read, write, and filter by scalar lists / arrays

# Working with Json fields (Prisma ORM v7) (/docs/orm/v7/prisma-client/special-fields-and-types/working-with-json-fields)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to read, write, and filter by Json fields

Location: ORM > v7 > Prisma Client > Special Fields and Types > Working with Json fields

Use the [`Json`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#json) Prisma ORM field type to read, write, and perform basic filtering on JSON types in the underlying database. In the following example, the `User` model has an optional `Json` field named `extendedPetsData`:

```prisma highlight=6;normal
model User {
  id               Int     @id @default(autoincrement())
  email            String  @unique
  name             String?
  posts            Post[]
  extendedPetsData Json? // [!code highlight]
}
```

Example field value:

```json
{
  "pet1": {
    "petName": "Claudine",
    "petType": "House cat"
  },
  "pet2": {
    "petName": "Sunny",
    "petType": "Gerbil"
  }
}
```

The `Json` field supports a few additional types, such as `string` and `boolean`. These additional types exist to match the types supported by [`JSON.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse):

```ts
export type JsonValue = string | number | boolean | null | JsonObject | JsonArray;
```

## Use cases for JSON fields [#use-cases-for-json-fields]

Reasons to store data as JSON rather than representing data as related models include:

* You need to store data that does not have a consistent structure
* You are importing data from another system and do not want to map that data to Prisma models

## Reading a `Json` field [#reading-a-json-field]

You can use the `Prisma.JsonArray` and `Prisma.JsonObject` utility classes to work with the contents of a `Json` field:

```ts
const { PrismaClient, Prisma } = require("@prisma/client");

const user = await prisma.user.findFirst({
  where: {
    id: 9,
  },
});

// Example extendedPetsData data:
// [{ name: 'Bob the dog' }, { name: 'Claudine the cat' }]

if (
  user?.extendedPetsData &&
  typeof user?.extendedPetsData === "object" &&
  Array.isArray(user?.extendedPetsData)
) {
  const petsObject = user?.extendedPetsData as Prisma.JsonArray;

  const firstPet = petsObject[0];
}
```

See also: [Advanced example: Update a nested JSON key value](#advanced-example-update-a-nested-json-key-value)

## Writing to a `Json` field [#writing-to-a-json-field]

The following example writes a JSON object to the `extendedPetsData` field:

```ts
var json = [{ name: "Bob the dog" }, { name: "Claudine the cat" }] as Prisma.JsonArray;

const createUser = await prisma.user.create({
  data: {
    email: "birgitte@prisma.io",
    extendedPetsData: json,
  },
});
```

> **Note**: JavaScript objects (for example, `{ extendedPetsData: "none"}`) are automatically converted to JSON.

See also: [Advanced example: Update a nested JSON key value](#advanced-example-update-a-nested-json-key-value)

## Filter on a `Json` field (simple) [#filter-on-a-json-field-simple]

You can filter rows of `Json` type.

### Filter on exact field value [#filter-on-exact-field-value]

The following query returns all users where the value of `extendedPetsData` matches the `json` variable exactly:

```ts
var json = [{ name: "Bob the dog" }, { name: "Claudine the cat" }];

const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      equals: json,
    },
  },
});
```

The following query returns all users where the value of `extendedPetsData` does **not** match the `json` variable exactly:

```ts
var json = [{ name: "Bob the dog" }, { name: "Claudine the cat" }];

const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      not: json,
    },
  },
});
```

## Filter on a `Json` field (advanced) [#filter-on-a-json-field-advanced]

You can also filter rows by the data inside a `Json` field. We call this **advanced `Json` filtering**. This functionality is supported by [PostgreSQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql) and [MySQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql) only with [different syntaxes for the `path` option](#path-syntax-depending-on-database).

> [!WARNING]
> PostgreSQL does not support [filtering on object key values in arrays](#filtering-on-object-key-value-inside-array).

### `path` syntax depending on database [#path-syntax-depending-on-database]

The filters below use a `path` option to select specific parts of the `Json` value to filter on. The implementation of that filtering differs between connectors:

* The [MySQL connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql) uses [MySQL's implementation of JSON path](https://dev.mysql.com/doc/refman/8.0/en/json.html#json-path-syntax)
* The [PostgreSQL connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql) uses the custom JSON functions and operators [supported in version 12 *and earlier*](https://www.postgresql.org/docs/11/functions-json.html)

For example, the following is a valid MySQL `path` value:

```
$petFeatures.petName
```

The following is a valid PostgreSQL `path` value:

```
["petFeatures", "petName"]
```

### Filter on object property [#filter-on-object-property]

You can filter on a specific property inside a block of JSON. In the following examples, the value of `extendedPetsData` is a one-dimensional, unnested JSON object:

```json highlight=11;normal
{
  "petName": "Claudine",
  "petType": "House cat"
}
```

The following query returns all users where the value of `petName` is `"Claudine"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: ["petName"],
      equals: "Claudine",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: "$.petName",
      equals: "Claudine",
    },
  },
});
```

The following query returns all users where the value of `petType` *contains* `"cat"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: ["petType"],
      string_contains: "cat",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: "$.petType",
      string_contains: "cat",
    },
  },
});
```

The following string filters are available:

* [`string_contains`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#string_contains)
* [`string_starts_with`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#string_starts_with)
* [`string_ends_with`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#string_ends_with) .

To use case insensitive filter with these, you can use the [`mode`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#mode) option:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: ["petType"],
      string_contains: "cat",
      mode: "insensitive",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: "$.petType",
      string_contains: "cat",
      mode: "insensitive",
    },
  },
});
```

### Filter on nested object property [#filter-on-nested-object-property]

You can filter on nested JSON properties. In the following examples, the value of `extendedPetsData` is a JSON object with several levels of nesting.

```json
{
  "pet1": {
    "petName": "Claudine",
    "petType": "House cat"
  },
  "pet2": {
    "petName": "Sunny",
    "petType": "Gerbil",
    "features": {
      "eyeColor": "Brown",
      "furColor": "White and black"
    }
  }
}
```

The following query returns all users where `"pet2"` → `"petName"` is `"Sunny"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: ["pet2", "petName"],
      equals: "Sunny",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: "$.pet2.petName",
      equals: "Sunny",
    },
  },
});
```

The following query returns all users where:

* `"pet2"` → `"petName"` is `"Sunny"`
* `"pet2"` → `"features"` → `"furColor"` contains `"black"`

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    AND: [
      {
        extendedPetsData: {
          path: ["pet2", "petName"],
          equals: "Sunny",
        },
      },
      {
        extendedPetsData: {
          path: ["pet2", "features", "furColor"],
          string_contains: "black",
        },
      },
    ],
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    AND: [
      {
        extendedPetsData: {
          path: "$.pet2.petName",
          equals: "Sunny",
        },
      },
      {
        extendedPetsData: {
          path: "$.pet2.features.furColor",
          string_contains: "black",
        },
      },
    ],
  },
});
```

### Filtering on an array value [#filtering-on-an-array-value]

You can filter on the presence of a specific value in a scalar array (strings, integers). In the following example, the value of `extendedPetsData` is an array of strings:

```json
["Claudine", "Sunny"]
```

The following query returns all users with a pet named `"Claudine"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      array_contains: ["Claudine"],
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      array_contains: "Claudine",
    },
  },
});
```

> [!NOTE]
> In PostgreSQL, the value of `array_contains` must be an array and not a string, even if the array only contains a single value.

The following array filters are available:

* [`array_contains`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#array_contains)
* [`array_starts_with`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#array_starts_with)
* [`array_ends_with`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#array_ends_with)

### Filtering on nested array value [#filtering-on-nested-array-value]

You can filter on the presence of a specific value in a scalar array (strings, integers). In the following examples, the value of `extendedPetsData` includes nested scalar arrays of names:

```json
{
  "cats": { "owned": ["Bob", "Sunny"], "fostering": ["Fido"] },
  "dogs": { "owned": ["Ella"], "fostering": ["Prince", "Empress"] }
}
```

#### Scalar value arrays [#scalar-value-arrays]

The following query returns all users that foster a cat named `"Fido"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: ["cats", "fostering"],
      array_contains: ["Fido"],
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: "$.cats.fostering",
      array_contains: "Fido",
    },
  },
});
```

> [!NOTE]
> In PostgreSQL, the value of `array_contains` must be an array and not a string, even if the array only contains a single value.

The following query returns all users that foster cats named `"Fido"` *and* `"Bob"`:

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: ["cats", "fostering"],
      array_contains: ["Fido", "Bob"],
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: "$.cats.fostering",
      array_contains: ["Fido", "Bob"],
    },
  },
});
```

#### JSON object arrays [#json-object-arrays]

  

#### PostgreSQL

```ts
const json = [{ status: "expired", insuranceID: 92 }];

const checkJson = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: ["insurances"],
      array_contains: json,
    },
  },
});
```

#### MySQL

```ts
const json = { status: "expired", insuranceID: 92 };

const checkJson = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: "$.insurances",
      array_contains: json,
    },
  },
});
```

* If you are using PostgreSQL, you must pass in an array of objects to match, even if that array only contains one object:

  ```json5
  [{ status: "expired", insuranceID: 92 }]
  // PostgreSQL
  ```

  If you are using MySQL, you must pass in a single object to match:

  ```json5
  { status: "expired", insuranceID: 92 }
  // MySQL
  ```

* If your filter array contains multiple objects, PostgreSQL will only return results if *all* objects are present - not if at least one object is present.

* You must set `array_contains` to a JSON object, not a string. If you use a string, Prisma Client escapes the quotation marks and the query will not return results. For example:

  ```ts
  array_contains: '[{"status": "expired", "insuranceID": 92}]';
  ```

  is sent to the database as:

  ```
  [{\"status\": \"expired\", \"insuranceID\": 92}]
  ```

### Targeting an array element by index [#targeting-an-array-element-by-index]

You can filter on the value of an element in a specific position.

```json
{ "owned": ["Bob", "Sunny"], "fostering": ["Fido"] }
```

  

#### PostgreSQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    comments: {
      path: ["owned", "1"],
      string_contains: "Bob",
    },
  },
});
```

#### MySQL

```ts
const getUsers = await prisma.user.findMany({
  where: {
    comments: {
      path: "$.owned[1]",
      string_contains: "Bob",
    },
  },
});
```

### Filtering on object key value inside array [#filtering-on-object-key-value-inside-array]

Depending on your provider, you can filter on the key value of an object inside an array.

> [!WARNING]
> Filtering on object key values within an array is **only** supported by the [MySQL database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql). However, you can still [filter on the presence of entire JSON objects](#json-object-arrays).

In the following example, the value of `extendedPetsData` is an array of objects with a nested `insurances` array, which contains two objects:

```json
[
  {
    "petName": "Claudine",
    "petType": "House cat",
    "insurances": [
      { "insuranceID": 92, "status": "expired" },
      { "insuranceID": 12, "status": "active" }
    ]
  },
  {
    "petName": "Sunny",
    "petType": "Gerbil"
  },
  {
    "petName": "Gerald",
    "petType": "Corn snake"
  },
  {
    "petName": "Nanna",
    "petType": "Moose"
  }
]
```

The following query returns all users where at least one pet is a moose:

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: "$[*].petType",
      array_contains: "Moose",
    },
  },
});
```

* `$[*]` is the root array of pet objects
* `petType` matches the `petType` key in any pet object

The following query returns all users where at least one pet has an expired insurance:

```ts
const getUsers = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: "$[*].insurances[*].status",
      array_contains: "expired",
    },
  },
});
```

* `$[*]` is the root array of pet objects
* `insurances[*]` matches any `insurances` array inside any pet object
* `status` matches any `status` key in any insurance object

## Advanced example: Update a nested JSON key value [#advanced-example-update-a-nested-json-key-value]

The following example assumes that the value of `extendedPetsData` is some variation of the following:

```json
{
  "petName": "Claudine",
  "petType": "House cat",
  "insurances": [
    { "insuranceID": 92, "status": "expired" },
    { "insuranceID": 12, "status": "active" }
  ]
}
```

The following example:

1. Gets all users
2. Change the `"status"` of each insurance object to `"expired"`
3. Get all users that have an expired insurance where the ID is `92`

  

#### PostgreSQL

```ts
const userQueries: string | any[] = [];

getUsers.forEach((user) => {
  if (
    user.extendedPetsData &&
    typeof user.extendedPetsData === "object" &&
    !Array.isArray(user.extendedPetsData)
  ) {
    const petsObject = user.extendedPetsData as Prisma.JsonObject;

    const i = petsObject["insurances"];

    if (i && typeof i === "object" && Array.isArray(i)) {
      const insurancesArray = i as Prisma.JsonArray;

      insurancesArray.forEach((i) => {
        if (i && typeof i === "object" && !Array.isArray(i)) {
          const insuranceObject = i as Prisma.JsonObject;

          insuranceObject["status"] = "expired";
        }
      });

      const whereClause = Prisma.validator<Prisma.UserWhereInput>()({
        id: user.id,
      });

      const dataClause = Prisma.validator<Prisma.UserUpdateInput>()({
        extendedPetsData: petsObject,
      });

      userQueries.push(
        prisma.user.update({
          where: whereClause,
          data: dataClause,
        }),
      );
    }
  }
});

if (userQueries.length > 0) {
  console.log(userQueries.length + " queries to run!");
  await prisma.$transaction(userQueries);
}

const json = [{ status: "expired", insuranceID: 92 }];

const checkJson = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: ["insurances"],
      array_contains: json,
    },
  },
});

console.log(checkJson.length);
```

#### MySQL

```ts
const userQueries: string | any[] = [];

getUsers.forEach((user) => {
  if (
    user.extendedPetsData &&
    typeof user.extendedPetsData === "object" &&
    !Array.isArray(user.extendedPetsData)
  ) {
    const petsObject = user.extendedPetsData as Prisma.JsonObject;

    const insuranceList = petsObject["insurances"]; // is a Prisma.JsonArray

    if (Array.isArray(insuranceList)) {
      insuranceList.forEach((insuranceItem) => {
        if (insuranceItem && typeof insuranceItem === "object" && !Array.isArray(insuranceItem)) {
          insuranceItem["status"] = "expired"; // is a  Prisma.JsonObject
        }
      });

      const whereClause = Prisma.validator<Prisma.UserWhereInput>()({
        id: user.id,
      });

      const dataClause = Prisma.validator<Prisma.UserUpdateInput>()({
        extendedPetsData: petsObject,
      });

      userQueries.push(
        prisma.user.update({
          where: whereClause,
          data: dataClause,
        }),
      );
    }
  }
});

if (userQueries.length > 0) {
  console.log(userQueries.length + " queries to run!");
  await prisma.$transaction(userQueries);
}

const json = { status: "expired", insuranceID: 92 };

const checkJson = await prisma.user.findMany({
  where: {
    extendedPetsData: {
      path: "$.insurances",
      array_contains: json,
    },
  },
});

console.log(checkJson.length);
```

## Using `null` Values [#using-null-values]

There are two types of `null` values possible for a `JSON` field in an SQL database.

* Database `NULL`: The value in the database is a `NULL`.
* JSON `null`: The value in the database contains a JSON value that is `null`.

To differentiate between these possibilities, we've introduced three *null enums* you can use:

* `JsonNull`: Represents the `null` value in JSON.
* `DbNull`: Represents the `NULL` value in the database.
* `AnyNull`: Represents both `null` JSON values and `NULL` database values. (Only when filtering)

> [!NOTE]
> - When filtering using any of the *null enums* you can not use a shorthand and leave the `equals` operator off.
> - These *null enums* do not apply to MongoDB because there the difference between a JSON `null` and a database `NULL` does not exist.
> - The *null enums* do not apply to the `array_contains` operator in all databases because there can only be a JSON `null` within a JSON array. Since there cannot be a database `NULL` within a JSON array, `{ array_contains: null }` is not ambiguous.

For example:

```prisma
model Log {
  id   Int  @id
  meta Json
}
```

Here is an example of using `AnyNull`:

```ts highlight=7;normal
import { Prisma } from "@prisma/client";

prisma.log.findMany({
  where: {
    data: {
      meta: {
        equals: Prisma.AnyNull,
      },
    },
  },
});
```

### Inserting `null` Values [#inserting-null-values]

This also applies to `create`, `update` and `upsert`. To insert a `null` value
into a `Json` field, you would write:

```ts highlight=5;normal
import { Prisma } from "@prisma/client";

prisma.log.create({
  data: {
    meta: Prisma.JsonNull,
  },
});
```

And to insert a database `NULL` into a `Json` field, you would write:

```ts highlight=5;normal
import { Prisma } from "@prisma/client";

prisma.log.create({
  data: {
    meta: Prisma.DbNull,
  },
});
```

### Filtering by `null` Values [#filtering-by-null-values]

To filter by `JsonNull` or `DbNull`, you would write:

```ts highlight=6;normal
import { Prisma } from "@prisma/client";

prisma.log.findMany({
  where: {
    meta: {
      equals: Prisma.AnyNull,
    },
  },
});
```

> [!NOTE]
> These *null enums* do not apply to MongoDB because MongoDB does not differentiate between a JSON `null` and a database `NULL`. They also do not apply to the `array_contains` operator in all databases because there can only be a JSON `null` within a JSON array. Since there cannot be a database `NULL` within a JSON array, `{ array_contains: null }` is not ambiguous.

## Typed `Json` Fields [#typed-json-fields]

Prisma's `Json` fields are untyped by default. To add strong typing, you can use the external package [prisma-json-types-generator](https://www.npmjs.com/package/prisma-json-types-generator).

1. First, install the package and add the generator to your `schema.prisma`:

   
     

#### bun

```bash
bun add --dev prisma-json-types-generator
```

#### pnpm

```bash
pnpm add -D prisma-json-types-generator
```

#### yarn

```bash
yarn add --dev prisma-json-types-generator
```

#### npm

```bash
npm install -D prisma-json-types-generator
```
   

   ```prisma title="schema.prisma"
   generator client {
     provider = "prisma-client"
     output   = "./generated"
   }

   generator json {
     provider = "prisma-json-types-generator"
   }
   ```

2. Next, link a field to a TypeScript type using an [AST comment](https://www.prisma.io/docs/orm/v7/prisma-schema/overview#comments).

   ```prisma highlight=4;normal title="schema.prisma" showLineNumbers
   model Log {
     id   Int @id

     /// [LogMetaType] // [!code highlight]
     meta Json
   }
   ```

3. Then, define `LogMetaType` in a type declaration file (e.g., `types.ts`) that is included in your `tsconfig.json`.

   ```ts title="types.ts" showLineNumbers
   declare global {
     namespace PrismaJson {
       type LogMetaType = { timestamp: number; host: string };
     }
   }

   // This file must be a module.
   export {};
   ```

Now, `Log.meta` will be strongly typed as `{ timestamp: number; host: string }`.

### Typing `String` Fields and Advanced Features [#typing-string-fields-and-advanced-features]

You can also apply these techniques to `String` fields. This is especially useful for creating string-based enums directly in your schema when your database does not support enum types.

```prisma
model Post {
  id     Int    @id

  /// !['draft' | 'published']
  status String

  /// [LogMetaType]
  meta   Json[]
}
```

This results in `post.status` being strongly typed as `'draft' | 'published'` and `post.meta` as `LogMetaType[]`.

For a complete guide on configuration, monorepo setup, and other advanced features, please refer to the [official `prisma-json-types-generator` documentation](https://github.com/arthurfiorette/prisma-json-types-generator#readme).

## `Json` FAQs [#json-faqs]

### Can you select a subset of JSON key/values to return? [#can-you-select-a-subset-of-json-keyvalues-to-return]

No - it is not yet possible to [select which JSON elements to return](https://github.com/prisma/orm/issues/2431). Prisma Client returns the entire JSON object.

### Can you filter on the presence of a specific key? [#can-you-filter-on-the-presence-of-a-specific-key]

No - it is not yet possible to filter on the presence of a specific key.

### Is case insensitive filtering supported? [#is-case-insensitive-filtering-supported]

Yes - you can use the `mode: 'insensitive'` option with string filters like `string_contains`, `string_starts_with`, and `string_ends_with`. See [Filter on object property](#filter-on-object-property) for examples.

### Can you sort an object property within a JSON value? [#can-you-sort-an-object-property-within-a-json-value]

No, [sorting object properties within a JSON value](https://github.com/prisma/orm/issues/10346) (order-by-prop) is not currently supported.

### How to set a default value for JSON fields? [#how-to-set-a-default-value-for-json-fields]

When you want to set a `@default` value the `Json` type, you need to enclose it with double-quotes inside the `@default` attribute (and potentially escape any "inner" double-quotes using a backslash), for example:

```prisma
model User {
  id    Int  @id @default(autoincrement())
  json1 Json @default("[]")
  json2 Json @default("{ \"hello\": \"world\" }")
}
```

## Related pages

- [`Composite types`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/composite-types): Work with composite types and embedded documents in MongoDB
- [`Null and undefined`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/null-and-undefined): How Prisma Client handles null and undefined
- [`Working with compound IDs and unique constraints`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-composite-ids-and-constraints): How to read, write, and filter by compound IDs and unique constraints
- [`Working with scalar lists`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-scalar-lists-arrays): How to read, write, and filter by scalar lists / arrays

# Working with scalar lists (Prisma ORM v7) (/docs/orm/v7/prisma-client/special-fields-and-types/working-with-scalar-lists-arrays)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to read, write, and filter by scalar lists / arrays

Location: ORM > v7 > Prisma Client > Special Fields and Types > Working with scalar lists

[Scalar lists](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#-modifier) are represented by the `[]` modifier and are only available if the underlying database supports scalar lists. The following example has one scalar `String` list named `pets`:

  

#### Relational databases

```prisma highlight=4;normal 
model User {
  id   Int      @id @default(autoincrement())
  name String
  pets String[] // [!code highlight]
}
```

#### MongoDB

```prisma highlight=4;normal 
model User {
  id   String   @id @default(auto()) @map("_id") @db.ObjectId
  name String
  pets String[] // [!code highlight]
}
```

Example field value:

```json5
["Fido", "Snoopy", "Brian"]
```

## Setting the value of a scalar list [#setting-the-value-of-a-scalar-list]

The following example demonstrates how to [`set`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference) the value of a scalar list (`coinflips`) when you create a model:

```ts
const createdUser = await prisma.user.create({
  data: {
    email: "eloise@prisma.io",
    coinflips: [true, true, true, false, true],
  },
});
```

## Unsetting the value of a scalar list [#unsetting-the-value-of-a-scalar-list]

> [!WARNING]
> This method is available on MongoDB only.

The following example demonstrates how to [`unset`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#unset) the value of a scalar list (`coinflips`):

```ts
const createdUser = await prisma.user.create({
  data: {
    email: "eloise@prisma.io",
    coinflips: {
      unset: true,
    },
  },
});
```

Unlike `set: null`, `unset` removes the list entirely.

## Adding items to a scalar list [#adding-items-to-a-scalar-list]

> [!NOTE]
> Available for PostgreSQL, CockroachDB, and MongoDB.

Use the [`push`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#push) method to add a single value to a scalar list:

```ts
const userUpdate = await prisma.user.update({
  where: {
    id: 9,
  },
  data: {
    coinflips: {
      push: true,
    },
  },
});
```

In earlier versions, you have to overwrite the entire value. The following example retrieves user, uses `push()` to add three new coin flips, and overwrites the `coinflips` field in an `update`:

```ts
const user = await prisma.user.findUnique({
  where: {
    email: "eloise@prisma.io",
  },
});

if (user) {
  console.log(user.coinflips);

  user.coinflips.push(true, true, false);

  const updatedUser = await prisma.user.update({
    where: {
      email: "eloise@prisma.io",
    },
    data: {
      coinflips: user.coinflips,
    },
  });

  console.log(updatedUser.coinflips);
}
```

## Filtering scalar lists [#filtering-scalar-lists]

> [!NOTE]
> Available for PostgreSQL, CockroachDB, and MongoDB.

Use [scalar list filters](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#scalar-list-filters) to filter for records with scalar lists that match a specific condition. The following example returns all posts where the tags list includes `databases` *and* `typescript`:

```ts
const posts = await prisma.post.findMany({
  where: {
    tags: {
      hasEvery: ["databases", "typescript"],
    },
  },
});
```

### `NULL` values in arrays [#null-values-in-arrays]

> [!NOTE]
> This section applies to PostgreSQL and CockroachDB.

When using scalar list filters with a relational database connector, array fields with a `NULL` value are not considered by the following conditions:

* `NOT` (array does not contain X)
* `isEmpty` (array is empty)

This means that records you might expect to see are not returned. Consider the following examples:

* The following query returns all posts where the `tags` **do not** include `databases`:

  ```ts
  const posts = await prisma.post.findMany({
    where: {
      NOT: {
        tags: {
          has: "databases",
        },
      },
    },
  });
  ```

  * ✔ Arrays that do not contain `"databases"`, such as `{"typescript", "graphql"}`
  * ✔ Empty arrays, such as `[]`

  The query does not return:

  * ✘ `NULL` arrays, even though they do not contain `"databases"`

The following query returns all posts where `tags` is empty:

```ts
const posts = await prisma.post.findMany({
  where: {
    tags: {
      isEmpty: true,
    },
  },
});
```

The query returns:

* ✔ Empty arrays, such as `[]`

The query does not return:

* ✘ `NULL` arrays, even though they could be considered empty

To work around this issue, you can set the default value of array fields to `[]`.

## Related pages

- [`Composite types`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/composite-types): Work with composite types and embedded documents in MongoDB
- [`Null and undefined`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/null-and-undefined): How Prisma Client handles null and undefined
- [`Working with compound IDs and unique constraints`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-composite-ids-and-constraints): How to read, write, and filter by compound IDs and unique constraints
- [`Working with Json fields`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-json-fields): How to read, write, and filter by Json fields

# Integration testing (Prisma ORM v7) (/docs/orm/v7/prisma-client/testing/integration-testing)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to setup and run integration tests with Prisma and Docker

Location: ORM > v7 > Prisma Client > Testing > Integration testing

Integration tests focus on testing how separate parts of the program work together. In the context of applications using a database, integration tests usually require a database to be available and contain data that is convenient to the scenarios intended to be tested.

One way to simulate a real world environment is to use [Docker](https://www.docker.com/get-started/) to encapsulate a database and some test data. This can be spun up and torn down with the tests and so operate as an isolated environment away from your production databases.

> **Note:** Prisma's testing series offers a more detailed walkthrough of setting up integration tests against a real database if you want a deeper companion resource.

## Prerequisites [#prerequisites]

This guide assumes you have [Docker](https://docs.docker.com/get-started/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) installed on your machine as well as `Jest` setup in your project.

See our [system requirements](https://www.prisma.io/docs/orm/v7/reference/system-requirements) for all minimum version requirements.

The following e-commerce schema will be used throughout the guide. This varies from the traditional `User` and `Post` models used in other parts of the docs, mainly because it is unlikely you will be running integration tests against your blog.

**Ecommerce schema**

```prisma title="schema.prisma"
// Can have 1 customer
// Can have many order details
model CustomerOrder {
  id           Int            @id @default(autoincrement())
  createdAt    DateTime       @default(now())
  customer     Customer       @relation(fields: [customerId], references: [id])
  customerId   Int
  orderDetails OrderDetails[]
}

// Can have 1 order
// Can have many products
model OrderDetails {
  id        Int           @id @default(autoincrement())
  products  Product       @relation(fields: [productId], references: [id])
  productId Int
  order     CustomerOrder @relation(fields: [orderId], references: [id])
  orderId   Int
  total     Decimal
  quantity  Int
}

// Can have many order details
// Can have 1 category
model Product {
  id           Int            @id @default(autoincrement())
  name         String
  description  String
  price        Decimal
  sku          Int
  orderDetails OrderDetails[]
  category     Category       @relation(fields: [categoryId], references: [id])
  categoryId   Int
}

// Can have many products
model Category {
  id       Int       @id @default(autoincrement())
  name     String
  products Product[]
}

// Can have many orders
model Customer {
  id      Int             @id @default(autoincrement())
  email   String          @unique
  address String?
  name    String?
  orders  CustomerOrder[]
}
```

The guide uses a singleton pattern for Prisma Client setup. Refer to the [singleton](https://www.prisma.io/docs/orm/v7/prisma-client/testing/unit-testing#singleton) docs for a walk through of how to set that up.

## Add Docker to your project [#add-docker-to-your-project]

![Docker compose code pointing towards image of container holding a Postgres database](https://www.prisma.io/img/orm/prisma-client/testing/Docker_Diagram_V1.png)

With Docker and Docker compose both installed on your machine you can use them in your project.

1. Begin by creating a `docker-compose.yml` file at your projects root. Here you will add a Postgres image and specify the environments credentials.

```yml title="docker-compose.yml"
# Set the version of docker compose to use
version: "3.9"

# The containers that compose the project
services:
  db:
    image: postgres:13
    restart: always
    container_name: integration-tests-prisma
    ports:
      - "5433:5432"
    environment:
      POSTGRES_USER: prisma
      POSTGRES_PASSWORD: prisma
      POSTGRES_DB: tests
```

> **Note**: The compose version used here (`3.9`) is the latest at the time of writing, if you are following along be sure to use the same version for consistency.

The `docker-compose.yml` file defines the following:

* The Postgres image (`postgres`) and version tag (`:13`). This will be downloaded if you do not have it locally available.
* The port `5433` is mapped to the internal (Postgres default) port `5432`. This will be the port number the database is exposed on externally.
* The database user credentials are set and the database given a name.

2. To connect to the database in the container, create a new connection string with the credentials defined in the `docker-compose.yml` file. For example:

```bash title=".env.test"
DATABASE_URL="postgresql://prisma:prisma@localhost:5433/tests"
```

> [!NOTE]
> The above `.env.test` file is used as part of a multiple `.env` file setup. Checkout the [using multiple .env files.](https://www.prisma.io/docs/orm/v7/more/dev-environment/environment-variables) section to learn more about setting up your project with multiple `.env` files

3. To create the container in a detached state so that you can continue to use the terminal tab, run the following command:

```bash
docker compose up -d
```

4. Next you can check that the database has been created by executing a `psql` command inside the container. Make a note of the container id.

   ```
   docker ps
   ```

   ```bash
   CONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS        PORTS                    NAMES
   1322e42d833f   postgres:13       "docker-entrypoint.s…"   2 seconds ago   Up 1 second   0.0.0.0:5433->5432/tcp   integration-tests-prisma
   ```

> **Note**: The container id is unique to each container, you will see a different id displayed.

5. Using the container id from the previous step, run `psql` in the container, login with the created user and check the database is created:

   ```
   docker exec -it 1322e42d833f psql -U prisma tests
   ```

   ```bash
   tests=# \l
                                 List of databases
      Name    | Owner  | Encoding |  Collate   |   Ctype    | Access privileges

    postgres  | prisma | UTF8     | en_US.utf8 | en_US.utf8 |
    template0 | prisma | UTF8     | en_US.utf8 | en_US.utf8 | =c/prisma        +
              |        |          |            |            | prisma=CTc/prisma
    template1 | prisma | UTF8     | en_US.utf8 | en_US.utf8 | =c/prisma        +
              |        |          |            |            | prisma=CTc/prisma
    tests     | prisma | UTF8     | en_US.utf8 | en_US.utf8 |
   (4 rows)
   ```

## Integration testing [#integration-testing]

Integration tests will be run against a database in a **dedicated test environment** instead of the production or development environments.

### The flow of operations [#the-flow-of-operations]

The flow for running said tests goes as follows:

1. Start the container and create the database
2. Migrate the schema
3. Run the tests
4. Destroy the container

Each test suite will seed the database before all the test are run. After all the tests in the suite have finished, the data from all the tables will be dropped and the connection terminated.

### The function to test [#the-function-to-test]

The ecommerce application you are testing has a function which creates an order. This function does the following:

* Accepts input about the customer making the order
* Accepts input about the product being ordered
* Checks if the customer has an existing account
* Checks if the product is in stock
* Returns an "Out of stock" message if the product doesn't exist
* Creates an account if the customer doesn't exist in the database
* Create the order

An example of how such a function might look can be seen below:

```ts title="create-order.ts"
import prisma from "../client";

export interface Customer {
  id?: number;
  name?: string;
  email: string;
  address?: string;
}

export interface OrderInput {
  customer: Customer;
  productId: number;
  quantity: number;
}

/**
 * Creates an order with customer.
 * @param input The order parameters
 */
export async function createOrder(input: OrderInput) {
  const { productId, quantity, customer } = input;
  const { name, email, address } = customer;

  // Get the product
  const product = await prisma.product.findUnique({
    where: {
      id: productId,
    },
  });

  // If the product is null its out of stock, return error.
  if (!product) return new Error("Out of stock");

  // If the customer is new then create the record, otherwise connect via their unique email
  await prisma.customerOrder.create({
    data: {
      customer: {
        connectOrCreate: {
          create: {
            name,
            email,
            address,
          },
          where: {
            email,
          },
        },
      },
      orderDetails: {
        create: {
          total: product.price,
          quantity,
          products: {
            connect: {
              id: product.id,
            },
          },
        },
      },
    },
  });
}
```

### The test suite [#the-test-suite]

The following tests will check if the `createOrder` function works as it should do. They will test:

* Creating a new order with a new customer
* Creating an order with an existing customer
* Show an "Out of stock" error message if a product doesn't exist

Before the test suite is run the database is seeded with data. After the test suite has finished a [`deleteMany`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#deletemany) is used to clear the database of its data.

> [!NOTE]
> Using `deleteMany` may suffice in situations where you know ahead of time how your schema is structured. This is because the operations need to be executed in the correct order according to how the model relations are setup.
> 
> However, this doesn't scale as well as having a more generic solution that maps over your models and performs a truncate on them. For those scenarios and examples of using raw SQL queries see [Deleting all data with raw SQL / `TRUNCATE`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud#deleting-all-data-with-raw-sql--truncate)

```ts title="__tests__/create-order.ts"
import prisma from "../src/client";
import { createOrder, Customer, OrderInput } from "../src/functions/index";

beforeAll(async () => {
  // create product categories
  await prisma.category.createMany({
    data: [{ name: "Wand" }, { name: "Broomstick" }],
  });

  console.log("✨ 2 categories successfully created!");

  // create products
  await prisma.product.createMany({
    data: [
      {
        name: 'Holly, 11", phoenix feather',
        description: "Harry Potters wand",
        price: 100,
        sku: 1,
        categoryId: 1,
      },
      {
        name: "Nimbus 2000",
        description: "Harry Potters broom",
        price: 500,
        sku: 2,
        categoryId: 2,
      },
    ],
  });

  console.log("✨ 2 products successfully created!");

  // create the customer
  await prisma.customer.create({
    data: {
      name: "Harry Potter",
      email: "harry@hogwarts.io",
      address: "4 Privet Drive",
    },
  });

  console.log("✨ 1 customer successfully created!");
});

afterAll(async () => {
  const deleteOrderDetails = prisma.orderDetails.deleteMany();
  const deleteProduct = prisma.product.deleteMany();
  const deleteCategory = prisma.category.deleteMany();
  const deleteCustomerOrder = prisma.customerOrder.deleteMany();
  const deleteCustomer = prisma.customer.deleteMany();

  await prisma.$transaction([
    deleteOrderDetails,
    deleteProduct,
    deleteCategory,
    deleteCustomerOrder,
    deleteCustomer,
  ]);

  await prisma.$disconnect();
});

it("should create 1 new customer with 1 order", async () => {
  // The new customers details
  const customer: Customer = {
    id: 2,
    name: "Hermione Granger",
    email: "hermione@hogwarts.io",
    address: "2 Hampstead Heath",
  };
  // The new orders details
  const order: OrderInput = {
    customer,
    productId: 1,
    quantity: 1,
  };

  // Create the order and customer
  await createOrder(order);

  // Check if the new customer was created by filtering on unique email field
  const newCustomer = await prisma.customer.findUnique({
    where: {
      email: customer.email,
    },
  });

  // Check if the new order was created by filtering on unique email field of the customer
  const newOrder = await prisma.customerOrder.findFirst({
    where: {
      customer: {
        email: customer.email,
      },
    },
  });

  // Expect the new customer to have been created and match the input
  expect(newCustomer).toEqual(customer);
  // Expect the new order to have been created and contain the new customer
  expect(newOrder).toHaveProperty("customerId", 2);
});

it("should create 1 order with an existing customer", async () => {
  // The existing customers email
  const customer: Customer = {
    email: "harry@hogwarts.io",
  };
  // The new orders details
  const order: OrderInput = {
    customer,
    productId: 1,
    quantity: 1,
  };

  // Create the order and connect the existing customer
  await createOrder(order);

  // Check if the new order was created by filtering on unique email field of the customer
  const newOrder = await prisma.customerOrder.findFirst({
    where: {
      customer: {
        email: customer.email,
      },
    },
  });

  // Expect the new order to have been created and contain the existing customer with an id of 1 (Harry Potter from the seed script)
  expect(newOrder).toHaveProperty("customerId", 1);
});

it("should show 'Out of stock' message if productId doesn't exit", async () => {
  // The existing customers email
  const customer: Customer = {
    email: "harry@hogwarts.io",
  };
  // The new orders details
  const order: OrderInput = {
    customer,
    productId: 3,
    quantity: 1,
  };

  // The productId supplied doesn't exit so the function should return an "Out of stock" message
  await expect(createOrder(order)).resolves.toEqual(new Error("Out of stock"));
});
```

## Running the tests [#running-the-tests]

This setup isolates a real world scenario so that you can test your applications functionality against real data in a controlled environment.

You can add some scripts to your projects `package.json` file which will setup the database and run the tests, then afterwards manually destroy the container.

> [!WARNING]
> If the test doesn't work for you, you'll need to ensure the test database is properly set up and ready before the suite runs.

```json title="package.json"
  "scripts": {
    "docker:up": "docker compose up -d",
    "docker:down": "docker compose down",
    "test": "yarn docker:up && yarn prisma migrate deploy && jest -i"
  },
```

The `test` script does the following:

1. Runs `docker compose up -d` to create the container with the Postgres image and database.
2. Applies the migrations found in `./prisma/migrations/` directory to the database, this creates the tables in the container's database.
3. Executes the tests.

Once you are satisfied you can run `yarn docker:down` to destroy the container, its database and any test data.

## Related pages

- [`Unit testing`](https://www.prisma.io/docs/orm/v7/prisma-client/testing/unit-testing): Learn how to setup and run unit tests with Prisma Client

# Unit testing (Prisma ORM v7) (/docs/orm/v7/prisma-client/testing/unit-testing)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to setup and run unit tests with Prisma Client

Location: ORM > v7 > Prisma Client > Testing > Unit testing

Unit testing aims to isolate a small portion (unit) of code and test it for logically predictable behaviors. It generally involves mocking objects or server responses to simulate real world behaviors. Some benefits to unit testing include:

* Quickly find and isolate bugs in code.
* Provides documentation for each module of code by way of indicating what certain code blocks should be doing.
* A helpful gauge that a refactor has gone well. The tests should still pass after code has been refactored.

In the context of Prisma ORM, this generally means testing a function which makes database calls using Prisma Client.

A single test should focus on how your function logic handles different inputs (such as a null value or an empty list).

This means that you should aim to remove as many dependencies as possible, such as external services and databases, to keep the tests and their environments as lightweight as possible.

> **Note**: Prisma's testing series provides additional background on unit testing patterns with Prisma ORM if you want to go deeper after this guide.

## Prerequisites [#prerequisites]

This guide assumes you have the JavaScript testing library [`Jest`](https://jestjs.io/) and [`ts-jest`](https://github.com/kulshekhar/ts-jest) already setup in your project.

## Mocking Prisma Client [#mocking-prisma-client]

To ensure your unit tests are isolated from external factors you can mock Prisma Client, this means you get the benefits of being able to use your schema (&#x2A;**type-safety***), without having to make actual calls to your database when your tests are run.

This guide will cover two approaches to mocking Prisma Client, a singleton instance and dependency injection. Both have their merits depending on your use cases. To help with mocking Prisma Client the [`jest-mock-extended`](https://github.com/marchaos/jest-mock-extended) package will be used.

  

#### bun

```bash
bun add jest-mock-extended@2.0.4 --dev
```

#### pnpm

```bash
pnpm add jest-mock-extended@2.0.4 --save-dev
```

#### yarn

```bash
yarn add jest-mock-extended@2.0.4 --dev
```

#### npm

```bash
npm install jest-mock-extended@2.0.4 --save-dev
```

> [!CAUTION]
> At the time of writing, this guide uses `jest-mock-extended` version `^2.0.4`.

### Singleton [#singleton]

The following steps guide you through mocking Prisma Client using a singleton pattern.

1. Create a file at your projects root called `client.ts` and add the following code. This will instantiate a Prisma Client instance.

   ```ts title="client.ts"
   import "dotenv/config";
   import { PrismaPg } from "@prisma/adapter-pg";
   import { PrismaClient } from "../generated/prisma/client";

   const connectionString = `${process.env.DATABASE_URL}`;

   const adapter = new PrismaPg({ connectionString });
   const prisma = new PrismaClient({ adapter });

   export { prisma };
   ```

2. Next create a file named `singleton.ts` at your projects root and add the following:

   ```ts title="singleton.ts"
   import { PrismaClient } from "../generated/prisma/client";
   import { mockDeep, mockReset, DeepMockProxy } from "jest-mock-extended";

   import prisma from "./client";

   jest.mock("./client", () => ({
     __esModule: true,
     default: mockDeep<PrismaClient>(),
   }));

   beforeEach(() => {
     mockReset(prismaMock);
   });

   export const prismaMock = prisma as unknown as DeepMockProxy<PrismaClient>;
   ```

The singleton file tells Jest to mock a default export (the Prisma Client instance in `./client.ts`), and uses the `mockDeep` method from `jest-mock-extended` to enable access to the objects and methods available on Prisma Client. It then resets the mocked instance before each test is run.

Next, add the `setupFilesAfterEnv` property to your `jest.config.js` file with the path to your `singleton.ts` file.

```js title="jest.config.js" highlight=5;add showLineNumbers
module.exports = {
  clearMocks: true,
  preset: "ts-jest",
  testEnvironment: "node",
  setupFilesAfterEnv: ["<rootDir>/singleton.ts"], {/* [!code ++] */}
};
```

### Dependency injection [#dependency-injection]

Another popular pattern that can be used is dependency injection.

1. Create a `context.ts` file and add the following:

   ```ts title="context.ts"
   import { PrismaClient } from "../generated/prisma/client";
   import { mockDeep, DeepMockProxy } from "jest-mock-extended";

   export type Context = {
     prisma: PrismaClient;
   };

   export type MockContext = {
     prisma: DeepMockProxy<PrismaClient>;
   };

   export const createMockContext = (): MockContext => {
     return {
       prisma: mockDeep<PrismaClient>(),
     };
   };
   ```

> [!NOTE]
> If you find that you're seeing a circular dependency error highlighted through mocking Prisma Client, try adding `"strictNullChecks": true`
> to your `tsconfig.json`.

2. To use the context, you would do the following in your test file:

   ```ts
   import { MockContext, Context, createMockContext } from "../context";

   let mockCtx: MockContext;
   let ctx: Context;

   beforeEach(() => {
     mockCtx = createMockContext();
     ctx = mockCtx as unknown as Context;
   });
   ```

This will create a new context before each test is run via the `createMockContext` function. This (`mockCtx`) context will be used to make a mock call to Prisma Client and run a query to test. The `ctx` context will be used to run a scenario query that is tested against.

## Example unit tests [#example-unit-tests]

A real world use case for unit testing Prisma ORM might be a signup form. Your user fills in a form which calls a function, which in turn uses Prisma Client to make a call to your database.

All of the examples that follow use the following schema model:

```prisma title="schema.prisma" showLineNumbers
model User {
  id                       Int     @id @default(autoincrement())
  email                    String  @unique
  name                     String?
  acceptTermsAndConditions Boolean
}
```

The following unit tests will mock the process of

* Creating a new user
* Updating a users name
* Failing to create a user if terms are not accepted

The functions that use the dependency injection pattern will have the context injected (passed in as a parameter) into them, whereas the functions that use the singleton pattern will use the singleton instance of Prisma Client.

```ts title="functions-with-context.ts"
import { Context } from "./context";

interface CreateUser {
  name: string;
  email: string;
  acceptTermsAndConditions: boolean;
}

export async function createUser(user: CreateUser, ctx: Context) {
  if (user.acceptTermsAndConditions) {
    return await ctx.prisma.user.create({
      data: user,
    });
  } else {
    return new Error("User must accept terms!");
  }
}

interface UpdateUser {
  id: number;
  name: string;
  email: string;
}

export async function updateUsername(user: UpdateUser, ctx: Context) {
  return await ctx.prisma.user.update({
    where: { id: user.id },
    data: user,
  });
}
```

```ts title="functions-without-context.ts"
import prisma from "./client";

interface CreateUser {
  name: string;
  email: string;
  acceptTermsAndConditions: boolean;
}

export async function createUser(user: CreateUser) {
  if (user.acceptTermsAndConditions) {
    return await prisma.user.create({
      data: user,
    });
  } else {
    return new Error("User must accept terms!");
  }
}

interface UpdateUser {
  id: number;
  name: string;
  email: string;
}

export async function updateUsername(user: UpdateUser) {
  return await prisma.user.update({
    where: { id: user.id },
    data: user,
  });
}
```

The tests for each methodology are fairly similar, the difference is how the mocked Prisma Client is used.

The &#x2A;**dependency injection*** example passes the context through to the function that is being tested as well as using it to call the mock implementation.

The &#x2A;**singleton*** example uses the singleton client instance to call the mock implementation.

```ts title="__tests__/with-singleton.ts"
import { createUser, updateUsername } from "../functions-without-context";
import { prismaMock } from "../singleton";

test("should create new user ", async () => {
  const user = {
    id: 1,
    name: "Rich",
    email: "hello@prisma.io",
    acceptTermsAndConditions: true,
  };

  prismaMock.user.create.mockResolvedValue(user);

  await expect(createUser(user)).resolves.toEqual({
    id: 1,
    name: "Rich",
    email: "hello@prisma.io",
    acceptTermsAndConditions: true,
  });
});

test("should update a users name ", async () => {
  const user = {
    id: 1,
    name: "Rich Haines",
    email: "hello@prisma.io",
    acceptTermsAndConditions: true,
  };

  prismaMock.user.update.mockResolvedValue(user);

  await expect(updateUsername(user)).resolves.toEqual({
    id: 1,
    name: "Rich Haines",
    email: "hello@prisma.io",
    acceptTermsAndConditions: true,
  });
});

test("should fail if user does not accept terms", async () => {
  const user = {
    id: 1,
    name: "Rich Haines",
    email: "hello@prisma.io",
    acceptTermsAndConditions: false,
  };

  prismaMock.user.create.mockImplementation();

  await expect(createUser(user)).resolves.toEqual(new Error("User must accept terms!"));
});
```

```ts title="__tests__/with-dependency-injection.ts"
import { MockContext, Context, createMockContext } from "../context";
import { createUser, updateUsername } from "../functions-with-context";

let mockCtx: MockContext;
let ctx: Context;

beforeEach(() => {
  mockCtx = createMockContext();
  ctx = mockCtx as unknown as Context;
});

test("should create new user ", async () => {
  const user = {
    id: 1,
    name: "Rich",
    email: "hello@prisma.io",
    acceptTermsAndConditions: true,
  };
  mockCtx.prisma.user.create.mockResolvedValue(user);

  await expect(createUser(user, ctx)).resolves.toEqual({
    id: 1,
    name: "Rich",
    email: "hello@prisma.io",
    acceptTermsAndConditions: true,
  });
});

test("should update a users name ", async () => {
  const user = {
    id: 1,
    name: "Rich Haines",
    email: "hello@prisma.io",
    acceptTermsAndConditions: true,
  };
  mockCtx.prisma.user.update.mockResolvedValue(user);

  await expect(updateUsername(user, ctx)).resolves.toEqual({
    id: 1,
    name: "Rich Haines",
    email: "hello@prisma.io",
    acceptTermsAndConditions: true,
  });
});

test("should fail if user does not accept terms", async () => {
  const user = {
    id: 1,
    name: "Rich Haines",
    email: "hello@prisma.io",
    acceptTermsAndConditions: false,
  };

  mockCtx.prisma.user.create.mockImplementation();

  await expect(createUser(user, ctx)).resolves.toEqual(new Error("User must accept terms!"));
});
```

## Related pages

- [`Integration testing`](https://www.prisma.io/docs/orm/v7/prisma-client/testing/integration-testing): Learn how to setup and run integration tests with Prisma and Docker

# Type safety Overview (Prisma ORM v7) (/docs/orm/v7/prisma-client/type-safety)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma Client provides full type safety for queries, even for partial queries or included relations. This page explains how to leverage the generated types and utilities

Location: ORM > v7 > Prisma Client > Type safety Overview

The generated code for Prisma Client contains several helpful types and utilities that you can use to make your application more type-safe. This page describes patterns for leveraging them.

> **Note**: For advanced type safety topics with Prisma ORM, see this [blog post](https://www.prisma.io/blog/satisfies-operator-ur8ys8ccq7zb) about improving your Prisma Client workflows with the new TypeScript `satisfies` keyword.

## Importing generated types [#importing-generated-types]

You can import the `Prisma` namespace and use dot notation to access types and utilities. The following example shows how to import the `Prisma` namespace and use it to access and use the `Prisma.UserSelect` [generated type](#what-are-generated-types):

```ts
import { Prisma } from "../path/to/generated/prisma/client";

// Build 'select' object
const userEmail: Prisma.UserSelect = {
  email: true,
};

// Use select object
const createUser = await prisma.user.create({
  data: {
    email: "bob@prisma.io",
  },
  select: userEmail,
});
```

See also: [Using the `Prisma.UserCreateInput` generated type](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud#create-a-single-record)

## What are generated types? [#what-are-generated-types]

Generated types are TypeScript types that are derived from your models. You can use them to create typed objects that you pass into top-level methods like `prisma.user.create(...)` or `prisma.user.update(...)`, or options such as `select` or `include`.

For example, `select` accepts an object of type `UserSelect`. Its object properties match those that are supported by `select` statements according to the model.

The first tab below shows the `UserSelect` generated type and how each property on the object has a type annotation. The second tab shows the original schema from which the type was generated.

  

#### Generated type

```ts
type Prisma.UserSelect = {
    id?: boolean | undefined;
    email?: boolean | undefined;
    name?: boolean | undefined;
    posts?: boolean | Prisma.PostFindManyArgs | undefined;
    profile?: boolean | Prisma.ProfileArgs | undefined;
}
```

#### Model

```prisma
model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique
  name    String?
  posts   Post[]
  profile Profile?
}
```

In TypeScript the concept of [type annotations](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-annotations-on-variables) is when you declare a variable and add a type annotation to describe the type of the variable. See the below example.

```ts
const myAge: number = 37;
const myName: string = "Rich";
```

Both of these variable declarations have been given a type annotation to specify what primitive type they are, `number` and `string` respectively. Most of the time this kind of annotation is not needed as TypeScript will infer the type of the variable based on how its initialized. In the above example `myAge` was initialized with a number so TypeScript guesses that it should be typed as a number.

Going back to the `UserSelect` type, if you were to use dot notation on the created object `userEmail`, you would have access to all of the fields on the `User` model that can be interacted with using a `select` statement.

```prisma
model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique
  name    String?
  posts   Post[]
  profile Profile?
}
```

```ts
import { Prisma } from "../path/to/generated/prisma/client";

const userEmail: Prisma.UserSelect = {
  email: true,
};

// properties available on the typed object
userEmail.id;
userEmail.email;
userEmail.name;
userEmail.posts;
userEmail.profile;
```

In the same mould, you can type an object with an `include` generated type then your object would have access to those properties on which you can use an `include` statement.

```ts
import { Prisma } from "../path/to/generated/prisma/client";

const userPosts: Prisma.UserInclude = {
  posts: true,
};

// properties available on the typed object
userPosts.posts;
userPosts.profile;
```

> See the [model query options](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#model-query-options) reference for more information about the different types available.

### Generated `UncheckedInput` types [#generated-uncheckedinput-types]

The `UncheckedInput` types are a special set of generated types that allow you to perform some operations that Prisma Client considers "unsafe", like directly writing [relation scalar fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations). You can choose either the "safe" `Input` types or the "unsafe" `UncheckedInput` type when doing operations like `create`, `update`, or `upsert`.

For example, this Prisma schema has a one-to-many relation between `User` and `Post`:

```prisma
model Post {
  id       Int     @id @default(autoincrement())
  title    String  @db.VarChar(255)
  content  String?
  author   User    @relation(fields: [authorId], references: [id])
  authorId Int
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}
```

The first tab shows the `PostUncheckedCreateInput` generated type. It contains the `authorId` property, which is a relation scalar field. The second tab shows an example query that uses the `PostUncheckedCreateInput` type. This query will result in an error if a user with an `id` of `1` does not exist.

  

#### Generated type

```ts
type PostUncheckedCreateInput = {
  id?: number;
  title: string;
  content?: string | null;
  authorId: number;
};
```

#### Example query

```ts
prisma.post.create({
  data: {
    title: "First post",
    content: "Welcome to the first post in my blog...",
    authorId: 1,
  },
});
```

The same query can be rewritten using the "safer" `PostCreateInput` type. This type does not contain the `authorId` field but instead contains the `author` relation field.

  

#### Generated type

```ts
type PostCreateInput = {
  title: string;
  content?: string | null;
  author: UserCreateNestedOneWithoutPostsInput;
};

type UserCreateNestedOneWithoutPostsInput = {
  create?: XOR<UserCreateWithoutPostsInput, UserUncheckedCreateWithoutPostsInput>;
  connectOrCreate?: UserCreateOrConnectWithoutPostsInput;
  connect?: UserWhereUniqueInput;
};
```

#### Example query

```ts
prisma.post.create({
  data: {
    title: "First post",
    content: "Welcome to the first post in my blog...",
    author: {
      connect: {
        id: 1,
      },
    },
  },
});
```

This query will also result in an error if an author with an `id` of `1` does not exist. In this case, Prisma Client will give a more descriptive error message. You can also use the [`connectOrCreate`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#connectorcreate) API to safely create a new user if one does not already exist with the given `id`.

We recommend using the "safe" `Input` types whenever possible.

## Type utilities [#type-utilities]

To help you create highly type-safe applications, Prisma Client provides a set of type utilities that tap into input and output types. These types are fully dynamic, which means that they adapt to any given model and schema. You can use them to improve autocompletion in your projects.

This is especially useful in [shared Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/shared-extensions).

The following type utilities are available in Prisma Client:

* `Exact<Input, Shape>`: Enforces strict type safety on `Input`. `Exact` makes sure that a generic type `Input` strictly complies with the type that you specify in `Shape`. It [narrows](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) `Input` down to the most precise types.
* `Args<Type, Operation>`: Retrieves the input arguments for any given model and operation. This is particularly useful for extension authors who want to do the following:
  * Re-use existing types to extend or modify them.
  * Benefit from the same auto-completion experience as on existing operations.
* `Result<Type, Arguments, Operation>`: Takes the input arguments and provides the result for a given model and operation. You would usually use this in conjunction with `Args`. As with `Args`, `Result` helps you to re-use existing types to extend or modify them.
* `Payload<Type, Operation>`: Retrieves the entire structure of the result, as scalars and relations objects for a given model and operation. For example, you can use this to determine which keys are scalars or objects at a type level.

As an example, here's a quick way you can enforce that the arguments to a function matches what you will pass to a `post.create`:

```ts
type PostCreateBody = Prisma.Args<typeof prisma.post, "create">["data"];

const addPost = async (postBody: PostCreateBody) => {
  const post = await prisma.post.create({ data: postBody });
  return post;
};

await addPost(myData);
//              ^ guaranteed to match the input of `post.create`
```

## Related pages

- [`Fields & types`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types): Learn how to use about special fields and types with Prisma Client
- [`What are Client Extensions`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions): Extend the functionality of Prisma Client
- [`Write your own SQL`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql): Learn how to use raw SQL queries in Prisma Client

# Operating against partial structures of your model types (Prisma ORM v7) (/docs/orm/v7/prisma-client/type-safety/operating-against-partial-structures-of-model-types)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

This page documents various scenarios for using the generated types from the Prisma namespace

Location: ORM > v7 > Prisma Client > Type Safety > Operating against partial structures of your model types

When using Prisma Client, every model from your [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) is translated into a dedicated TypeScript type. For example, assume you have the following `User` and `Post` models:

```prisma
model User {
  id    Int     @id
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int     @id
  author    User    @relation(fields: [userId], references: [id])
  title     String
  published Boolean @default(false)
  userId    Int
}
```

The Prisma Client code that's generated from this schema contains this representation of the `User` type:

```ts
export type User = {
  id: string;
  email: string;
  name: string | null;
};
```

## Problem: Using variations of the generated model type [#problem-using-variations-of-the-generated-model-type]

### Description [#description]

In some scenarios, you may need a *variation* of the generated `User` type. For example, when you have a function that expects an instance of the `User` model that carries the `posts` relation. Or when you need a type to pass only the `User` model's `email` and `name` fields around in your application code.

### Solution [#solution]

As a solution, you can customize the generated model type using Prisma Client's helper types.

The `User` type only contains the model's [scalar](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#scalar-fields) fields, but doesn't account for any relations. That's because [relations are not included by default](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields#return-the-default-fields) in Prisma Client queries.

However, sometimes it's useful to have a type available that **includes a relation** (i.e. a type that you'd get from an API call that uses [`include`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields#return-nested-objects-by-selecting-relation-fields)). Similarly, another useful scenario could be to have a type available that **includes only a subset of the model's scalar fields** (i.e. a type that you'd get from an API call that uses [`select`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/select-fields#select-specific-fields)).

One way of achieving this would be to define these types manually in your application code:

```ts
// 1: Define a type that includes the relation to `Post`
type UserWithPosts = {
  id: string;
  email: string;
  name: string | null;
  posts: Post[];
};

// 2: Define a type that only contains a subset of the scalar fields
type UserPersonalData = {
  email: string;
  name: string | null;
};
```

While this is certainly feasible, this approach increases the maintenance burden upon changes to the Prisma schema as you need to manually maintain the types. A cleaner solution to this is to use the `UserGetPayload` type that is generated and exposed by Prisma Client under the `Prisma` namespace in combination with TypeScript's `satisfies` operator.

The following example uses the `satisfies` operator to create two type-safe objects and then uses the `Prisma.UserGetPayload` utility function to create a type that can be used to return all users and their posts.

```ts
import { Prisma } from "@prisma/client";

// 1: Define a type that includes the relation to `Post`
const userWithPosts = { include: { posts: true } } satisfies Prisma.UserDefaultArgs;

// 2: Define a type that only contains a subset of the scalar fields
const userPersonalData = { select: { email: true, name: true } } satisfies Prisma.UserDefaultArgs;

// 3: This type will include a user and all their posts
type UserWithPosts = Prisma.UserGetPayload<typeof userWithPosts>;
```

The main benefits of the latter approach are:

* Cleaner approach as it leverages Prisma Client's generated types
* Reduced maintenance burden and improved type safety when the schema changes

## Problem: Getting access to the return type of a function [#problem-getting-access-to-the-return-type-of-a-function]

### Description [#description-1]

When doing [`select`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#select) or [`include`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#include) operations on your models and returning these variants from a function, it can be difficult to gain access to the return type, e.g:

```ts
// Function definition that returns a partial structure
async function getUsersWithPosts() {
  const users = await prisma.user.findMany({ include: { posts: true } });
  return users;
}
```

Extracting the type that represents "users with posts" from the above code snippet requires some advanced TypeScript usage:

```ts
// Function definition that returns a partial structure
async function getUsersWithPosts() {
  const users = await prisma.user.findMany({ include: { posts: true } });
  return users;
}

// Extract `UsersWithPosts` type with
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T;
type UsersWithPosts = ThenArg<ReturnType<typeof getUsersWithPosts>>;

// run inside `async` function
const usersWithPosts: UsersWithPosts = await getUsersWithPosts();
```

### Solution [#solution-1]

Use the native TypeScript utility types [`Awaited`](https://www.typescriptlang.org/docs/handbook/utility-types.html#awaitedtype) and [`ReturnType`](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype) to extract the type:

```ts
type UsersWithPosts = Awaited<ReturnType<typeof getUsersWithPosts>>;
```

## Related pages

- [`How to use Prisma ORM's type system`](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety/prisma-type-system): How to use Prisma ORM's type system

# How to use Prisma ORM's type system (Prisma ORM v7) (/docs/orm/v7/prisma-client/type-safety/prisma-type-system)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to use Prisma ORM's type system

Location: ORM > v7 > Prisma Client > Type Safety > How to use Prisma ORM's type system

This guide introduces Prisma ORM's type system and explains how to introspect existing native types in your database, and how to use types when you apply schema changes to your database with Prisma Migrate or `db push`.

## How does Prisma ORM's type system work? [#how-does-prisma-orms-type-system-work]

Prisma ORM uses *types* to define the kind of data that a field can hold. Prisma ORM provides a small number of core [scalar types](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) that cover most default use cases. For example, take the following blog post model:

```prisma title="schema.prisma" showLineNumbers
datasource db {
  provider = "postgresql"
}

model Post {
  id        Int      @id
  title     String
  createdAt DateTime
}
```

The `title` field of the `Post` model uses the `String` scalar type, while the `createdAt` field uses the `DateTime` scalar type.

Databases also have their own type system, which defines the type of value that a column can hold. Most databases provide a large number of data types to allow fine-grained control over exactly what a column can store. For example, a database might provide inbuilt support for multiple sizes of integers, or for XML data. The names of these types vary between databases. For example, in PostgreSQL the column type for booleans is `boolean`, whereas in MySQL the `tinyint(1)` type is typically used.

In the blog post example above, we are using the PostgreSQL connector. This is specified in the `datasource` block of the Prisma schema.

### Default type mappings [#default-type-mappings]

To allow you to get started with our core scalar types, Prisma ORM provides *default type mappings* that map each scalar type to a default type in the underlying database. For example:

* by default Prisma ORM's `String` type gets mapped to PostgreSQL's `text` type and MySQL's `varchar` type
* by default Prisma ORM's `DateTime` type gets mapped to PostgreSQL's `timestamp(3)` type and SQL Server's `datetime2` type

See Prisma ORM's [database connector pages](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases) for the default type mappings for a given database. For example, [this table](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#prisma-to-postgresql) gives the default type mappings for PostgreSQL.\
To see the default type mappings for all databases for a specific given Prisma ORM type, see the [model field scalar types section](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) of the Prisma schema reference. For example, [this table](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#float) gives the default type mappings for the `Float` scalar type.

### Native type mappings [#native-type-mappings]

Sometimes you may need to use a more specific database type that is not one of the default type mappings for your Prisma ORM type. For this purpose, Prisma ORM provides [native type attributes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#native-types-mapping) to refine the core scalar types. For example, in the `createdAt` field of your `Post` model above you may want to use a date-only column in your underlying PostgreSQL database, by using the `date` type instead of the default type mapping of `timestamp(3)`. To do this, add a `@db.Date` native type attribute to the `createdAt` field:

```prisma title="schema.prisma" showLineNumbers
model Post {
  id        Int      @id
  title     String
  createdAt DateTime @db.Date
}
```

Native type mappings allow you to express all the types in your database. However, you do not need to use them if the Prisma ORM defaults satisfy your needs. This leads to a shorter, more readable Prisma schema for common use cases.

## How to introspect database types [#how-to-introspect-database-types]

When you [introspect](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) an existing database, Prisma ORM will take the database type of each table column and represent it in your Prisma schema using the correct Prisma ORM type for the corresponding model field. If the database type is not the default database type for that Prisma ORM scalar type, Prisma ORM will also add a native type attribute.

As an example, take a `User` table in a PostgreSQL database, with:

* an `id` column with a data type of `serial`
* a `name` column with a data type of `text`
* an `isActive` column with a data type of `boolean`

You can create this with the following SQL command:

```sql
CREATE TABLE "public"."User" (
  id serial PRIMARY KEY NOT NULL,
  name text NOT NULL,
  "isActive" boolean NOT NULL
);
```

Introspect your database with the following command run from the root directory of your project:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

You will get the following Prisma schema:

```prisma title="schema.prisma" showLineNumbers
model User {
  id       Int     @id @default(autoincrement())
  name     String
  isActive Boolean
}
```

The `id`, `name` and `isActive` columns in the database are mapped respectively to the `Int`, `String` and `Boolean` Prisma ORM types. The database types are the *default* database types for these Prisma ORM types, so Prisma ORM does not add any native type attributes.

Now add a `createdAt` column to your database with a data type of `date` by running the following SQL command:

```sql
ALTER TABLE "public"."User"
ADD COLUMN "createdAt" date NOT NULL;
```

Introspect your database again:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

Your Prisma schema now includes the new `createdAt` field with a Prisma ORM type of `DateTime`. The `createdAt` field also has a `@db.Date` native type attribute, because PostgreSQL's `date` is not the default type for the `DateTime` type:

```prisma title="schema.prisma" highlight=5;add showLineNumbers
model User {
  id        Int      @id @default(autoincrement())
  name      String
  isActive  Boolean
  createdAt DateTime @db.Date // [!code ++]
}
```

## How to use types when you apply schema changes to your database [#how-to-use-types-when-you-apply-schema-changes-to-your-database]

When you apply schema changes to your database using Prisma Migrate or `db push`, Prisma ORM will use both the Prisma ORM scalar type of each field and any native attribute it has to determine the correct database type for the corresponding column in the database.

As an example, create a Prisma schema with the following `Post` model:

```prisma title="schema.prisma" showLineNumbers
model Post {
  id        Int      @id
  title     String
  createdAt DateTime
  updatedAt DateTime @db.Date
}
```

This `Post` model has:

* an `id` field with a Prisma ORM type of `Int`
* a `title` field with a Prisma ORM type of `String`
* a `createdAt` field with a Prisma ORM type of `DateTime`
* an `updatedAt` field with a Prisma ORM type of `DateTime` and a `@db.Date` native type attribute

Now apply these changes to an empty PostgreSQL database with the following command, run from the root directory of your project:

  

#### bun

```bash
bunx prisma db push
```

#### pnpm

```bash
pnpm prisma db push
```

#### yarn

```bash
yarn prisma db push
```

#### npm

```bash
npx prisma db push
```

You will see that the database has a newly created `Post` table, with:

* an `id` column with a database type of `integer`
* a `title` column with a database type of `text`
* a `createdAt` column with a database type of `timestamp(3)`
* an `updatedAt` column with a database type of `date`

Notice that the `@db.Date` native type attribute modifies the database type of the `updatedAt` column to `date`, rather than the default of `timestamp(3)`.

## More on using Prisma ORM's type system [#more-on-using-prisma-orms-type-system]

For further reference information on using Prisma ORM's type system, see the following resources:

* The [database connector](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases) page for each database provider has a type mapping section with a table of default type mappings between Prisma ORM types and database types, and a table of database types with their corresponding native type attribute in Prisma ORM. For example, the type mapping section for PostgreSQL is in [Prisma to PostgreSQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#prisma-to-postgresql).
* The [model field scalar types](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) section of the Prisma schema reference has a subsection for each Prisma ORM scalar type. This includes a table of default mappings for that Prisma ORM type in each database, and a table for each database listing the corresponding database types and their native type attributes in Prisma ORM. For example, the entry for the `String` Prisma ORM type is in [`String`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#string).

## Related pages

- [`Operating against partial structures of your model types`](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety/operating-against-partial-structures-of-model-types): This page documents various scenarios for using the generated types from the Prisma namespace

# Write your own SQL (Prisma ORM v7) (/docs/orm/v7/prisma-client/using-raw-sql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use raw SQL queries in Prisma Client

Location: ORM > v7 > Prisma Client > Write your own SQL

The Prisma Client API covers most queries, but some situations call for raw SQL.

This can happen for various reasons, such as the need to optimize the performance of a specific query or because your data requirements can't be fully expressed by Prisma Client's query API.

In most cases, [TypedSQL](#writing-type-safe-queries-with-prisma-client-and-typedsql) allows you to express your query in SQL while keeping typed inputs and outputs. However, since TypedSQL is statically typed, it may not handle certain scenarios, such as dynamically generated `WHERE` clauses. In these cases, you will need to use [`$queryRaw`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#queryraw) or [`$executeRaw`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#executeraw), or their unsafe counterparts.

## Writing type-safe queries with Prisma Client and TypedSQL [#writing-type-safe-queries-with-prisma-client-and-typedsql]

### What is TypedSQL? [#what-is-typedsql]

TypedSQL lets you write queries in `.sql` files and import them into your TypeScript code as functions with fully typed inputs and outputs.

With TypedSQL, you can:

1. Write complex SQL queries using familiar syntax
2. Benefit from full IDE support and syntax highlighting for SQL
3. Import your SQL queries as fully typed functions in your TypeScript code
4. Maintain the flexibility of raw SQL with the safety of Prisma's type system

TypedSQL is particularly useful for:

* Complex reporting queries that are difficult to express using Prisma's query API
* Performance-critical operations that require fine-tuned SQL
* Leveraging database-specific features not yet supported in Prisma's API

For a detailed guide on how to get started with TypedSQL, including setup instructions and usage examples, please refer to our [TypedSQL documentation](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql).

## Raw queries [#raw-queries]

While not as ergonomic as [TypedSQL](#writing-type-safe-queries-with-prisma-client-and-typedsql), raw queries are still supported and useful when TypedSQL queries are not possible due to features not yet supported in TypedSQL or when the query is dynamically generated.

### Alternative approaches to raw SQL queries in relational databases [#alternative-approaches-to-raw-sql-queries-in-relational-databases]

Prisma ORM supports four methods to execute raw SQL queries in relational databases:

* [`$queryRaw`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#queryraw)
* [`$executeRaw`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#executeraw)
* [`$queryRawUnsafe`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#queryrawunsafe)
* [`$executeRawUnsafe`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#executerawunsafe)

These commands are similar to using TypedSQL, but they are not type-safe and are written as strings in your code rather than in dedicated `.sql` files.

### Alternative approaches to raw queries in document databases [#alternative-approaches-to-raw-queries-in-document-databases]

For MongoDB, Prisma ORM supports three methods to execute raw queries:

* [`$runCommandRaw`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#runcommandraw)
* [`<model>.findRaw`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#findraw)
* [`<model>.aggregateRaw`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#aggregateraw)

These methods allow you to execute raw MongoDB commands and queries, providing flexibility when you need to use MongoDB-specific features or optimizations.

`$runCommandRaw` is used to execute database commands, `<model>.findRaw` is used to find documents that match a filter, and `<model>.aggregateRaw` is used for aggregation operations.

Similar to raw queries in relational databases, these methods are not type-safe and require manual handling of the query results.

## Related pages

- [`Fields & types`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types): Learn how to use about special fields and types with Prisma Client
- [`Type safety Overview`](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety): Prisma Client provides full type safety for queries, even for partial queries or included relations. This page explains how to leverage the generated types and utilities
- [`What are Client Extensions`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions): Extend the functionality of Prisma Client

# Raw queries (Prisma ORM v7) (/docs/orm/v7/prisma-client/using-raw-sql/raw-queries)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how you can send raw SQL and MongoDB queries to your database using the raw() methods from the Prisma Client API

Location: ORM > v7 > Prisma Client > Using Raw SQL > Raw queries

> [!WARNING]
> We recommend using [TypedSQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql) for type-safe SQL queries instead of the raw queries described below.

Prisma Client supports sending raw queries to your database. You may wish to use raw queries if:

* you want to run a heavily optimized query
* you require a feature that Prisma Client does not yet support (please [consider raising an issue](https://github.com/prisma/orm/issues/new/choose))

Raw queries are available for all relational databases Prisma ORM supports, as well as MongoDB. For more details, see the relevant sections:

* [Raw queries with relational databases](#raw-queries-with-relational-databases)
* [Raw queries with MongoDB](#raw-queries-with-mongodb)

## Raw queries with relational databases [#raw-queries-with-relational-databases]

For relational databases, Prisma Client exposes four methods that allow you to send raw queries. You can use:

* `$queryRaw` to return actual records (for example, using `SELECT`).
* `$executeRaw` to return a count of affected rows (for example, after an `UPDATE` or `DELETE`).
* `$queryRawUnsafe` to return actual records (for example, using `SELECT`) using a raw string.
* `$executeRawUnsafe` to return a count of affected rows (for example, after an `UPDATE` or `DELETE`) using a raw string.

The methods with "Unsafe" in the name are a lot more flexible but are at **significant risk of making your code vulnerable to SQL injection**.

The other two methods are safe to use with a simple template tag, no string building, and no concatenation. **However**, caution is required for more complex use cases as it is still possible to introduce SQL injection if these methods are used in certain ways. For more details, see the [SQL injection prevention](#sql-injection-prevention) section below.

> **Note**: All methods in the above list can only run **one** query at a time. You cannot append a second query - for example, calling any of them with `select 1; select 2;` will not work.

### `$queryRaw` [#queryraw]

`$queryRaw` returns actual database records. For example, the following `SELECT` query returns all fields for each record in the `User` table:

```ts no-lines
const result = await prisma.$queryRaw`SELECT * FROM User`;
```

The method is implemented as a [tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates), which allows you to pass a template literal where you can insert your [variables](#using-variables). In turn, Prisma Client creates prepared statements that are safe from SQL injections:

```ts no-lines
const email = "emelie@prisma.io";
const result = await prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}`;
```

You can also use the [`Prisma.sql`](#tagged-template-helpers) helper, in fact, the `$queryRaw` method will **only accept** a template string or the `Prisma.sql` helper:

```ts no-lines
const email = "emelie@prisma.io";
const result = await prisma.$queryRaw(Prisma.sql`SELECT * FROM User WHERE email = ${email}`);
```

> [!WARNING]
> If you use string building to incorporate untrusted input into queries passed to this method, then you open up the possibility for SQL injection attacks. SQL injection attacks can expose your data to modification or deletion. The preferred mechanism would be to include the text of the query at the point that you run this method. For more information on this risk and also examples of how to prevent it, see the [SQL injection prevention](#sql-injection-prevention) section below.

#### Considerations [#considerations]

Be aware that:

* Template variables cannot be used inside SQL string literals. For example, the following query would **not** work:

  ```ts no-lines
  const name = "Bob";
  await prisma.$queryRaw`SELECT 'My name is ${name}';`;
  ```

  Instead, you can either pass the whole string as a variable, or use string concatenation:

  ```ts no-lines
  const name = "My name is Bob";
  await prisma.$queryRaw`SELECT ${name};`;
  ```

  ```ts no-lines
  const name = "Bob";
  await prisma.$queryRaw`SELECT 'My name is ' || ${name};`;
  ```

* Template variables can only be used for data values (such as `email` in the example above). Variables cannot be used for identifiers such as column names, table names or database names, or for SQL keywords. For example, the following two queries would **not** work:

  ```ts no-lines
  const myTable = "user";
  await prisma.$queryRaw`SELECT * FROM ${myTable};`;
  ```

  ```ts no-lines
  const ordering = "desc";
  await prisma.$queryRaw`SELECT * FROM Table ORDER BY ${ordering};`;
  ```

* Prisma maps any database values returned by `$queryRaw` and `$queryRawUnsafe` to their corresponding JavaScript types. Learn more about [raw query type mapping](#raw-query-type-mapping).

* `$queryRaw` does not support dynamic table names in PostgreSQL databases. Learn more about [dynamic table names in PostgreSQL](#dynamic-table-names-in-postgresql)

#### Return type [#return-type]

`$queryRaw` returns an array. Each object corresponds to a database record:

```json5
[
  { id: 1, email: "emelie@prisma.io", name: "Emelie" },
  { id: 2, email: "yin@prisma.io", name: "Yin" },
]
```

You can also [type the results of `$queryRaw`](#typing-queryraw-results).

#### Signature [#signature]

```ts no-lines
$queryRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): PrismaPromise<T>;
```

#### Typing `$queryRaw` results [#typing-queryraw-results]

`PrismaPromise<T>` uses a [generic type parameter `T`](https://www.typescriptlang.org/docs/handbook/generics.html). You can determine the type of `T` when you invoke the `$queryRaw` method. In the following example, `$queryRaw` returns `User[]`:

```ts
// import the generated `User` type from the `@prisma/client` module
import { User } from "@prisma/client";

const result = await prisma.$queryRaw<User[]>`SELECT * FROM User`;
// result is of type: `User[]`
```

> **Note**: If you do not provide a type, `$queryRaw` defaults to `unknown`.

If you are selecting **specific fields** of the model or want to include relations, refer to the documentation about [leveraging Prisma Client's generated types](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety/operating-against-partial-structures-of-model-types#problem-using-variations-of-the-generated-model-type) if you want to make sure that the results are properly typed.

#### Type caveats when using raw SQL [#type-caveats-when-using-raw-sql]

When you type the results of `$queryRaw`, the raw data might not always match the suggested TypeScript type. For example, the following Prisma model includes a `Boolean` field named `published`:

```prisma highlight=3;normal
model Post {
  id        Int     @id @default(autoincrement())
  published Boolean @default(false) // [!code highlight]
  title     String
  content   String?
}
```

The following query returns all posts. It then prints out the value of the `published` field for each `Post`:

```ts
const result = await prisma.$queryRaw<Post[]>`SELECT * FROM Post`;

result.forEach((x) => {
  console.log(x.published);
});
```

For regular CRUD queries, the Prisma Client query engine standardizes the return type for all databases. **Using the raw queries does not**. If the database provider is MySQL, the returned values are `1` or `0`. However, if the database provider is PostgreSQL, the values are `true` or `false`.

> **Note**: Prisma sends JavaScript integers to PostgreSQL as `INT8`. This might conflict with your user-defined functions that accept only `INT4` as input. If you use `$queryRaw` in conjunction with a PostgreSQL database, update the input types to `INT8`, or cast your query parameters to `INT4`.

#### Dynamic table names in PostgreSQL [#dynamic-table-names-in-postgresql]

[It is not possible to interpolate table names](#considerations). This means that you cannot use dynamic table names with `$queryRaw`. Instead, you must use [`$queryRawUnsafe`](#queryrawunsafe), as follows:

```ts
let userTable = "User";
let result = await prisma.$queryRawUnsafe(`SELECT * FROM ${userTable}`);
```

Note that if you use `$queryRawUnsafe` in conjunction with user inputs, you risk SQL injection attacks. Learn more about [`$queryRawUnsafe()`](#queryrawunsafe).

### `$queryRawUnsafe()` [#queryrawunsafe]

The `$queryRawUnsafe()` method allows you to pass a raw string (or template string) to the database.

> [!WARNING]
> If you use this method with user inputs (in other words, `SELECT * FROM table WHERE columnName = ${userInput}`), then you open up the possibility for SQL injection attacks. SQL injection attacks can expose your data to modification or deletion.<br /><br />
> 
> Wherever possible you should use the `$queryRaw` method instead. When used correctly `$queryRaw` method is significantly safer but note that the `$queryRaw` method can also be made vulnerable in certain circumstances. For more information, see the [SQL injection prevention](#sql-injection-prevention) section below.

The following query returns all fields for each record in the `User` table:

```ts
// import the generated `User` type from the `@prisma/client` module
import { User } from "@prisma/client";

const result = await prisma.$queryRawUnsafe("SELECT * FROM User");
```

You can also run a parameterized query. The following example returns all users whose email contains the string `emelie@prisma.io`:

```ts
prisma.$queryRawUnsafe("SELECT * FROM users WHERE email = $1", "emelie@prisma.io");
```

> **Note**: Prisma sends JavaScript integers to PostgreSQL as `INT8`. This might conflict with your user-defined functions that accept only `INT4` as input. If you use a parameterized `$queryRawUnsafe` query in conjunction with a PostgreSQL database, update the input types to `INT8`, or cast your query parameters to `INT4`.

For more details on using parameterized queries, see the [parameterized queries](#parameterized-queries) section below.

#### Signature [#signature-1]

```ts no-lines
$queryRawUnsafe<T = unknown>(query: string, ...values: any[]): PrismaPromise<T>;
```

### `$executeRaw` [#executeraw]

`$executeRaw` returns the *number of rows affected by a database operation*, such as `UPDATE` or `DELETE`. This function does **not** return database records. The following query updates records in the database and returns a count of the number of records that were updated:

```ts
const result: number =
  await prisma.$executeRaw`UPDATE User SET active = true WHERE emailValidated = true`;
```

The method is implemented as a [tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates), which allows you to pass a template literal where you can insert your [variables](#using-variables). In turn, Prisma Client creates prepared statements that are safe from SQL injections:

```ts
const emailValidated = true;
const active = true;

const result: number =
  await prisma.$executeRaw`UPDATE User SET active = ${active} WHERE emailValidated = ${emailValidated};`;
```

> [!WARNING]
> If you use string building to incorporate untrusted input into queries passed to this method, then you open up the possibility for SQL injection attacks. SQL injection attacks can expose your data to modification or deletion. The preferred mechanism would be to include the text of the query at the point that you run this method. For more information on this risk and also examples of how to prevent it, see the [SQL injection prevention](#sql-injection-prevention) section below.

#### Considerations [#considerations-1]

Be aware that:

* `$executeRaw` does not support multiple queries in a single string (for example, `ALTER TABLE` and `CREATE TABLE` together).

* Prisma Client submits prepared statements, and prepared statements only allow a subset of SQL statements. For example, `START TRANSACTION` is not permitted. You can learn more about [the syntax that MySQL allows in Prepared Statements here](https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html).

* [`PREPARE` does not support `ALTER`](https://www.postgresql.org/docs/current/sql-prepare.html) - see the [workaround](#alter-limitation-postgresql).

* Template variables cannot be used inside SQL string literals. For example, the following query would **not** work:

  ```ts no-lines
  const name = "Bob";
  await prisma.$executeRaw`UPDATE user SET greeting = 'My name is ${name}';`;
  ```

  Instead, you can either pass the whole string as a variable, or use string concatenation:

  ```ts no-lines
  const name = "My name is Bob";
  await prisma.$executeRaw`UPDATE user SET greeting = ${name};`;
  ```

  ```ts no-lines
  const name = "Bob";
  await prisma.$executeRaw`UPDATE user SET greeting = 'My name is ' || ${name};`;
  ```

* Template variables can only be used for data values (such as `email` in the example above). Variables cannot be used for identifiers such as column names, table names or database names, or for SQL keywords. For example, the following two queries would **not** work:

  ```ts no-lines
  const myTable = "user";
  await prisma.$executeRaw`UPDATE ${myTable} SET active = true;`;
  ```

  ```ts no-lines
  const ordering = "desc";
  await prisma.$executeRaw`UPDATE User SET active = true ORDER BY ${desc};`;
  ```

#### Return type [#return-type-1]

`$executeRaw` returns a `number`.

#### Signature [#signature-2]

```ts
$executeRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): PrismaPromise<number>;
```

### `$executeRawUnsafe()` [#executerawunsafe]

The `$executeRawUnsafe()` method allows you to pass a raw string (or template string) to the database. Like `$executeRaw`, it does **not** return database records, but returns the number of rows affected.

> [!WARNING]
> If you use this method with user inputs (in other words, `SELECT * FROM table WHERE columnName = ${userInput}`), then you open up the possibility for SQL injection attacks. SQL injection attacks can expose your data to modification or deletion.<br /><br />
> 
> Wherever possible you should use the `$executeRaw` method instead. When used correctly `$executeRaw` method is significantly safer but note that the `$executeRaw` method can also be made vulnerable in certain circumstances. For more information, see the [SQL injection prevention](#sql-injection-prevention) section below.

The following example uses a template string to update records in the database. It then returns a count of the number of records that were updated:

```ts
const emailValidated = true;
const active = true;

const result = await prisma.$executeRawUnsafe(
  `UPDATE User SET active = ${active} WHERE emailValidated = ${emailValidated}`,
);
```

The same can be written as a parameterized query:

```ts
const result = prisma.$executeRawUnsafe(
  "UPDATE User SET active = $1 WHERE emailValidated = $2",
  "yin@prisma.io",
  true,
);
```

For more details on using parameterized queries, see the [parameterized queries](#parameterized-queries) section below.

#### Signature [#signature-3]

```ts no-lines
$executeRawUnsafe<T = unknown>(query: string, ...values: any[]): PrismaPromise<number>;
```

### Raw query type mapping [#raw-query-type-mapping]

Prisma maps any database values returned by `$queryRaw` and `$queryRawUnsafe`to their corresponding [JavaScript types](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures). This behavior is the same as for regular Prisma query methods like `findMany()`.

As an example, take a raw query that selects columns with `BigInt`, `Bytes`, `Decimal` and `Date` types from a table:

```ts
const result = await prisma.$queryRaw`SELECT bigint, bytes, decimal, date FROM "Table";`;

console.log(result);
```

```bash
{ bigint: BigInt("123"), bytes: <Buffer 01 02>), decimal: Decimal("12.34"), date: Date("<some_date>") }
```

In the `result` object, the database values have been mapped to the corresponding JavaScript types.

The following table shows the conversion between types used in the database and the JavaScript type returned by the raw query:

| Database type           | JavaScript type |
| ----------------------- | --------------- |
| Text                    | `String`        |
| 32-bit integer          | `Number`        |
| 32-bit unsigned integer | `BigInt`        |
| Floating point number   | `Number`        |
| Double precision number | `Number`        |
| 64-bit integer          | `BigInt`        |
| Decimal / numeric       | `Decimal`       |
| Bytes                   | `Uint8Array`    |
| Json                    | `Object`        |
| DateTime                | `Date`          |
| Date                    | `Date`          |
| Time                    | `Date`          |
| Uuid                    | `String`        |
| Xml                     | `String`        |

Note that the exact name for each database type will vary between databases – for example, the boolean type is known as `boolean` in PostgreSQL and `STRING` in CockroachDB. See the [Scalar types reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) for full details of type names for each database.

### Raw query typecasting behavior [#raw-query-typecasting-behavior]

Raw queries with Prisma Client might require parameters to be in the expected types of the SQL function or query. Prisma Client does not do subtle, implicit casts.

As an example, take the following query using PostgreSQL's `LENGTH` function, which only accepts the `text` type as an input:

```ts
await prisma.$queryRaw`SELECT LENGTH(${42});`;
```

This query returns an error:

```bash wrap
// ERROR: function length(integer) does not exist
// HINT: No function matches the given name and argument types. You might need to add explicit type casts.
```

The solution in this case is to explicitly cast `42` to the `text` type:

```ts
await prisma.$queryRaw`SELECT LENGTH(${42}::text);`;
```

### Transactions [#transactions]

You can use `.$executeRaw()` and `.$queryRaw()` inside a [transaction](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions).

### Using variables [#using-variables]

`$executeRaw` and `$queryRaw` are implemented as [**tagged templates**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates). Tagged templates are the recommended way to use variables with raw SQL in the Prisma Client.

The following example includes a placeholder named `${userId}`:

```ts
const userId = 42;
const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${userId};`;
```

✔ Benefits of using the tagged template versions of `$queryRaw` and `$executeRaw` include:

* Prisma Client escapes all variables.
* Tagged templates are database-agnostic - you do not need to remember if variables should be written as `$1` (PostgreSQL) or `?` (MySQL).
* [SQL Template Tag](https://github.com/blakeembrey/sql-template-tag) give you access to [useful helpers](#tagged-template-helpers).
* Embedded, named variables are easier to read.

> **Note**: You cannot pass a table or column name into a tagged template placeholder. For example, you cannot `SELECT ?` and pass in `*` or `id, name` based on some condition.

#### Tagged template helpers [#tagged-template-helpers]

Prisma Client specifically uses [SQL Template Tag](https://github.com/blakeembrey/sql-template-tag), which exposes a number of helpers. For example, the following query uses `join()` to pass in a list of IDs:

```ts
import { Prisma } from "@prisma/client";

const ids = [1, 3, 5, 10, 20];
const result = await prisma.$queryRaw`SELECT * FROM User WHERE id IN (${Prisma.join(ids)})`;
```

The following example uses the `empty` and `sql` helpers to change the query depending on whether `userName` is empty:

```ts
import { Prisma } from "@prisma/client";

const userName = "";
const result = await prisma.$queryRaw`SELECT * FROM User ${
  userName ? Prisma.sql`WHERE name = ${userName}` : Prisma.empty // Cannot use "" or NULL here!
}`;
```

#### `ALTER` limitation (PostgreSQL) [#alter-limitation-postgresql]

PostgreSQL [does not support using `ALTER` in a prepared statement](https://www.postgresql.org/docs/current/sql-prepare.html), which means that the following queries **will not work**:

```ts
await prisma.$executeRaw`ALTER USER prisma WITH PASSWORD "${password}"`;
await prisma.$executeRaw(Prisma.sql`ALTER USER prisma WITH PASSWORD "${password}"`);
```

You can use the following query, but be aware that this is potentially **unsafe** as `${password}` is not escaped:

```ts
await prisma.$executeRawUnsafe('ALTER USER prisma WITH PASSWORD "$1"', password})
```

### Unsupported types [#unsupported-types]

[`Unsupported` types](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#unsupported) need to be cast to Prisma Client supported types before using them in `$queryRaw` or `$queryRawUnsafe`. For example, take the following model, which has a `location` field with an `Unsupported` type:

```tsx
model Country {
  location  Unsupported("point")?
}
```

The following query on the unsupported field will **not** work:

```tsx
await prisma.$queryRaw`SELECT location FROM Country;`;
```

Instead, cast `Unsupported` fields to any supported Prisma Client type, **if your `Unsupported` column supports the cast**.

The most common type you may want to cast your `Unsupported` column to is `String`. For example, on PostgreSQL, this would map to the `text` type:

```tsx
await prisma.$queryRaw`SELECT location::text FROM Country;`;
```

The database will thus provide a `String` representation of your data which Prisma Client supports.

For details of supported Prisma types, see the [Prisma connector overview](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases) for the relevant database.

## SQL injection prevention [#sql-injection-prevention]

The ideal way to avoid SQL injection in Prisma Client is to use the ORM models to perform queries wherever possible.

Where this is not possible and raw queries are required, Prisma Client provides various raw methods, but it is important to use these methods safely.

This section will provide various examples of using these methods safely and unsafely. You can test these examples in the [Prisma Playground](https://playground.prisma.io/examples).

### In `$queryRaw` and `$executeRaw` [#in-queryraw-and-executeraw]

#### Simple, safe use of `$queryRaw` and `$executeRaw` [#simple-safe-use-of-queryraw-and-executeraw]

These methods can mitigate the risk of SQL injection by escaping all variables when you use tagged templates and sends all queries as prepared statements.

```ts
$queryRaw`...`; // Tagged template
$executeRaw`...`; // Tagged template
```

The following example is safe ✅ from SQL Injection:

```ts
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const result = await prisma.$queryRaw`SELECT id, name FROM "User" WHERE name = ${inputString}`;

console.log(result);
```

#### Unsafe use of `$queryRaw` and `$executeRaw` [#unsafe-use-of-queryraw-and-executeraw]

However, it is also possible to use these methods in unsafe ways.

One way is by artificially generating a tagged template that unsafely concatenates user input.

The following example is vulnerable ❌ to SQL Injection:

```ts
// Unsafely generate query text
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`; // SQL Injection
const query = `SELECT id, name FROM "User" WHERE name = ${inputString}`;

// Version for Typescript
const stringsArray: any = [...[query]];

// Version for Javascript
const stringsArray = [...[query]];

// Use the `raw` property to impersonate a tagged template
stringsArray.raw = [query];

// Use queryRaw
const result = await prisma.$queryRaw(stringsArray);
console.log(result);
```

Another way to make these methods vulnerable is misuse of the `Prisma.raw` function.

The following examples are all vulnerable ❌ to SQL Injection:

```ts
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const result = await prisma.$queryRaw`SELECT id, name FROM "User" WHERE name = ${Prisma.raw(
  inputString,
)}`;
console.log(result);
```

```ts
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const result = await prisma.$queryRaw(
  Prisma.raw(`SELECT id, name FROM "User" WHERE name = ${inputString}`),
);
console.log(result);
```

```ts
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
const query = Prisma.raw(`SELECT id, name FROM "User" WHERE name = ${inputString}`);
const result = await prisma.$queryRaw(query);
console.log(result);
```

#### Safely using `$queryRaw` and `$executeRaw` in more complex scenarios [#safely-using-queryraw-and-executeraw-in-more-complex-scenarios]

##### Building raw queries separate to query execution [#building-raw-queries-separate-to-query-execution]

If you want to build your raw queries elsewhere or separate to your parameters you will need to use one of the following methods.

In this example, the `sql` helper method is used to build the query text by safely including the variable. It is safe ✅ from SQL Injection:

```ts
// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;

// Safe if the text query below is completely trusted content
const query = Prisma.sql`SELECT id, name FROM "User" WHERE name = ${inputString}`;

const result = await prisma.$queryRaw(query);
console.log(result);
```

In this example which is safe ✅ from SQL Injection, the `sql` helper method is used to build the query text including a parameter marker for the input value. Each variable is represented by a marker symbol (`?` for MySQL, `$1`, `$2`, and so on for PostgreSQL). Note that the examples just show PostgreSQL queries.

```ts
// Version for Typescript
const query: any;

// Version for Javascript
const query;

// Safe if the text query below is completely trusted content
query = Prisma.sql`SELECT id, name FROM "User" WHERE name = $1`;

// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
query.values = [inputString];

const result = await prisma.$queryRaw(query);
console.log(result);
```

> **Note**: PostgreSQL variables are represented by `$1`, etc

##### Building raw queries elsewhere or in stages [#building-raw-queries-elsewhere-or-in-stages]

If you want to build your raw queries somewhere other than where the query is executed, the ideal way to do this is to create an `Sql` object from the segments of your query and pass it the parameter value.

In the following example we have two variables to parameterize. The example is safe ✅ from SQL Injection as long as the query strings being passed to `Prisma.sql` only contain trusted content:

```ts
// Example is safe if the text query below is completely trusted content
const query1 = `SELECT id, name FROM "User" WHERE name = `; // The first parameter would be inserted after this string
const query2 = ` OR name = `; // The second parameter would be inserted after this string

const inputString1 = "Fred";
const inputString2 = `'Sarah' UNION SELECT id, title FROM "Post"`;

const query = Prisma.sql([query1, query2, ""], inputString1, inputString2);
const result = await prisma.$queryRaw(query);
console.log(result);
```

> Note: Notice that the string array being passed as the first parameter `Prisma.sql` needs to have an empty string at the end as the `sql` function expects one more query segment than the number of parameters.

If you want to build your raw queries into one large string, this is still possible but requires some care as it is uses the potentially dangerous `Prisma.raw` method. You also need to build your query using the correct parameter markers for your database as Prisma won't be able to provide markers for the relevant database as it usually is.

The following example is safe ✅ from SQL Injection as long as the query strings being passed to `Prisma.raw` only contain trusted content:

```ts
// Version for Typescript
const query: any;

// Version for Javascript
const query;

// Example is safe if the text query below is completely trusted content
const query1 = `SELECT id, name FROM "User" `;
const query2 = `WHERE name = $1 `;

query = Prisma.raw(`${query1}${query2}`);

// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`;
query.values = [inputString];

const result = await prisma.$queryRaw(query);
console.log(result);
```

### In `$queryRawUnsafe` and `$executeRawUnsafe` [#in-queryrawunsafe-and-executerawunsafe]

#### Using `$queryRawUnsafe` and `$executeRawUnsafe` unsafely [#using-queryrawunsafe-and-executerawunsafe-unsafely]

If you cannot use tagged templates, you can instead use [`$queryRawUnsafe`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#queryrawunsafe) or [`$executeRawUnsafe`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#executerawunsafe). However, **be aware that these functions significantly increase the risk of SQL injection vulnerabilities in your code**.

The following example concatenates `query` and `inputString`. Prisma Client ❌ **cannot** escape `inputString` in this example, which makes it vulnerable to SQL injection:

```ts
const inputString = '"Sarah" UNION SELECT id, title, content FROM Post'; // SQL Injection
const query = "SELECT id, name, email FROM User WHERE name = " + inputString;
const result = await prisma.$queryRawUnsafe(query);

console.log(result);
```

#### Parameterized queries [#parameterized-queries]

As an alternative to tagged templates, `$queryRawUnsafe` supports standard parameterized queries where each variable is represented by a symbol (`?` for MySQL, `$1`, `$2`, and so on for PostgreSQL). Note that the examples just show PostgreSQL queries.

The following example is safe ✅ from SQL Injection:

```ts
const userName = "Sarah";
const email = "sarah@prisma.io";
const result = await prisma.$queryRawUnsafe(
  "SELECT * FROM User WHERE (name = $1 OR email = $2)",
  userName,
  email,
);
```

> **Note**: PostgreSQL variables are represented by `$1` and `$2`

As with tagged templates, Prisma Client escapes all variables when they are provided in this way.

> **Note**: You cannot pass a table or column name as a variable into a parameterized query. For example, you cannot `SELECT ?` and pass in `*` or `id, name` based on some condition.

##### Parameterized PostgreSQL `ILIKE` query [#parameterized-postgresql-ilike-query]

When you use `ILIKE`, the `%` wildcard character(s) should be included in the variable itself, not the query (`string`). This example is safe ✅ from SQL Injection.

```ts
const userName = "Sarah";
const emailFragment = "prisma.io";
const result = await prisma.$queryRawUnsafe(
  'SELECT * FROM "User" WHERE (name = $1 OR email ILIKE $2)',
  userName,
  `%${emailFragment}`,
);
```

> **Note**: Using `%$2` as an argument would not work

## Raw queries with MongoDB [#raw-queries-with-mongodb]

For MongoDB, Prisma Client exposes three methods that allow you to send raw queries. You can use:

* `$runCommandRaw` to run a command against the database
* `<model>.findRaw` to find zero or more documents that match the filter.
* `<model>.aggregateRaw` to perform aggregation operations on a collection.

### `$runCommandRaw()` [#runcommandraw]

`$runCommandRaw()` runs a raw MongoDB command against the database. As input, it accepts all [MongoDB database commands](https://www.mongodb.com/docs/manual/reference/command/), with the following exceptions:

* `find` (use [`findRaw()`](#findraw) instead)
* `aggregate` (use [`aggregateRaw()`](#aggregateraw) instead)

When you use `$runCommandRaw()` to run a MongoDB database command, note the following:

* The object that you pass when you invoke `$runCommandRaw()` must follow the syntax of the MongoDB database command.
* You must connect to the database with an appropriate role for the MongoDB database command.

In the following example, a query inserts two records with the same `_id`. This bypasses normal document validation.

```ts no-lines
prisma.$runCommandRaw({
  insert: "Pets",
  bypassDocumentValidation: true,
  documents: [
    {
      _id: 1,
      name: "Felinecitas",
      type: "Cat",
      breed: "Russian Blue",
      age: 12,
    },
    {
      _id: 1,
      name: "Nao Nao",
      type: "Dog",
      breed: "Chow Chow",
      age: 2,
    },
  ],
});
```

> [!WARNING]
> Do not use `$runCommandRaw()` for queries which contain the `"find"` or `"aggregate"` commands, because you might be unable to fetch all data. This is because MongoDB returns a [cursor](https://www.mongodb.com/docs/manual/tutorial/iterate-a-cursor/) that is attached to your MongoDB session, and you might not hit the same MongoDB session every time. For these queries, you should use the specialised [`findRaw()`](#findraw) and [`aggregateRaw()`](#aggregateraw) methods instead.

#### Return type [#return-type-2]

`$runCommandRaw()` returns a `JSON` object whose shape depends on the inputs.

#### Signature [#signature-4]

```ts no-lines
$runCommandRaw(command: InputJsonObject): PrismaPromise<JsonObject>;
```

### `findRaw()` [#findraw]

`<model>.findRaw()` returns actual database records. It will find zero or more documents that match the filter on the `User` collection:

```ts no-lines
const result = await prisma.user.findRaw({
  filter: { age: { $gt: 25 } },
  options: { projection: { _id: false } },
});
```

#### Return type [#return-type-3]

`<model>.findRaw()` returns a `JSON` object whose shape depends on the inputs.

#### Signature [#signature-5]

```ts no-lines
<model>.findRaw(args?: {filter?: InputJsonObject, options?: InputJsonObject}): PrismaPromise<JsonObject>;
```

* `filter`: The query predicate filter. If unspecified, then all documents in the collection will match the [predicate](https://www.mongodb.com/docs/manual/reference/mql/query-predicates/).
* `options`: Additional options to pass to the [`find` command](https://www.mongodb.com/docs/manual/reference/command/find/#command-fields).

### `aggregateRaw()` [#aggregateraw]

`<model>.aggregateRaw()` returns aggregated database records. It will perform aggregation operations on the `User` collection:

```ts no-lines
const result = await prisma.user.aggregateRaw({
  pipeline: [
    { $match: { status: "registered" } },
    { $group: { _id: "$country", total: { $sum: 1 } } },
  ],
});
```

#### Return type [#return-type-4]

`<model>.aggregateRaw()` returns a `JSON` object whose shape depends on the inputs.

#### Signature [#signature-6]

```ts no-lines
<model>.aggregateRaw(args?: {pipeline?: InputJsonObject[], options?: InputJsonObject}): PrismaPromise<JsonObject>;
```

* `pipeline`: An array of aggregation stages to process and transform the document stream via the [aggregation pipeline](https://www.mongodb.com/docs/atlas/data-federation/supported-unsupported/supported-aggregation/).
* `options`: Additional options to pass to the [`aggregate` command](https://www.mongodb.com/docs/manual/reference/command/aggregate/#command-fields).

#### Caveats [#caveats]

When working with custom objects like `ObjectId` or `Date,` you will have to pass them according to the [MongoDB extended JSON Spec](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/#type-representations).
Example:

```ts no-lines
const result = await prisma.user.aggregateRaw({
  pipeline: [
    { $match: { _id: { $oid: id } } },
    //                     ^ notice the $oid convention here
  ],
});
```

## Related pages

- [`SafeQL & Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/safeql): Learn how to use SafeQL and Prisma Client extensions to work around features not natively supported by Prisma, such as PostGIS
- [`TypedSQL`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql): Learn how to use TypedSQL to write fully type-safe SQL queries that are compatible with any SQL console and Prisma Client

# SafeQL & Prisma Client (Prisma ORM v7) (/docs/orm/v7/prisma-client/using-raw-sql/safeql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use SafeQL and Prisma Client extensions to work around features not natively supported by Prisma, such as PostGIS

Location: ORM > v7 > Prisma Client > Using Raw SQL > SafeQL & Prisma Client

## Overview [#overview]

This page explains how to improve the experience of writing raw SQL in Prisma ORM. It uses [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions) and [SafeQL](https://safeql.dev) to create custom, type-safe Prisma Client queries which abstract custom SQL that your app might need (using `$queryRaw`).

The example will be using [PostGIS](https://postgis.net/) and PostgreSQL, but is applicable to any raw SQL queries that you might need in your application.

> [!NOTE]
> This page builds on the [legacy raw query methods](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries) available in Prisma Client. While many use cases for raw SQL in Prisma Client are covered by [TypedSQL](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql), using these legacy methods is still the recommended approach for working with `Unsupported` fields.

## What is SafeQL? [#what-is-safeql]

[SafeQL](https://safeql.dev/) allows for advanced linting and type safety within raw SQL queries. After setup, SafeQL works with Prisma Client `$queryRaw` and `$executeRaw` to provide type safety when raw queries are required.

SafeQL runs as an [ESLint](https://eslint.org/) plugin and is configured using ESLint rules. This guide doesn't cover setting up ESLint and we will assume that you already having it running in your project.

## Prerequisites [#prerequisites]

To follow along, you will be expected to have:

* A [PostgreSQL](https://www.postgresql.org/) database with PostGIS installed
* Prisma ORM set up in your project
* ESLint set up in your project

## Geographic data support in Prisma ORM [#geographic-data-support-in-prisma-orm]

At the time of writing, Prisma ORM does not support working with geographic data, specifically using [PostGIS](https://github.com/prisma/orm/issues/2789).

A model that has geographic data columns will be stored using the [`Unsupported`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#unsupported) data type. Fields with `Unsupported` types are present in the generated Prisma Client and will be typed as `any`. A model with a required `Unsupported` type does not expose write operations such as `create`, and `update`.

Prisma Client supports write operations on models with a required `Unsupported` field using `$queryRaw` and `$executeRaw`. You can use Prisma Client extensions and SafeQL to improve the type-safety when working with geographical data in raw queries.

## 1. Set up Prisma ORM for use with PostGIS [#1-set-up-prisma-orm-for-use-with-postgis]

If you haven't already, enable the `postgresqlExtensions` Preview feature and add the `postgis` PostgreSQL extension in your Prisma schema:

```prisma
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["postgresqlExtensions"] // [!code ++]
}

datasource db {
  provider   = "postgresql"
  extensions = [postgis] // [!code ++]
}
```

> [!WARNING]
> If you are not using a hosted database provider, you will likely need to install the `postgis` extension. Refer to [PostGIS's docs](http://postgis.net/documentation/getting_started/#installing-postgis) to learn more about how to get started with PostGIS. If you're using Docker Compose, you can use the following snippet to set up a PostgreSQL database that has PostGIS installed:
> 
> ```yaml
> version: "3.6"
> services:
>   pgDB:
>     image: postgis/postgis:13-3.1-alpine
>     restart: always
>     ports:
>       - "5432:5432"
>     volumes:
>       - db_data:/var/lib/postgresql/data
>     environment:
>       POSTGRES_PASSWORD: password
>       POSTGRES_DB: geoexample
> volumes:
>   db_data:
> ```

Next, create a migration and execute a migration to enable the extension:

  

#### bun

```bash
bunx prisma migrate dev --name add-postgis
```

#### pnpm

```bash
pnpm prisma migrate dev --name add-postgis
```

#### yarn

```bash
yarn prisma migrate dev --name add-postgis
```

#### npm

```bash
npx prisma migrate dev --name add-postgis
```

For reference, the output of the migration file should look like the following:

```sql title="migrations/TIMESTAMP_add_postgis/migration.sql"
-- CreateExtension
CREATE EXTENSION IF NOT EXISTS "postgis";
```

You can double-check that the migration has been applied by running `prisma migrate status`.

## 2. Create a new model that uses a geographic data column [#2-create-a-new-model-that-uses-a-geographic-data-column]

Add a new model with a column with a `geography` data type once the migration is applied. For this guide, we'll use a model called `PointOfInterest`.

```prisma
model PointOfInterest {
  id       Int                                   @id @default(autoincrement())
  name     String
  location Unsupported("geography(Point, 4326)")
}
```

You'll notice that the `location` field uses an [`Unsupported`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#unsupported) type. This means that we lose a lot of the benefits of Prisma ORM when working with `PointOfInterest`. We'll be using [SafeQL](https://safeql.dev/) to fix this.

Like before, create and execute a migration using the `prisma migrate dev` command to create the `PointOfInterest` table in your database:

  

#### bun

```bash
bunx prisma migrate dev --name add-poi
```

#### pnpm

```bash
pnpm prisma migrate dev --name add-poi
```

#### yarn

```bash
yarn prisma migrate dev --name add-poi
```

#### npm

```bash
npx prisma migrate dev --name add-poi
```

For reference, here is the output of the SQL migration file generated by Prisma Migrate:

```sql title="migrations/TIMESTAMP_add_poi/migration.sql"
-- CreateTable
CREATE TABLE "PointOfInterest" (
    "id" SERIAL NOT NULL,
    "name" TEXT NOT NULL,
    "location" geography(Point, 4326) NOT NULL,

    CONSTRAINT "PointOfInterest_pkey" PRIMARY KEY ("id")
);
```

## 3. Integrate SafeQL [#3-integrate-safeql]

SafeQL integrates with Prisma ORM to lint `$queryRaw` and `$executeRaw` Prisma operations. You can reference [SafeQL's integration guide](https://safeql.dev/compatibility/prisma.html) or follow the steps below.

### 3.1. Install the `@ts-safeql/eslint-plugin` npm package [#31-install-the-ts-safeqleslint-plugin-npm-package]

  

#### bun

```bash
bun add --dev @ts-safeql/eslint-plugin libpg-query
```

#### pnpm

```bash
pnpm add -D @ts-safeql/eslint-plugin libpg-query
```

#### yarn

```bash
yarn add --dev @ts-safeql/eslint-plugin libpg-query
```

#### npm

```bash
npm install -D @ts-safeql/eslint-plugin libpg-query
```

This ESLint plugin is what will allow for queries to be linted.

### 3.2. Add `@ts-safeql/eslint-plugin` to your ESLint plugins [#32-add-ts-safeqleslint-plugin-to-your-eslint-plugins]

Next, add `@ts-safeql/eslint-plugin` to your list of ESLint plugins. In our example we are using an `.eslintrc.js` file, but this can be applied to any way that you [configure ESLint](https://eslint.org/docs/latest/use/configure/).

```js title=".eslintrc.js" highlight=3
/** @type {import('eslint').Linter.Config} */
module.exports = {
  "plugins": [..., "@ts-safeql/eslint-plugin"],
  ...
}
```

### 3.3 Add `@ts-safeql/check-sql` rules [#33-add-ts-safeqlcheck-sql-rules]

Now, setup the rules that will enable SafeQL to mark invalid SQL queries as ESLint errors.

```js title=".eslintrc.js" highlight=4-22;add
/** @type {import('eslint').Linter.Config} */
module.exports = {
  plugins: [..., '@ts-safeql/eslint-plugin'],
  rules: { // [!code ++]
    '@ts-safeql/check-sql': [ // [!code ++]
      'error', // [!code ++]
      { // [!code ++]
        connections: [ // [!code ++]
          { // [!code ++]
            // The migrations path: // [!code ++]
            migrationsDir: './prisma/migrations', // [!code ++]
            targets: [ // [!code ++]
              // This makes `prisma.$queryRaw` and `prisma.$executeRaw` commands linted // [!code ++]
              { tag: 'prisma.+($queryRaw|$executeRaw)', transform: '{type}[]' }, // [!code ++]
            ], // [!code ++]
          }, // [!code ++]
        ], // [!code ++]
      }, // [!code ++]
    ], // [!code ++]
  }, // [!code ++]
} // [!code ++]
```

> **Note**: If your `PrismaClient` instance is called something different than `prisma`, you need to adjust the value for `tag` accordingly. For example, if it is called `db`, the value for `tag` should be `'db.+($queryRaw|$executeRaw)'`.

### 3.4. Connect to your database [#34-connect-to-your-database]

Finally, set up a `connectionUrl` for SafeQL so that it can introspect your database and retrieve the table and column names you use in your schema. SafeQL then uses this information for linting and highlighting problems in your raw SQL statements.

Our example relies on the [`dotenv`](https://github.com/motdotla/dotenv) package to get the same connection string that is used by Prisma ORM. We recommend this in order to keep your database URL out of version control.

If you haven't installed `dotenv` yet, you can install it as follows:

  

#### bun

```bash
bun add dotenv
```

#### pnpm

```bash
pnpm add dotenv
```

#### yarn

```bash
yarn add dotenv
```

#### npm

```bash
npm install dotenv
```

Then update your ESLint config as follows:

```js title=".eslintrc.js" highlight=1,6-9,16;add
require("dotenv").config(); // [!code ++]

/** @type {import('eslint').Linter.Config} */
module.exports = {
  plugins: ["@ts-safeql/eslint-plugin"],
  // exclude `parserOptions` if you are not using TypeScript // [!code ++]
  parserOptions: {
    // [!code ++]
    project: "./tsconfig.json", // [!code ++]
  }, // [!code ++]
  rules: {
    "@ts-safeql/check-sql": [
      "error",
      {
        connections: [
          {
            connectionUrl: process.env.DATABASE_URL, // [!code ++]
            // The migrations path:
            migrationsDir: "./prisma/migrations",
            targets: [
              // what you would like SafeQL to lint. This makes `prisma.$queryRaw` and `prisma.$executeRaw`
              // commands linted
              { tag: "prisma.+($queryRaw|$executeRaw)", transform: "{type}[]" },
            ],
          },
        ],
      },
    ],
  },
};
```

SafeQL is now configured to lint the raw SQL you write with Prisma Client.

## 4. Creating extensions to make raw SQL queries type-safe [#4-creating-extensions-to-make-raw-sql-queries-type-safe]

In this section, we'll create two [`model`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model) extensions with custom queries to be able to work conveniently with the `PointOfInterest` model:

1. A `create` query that allows us to create new `PointOfInterest` records in the database
2. A `findClosestPoints` query that returns the `PointOfInterest` records that are closest to a given coordinate

### 4.1. Adding an extension to create `PointOfInterest` records [#41-adding-an-extension-to-create-pointofinterest-records]

The `PointOfInterest` model in the Prisma schema uses an `Unsupported` type. As a consequence, the generated `PointOfInterest` type in Prisma Client can't be used to carry values for latitude and longitude.

We will resolve this by defining two custom types that better represent our model in TypeScript:

```ts
type MyPoint = {
  latitude: number;
  longitude: number;
};

type MyPointOfInterest = {
  name: string;
  location: MyPoint;
};
```

Next, you can add a `create` query to the `pointOfInterest` property of your Prisma Client:

```ts highlight=19;normal
const prisma = new PrismaClient().$extends({
  model: {
    pointOfInterest: {
      async create(data: { name: string; latitude: number; longitude: number }) {
        // Create an object using the custom types from above
        const poi: MyPointOfInterest = {
          name: data.name,
          location: {
            latitude: data.latitude,
            longitude: data.longitude,
          },
        };

        // Insert the object into the database
        const point = `POINT(${poi.location.longitude} ${poi.location.latitude})`;
        await prisma.$queryRaw`
          INSERT INTO "PointOfInterest" (name, location) VALUES (${poi.name}, ST_GeomFromText(${point}, 4326));
        `;

        // Return the object
        return poi;
      },
    },
  },
});
```

Notice that the SQL in the line that's highlighted in the code snippet gets checked by SafeQL! For example, if you change the name of the table from `"PointOfInterest"` to `"PointOfInterest2"`, the following error appears:

```
error  Invalid Query: relation "PointOfInterest2" does not exist  @ts-safeql/check-sql
```

This also works with the column names `name` and `location`.

You can now create new `PointOfInterest` records in your code as follows:

```ts
const poi = await prisma.pointOfInterest.create({
  name: "Berlin",
  latitude: 52.52,
  longitude: 13.405,
});
```

### 4.2. Adding an extension to query for closest to `PointOfInterest` records [#42-adding-an-extension-to-query-for-closest-to-pointofinterest-records]

Next, add a Prisma Client extension that finds the closest points of interest to a given longitude and latitude.

```ts
const prisma = new PrismaClient().$extends({
  model: {
    pointOfInterest: {
      async create(data: { name: string; latitude: number; longitude: number }) {
        // ... same code as before
      },

      async findClosestPoints(latitude: number, longitude: number) {
        // Query for closest points of interest
        const result = await prisma.$queryRaw<
          {
            id: number | null;
            name: string | null;
            st_x: number | null;
            st_y: number | null;
          }[]
        >`SELECT id, name, ST_X(location::geometry), ST_Y(location::geometry)
            FROM "PointOfInterest"
            ORDER BY ST_DistanceSphere(location::geometry, ST_MakePoint(${longitude}, ${latitude})) DESC`;

        // Transform to our custom type
        const pois: MyPointOfInterest[] = result.map((data) => {
          return {
            name: data.name,
            location: {
              latitude: data.st_x || 0,
              longitude: data.st_y || 0,
            },
          };
        });

        // Return data
        return pois;
      },
    },
  },
});
```

Now, you can use our Prisma Client as normal to find close points of interest to a given longitude and latitude using the custom method created on the `PointOfInterest` model.

```ts
const closestPointOfInterest = await prisma.pointOfInterest.findClosestPoints(53.5488, 9.9872);
```

Similar to before, we again have the benefit of SafeQL to add extra type safety to our raw queries. For example, if we removed the cast to `geometry` for `location` by changing `location::geometry` to just `location`, we would get linting errors in the `ST_X`, `ST_Y` or `ST_DistanceSphere` functions respectively.

```bash
error  Invalid Query: function st_distancesphere(geography, geometry) does not exist  @ts-safeql/check-sql
```

## Conclusion [#conclusion]

While you may sometimes need to drop down to raw SQL when using Prisma ORM, you can use various techniques to make the experience of writing raw SQL queries with Prisma ORM better.

In this article, you have used SafeQL and Prisma Client extensions to create custom, type-safe Prisma Client queries to abstract PostGIS operations which are currently not natively supported in Prisma ORM.

## Related pages

- [`Raw queries`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries): Learn how you can send raw SQL and MongoDB queries to your database using the raw() methods from the Prisma Client API
- [`TypedSQL`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/typedsql): Learn how to use TypedSQL to write fully type-safe SQL queries that are compatible with any SQL console and Prisma Client

# TypedSQL (Prisma ORM v7) (/docs/orm/v7/prisma-client/using-raw-sql/typedsql)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to use TypedSQL to write fully type-safe SQL queries that are compatible with any SQL console and Prisma Client

Location: ORM > v7 > Prisma Client > Using Raw SQL > TypedSQL

## Getting started with TypedSQL [#getting-started-with-typedsql]

To start using TypedSQL in your Prisma project, follow these steps:

1. Ensure you have `@prisma/client` and `prisma` installed:

   
     

#### bun

```bash
bun add @prisma/client@7
bun add --dev prisma@prev
```

#### pnpm

```bash
pnpm add @prisma/client@7
pnpm add -D prisma@prev
```

#### yarn

```bash
yarn add @prisma/client@7
yarn add --dev prisma@prev
```

#### npm

```bash
npm install @prisma/client@7
npm install -D prisma@prev
```
   

2. Add the `typedSql` preview feature flag to your `schema.prisma` file:

   ```prisma
   generator client {
    provider = "prisma-client"
    previewFeatures = ["typedSql"]
    output = "../src/generated/prisma"
   }
   ```

   > [!NOTE]
> Using driver adapters with TypedSQL
> 
> If you are deploying Prisma in serverless or edge environments, you can use [driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers#driver-adapters) to connect through JavaScript database drivers. Driver adapters are compatible with TypedSQL, with the exception of `@prisma/adapter-better-sqlite3`. For SQLite support, use [`@prisma/adapter-libsql`](https://www.npmjs.com/package/@prisma/adapter-libsql) instead. All other driver adapters are supported.

3. Create a `sql` directory inside your `prisma` directory. This is where you'll write your SQL queries.

   ```bash
   mkdir -p prisma/sql
   ```

   > [!NOTE]
> Custom SQL folder location
> 
> Starting with Prisma 6.12.0, you can configure a custom location for your SQL files using the Prisma config file. Create a `prisma.config.ts` file in your project root and specify the `typedSql.path` option:
> 
> ```typescript title="prisma.config.ts"
> import "dotenv/config";
> import { defineConfig } from "prisma/config";
>
> export default defineConfig({
>   schema: "prisma/schema.prisma",
>   typedSql: {
>     path: "./prisma/sql",
>   },
> });
> ```

4. Create a new `.sql` file in your `prisma/sql` directory. For example, `getUsersWithPosts.sql`. Note that the file name must be a valid JS identifier and cannot start with a `$`.

5. Write your SQL queries in your new `.sql` file. For example:

   ```sql title="prisma/sql/getUsersWithPosts.sql"
   SELECT u.id, u.name, COUNT(p.id) as "postCount"
   FROM "User" u
   LEFT JOIN "Post" p ON u.id = p."authorId"
   GROUP BY u.id, u.name
   ```

6. Generate Prisma Client with the `sql` flag to ensure TypeScript functions and types for your SQL queries are created:

   > [!WARNING]
> Make sure that any pending migrations are applied before generating the client with the `sql` flag.

   ```bash
   prisma generate --sql
   ```

   If you don't want to regenerate the client after every change, this command also works with the existing `--watch` flag:

   ```bash
   prisma generate --sql --watch
   ```

7. Now you can import and use your SQL queries in your TypeScript code:

```typescript title="/src/index.ts"
import { PrismaClient } from "./generated/prisma/client";
import { getUsersWithPosts } from "./generated/prisma/sql";

const prisma = new PrismaClient();

const usersWithPostCounts = await prisma.$queryRawTyped(getUsersWithPosts());
console.log(usersWithPostCounts);
```

> [!NOTE]
> If you do not customize the generator `output`, you can import from `@prisma/client` and `@prisma/client/sql` instead.

## Passing Arguments to TypedSQL Queries [#passing-arguments-to-typedsql-queries]

To pass arguments to your TypedSQL queries, you can use parameterized queries. This allows you to write flexible and reusable SQL statements while maintaining type safety. Here's how to do it:

1. In your SQL file, use placeholders for the parameters you want to pass. The syntax for placeholders depends on your database engine:

For PostgreSQL, use the positional placeholders `$1`, `$2`, etc. For MySQL, use `?`. In SQLite, you can use positional (`$1`, `$2`), general (`?`), or named placeholders (`:minAge`, `:maxAge`):

  

#### PostgreSQL

```sql title="prisma/sql/getUsersByAge.sql" 
SELECT id, name, age
FROM users
WHERE age > $1 AND age < $2
```

#### MySQL

```sql title="prisma/sql/getUsersByAge.sql" 
SELECT id, name, age
FROM users
WHERE age > ? AND age < ?
```

#### SQLite

```sql title="prisma/sql/getUsersByAge.sql" 
SELECT id, name, age
FROM users
WHERE age > :minAge AND age < :maxAge
```

> [!NOTE]
> See below for information on how to [define argument types in your SQL files](#defining-argument-types-in-your-sql-files).

1. When using the generated function in your TypeScript code, pass the arguments as additional parameters to `$queryRawTyped`:

```typescript title="/src/index.ts"
import { PrismaClient } from "./generated/prisma/client";
import { getUsersByAge } from "./generated/prisma/sql";

const prisma = new PrismaClient();

const minAge = 18;
const maxAge = 30;
const users = await prisma.$queryRawTyped(getUsersByAge(minAge, maxAge));
console.log(users);
```

By using parameterized queries, you ensure type safety and protect against SQL injection vulnerabilities. The TypedSQL generator will create the appropriate TypeScript types for the parameters based on your SQL query, providing full type checking for both the query results and the input parameters.

### Passing array arguments to TypedSQL [#passing-array-arguments-to-typedsql]

TypedSQL supports passing arrays as arguments for PostgreSQL. Use PostgreSQL's `ANY` operator with an array parameter.

```sql title="prisma/sql/getUsersByIds.sql"
SELECT id, name, email
FROM users
WHERE id = ANY($1)
```

```typescript title="/src/index.ts"
import { PrismaClient } from "./generated/prisma/client";
import { getUsersByIds } from "./generated/prisma/sql";

const prisma = new PrismaClient();

const userIds = [1, 2, 3];
const users = await prisma.$queryRawTyped(getUsersByIds(userIds));
console.log(users);
```

TypedSQL will generate the appropriate TypeScript types for the array parameter, ensuring type safety for both the input and the query results.

> [!NOTE]
> When passing array arguments, be mindful of the maximum number of placeholders your database supports in a single query. For very large arrays, you may need to split the query into multiple smaller queries.

### Defining argument types in your SQL files [#defining-argument-types-in-your-sql-files]

Argument typing in TypedSQL is accomplished via specific comments in your SQL files. These comments are of the form:

```sql
-- @param {Type} $N:alias optional description
```

Where `Type` is a valid database type, `N` is the position of the argument in the query, and `alias` is an optional alias for the argument that is used in the TypeScript type.

As an example, if you needed to type a single string argument with the alias `name` and the description "The name of the user", you would add the following comment to your SQL file:

```sql
-- @param {String} $1:name The name of the user
```

To indicate that a parameter is nullable, add a question mark after the alias:

```sql
-- @param {String} $1:name? The name of the user (optional)
```

Currently accepted types are `Int`, `BigInt`, `Float`, `Boolean`, `String`, `DateTime`, `Json`, `Bytes`, `null`, and `Decimal`.

Taking the [example from above](#passing-arguments-to-typedsql-queries), the SQL file would look like this:

```sql
-- @param {Int} $1:minAge
-- @param {Int} $2:maxAge
SELECT id, name, age
FROM users
WHERE age > $1 AND age < $2
```

The format of argument type definitions is the same regardless of the database engine.

> [!NOTE]
> Manual argument type definitions are not supported for array arguments. For these arguments, you will need to rely on the type inference provided by TypedSQL.

## Examples [#examples]

For practical examples of how to use TypedSQL, please refer to the [TypedSQL example in the Prisma Examples repo](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/basic-typedsql).

## Limitations of TypedSQL [#limitations-of-typedsql]

### Supported Databases [#supported-databases]

TypedSQL supports recent versions of MySQL and PostgreSQL without any further configuration. For MySQL versions older than 8.0 and all SQLite versions, you will need to manually [describe argument types](#defining-argument-types-in-your-sql-files) in your SQL files. The types of inputs are inferred in all supported versions of PostgreSQL and MySQL 8.0 and later.

TypedSQL does not work with MongoDB, as it is specifically designed for SQL databases.

### Active Database Connection Required [#active-database-connection-required]

TypedSQL requires an active database connection to function properly. This means you need to have a running database instance that Prisma can connect to when generating the client with the `--sql` flag. TypedSQL uses the connection string defined in `prisma.config.ts` (`datasource.url`) to establish this connection.

### Dynamic SQL Queries with Dynamic Columns [#dynamic-sql-queries-with-dynamic-columns]

TypedSQL does not natively support constructing SQL queries with dynamically added columns. When you need to create a query where the columns are determined at runtime, you must use the `$queryRawUnsafe` and `$executeRawUnsafe` methods. These methods allow for the execution of raw SQL, which can include dynamic column selections.

**Example of a query using dynamic column selection:**

```typescript
const columns = "name, email, age"; // Columns determined at runtime
const result = await prisma.$queryRawUnsafe(`SELECT ${columns} FROM Users WHERE active = true`);
```

In this example, the columns to be selected are defined dynamically and included in the SQL query. While this approach provides flexibility, it requires careful attention to security, particularly to [avoid SQL injection vulnerabilities](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#sql-injection-prevention). Raw SQL queries also forego the type safety of TypedSQL.

## Acknowledgements [#acknowledgements]

This feature was heavily inspired by [PgTyped](https://github.com/adelsz/pgtyped) and [SQLx](https://github.com/launchbadge/sqlx). SQLite parsing is also handled by SQLx.

## Related pages

- [`Raw queries`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries): Learn how you can send raw SQL and MongoDB queries to your database using the raw() methods from the Prisma Client API
- [`SafeQL & Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/safeql): Learn how to use SafeQL and Prisma Client extensions to work around features not natively supported by Prisma, such as PostGIS

# Limitations and known issues (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/limitations-and-known-issues)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Location: ORM > v7 > Prisma Migrate > Understanding Prisma Migrate > Limitations and known issues

## MongoDB connector not supported [#mongodb-connector-not-supported]

Prisma Migrate does not currently support the MongoDB connector.

## You cannot automatically switch database providers [#you-cannot-automatically-switch-database-providers]

Prisma Migrate generates SQL files that are specific to your provider. This means that you cannot use the same migration files for PostgreSQL in production and SQLite in development, because the syntax in the migrations will be incompatible.

As of [2.15.0](https://github.com/prisma/orm/releases/2.15.0), Prisma Migrate detects when the migrations do not match the configured provider and prints a helpful error message. For example, if your migrations are for a PostgreSQL database but your `provider` is set to `mysql`:

```
Error: P3014

The datasource provider `postgresql` specified in your schema does not match the one specified in the migration_lock.toml, mysql. Please remove your current migration directory and start a new migration history with prisma migrate dev.
```

In order to manually switch the database provider, you must:

* Change the `provider` parameters in the `datasource` block in your schema
* Update the `url` in the `datasource` object in your config
* Archive or remove your existing migration history - there must not be a `./prisma/migrations` folder
* Run `prisma migrate dev` to start a new migration history

The last step creates a new initial migration that goes from an empty database to your current `schema.prisma`. Be aware that:

* This migration will *only* contain what is reflected in your `schema.prisma`. If you manually edited your previous migration files to add custom SQL you will need to again add this yourself.
* The newly created database using the new provider will not contain any data.

## Data loss when resetting database [#data-loss-when-resetting-database]

In a development environment, Prisma Migrate sometimes prompts you to reset the database. Resetting drops and recreates the database, which results in data loss. The database is reset when:

* You call `prisma migrate reset` explicitly
* You call `prisma migrate dev` and Prisma Migrate detects drift in the database or a migration history conflict

The `prisma migrate dev` and `prisma migrate reset` commands are designed to be used **in development only**, and should not affect production data.

When the database is reset, if Prisma Migrate detects a seed script in `prisma.config.ts`, it will trigger seeding.

> [!NOTE]
> Note
> 
> To re-create data automatically when the database is reset, see the [seeding guide](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/seeding).

## Prisma Migrate and PgBouncer [#prisma-migrate-and-pgbouncer]

You might see the following error if you attempt to run Prisma Migrate commands in an environment that uses PgBouncer for connection pooling:

```bash allowCopy=false
Error: undefined: Database error
Error querying the database: db error: ERROR: prepared statement "s0" already exists
```

See [Prisma Migrate and PgBouncer workaround](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/pgbouncer) for further information and a workaround. Follow [GitHub issue #6485](https://github.com/prisma/orm/issues/6485) for updates.

## Prisma Migrate in non-interactive environments [#prisma-migrate-in-non-interactive-environments]

Prisma ORM detects when you run CLI commands in non-interactive environments, such as Docker, from Node scripts or in bash shells. When this happens a warning displays, indicating that the environment is non-interactive and the `migrate dev` command is not supported.

To ensure the Docker environment picks up the command, run the image in `interactive` mode so that it reacts to the `migrate dev` command.

```bash
docker run --interactive --tty <image name>
# or
docker -it <image name>

# Example usage
docker run -it node
```

## Related pages

- [`About the shadow database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database): Learn how Prisma Migrate uses shadow databases to detect schema drift
- [`Migration histories`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/migration-histories): How Prisma ORM uses migration histories to track changes to your schema
- [`Understanding Migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/mental-model): A mental model guide for working with Prisma Migrate in your project

# Understanding Migrations (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/mental-model)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A mental model guide for working with Prisma Migrate in your project

Location: ORM > v7 > Prisma Migrate > Understanding Prisma Migrate > Understanding Migrations

## What are database migrations? [#what-are-database-migrations]

Database migrations are a controlled set of changes that modify and evolve the structure of your database schema. Migrations help you transition your database schema from one state to another. For example, within a migration you can create or remove tables and columns, split fields in a table, or add types and constraints to your database.

### Patterns for evolving database schemas [#patterns-for-evolving-database-schemas]

For migrations, there are two main types of migrations that can be made:

* **Model/Entity-first migration:** with this pattern, you define the structure of the database schema with code and then use a migration tool to generate the SQL, for example, for syncing your application and database schema.

![Model-first migration flow](https://www.prisma.io/img/orm/prisma-migrate/understanding-prisma-migrate/mental-model-illustrations/entity-first-migration-flow.png)

* **Database-first migration:** with this pattern, you define the structure of your database and apply it to your database using SQL. You then *introspect* the database to generate the code that describes the structure of your database to sync your application and database schema.

![Database-first migration flow](https://www.prisma.io/img/orm/prisma-migrate/understanding-prisma-migrate/mental-model-illustrations/database-first-migration-flow.png)

> [!NOTE]
> Note
> 
> For simplicity, we chose the terminology above to describe the different patterns for evolving database schemas. Other tools and libraries may use different terminology to describe the different patterns.

The migration files (SQL) should ideally be stored together with your application code. They should also be tracked in version control and shared with the rest of the team working on the application. Migrations provide *state management* which helps you to track the state of the database.

Migrations also allow you to replicate the state of a database at a specific point in time which is useful when collaborating with other members of the team, e.g. switching between different branches. For further information on database migrations, see the [Prisma Data Guide](https://www.prisma.io/dataguide/types/relational/what-are-database-migrations).

## What is Prisma Migrate? [#what-is-prisma-migrate]

Prisma Migrate is a database migration tool that supports the *model/ entity-first* migration pattern to manage database schemas in your local environment and in production.

The workflow when using Prisma Migrate in your project would be iterative and look like this:

### Local development environment (Feature branch) [#local-development-environment-feature-branch]

* Evolve your Prisma schema
* Use either [`prisma migrate dev`](#track-your-migration-history-with-prisma-migrate-dev) or [`prisma db push`](#prototype-your-schema) to sync your Prisma schema with the database schema of your local development database

### Preview/ staging environment(Feature pull request) [#preview-staging-environmentfeature-pull-request]

1. Push your changes to the feature pull request
2. Use a CI system (e.g. GitHub Actions) to sync your Prisma schema and migration history with your preview database using `prisma migrate deploy`

### Production (main branch) [#production-main-branch]

* Merge your application code from the feature branch to your main branch.
* Use a CI system (e.g. GitHub Actions) to sync your Prisma schema and migration history with your production database using `prisma migrate deploy`

![Prisma Migrate workflow](https://www.prisma.io/img/orm/prisma-migrate/understanding-prisma-migrate/mental-model-illustrations/prisma-migrate-lifecycle.png)

## How Prisma Migrate tracks the migration state [#how-prisma-migrate-tracks-the-migration-state]

Prisma Migrate uses the following pieces of state to track the state of your database schema:

* **Prisma schema**: your source of truth that defines the structure of the database schema.
* **Migrations history**: SQL files in your `prisma/migrations` folder representing the history of changes made to your database schema.
* **Migrations table**: `prisma_migrations` table in the database that stores metadata for migrations that have been applied to the database.
* **Database schema**: the state of the database.

![Prisma Migrate "state management"](https://www.prisma.io/img/orm/prisma-migrate/understanding-prisma-migrate/mental-model-illustrations/prisma-migrate-state-mgt.png)

## Requirements when working with Prisma Migrate [#requirements-when-working-with-prisma-migrate]

* Ideally, you should use one database per environment. For example, you might have a separate database for development, preview, and production environments.
* The databases you use in development environments are disposable, so you can create, use, and delete databases on demand.
* The database configuration used in each environments should be consistent. This is important to ensure a certain migration that moves across the workflow yields the same changes to the database.
* The Prisma schema serves as the source of truth — describing the shape of your [database schema](https://www.prisma.io/dataguide/intro/database-glossary#schema).

## Evolve your database schema with Prisma Migrate [#evolve-your-database-schema-with-prisma-migrate]

This section describes how you can evolve your database schema in different environments: development, staging, and production, using Prisma Migrate.

### Prisma Migrate in a development environment (local) [#prisma-migrate-in-a-development-environment-local]

#### Track your migration history with `prisma migrate dev` [#track-your-migration-history-with-prisma-migrate-dev]

The [`prisma migrate dev`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-dev) command allows you to track the changes you make to your database. The `prisma migrate dev` command automatically generates SQL migration files (saved in `/prisma/migrations`) and applies them to the database. When a migration is applied to the database, the migrations table (`_prisma_migrations`) in your database is also updated.

![Prisma Migrate dev flow](https://www.prisma.io/img/orm/prisma-migrate/understanding-prisma-migrate/mental-model-illustrations/prisma-migrate-dev-flow.png)

The `prisma migrate dev` command tracks the state of the database using the following pieces of state:

* the Prisma schema
* the migrations history
* the migrations table
* the database schema

> [!NOTE]
> Note
> 
> The pieces of state used to track the state of a migration are the same as the ones described in [how Prisma Migrate tracks the migration state](#how-prisma-migrate-tracks-the-migration-state) section.

You can customize migrations before you apply them to the database using the `--create-only` flag. For example, you might want to edit a migration if you want to rename columns without incurring any data loss or load database extensions (in PostgreSQL) and database views (currently not supported).

Under the hood, Prisma Migrate uses a [shadow database](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database) to detect a [schema drift](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database#detecting-schema-drift) and generate new migrations.

> [!NOTE]
> Note
> 
> `prisma migrate dev` is intended to be used only in development with a disposable database.

If `prisma migrate dev` detects a schema drift or a migration history conflict, you will be prompted to reset (drop and recreate your database) your database to sync the migration history and the database schema.

**Expand to see the shadow database explained using a cartoon**

![A cartoon that shows how the shadow database works.](https://www.prisma.io/img/orm/prisma-migrate/understanding-prisma-migrate/shadow-database.png)

#### Resolve schema drifts [#resolve-schema-drifts]

A schema drift occurs when the expected database schema is different from what is in the migration history. For example, this can occur when you manually update the database schema without also updating the Prisma schema and `prisma/migrations` accordingly.

For such instances, you can use the [`prisma migrate diff`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-diff) command to compare your migration history and revert changes made to your database schema.

![Revert database schema with migrate diff](https://www.prisma.io/img/orm/prisma-migrate/understanding-prisma-migrate/mental-model-illustrations/prisma-migrate-diff-flow.png)

You can use `migrate diff` to generate the SQL that either:

* Reverts the changes made in the database schema to synchronize it with the current Prisma schema
* Moves your database schema forward to apply missing changes from the Prisma schema and `/migrations`

You can then apply the changes to your database using [`prisma db execute`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-execute) command.

#### Prototype your schema [#prototype-your-schema]

The [`prisma db push`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-push) command allows you to sync your Prisma schema and database schema without persisting a migration (`/prisma/migrations`). The `prisma db push` command tracks the state of the database using the following pieces of state:

* the Prisma schema
* the database schema

![prisma db push development flow](https://www.prisma.io/img/orm/prisma-migrate/understanding-prisma-migrate/mental-model-illustrations/db-push-flow.png)

The `prisma db push` command is useful when:

* You want to **quickly prototype and iterate** on schema design locally without the need to deploy these changes to other environments such as other developers, or staging and production environments.
* You are prioritizing reaching a **desired end-state** and not the changes or steps executed to reach that end-state (there is no way to preview changes made by `prisma db push`)
* You do not need to control how schema changes impact data. There is no way to orchestrate schema and data migrations - if `prisma db push` anticipates that changes will result in data loss, you can either accept data loss with the `--accept-data-loss` option or stop the process - there is no way to customize the changes.

If the `prisma db push` command detects destructive change to your database schema, it will prompt you to reset your database. For example, this will happen when you add a required field to a table with existing content without providing a default value.

> [!NOTE]
> Schema Drift
> 
> A [schema drift](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/troubleshooting#schema-drift) occurs when your database schema is out of sync with your migrations history and migrations table.

### Prisma Migrate in a staging and production environment [#prisma-migrate-in-a-staging-and-production-environment]

#### Sync your migration histories [#sync-your-migration-histories]

The [`prisma migrate deploy`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-deploy) command allows you to sync your migration history from your development environment with your database in your **staging or production environment**.

Under the hood, the `migrate deploy` command:

1. Compares already applied migrations (captured `_prisma_migrations`) and the migration history (`/prisma/migrations`)
2. Applies pending migrations
3. Updates `_prisma_migrations` table with the new migrations

![Workflow of Prisma Migrate](https://www.prisma.io/img/orm/prisma-migrate/workflows/deploy-db.png)

The command should be run in an automated CI/ CD environment, for example GitHub Actions.

If you don't have a migration history (`/migrations`), i.e using `prisma db push`, you will have to continue using `prisma db push` in your staging and production environments. Beware of the changes being applied to the database schema as some of them might be destructive. For example, `prisma db push` can't tell when you're performing a column rename. It will prompt a database reset (drop and re-creation).

## Related pages

- [`About the shadow database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database): Learn how Prisma Migrate uses shadow databases to detect schema drift
- [`Limitations and known issues`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/limitations-and-known-issues)
- [`Migration histories`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/migration-histories): How Prisma ORM uses migration histories to track changes to your schema

# Migration histories (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/migration-histories)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How Prisma ORM uses migration histories to track changes to your schema

Location: ORM > v7 > Prisma Migrate > Understanding Prisma Migrate > Migration histories

Your migration history is the story of the changes to your data model, and is represented by:

* A `prisma/migrations` folder with a sub-folder and `migration.sql` file for each migration:

```
migrations/
  └─ 20210313140442_init/
    └─ migration.sql
  └─ 20210313140442_added_job_title/
    └─ migration.sql
```

The `migrations` folder is the **source of truth** for the history of your data model.

* A `_prisma_migrations` table in the database, which is used to check:
  * If a migration was run against the database
  * If an applied migration was deleted
  * If an applied migration was changed

If you change or delete a migration (**not** recommended), the next steps depend on whether you are in a [development environment](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production#production-and-testing-environments) (and therefore using `migrate dev`) or a [production / testing environment](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production#production-and-testing-environments) (and therefore using `migrate deploy`).

## Do not edit or delete migrations that have been applied [#do-not-edit-or-delete-migrations-that-have-been-applied]

In general, you **should not edit or delete** a migration that has already been applied. Doing so can lead to inconsistencies between development and production environment migration histories, which may have unforeseen consequences, even if the change does not *appear* to break anything at first.

The following scenario simulates a change that creates a seemingly harmless inconsistency:

* Modify an **existing migration** that has **already been applied** in a development environment by changing the value of `VARCHAR(550)` to `VARCHAR(560)`:

  ```sql title="migrations.sql"
    -- AlterTable
   ALTER TABLE "Post" ALTER COLUMN "content" SET DATA TYPE VARCHAR(560);
  ```

  After making this change, the end state of the migration history no longer matches the Prisma schema, which still has `@db.VarChar(550)`.
* Running `prisma migrate dev` results in an error because a migration has been changed and suggests resetting the database.
* Run `prisma migrate reset` - Prisma Migrate resets the database and replays all migrations, including the migration you edited.
* After applying all existing migrations, Prisma Migrate compares the end state of the migration history to the Prisma schema and detects a discrepancy:
  * Prisma schema has `@db.VarChar(550)`
  * Database schema has `VARCHAR(560)`
* Prisma Migrate generates a new migration to change the value back to `550`, because the end state of the migration history should match the Prisma schema.
* From now on, when you use `prisma migrate deploy` to deploy migrations to production and test environments, Prisma Migrate will always **warn you** that migration histories do not match (and continue to warn you each time you run the command ) - even though the schema end states match:

  ```
  6 migrations found in prisma/migrations
  WARNING The following migrations have been modified since they were applied:
  20210310143435_change_type
  ```

A change that does not appear to break anything after a `migrate reset` can hide problems - you may end up with a bug in production that you cannot replicate in development, or the other way around - particularly if the change concerns a highly customized migration.

If Prisma Migrate reports a missing or edited migration that has already been applied, we recommend fixing the **root cause** (restoring the file or reverting the change) rather than resetting.

## Committing the migration history to source control [#committing-the-migration-history-to-source-control]

You must commit the entire `prisma/migrations` folder to source control. This includes the `prisma/migrations/migration_lock.toml` file, which is used to detect if you have [attempted to change providers](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/limitations-and-known-issues#you-cannot-automatically-switch-database-providers).

Source-controlling the `schema.prisma` file is not enough - you must include your migration history. This is because:

* As you start to [customize migrations](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production#customizing-migrations), your migration history contains **information that cannot be represented in the Prisma schema**. For example, you can customize a migration to mitigate data loss that would be caused by a breaking change.
* The `prisma migrate deploy` command, which is used to deploy changes to staging, testing, and production environments, *only* runs migration files. It does not use the Prisma schema to fetch the models.

## Related pages

- [`About the shadow database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database): Learn how Prisma Migrate uses shadow databases to detect schema drift
- [`Limitations and known issues`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/limitations-and-known-issues)
- [`Understanding Migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/mental-model): A mental model guide for working with Prisma Migrate in your project

# About the shadow database (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how Prisma Migrate uses shadow databases to detect schema drift

Location: ORM > v7 > Prisma Migrate > Understanding Prisma Migrate > About the shadow database

The shadow database is a second, *temporary* database that is **created and deleted automatically**\* each time you run `prisma migrate dev` and is primarily used to **detect problems** such as schema drift or potential data loss of the generated migration.

[`migrate diff` command](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-diff) also requires a shadow database when diffing against a local `migrations` directory with `--from-migrations` or `--to-migrations`.

* If your database does not allow creation and deleting of databases (e.g. in a cloud-hosted environment), you need to [create and configure the shadow database manually](#cloud-hosted-shadow-databases-must-be-created-manually).

> [!WARNING]
> The shadow database is **not** required in production, and is not used by production-focused commands such as `prisma migrate resolve` and `prisma migrate deploy`.

## How the shadow database works [#how-the-shadow-database-works]

When you run `prisma migrate dev` to create a new migration, Prisma Migrate uses the shadow database to:

* [Detect schema drift](#detecting-schema-drift), which means checking that no **unexpected changes** have been made to the development database
* [Generate new migrations](#generating-new-migrations) and evaluate if those could lead to **data loss** when applied

### Detecting schema drift [#detecting-schema-drift]

To detect drift in development, Prisma Migrate:

* Creates a fresh copy of the shadow database (or performs a soft reset if the shadow database is configured via [`shadowDatabaseUrl`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#datasource))
* Reruns the **current**, existing migration history in the shadow database.
* **Introspects** the shadow database to generate the 'current state' of your Prisma schema.
* Compares the end state of the current migration history to the development database.
* Reports **schema drift** if the end state of the current migration history (via the shadow database) does not match the development database (for example, due to a manual change)

If Prisma Migrate does not detect schema drift, it moves on to [generating new migrations](#generating-new-migrations).

> [!NOTE]
> Note
> 
> The shadow database is not responsible for checking if a migration file has been **edited or deleted**. This is done using the `checksum` field in the `_prisma_migrations` table.

If Prisma Migrate detects schema drift, it outputs detailed information about which parts of the database have drifted. The following example output could be shown when the development database has been modified manually: The `Color` enum is missing the expected variant `RED` and includes the unexpected variant `TRANSPARENT`:

```
[*] Changed the `Color` enum
  [+] Added variant `TRANSPARENT`
  [-] Removed variant `RED`
```

### Generating new migrations [#generating-new-migrations]

Assuming Prisma Migrate did not [detect schema drift](#detecting-schema-drift), it moves on to generating new migrations from Prisma schema changes. To generate new migrations, Prisma Migrate:

1. Calculates the target database schema as a function of the current Prisma schema.
2. Compares the end state of the existing migration history and the target schema, and generates steps to get from one to the other.
3. Renders these steps to a SQL string and saves it in the new migration file.
4. Evaluate data loss caused by the SQL and warns about that.
5. Applies the generated migration to the development database (assuming you have not specified the `--create-only` flag)
6. Drops the shadow database (shadow databases configured via [`shadowDatabaseUrl`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#datasource) are not dropped, but are reset at the start of the `migrate dev` command)

## Manually configuring the shadow database [#manually-configuring-the-shadow-database]

In some cases it might make sense (e.g. when [creating and dropping databases is not allowed on cloud-hosted databases](#cloud-hosted-shadow-databases-must-be-created-manually)) to manually define the connection string and name of the database that should be used as the shadow database for `migrate dev`. In such a case you can:

1. Create a dedicated database that should be used as the shadow database
2. Add the connection string of that database your environment variable `SHADOW_DATABASE_URL` (or `.env` file)
3. Configure the `shadowDatabaseUrl` field in `prisma.config.ts` under the `datasource` object. In Prisma 6 and below, add the `shadowDatabaseUrl` field to the `datasource` block in your `schema.prisma` file.

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
    shadowDatabaseUrl: env("SHADOW_DATABASE_URL"), // [!code highlight]
  },
});
```

> [!WARNING]
> Important
> 
> Do not use the exact same values for `url` and `shadowDatabaseUrl` as that might delete all the data in your database.

## Cloud-hosted shadow databases must be created manually [#cloud-hosted-shadow-databases-must-be-created-manually]

Some cloud providers do not allow you to drop and create databases with SQL. Some require to create or drop the database via an online interface, and some really limit you to 1 database. If you **develop** in such a cloud-hosted environment, you must:

1. Create a dedicated cloud-hosted shadow database
2. Add the URL to your environment variable `SHADOW_DATABASE_URL`
3. Configure the `shadowDatabaseUrl` field in `prisma.config.ts` under the `datasource` object. In Prisma 6 and below, add the `shadowDatabaseUrl` field to the `datasource` block in your `schema.prisma` file.

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
    shadowDatabaseUrl: env("SHADOW_DATABASE_URL"), // [!code highlight]
  },
});
```

> [!WARNING]
> Important
> 
> Do not use the exact same values for `url` and `shadowDatabaseUrl` as that might delete all the data in your database.

## Shadow database user permissions [#shadow-database-user-permissions]

In order to create and delete the shadow database when using `migrate dev`, Prisma Migrate currently requires that the database user defined in your `datasource` has permission to **create databases**.

| Database             | Database user requirements                                                                                                                                                                                             |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SQLite               | No special requirements.                                                                                                                                                                                               |
| MySQL/MariaDB        | Database user must have `CREATE`, `ALTER`, `DROP`, `INDEX`, and `REFERENCES` on shadow databases (see [MySQL/MariaDB shadow database privileges](#mysqlmariadb-shadow-database-privileges) below)                      |
| PostgreSQL           | The user must be a super user or have `CREATEDB` privilege. See `CREATE ROLE` ([PostgreSQL official documentation](https://www.postgresql.org/docs/12/sql-createrole.html))                                            |
| Microsoft SQL Server | The user must be a site admin or have the `SERVER` securable. See the [official documentation](https://learn.microsoft.com/en-us/sql/relational-databases/security/permissions-database-engine?view=sql-server-ver15). |

### MySQL/MariaDB shadow database privileges [#mysqlmariadb-shadow-database-privileges]

When Prisma Migrate creates shadow databases automatically during `migrate dev`, it names them `prisma_migrate_shadow_db_<id>`. Grant the required privileges on that name pattern instead of on all databases (`*.*`):

```
GRANT CREATE, ALTER, DROP, INDEX, REFERENCES ON `prisma_migrate_shadow_db%`.* TO 'user'@'%';
```

`INDEX` is required because generated migrations create and drop indexes with standalone `CREATE INDEX` and `DROP INDEX` statements, which the `CREATE` and `ALTER` privileges alone do not permit.

If you configure a dedicated shadow database with `shadowDatabaseUrl`, grant the same privileges on that database (for example `` `myapp_shadow`.* ``) instead of on the `prisma_migrate_shadow_db%` pattern.

Wildcard database names in `GRANT` are deprecated in MySQL as of 8.0.35, and when the [`partial_revokes`](https://dev.mysql.com/doc/refman/8.0/en/partial-revokes.html) system variable is enabled MySQL treats `%` as a literal character, so the grant above no longer matches the generated shadow database names. On such servers, configure a dedicated shadow database with `shadowDatabaseUrl` and grant the privileges on that database by name. See [Database privileges in the MySQL `GRANT` reference](https://dev.mysql.com/doc/refman/8.0/en/grant.html#grant-database-privileges). MariaDB supports wildcard database names without these caveats.

Prisma Migrate throws the following error if it cannot create the shadow database with the credentials your connection URL supplied:

```
Error: A migration failed when applied to the shadow database
Database error: Error querying the database: db error: ERROR: permission denied to create database
```

To resolve this error:

* If you are working locally, we recommend that you update the database user's privileges.
* If you are developing against a database that does not allow creating and dropping databases (for any reason) see [Manually configuring the shadow database](#manually-configuring-the-shadow-database)
* If you are developing against a cloud-based database (for example, on Heroku, Digital Ocean, or Vercel Postgres) see: [Cloud-hosted shadow databases](#cloud-hosted-shadow-databases-must-be-created-manually).
* If you are developing against a cloud-based database (for example, on Heroku, Digital Ocean, or Vercel Postgres) and are currently **prototyping** such that you don't care about generated migration files and only need to apply your Prisma schema to the database schema, you can run [`prisma db push`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db) instead of the `prisma migrate dev` command.

> [!NOTE]
> Important
> 
> The shadow database is *only* required in a development environment (specifically for the `prisma migrate dev` command) - you **do not** need to make any changes to your production environment.

## Related pages

- [`Limitations and known issues`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/limitations-and-known-issues)
- [`Migration histories`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/migration-histories): How Prisma ORM uses migration histories to track changes to your schema
- [`Understanding Migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/mental-model): A mental model guide for working with Prisma Migrate in your project

# Baselining a database (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/baselining)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to initialize a migration history for an existing database that contains important data.

Location: ORM > v7 > Prisma Migrate > Workflows > Baselining a database

Baselining is the process of initializing a migration history for a database that:

* ✔ Existed before you started using Prisma Migrate
* ✔ Contains data that must be maintained (like production), which means that the database cannot be reset

Baselining tells Prisma Migrate to assume that one or more migrations have **already been applied**. This prevents generated migrations from failing when they try to create tables and fields that already exist.

Since this is working with development database, the assumption is that the database can be reset and reseeded.

Baselining is part of [adding Prisma Migrate to a project with an existing database](https://www.prisma.io/docs/orm/v7/prisma-migrate/getting-started#adding-to-an-existing-project).

> [!WARNING]
> This guide **does not apply for MongoDB**.<br />
> Instead of `migrate deploy`, [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) is used for [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

## Why you need to baseline [#why-you-need-to-baseline]

When you add Prisma Migrate to an existing project, your initial migration contains all the SQL required to recreate the state of the database **before you started using Prisma Migrate**:

![The image shows a database labelled 'Existing database', and a list of existing database features next to it - 24 tables, 13 relationships, 92 fields, 3 indexes. An arrow labelled 'represented by' connects the database features list to a box that represents a migration. The existing databases's features are represented by a single migration.](https://www.prisma.io/img/orm/prisma-migrate/workflows/existing-database.png)

> [!NOTE]
> You can edit the initial migration to include schema elements that cannot be represented in the Prisma schema - such as stored procedures or triggers.

You need this initial migration to create and reset **development environments**:

![The image shows a migration history with three migrations. Each migration is represented by a file icon and a name, and all migrations are surrounded by a box labelled 'migration history'. The first migration has an additional label: "State of database before Prisma Migrate", and the two remaining migrations are labelled "Generated as part of the Prisma Migrate workflow". An arrow labelled "prisma migrate dev" connects the migration history box to a database labelled "new development database", signifying that all three migrations are applied to the development database - none are skipped.](https://www.prisma.io/img/orm/prisma-migrate/workflows/new-dev-db.png)

However, when you `prisma migrate deploy` your migrations to databases that already exist and *cannot* be reset - such as production - you **do not want to include the initial migrations**.

The target database already contains the tables and columns created by the initial migration, and attempting to create these elements again will most likely result in an error.

![A migration history represented by three migration files (file icon and name), surrounded by a box labelled 'migration history'. The first migration is marked 'do not apply', and the second two migrations are marked 'apply'. An arrow labelled with the command 'prisma migrate deploy' points from the migration history to a database labelled 'production'.](https://www.prisma.io/img/orm/prisma-migrate/workflows/deploy-db.png)

Baselining solves this problem by telling Prisma Migrate to pretend that the initial migration(s) **have already been applied**.

## Baselining a database [#baselining-a-database]

To create a baseline migration:

* If you already have a `prisma/migrations` folder, delete, move, rename, or archive this folder.
* Create a new `prisma/migrations` directory.
* Then create another new directory with your preferred name. What's important is to use a prefix of `0_` so that Prisma migrate applies migrations in a [lexicographic order](https://en.wikipedia.org/wiki/Lexicographic_order). You can use a different value such as the current timestamp.
* Generate a migration and save it to a file using `prisma migrate diff`:

  

#### bun

```bash
bunx prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0_init/migration.sql
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0_init/migration.sql
```

#### yarn

```bash
yarn prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0_init/migration.sql
```

#### npm

```bash
npx prisma migrate diff \
  --from-empty \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0_init/migration.sql
```

* Run the `prisma migrate resolve` command for each migration that should be ignored:

  

#### bun

```bash
bunx prisma migrate resolve --applied 0_init
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied 0_init
```

#### yarn

```bash
yarn prisma migrate resolve --applied 0_init
```

#### npm

```bash
npx prisma migrate resolve --applied 0_init
```

This command adds the target migration to the `_prisma_migrations` table and marks it as applied. When you run `prisma migrate deploy` to apply new migrations, Prisma Migrate:

1. Skips all migrations marked as 'applied', including the baseline migration
2. Applies any new migrations that come *after* the baseline migration

## Related pages

- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.
- [`Native database types`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-types): Native database types

# Customizing migrations (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/customizing-migrations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to edit a migration file before applying it to avoid data loss in production.

Location: ORM > v7 > Prisma Migrate > Workflows > Customizing migrations

In some scenarios, you need to edit a migration file before you apply it. For example, to [change the direction of a 1-1 relation](#example-change-the-direction-of-a-1-1-relation) (moving the foreign key from one side to another) without data loss, you need to move data as part of the migration - this SQL is not part of the default migration, and must be written by hand.

This guide explains how to edit migration files and gives some examples of use cases where you may want to do this.

## How to edit a migration file [#how-to-edit-a-migration-file]

To edit a migration file before applying it, the general procedure is the following:

* Make a schema change that requires custom SQL (for example, to preserve existing data)
* Create a draft migration using:

  

#### bun

```bash
bunx prisma migrate dev --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --create-only
```

#### yarn

```bash
yarn prisma migrate dev --create-only
```

#### npm

```bash
npx prisma migrate dev --create-only
```

* Modify the generated SQL file.
* Apply the modified SQL by running:

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

### Example: Rename a field [#example-rename-a-field]

By default, renaming a field in the schema results in a migration that will:

* `CREATE` a new column (for example, `fullname`)
* `DROP` the existing column (for example, `name`) and the data in that column

To actually **rename** a field and avoid data loss when you run the migration in production, you need to modify the generated migration SQL before applying it to the database. Consider the following schema fragment - the `biograpy` field is spelled wrong.

```prisma highlight=3;normal; title="schema.prisma"
model Profile {
  id       Int    @id @default(autoincrement())
  biograpy String // [!code highlight]
  userId   Int    @unique
  user     User   @relation(fields: [userId], references: [id])
}
```

To rename the `biograpy` field to `biography`:

Rename the field in the schema:

```prisma highlight=3;delete|4;add; title="schema.prisma
model Profile {
  id        Int    @id @default(autoincrement())
  biograpy  String // [!code --]
  biography String // [!code ++]
  userId    Int    @unique
  user      User   @relation(fields: [userId], references: [id])
}
```

* Run the following command to create a **draft migration** that you can edit before applying to the database:

  

#### bun

```bash
bunx prisma migrate dev --name rename-migration --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --name rename-migration --create-only
```

#### yarn

```bash
yarn prisma migrate dev --name rename-migration --create-only
```

#### npm

```bash
npx prisma migrate dev --name rename-migration --create-only
```

* Edit the draft migration as shown, changing `DROP` / `DELETE` to a single `RENAME COLUMN`:

  

#### Before

```sql title="migration.sql" 
ALTER TABLE "Profile" DROP COLUMN "biograpy",
ADD COLUMN  "biography" TEXT NOT NULL;
```

#### After

```sql title="migration.sql" 
ALTER TABLE "Profile"
RENAME COLUMN "biograpy" TO "biography"
```

* Save and apply the migration:

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

You can use the same technique to rename a `model` - edit the generated SQL to *rename* the table rather than drop and re-create it.

### Example: Use the expand and contract pattern to evolve the schema without downtime [#example-use-the-expand-and-contract-pattern-to-evolve-the-schema-without-downtime]

Making schema changes to existing fields, e.g., renaming a field can lead to downtime. It happens in the time frame between applying a migration that modifies an existing field, and deploying a new version of the application code which uses the modified field.

You can prevent downtime by breaking down the steps required to alter a field into a series of discrete steps designed to introduce the change gradually. This pattern is known as the *expand and contract pattern*.

The pattern involves two components: your application code accessing the database and the database schema you intend to alter.

With the *expand and contract* pattern, renaming the field `bio` to `biography` would look as follows with Prisma:

* Add the new `biography` field to your Prisma schema and create a migration

```prisma highlight=4;add; title="schema.prisma"
model Profile {
 id        Int    @id @default(autoincrement())
 bio       String
 biography String // [!code ++]
 userId    Int    @unique
 user      User   @relation(fields: [userId], references: [id])
}
```

* *Expand*: update the application code and write to both the `bio` and `biography` fields, but continue reading from the `bio` field, and deploy the code
* Create an empty migration and copy existing data from the `bio` to the `biography` field

  

#### bun

```bash
bunx prisma migrate dev --name copy_biography --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --name copy_biography --create-only
```

#### yarn

```bash
yarn prisma migrate dev --name copy_biography --create-only
```

#### npm

```bash
npx prisma migrate dev --name copy_biography --create-only
```

```sql title="migration.sql"
UPDATE "Profile" SET biography = bio;
```

4. Verify the integrity of the `biography` field in the database
5. Update application code to **read** from the new `biography` field
6. Update application code to **stop writing** to the `bio` field
7. *Contract*: remove the `bio` from the Prisma schema, and create a migration to remove the `bio` field

```prisma highlight=3;delete; title="schema.prisma"
model Profile {
 id        Int    @id @default(autoincrement())
 bio       String // [!code --]
 biography String
 userId    Int    @unique
 user      User   @relation(fields: [userId], references: [id])
}
```

  

#### bun

```bash
bunx prisma migrate dev --name remove_bio
```

#### pnpm

```bash
pnpm prisma migrate dev --name remove_bio
```

#### yarn

```bash
yarn prisma migrate dev --name remove_bio
```

#### npm

```bash
npx prisma migrate dev --name remove_bio
```

By using this approach, you avoid potential downtime that altering existing fields that are used in the application code are prone to, and reduce the amount of coordination required between applying the migration and deploying the updated application code.

Note that this pattern is applicable in any situation involving a change to a column that has data and is in use by the application code. Examples include combining two fields into one, or transforming a `1:n` relation to a `m:n` relation.

To learn more, check out the Data Guide article on [the expand and contract pattern](https://www.prisma.io/dataguide/types/relational/expand-and-contract-pattern)

### Example: Change the direction of a 1-1 relation [#example-change-the-direction-of-a-1-1-relation]

To change the direction of a 1-1 relation:

* Make the change in the schema:

```prisma title="schema.prisma"
model User {
 id        Int      @id @default(autoincrement())
 name      String
 posts     Post[]
 profile   Profile? @relation(fields: [profileId], references: [id])
 profileId Int      @unique
}

model Profile {
 id        Int    @id @default(autoincrement())
 biography String
 user      User
}
```

* Run the following command to create a **draft migration** that you can edit before applying to the database:

  

#### bun

```bash
bunx prisma migrate dev --name rename-migration --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --name rename-migration --create-only
```

#### yarn

```bash
yarn prisma migrate dev --name rename-migration --create-only
```

#### npm

```bash
npx prisma migrate dev --name rename-migration --create-only
```

```text
⚠️  There will be data loss when applying the migration:

• The migration will add a unique constraint covering the columns `[profileId]` on the table `User`. If there are existing duplicate values, the migration will fail.
```

* Edit the draft migration as shown:

  

#### Before

```sql title="migration" 
-- DropForeignKey
ALTER TABLE "Profile" DROP CONSTRAINT "Profile_userId_fkey";

-- DropIndex
DROP INDEX "Profile_userId_unique";

-- AlterTable
ALTER TABLE "Profile" DROP COLUMN "userId";

-- AlterTable
ALTER TABLE "User" ADD COLUMN     "profileId" INTEGER NOT NULL;

-- CreateIndex
CREATE UNIQUE INDEX "User_profileId_unique" ON "User"("profileId");

-- AddForeignKey
ALTER TABLE "User" ADD FOREIGN KEY ("profileId") REFERENCES "Profile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
```

#### After

```sql title="migration" 
-- DropForeignKey
ALTER TABLE "Profile" DROP CONSTRAINT "Profile_userId_fkey";

-- DropIndex
DROP INDEX "Profile_userId_unique";

-- AlterTable
ALTER TABLE "User" ADD COLUMN "profileId" INTEGER;

UPDATE "User"
SET "profileId" = "Profile".id
FROM "Profile"
WHERE "User".id = "Profile"."userId";

ALTER TABLE "User" ALTER COLUMN "profileId" SET NOT NULL;

-- AlterTable
ALTER TABLE "Profile" DROP COLUMN "userId";

-- CreateIndex
CREATE UNIQUE INDEX "User_profileId_unique" ON "User"("profileId");

-- AddForeignKey
ALTER TABLE "User" ADD FOREIGN KEY ("profileId") REFERENCES "Profile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
```

* Save and apply the migration:

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.
- [`Native database types`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-types): Native database types

# Development and production (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/development-and-production)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to use Prisma Migrate commands in development and production environments

Location: ORM > v7 > Prisma Migrate > Workflows > Development and production

In a development environment, use the `migrate dev` command to generate and apply migrations:

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

### Create and apply migrations [#create-and-apply-migrations]

> [!CAUTION]
> `migrate dev` is a development command and should never be used in a production environment.

This command:

* Reruns the existing migration history in the [shadow database](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database) in order to detect schema drift (edited or deleted migration file, or a manual changes to the database schema)
* Applies pending migrations to the shadow database (for example, new migrations created by colleagues)
* If it detects changes to the Prisma schema, it generates a new migration from these changes
* Applies all unapplied migrations to the development database and updates the `_prisma_migrations` table
* Triggers the generation of artifacts (for example, Prisma Client)

The `migrate dev` command will prompt you to reset the database in the following scenarios:

* Migration history conflicts caused by [modified or missing migrations](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/migration-histories#do-not-edit-or-delete-migrations-that-have-been-applied)
* The database schema has drifted away from the end-state of the migration history

### Reset the development database [#reset-the-development-database]

You can also `reset` the database yourself to undo manual changes or `db push` experiments by running:

  

#### bun

```bash
bunx prisma migrate reset
```

#### pnpm

```bash
pnpm prisma migrate reset
```

#### yarn

```bash
yarn prisma migrate reset
```

#### npm

```bash
npx prisma migrate reset
```

> [!WARNING]
> `migrate reset` is a development command and should never be used in a production environment.

This command:

* Drops the database/schema¹ if possible, or performs a soft reset if the environment does not allow deleting databases/schemas\*
* Creates a new database/schema¹ with the same name if the database/schema¹ was dropped
* Applies all migrations

> [!NOTE]
> For MySQL and MongoDB this refers to the database, for PostgreSQL and SQL Server to the schema, and for SQLite to the database file.

To re-create data in your development database as often as needed, run `npx prisma db seed`. See the [seeding guide](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/seeding).

### Customizing migrations [#customizing-migrations]

Sometimes, you need to modify a migration **before applying it**. For example:

* You want to introduce a significant refactor, such as changing blog post tags from a `String[]` to a `Tag[]`
* You want to [rename a field](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations#example-rename-a-field) (by default, Prisma Migrate will drop the existing field)
* You want to [change the direction of a 1-1 relationship](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations#example-change-the-direction-of-a-1-1-relation)
* You want to add features that cannot be represented in Prisma Schema Language - such as a stored procedure or a trigger.

The `--create-only` command allows you to create a migration without applying it:

  

#### bun

```bash
bunx prisma migrate dev --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --create-only
```

#### yarn

```bash
yarn prisma migrate dev --create-only
```

#### npm

```bash
npx prisma migrate dev --create-only
```

To apply the edited migration, run `prisma migrate dev` again.

Refer to [Customizing migrations](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations) for examples.

### Team development [#team-development]

See: [Team development with Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production) .

## Production and testing environments [#production-and-testing-environments]

In production and testing environments, use the `migrate deploy` command to apply migrations:

  

#### bun

```bash
bunx prisma migrate deploy
```

#### pnpm

```bash
pnpm prisma migrate deploy
```

#### yarn

```bash
yarn prisma migrate deploy
```

#### npm

```bash
npx prisma migrate deploy
```

`migrate deploy` should generally be part of an automated CI/CD pipeline, and we do not recommend running this command locally to deploy changes to a production database.

This command:

* Compares applied migrations against the migration history and **warns** if any migrations have been modified:

  ```bash
  WARNING The following migrations have been modified since they were applied:
  20210313140442_favorite_colors
  ```
* Applies pending migrations

The `migrate deploy` command:

* **Does not** issue a warning if an already applied migration is *missing* from migration history
* **Does not** detect drift (production database schema differs from migration history end state - for example, due to a hotfix)
* **Does not** reset the database or generate artifacts (such as Prisma Client)
* **Does not** rely on a shadow database

See also:

* [Prisma Migrate in deployment](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-database-changes-with-prisma-migrate)
* [Production troubleshooting](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing)

### Advisory locking [#advisory-locking]

Prisma Migrate makes use of advisory locking when you run production commands such as:

* `prisma migrate deploy`
* `prisma migrate dev`
* `prisma migrate resolve`

This safeguard ensures that multiple commands cannot run at the same time - for example, if you merge two pull requests in quick succession.

Advisory locking has a **10 second timeout** (not configurable), and uses the default advisory locking mechanism available in the underlying provider:

* [PostgreSQL](https://www.postgresql.org/docs/9.4/explicit-locking.html#ADVISORY-LOCKS)
* [MySQL](https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html)
* [Microsoft SQL server](https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-getapplock-transact-sql?view=sql-server-ver15)

Prisma Migrate's implementation of advisory locking is purely to avoid catastrophic errors - if your command times out, you will need to run it again.

Since `5.3.0`, the advisory locking can be disabled using the [`PRISMA_SCHEMA_DISABLE_ADVISORY_LOCK` environment variable](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference#prisma_schema_disable_advisory_lock)

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.
- [`Native database types`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-types): Native database types

# Generating down migrations (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to generate a down migration SQL file that reverses a given migration file

Location: ORM > v7 > Prisma Migrate > Workflows > Generating down migrations

When generating a migration SQL file, you may wish to also create a "down migration" SQL file that reverses the schema changes in the corresponding "up migration" file. Note that "down migrations" are also sometimes called "migration rollbacks".

This guide explains how to use Prisma Migrate's [`migrate diff` command](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-diff) to create a down migration, and how to apply it to your production database with the [`db execute`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-execute) command in the case of a failed up migration.

> [!WARNING]
> This guide applies to generating SQL down migrations for relational databases only. It does not apply to MongoDB.

## Considerations when generating down migrations [#considerations-when-generating-down-migrations]

When generating a down migration file, there are some considerations to be aware of:

* The down migration can be used to revert your database schema after a failed migration using the steps in [How to apply your down migration to a failed migration](#how-to-apply-your-down-migration-to-a-failed-migration). This requires the use of the `migrate resolve` command, which can only be used on failed migrations. If your up migration was successful and you want to revert it, you will instead need to revert your `schema.prisma` file to its state before the up migration, and generate a new migration with the `migrate dev` command.
* The down migration will revert your database schema, but other changes to data and application code that are carried out as part of the up migration will not be reverted. For example, if you have a script that changes data during the migration, this data will not be changed back when you run the down migration.
* You will not be able to use `migrate diff` to revert manually changed or added SQL in your migration files. If you have any custom additions, such as a view or trigger, you will need to:
  * Create the down migration following [the instructions below](#how-to-generate-and-run-down-migrations)
  * Create the up migration using [`migrate dev --create-only`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference), so that it can be edited before it is applied to the database
  * Manually add your custom SQL to the up migration (e.g. adding a view)
  * Manually add the inverted custom SQL to the down migration (e.g. dropping the view)

## How to generate and run down migrations [#how-to-generate-and-run-down-migrations]

This section describes how to generate a down migration SQL file along with the corresponding up migration, and then run it to revert your database schema after a failed up migration on production.

As an example, take the following Prisma schema with a `User` and `Post` model as a starting point:

```prisma title="schema.prisma"
model Post {
  id       Int     @id @default(autoincrement())
  title    String  @db.VarChar(255)
  content  String?
  author   User    @relation(fields: [authorId], references: [id])
  authorId Int
}

model User {
  id    Int     @id @default(autoincrement())
  name  String?
  posts Post[]
}
```

You will need to create the down migration first, before creating the corresponding up migration.

### Generating the migrations [#generating-the-migrations]

* Edit your Prisma schema to make the changes you require for your up migration. In this example, you will add a new `Profile` model:

  ```prisma title="schema.prisma" highlight=8-14;add|20;add
  model Post {
    id       Int     @id @default(autoincrement())
    title    String  @db.VarChar(255)
    content  String?
    author   User    @relation(fields: [authorId], references: [id])
    authorId Int
  }

  model Profile { // [!code ++]
    id     Int     @id @default(autoincrement()) // [!code ++]
    bio    String? // [!code ++]
    user   User    @relation(fields: [userId], references: [id]) // [!code ++]
    userId Int     @unique // [!code ++]
  } // [!code ++]

  model User {
    id      Int      @id @default(autoincrement())
    name    String?
    posts   Post[]
    profile Profile? // [!code ++]
  }
  ```

* Generate the SQL file for the down migration. To do this, you will use `migrate diff` to make a comparison:

  * from the newly edited schema
  * to the state of the schema after the last migration

  and output this to a SQL script, `down.sql`.

  There are two potential options for specifying the 'to' state:

  * Using `--to-migrations`: this makes a comparison to the state of the migrations given in the migrations directory. This is the preferred option, as it is more robust. To use this option, run:

  

#### bun

```bash
bunx prisma migrate diff \
  --from-schema prisma/schema.prisma \
  --to-migrations prisma/migrations \
  --script > down.sql
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --from-schema prisma/schema.prisma \
  --to-migrations prisma/migrations \
  --script > down.sql
```

#### yarn

```bash
yarn prisma migrate diff \
  --from-schema prisma/schema.prisma \
  --to-migrations prisma/migrations \
  --script > down.sql
```

#### npm

```bash
npx prisma migrate diff \
  --from-schema prisma/schema.prisma \
  --to-migrations prisma/migrations \
  --script > down.sql
```

* Using `--to-config-datasource` (Prisma v7) or `--to-schema-datasource` (Prisma 6): this makes a comparison to the state of the database. This does not require a shadow database, but it does rely on the database having an up-to-date schema. To use this option, run:

  

#### bun

```bash
bunx prisma migrate diff \
  --from-schema prisma/schema.prisma \
  --to-config-datasource \
  --script > down.sql
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --from-schema prisma/schema.prisma \
  --to-config-datasource \
  --script > down.sql
```

#### yarn

```bash
yarn prisma migrate diff \
  --from-schema prisma/schema.prisma \
  --to-config-datasource \
  --script > down.sql
```

#### npm

```bash
npx prisma migrate diff \
  --from-schema prisma/schema.prisma \
  --to-config-datasource \
  --script > down.sql
```

* Generate and apply the up migration with a name of `add_profile`:

  

#### bun

```bash
bunx prisma migrate dev --name add_profile
```

#### pnpm

```bash
pnpm prisma migrate dev --name add_profile
```

#### yarn

```bash
yarn prisma migrate dev --name add_profile
```

#### npm

```bash
npx prisma migrate dev --name add_profile
```

This will create a new `<timestamp>_add_profile` directory inside the `prisma/migrations` directory, with your new `migration.sql` up migration file inside.

* Copy your `down.sql` file into the new directory along with the up migration file.

### How to apply your down migration to a failed migration [#how-to-apply-your-down-migration-to-a-failed-migration]

To apply the down migration on your production database after a failed up migration:

* Use `db execute` to run your `down.sql` file on the database server (using the database URL configured in `prisma.config.ts`):

  

#### bun

```bash
bunx prisma db execute --file ./down.sql
```

#### pnpm

```bash
pnpm prisma db execute --file ./down.sql
```

#### yarn

```bash
yarn prisma db execute --file ./down.sql
```

#### npm

```bash
npx prisma db execute --file ./down.sql
```

* Use `migrate resolve` to record that you rolled back the up migration named `add_profile`:

  

#### bun

```bash
bunx prisma migrate resolve --rolled-back add_profile
```

#### pnpm

```bash
pnpm prisma migrate resolve --rolled-back add_profile
```

#### yarn

```bash
yarn prisma migrate resolve --rolled-back add_profile
```

#### npm

```bash
npx prisma migrate resolve --rolled-back add_profile
```

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.
- [`Native database types`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-types): Native database types

# Native database functions (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/native-database-functions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to enable PostgreSQL native database functions for projects that use Prisma Migrate.

Location: ORM > v7 > Prisma Migrate > Workflows > Native database functions

In PostgreSQL, some [native database functions](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/unsupported-database-features#native-database-functions) are part of optional extensions. For example, in PostgreSQL versions 12.13 and earlier the `gen_random_uuid()` function is part of the [`pgcrypto`](https://www.postgresql.org/docs/10/pgcrypto.html) extension.

To use a PostgreSQL extension, you must install it on the file system of your database server and then activate the extension. If you use Prisma Migrate, this must be done as part of a migration.

> [!WARNING]
> Do not activate extensions outside a migration file if you use Prisma Migrate. The [shadow database](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database) requires the same extensions. Prisma Migrate creates and deletes the shadow database automatically, so the only way to activate an extension is to include it in a migration file.

In Prisma ORM versions 4.5.0 and later, you can activate the extension by declaring it in your Prisma schema with the [`postgresqlExtensions` preview feature](https://www.prisma.io/docs/orm/v7/prisma-schema/postgresql-extensions):

```prisma title="schema.prisma"
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["postgresqlExtensions"] // [!code ++]
}

datasource db {
  provider   = "postgresql"
  extensions = [pgcrypto] // [!code ++]
}
```

You can then apply these changes to your database with Prisma Migrate. See [How to migrate PostgreSQL extensions](https://www.prisma.io/docs/orm/v7/prisma-schema/postgresql-extensions) for details.

In earlier versions of Prisma ORM, you must instead add a SQL command to your migration file to activate the extension. See [How to install a PostgreSQL extension as part of a migration](#how-to-install-a-postgresql-extension-as-part-of-a-migration).

## How to install a PostgreSQL extension as part of a migration [#how-to-install-a-postgresql-extension-as-part-of-a-migration]

This section describes how to add a SQL command to a migration file to activate a PostgreSQL extension. If you manage PostgreSQL extensions in your Prisma Schema with the `postgresqlExtensions` preview feature instead, see [How to migrate PostgreSQL extensions](https://www.prisma.io/docs/orm/v7/prisma-schema/postgresql-extensions).

The following example demonstrates how to install the `pgcrypto` extension as part of a migration:

* Add the field with the native database function to your schema:

```prisma title="schema.prisma"
model User {
 id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
}
```

If you include a cast operator (such as `::TEXT`), you must surround the entire function with parentheses:

```prisma title="schema.prisma"
@default(dbgenerated("(gen_random_uuid()::TEXT)"))
```

* Use the `--create-only` flag to generate a new migration without applying it:

  

#### bun

```bash
bunx prisma migrate dev --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --create-only
```

#### yarn

```bash
yarn prisma migrate dev --create-only
```

#### npm

```bash
npx prisma migrate dev --create-only
```

* Open the generated `migration.sql` file and enable the `pgcrypto` module:

```sql title="migration.sql"
CREATE EXTENSION IF NOT EXISTS pgcrypto;

ADD COLUMN "id" UUID NOT NULL DEFAULT gen_random_uuid(),
ADD PRIMARY KEY ("id");
```

* Apply the migration:

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

Each time you reset the database or add a new member to your team, all required functions are part of the migration history.

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database types`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-types): Native database types

# Native database types (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/native-database-types)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Native database types

Location: ORM > v7 > Prisma Migrate > Workflows > Native database types

Prisma Migrate translates the model defined in your [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) into features in your database.

![A diagram that shows a Prisma schema on the left (labeled: Prisma schema, models) and a database on the right (labeled: Database, tables). Two parallel arrows connect the schema and the database, showing how '@unique' maps to 'UNIQUE' and '@id' maps to 'PRIMARY KEY'.](https://www.prisma.io/img/orm/prisma-migrate/understanding-prisma-migrate/migrate-mapping.png)

Every¹ feature in your [data model](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models) maps to a corresponding feature in the underlying database. &#x2A;*If you can define a feature in the Prisma schema, it is supported by Prisma Migrate.**

For a complete list of Prisma schema features, refer to:

* [Database features matrix](https://www.prisma.io/docs/orm/v7/reference/database-features) for a list of database features and what they map to in the Prisma schema.
* [Prisma schema reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) for a list of all Prisma schema features, including field types, attributes, and functions.

Prisma Migrate also supports mapping each field to a [specific native type](#mapping-fields-to-a-specific-native-type), and there are ways to [include features without a Prisma schema equivalent in your database](#handling-unsupported-database-features).

> [!NOTE]
> Comments and Prisma ORM-level functions (`uuid()` and `cuid()`) do not map to database features.

## Mapping fields to a specific native type [#mapping-fields-to-a-specific-native-type]

Each Prisma ORM type maps to a default underlying database type - for example, the PostgreSQL connector maps `String` to `text` by default. [Native database type attributes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#native-types-mapping) determines which *specific* native type should be created in the database.

> [!NOTE]
> Some Prisma ORM types only map to a single native type.

In the following example, the `name` and `title` fields have a `@db.VarChar(X)` type attribute:

```prisma title="schema.prisma" highlight=8,14;normal
datasource db {
  provider = "postgresql"
}

model User {
  id    Int    @id @default(autoincrement())
  name  String @db.VarChar(200)
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String  @db.VarChar(150)
  published Boolean @default(true)
  authorId  Int
  author    User    @relation(fields: [authorId], references: [id])
}
```

Prisma Migrate uses the specified types when it creates a migration:

```sql title="migration.sql" highlight=4,10;normal
  -- CreateTable
CREATE TABLE "User" (
    "id" SERIAL,
    "name" VARCHAR(200) NOT NULL,
    PRIMARY KEY ("id")
);
  -- CreateTable
CREATE TABLE "Post" (
    "id" SERIAL,
    "title" VARCHAR(150) NOT NULL,
    "published" BOOLEAN NOT NULL DEFAULT true,
    "authorId" INTEGER NOT NULL,
    PRIMARY KEY ("id")
);

  -- AddForeignKey
ALTER TABLE "Post" ADD FOREIGN KEY("authorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
```

### Mappings by Prisma ORM type [#mappings-by-prisma-orm-type]

For type mappings organized by Prisma ORM type, refer to the [Prisma schema reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) documentation.

### Mappings by database provider [#mappings-by-database-provider]

For type mappings organized by database provider, see:

* [PostgreSQL mappings](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#prisma-to-postgresql)
* [MySQL mappings](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#type-mapping-between-mysql-and-prisma-schema)
* [Microsoft SQL Server mappings](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server#type-mappings)
* [SQLite mappings](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite#type-mappings)

## Handling unsupported database features [#handling-unsupported-database-features]

Prisma Migrate cannot automatically create database features that have no equivalent in Prisma Schema Language (PSL). For example, there is currently no way to define a stored procedure or a trigger in PSL. However, there are ways to add unsupported features to your database with Prisma Migrate:

* [Handle unsupported field types](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/unsupported-database-features#unsupported-field-types) (like `circle`)
* [Handle unsupported features](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/unsupported-database-features#unsupported-database-features), like stored procedures
* [How to use native database functions](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/unsupported-database-features#native-database-functions)

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.

# Patching & hotfixing (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to reconcile the migration history after applying a hotfix or patch to a production environment.

Location: ORM > v7 > Prisma Migrate > Workflows > Patching & hotfixing

Patching or hotfixing a database involves making an often time critical change directly in production. For example, you might add an index directly to a production database to resolve an issue with a slow-running query.

Patching the production database directly results in **schema drift**: your database schema has 'drifted away' from the source of truth, and is out of sync with your migration history. You can use the `prisma migrate resolve` command to reconcile your migration history *without* having to remove and re-apply the hotfix with `prisma migrate deploy`.

> [!WARNING]
> This guide **does not apply for MongoDB**.<br />
> Instead of `migrate dev`, [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) is used for [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

## Reconciling your migration history with a patch or hotfix [#reconciling-your-migration-history-with-a-patch-or-hotfix]

The following scenario assumes that you made a manual change in production and want to propagate that change to your migration history and other databases.

To reconcile your migration history and database schema in production:

* Replicate the change you made in production in the schema - for example, add an `@@index` to a particular model.
* Generate a new migration and take note of the full migration name, including a timestamp, which is written to the CLI:(`20210316150542_retroactively_add_index`):

  

#### bun

```bash
bunx prisma migrate dev --name retroactively-add-index
```

#### pnpm

```bash
pnpm prisma migrate dev --name retroactively-add-index
```

#### yarn

```bash
yarn prisma migrate dev --name retroactively-add-index
```

#### npm

```bash
npx prisma migrate dev --name retroactively-add-index
```

```bash no-copy
migrations/
└─ 20210316150542_retroactively_add_index/
└─ migration.sql

Your database is now in sync with your schema.

✔ Generated Prisma Client (2.19.0-dev.29) to .\node_modules\@prisma\client in 190ms
```

* Push the migration to production &#x2A;*without running `migrate deploy`**. Instead, mark the migration created in the previous step as 'already applied' so that Prisma Migrate does not attempt to apply your hotfix a second time:

  

#### bun

```bash
bunx prisma migrate resolve --applied "20201127134938-retroactively-add-index"
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied "20201127134938-retroactively-add-index"
```

#### yarn

```bash
yarn prisma migrate resolve --applied "20201127134938-retroactively-add-index"
```

#### npm

```bash
npx prisma migrate resolve --applied "20201127134938-retroactively-add-index"
```

This command adds the migration to the migration history table without running the actual SQL.

* Repeat the previous step for other databases that were patched - for example, if you applied the patch to a staging database.
* Propagate the migration to other databases that were not patched - for example, by committing the migration to source control and allowing your CI/CD pipeline to apply it to all databases. The migration will not be applied to databases where it has been marked as already applied by the `prisma migrate resolve` command.

## Failed migration [#failed-migration]

A migration might fail if:

* You [modify a migration before running it](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations) and introduce a syntax error
* You add a mandatory (`NOT NULL`) column to a table that already has data
* The migration process stopped unexpectedly
* The database shut down in the middle of the migration process

Each migration in the `_prisma_migrations` table has a `logs` column that stores the error.

There are two ways to deal with failed migrations in a production environment:

* Roll back, optionally fix issues, and re-deploy
* Manually complete the migration steps and resolve the migration

### Option 1: Mark the migration as rolled back and re-deploy [#option-1-mark-the-migration-as-rolled-back-and-re-deploy]

The following example demonstrates how to roll back a migration, optionally make changes to fix the issue, and re-deploy:

* Mark the migration as rolled back - this updates the migration record in the `_prisma_migrations` table to register it as rolled back, allowing it to be applied again:

  

#### bun

```bash
bunx prisma migrate resolve --rolled-back "20201127134938_added_bio_index"
```

#### pnpm

```bash
pnpm prisma migrate resolve --rolled-back "20201127134938_added_bio_index"
```

#### yarn

```bash
yarn prisma migrate resolve --rolled-back "20201127134938_added_bio_index"
```

#### npm

```bash
npx prisma migrate resolve --rolled-back "20201127134938_added_bio_index"
```

* If the migration was partially run, you can either:
  * Modify the migration to check if a step was already completed (for example: `CREATE TABLE ... IF NOT EXISTS`) *OR*
  * Manually revert the steps that were completed (for example, delete created tables)

If you modify the migration, make sure you copy it back to source control to ensure that state of your production database is reflected exactly in development.

* Fix the root cause of the failed migration, if relevant - for example, if the migration failed due to an issue with the SQL script itself. Make sure that you copy any changed migrations back to source control.

* Re-deploy the migration:

  

#### bun

```bash
bunx prisma migrate deploy
```

#### pnpm

```bash
pnpm prisma migrate deploy
```

#### yarn

```bash
yarn prisma migrate deploy
```

#### npm

```bash
npx prisma migrate deploy
```

### Option 2: Manually complete migration and resolve as applied [#option-2-manually-complete-migration-and-resolve-as-applied]

The following example demonstrates how to manually complete the steps of a migration and mark that migration as applied.

* Manually complete the migration steps on the production database. Make sure that any manual steps exactly match the steps in the migration file, and copy any changes back to source control.

* Resolve the migration as applied - this tells Prisma Migrate to consider the migration successfully applied:

  

#### bun

```bash
bunx prisma migrate resolve --applied "20201127134938_my_migration"
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied "20201127134938_my_migration"
```

#### yarn

```bash
yarn prisma migrate resolve --applied "20201127134938_my_migration"
```

#### npm

```bash
npx prisma migrate resolve --applied "20201127134938_my_migration"
```

## Fixing failed migrations with `migrate diff` and `db execute` [#fixing-failed-migrations-with-migrate-diff-and-db-execute]

> [!NOTE]
> **Prisma v7 note**: The `--url` flag has been removed from `prisma db execute`. To run these commands against a production database, you'll need to configure the production database URL in your `prisma.config.ts` file before running `db execute`. You can create a separate config file for production (e.g., `prisma.config.prod.ts`) and use `--config prisma.config.prod.ts` to specify it.

To help with fixing a failed migration, Prisma ORM provides the following commands for creating and executing a migration file:

* [`prisma migrate diff`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-diff) which diffs two database schema sources to create a migration taking one to the state of the second. You can output either a summary of the difference or a sql script. The script can be output into a file via `> file_name.sql` or be piped to the `db execute --stdin` command.
* [`prisma db execute`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-execute) which applies a SQL script to the database without interacting with the Prisma migrations table.

This section gives an example scenario of a failed migration, and explains how to use `migrate diff` and `db execute` to fix it.

### Example of a failed migration [#example-of-a-failed-migration]

Imagine that you have the following `User` model in your schema, in both your local development environment and your production environment:

```prisma title="schema.prisma" showLineNumbers
model User {
  id   Int    @id
  name String
}
```

At this point, your schemas are in sync, but the data in the two environments is different.

You then decide to make changes to your data model, adding another `Post` model and making the `name` field on `User` unique:

```prisma title="schema.prisma" showLineNumbers
model User {
  id    Int     @id
  name  String  @unique
  email String?
}

model Post {
  id    Int    @id
  title String
}
```

You create a migration called 'Unique' with the command `npx prisma migrate dev -n Unique` which is saved in your local migrations history. Applying the migration succeeds in your dev environment and now it is time to release to production.

Unfortunately this migration can only be partially executed. Creating the `Post` model and adding the `email` column succeeds, but making the `name` field unique fails with the following error:

```bash
ERROR 1062 (23000): Duplicate entry 'paul' for key 'User_name_key'
```

This is because there is non-unique data in your production database (e.g. two users with the same name).

You now need to recover manually from the partially executed migration. Until you recover from the failed state, further migrations using `prisma migrate deploy` are impossible.

At this point there are two options, depending on what you decide to do with the non-unique data:

* You realize that non-unique data is valid and you cannot move forward with your current development work. You want to roll back the complete migration. To do this, see [Moving backwards and reverting all changes](#moving-backwards-and-reverting-all-changes)
* The existence of non-unique data in your database is unintentional and you want to fix that. After fixing, you want to go ahead with the rest of the migration. To do this, see [Moving forwards and applying missing changes](#moving-forwards-and-applying-missing-changes)

#### Moving backwards and reverting all changes [#moving-backwards-and-reverting-all-changes]

In this case, you need to create a migration that takes your production database to the state of your data model before the last migration.

* First you need your migration history at the time before the failed migration. You can either get this from your git history, or locally delete the folder of the last failed migration in your migration history.
* You now want to take your production environment from its current failed state back to the state specified in your local migrations history:
  * Run the following `prisma migrate diff` command:

    ```bash wrap
    # Prisma 6
    npx prisma migrate diff \
      --from-url "$DATABASE_URL_PROD" \
      --to-migrations ./prisma/migrations \
      --shadow-database-url $SHADOW_DATABASE_URL \
      --script > backward.sql

    # Prisma v7 (with production config)
    npx prisma migrate diff \
      --from-config-datasource \
      --to-migrations ./prisma/migrations \
      --config prisma.config.prod.ts \
      --script > backward.sql
    ```

    This will create a SQL script file containing all changes necessary to take your production environment from its current failed state to the target state defined by your migrations history.

  * Run the following `prisma db execute` command:

    ```bash
    # Prisma 6
    npx prisma db execute --url "$DATABASE_URL_PROD" --file backward.sql

    # Prisma v7 (with production config)
    npx prisma db execute --config prisma.config.prod.ts --file backward.sql
    ```

    This applies the changes in the SQL script against the target database without interacting with the migrations table.

  * Run the following `prisma migrate resolve` command:

    
      

#### bun

```bash
bunx prisma migrate resolve --rolled-back Unique
```

#### pnpm

```bash
pnpm prisma migrate resolve --rolled-back Unique
```

#### yarn

```bash
yarn prisma migrate resolve --rolled-back Unique
```

#### npm

```bash
npx prisma migrate resolve --rolled-back Unique
```
    

    This will mark the failed migration called 'Unique' in the migrations table on your production environment as rolled back.

Your local migration history now yields the same result as the state your production database is in. You can now modify the datamodel again to create a migration that suits your new understanding of the feature you're working on (with non-unique names).

#### Moving forwards and applying missing changes [#moving-forwards-and-applying-missing-changes]

In this case, you need to fix the non-unique data and then go ahead with the rest of the migration as planned:

* The error message from trying to deploy the migration to production already told you there was duplicate data in the column `name`. You need to either alter or delete the offending rows.
* Continue applying the rest of the failed migration to get to the data model defined in your `schema.prisma` file
* Run the following `prisma migrate diff` command

  

#### bun

```bash
bunx prisma migrate diff --from-config-datasource --to-schema schema.prisma --config prisma.config.prod.ts --script > forward.sql
```

#### pnpm

```bash
pnpm prisma migrate diff --from-config-datasource --to-schema schema.prisma --config prisma.config.prod.ts --script > forward.sql
```

#### yarn

```bash
yarn prisma migrate diff --from-config-datasource --to-schema schema.prisma --config prisma.config.prod.ts --script > forward.sql
```

#### npm

```bash
npx prisma migrate diff --from-config-datasource --to-schema schema.prisma --config prisma.config.prod.ts --script > forward.sql
```

This will create a SQL script file containing all changes necessary to take your production environment from its current failed state to the target state defined in your `schema.prisma` file.

* Run the following `prisma db execute` command:

  

#### bun

```bash
bunx prisma db execute --config prisma.config.prod.ts --file forward.sql
```

#### pnpm

```bash
pnpm prisma db execute --config prisma.config.prod.ts --file forward.sql
```

#### yarn

```bash
yarn prisma db execute --config prisma.config.prod.ts --file forward.sql
```

#### npm

```bash
npx prisma db execute --config prisma.config.prod.ts --file forward.sql
```

This applies the changes in the SQL script against the target database without interacting with the migrations table.

* Run the following `prisma migrate resolve` command:

  

#### bun

```bash
bunx prisma migrate resolve --applied Unique
```

#### pnpm

```bash
pnpm prisma migrate resolve --applied Unique
```

#### yarn

```bash
yarn prisma migrate resolve --applied Unique
```

#### npm

```bash
npx prisma migrate resolve --applied Unique
```

This will mark the failed migration called 'Unique' in the migrations table on your production environment as applied.

Your local migration history now yields the same result as the state your production environment is in. You can now continue using the already known `migrate dev` /`migrate deploy` workflow.

## Prisma Migrate and PgBouncer [#prisma-migrate-and-pgbouncer]

You might see the following error if you attempt to run Prisma Migrate commands in an environment that uses PgBouncer for connection pooling:

```bash
Error: undefined: Database error
Error querying the database: db error: ERROR: prepared statement "s0" already exists
```

See [Prisma Migrate and PgBouncer workaround](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/pgbouncer) for further information and a workaround. Follow [GitHub issue #6485](https://github.com/prisma/orm/issues/6485) for updates.

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.

# Prototyping your schema (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Rapidly prototype your Prisma schema using db push without migrations

Location: ORM > v7 > Prisma Migrate > Workflows > Prototyping your schema

The Prisma CLI has a dedicated command for prototyping schemas: [`db push`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-push)

`db push` uses the same engine as Prisma Migrate to synchronize your Prisma schema with your database schema. The `db push` command:

* Introspects the database to infer and executes the changes required to make your database schema reflect the state of your Prisma schema.
* Does not automatically trigger generators (for example, Prisma Client). You need to manually invoke `prisma generate` after making schema changes.
* If `db push` anticipates that the changes could result in data loss, it will:
  * Throw an error
  * Require the `--accept-data-loss` option if you still want to make the changes

> [!NOTE]
> Notes
> 
> * `db push` does not interact with or rely on migrations. The migrations table `_prisma_migrations` will not be created or updated, and no migration files will be generated.
> * When working with PlanetScale, we recommend that you use `db push` instead of `migrate`. For details refer to our Getting started documentation, either [Start from scratch guide](https://www.prisma.io/docs/v7/prisma-orm/quickstart/planetscale) or [Add to existing project guide](https://www.prisma.io/docs/v7/prisma-orm/add-to-existing-project/planetscale) depending on your situation.

## Choosing `db push` or Prisma Migrate [#choosing-db-push-or-prisma-migrate]

`db push` works well if:

* You want to **quickly prototype and iterate** on schema design locally without the need to deploy these changes to other environments such as other developers, or staging and production environments.
* You are prioritizing reaching a **desired end-state** and not the changes or steps executed to reach that end-state (there is no way to preview changes made by `db push`)
* You do not need to control how schema changes impact data. There is no way to orchestrate schema and data migrations—if `db push` anticipates that changes will result in data loss, you can either accept data loss with the `--accept-data-loss` option or stop the process. There is no way to customize the changes.

See [Schema prototyping with `db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) for an example of how to use `db push` in this way.

`db push` is **not recommended** if:

* You want to replicate your schema changes in other environments without losing data. You can use `db push` for prototyping, but you should use migrations to commit the schema changes and apply these in your other environments.
* You want fine-grained control over how the schema changes are executed - for example, [renaming a column instead of dropping it and creating a new one](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations#example-rename-a-field).
* You want to keep track of changes made to the database schema over time. `db push` does not create any artifacts that allow you to keep track of these changes.
* You want the schema changes to be reversible. You can use `db push` again to revert to the original state, but this might result in data loss.

## Using Prisma Migrate and `db push` together [#using-prisma-migrate-and-db-push-together]

You can [use `db push` and Prisma Migrate together in your development workflow](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) . For example, you can:

* Use `db push` to prototype a schema at the start of a project and initialize a migration history when you are happy with the first draft
* Use `db push` to prototype a change to an existing schema, then run `prisma migrate dev` to generate a migration from your changes (you will be asked to reset)

## Prototyping a new schema [#prototyping-a-new-schema]

The following scenario demonstrates how to use `db push` to synchronize a new schema with an empty database, and evolve that schema - including what happens when `db push` detects that a change will result in data loss.

* Create a first draft of your schema:

  ```prisma title="schema.prisma"
  generator client {
    provider = "prisma-client"
    output   = "./generated"
  }

  datasource db {
    provider = "postgresql"
  }

  model User {
    id       Int      @id @default(autoincrement())
    name     String
    jobTitle String
    posts    Post[]
    profile  Profile?
  }

  model Profile {
    id       Int    @id @default(autoincrement())
    biograpy String // Intentional typo!
    userId   Int    @unique
    user     User   @relation(fields: [userId], references: [id])
  }

  model Post {
    id         Int        @id @default(autoincrement())
    title      String
    published  Boolean    @default(true)
    content    String     @db.VarChar(500)
    authorId   Int
    author     User       @relation(fields: [authorId], references: [id])
    categories Category[]
  }

  model Category {
    id    Int    @id @default(autoincrement())
    name  String @db.VarChar(50)
    posts Post[]

    @@unique([name])
  }
  ```

* Use `db push` to push the initial schema to the database:

  
    

#### bun

```bash
bunx prisma db push
```

#### pnpm

```bash
pnpm prisma db push
```

#### yarn

```bash
yarn prisma db push
```

#### npm

```bash
npx prisma db push
```
  

* Create some example content:

  ```ts title="main.ts"
  const add = await prisma.user.create({
    data: {
      name: "Eloise",
      jobTitle: "Programmer",
      posts: {
        create: {
          title: "How to create a MySQL database",
          content: "Some content",
        },
      },
    },
  });
  ```

* Make an additive change - for example, create a new required field:

  ```prisma highlight=6;add title="schema.prisma"
  model Post {
    id          Int        @id @default(autoincrement())
    title       String
    description String // [!code ++]
    published   Boolean    @default(true)
    content     String     @db.VarChar(500)
    authorId    Int
    author      User       @relation(fields: [authorId], references: [id])
    categories  Category[]
  }
  ```

* Push the changes:

  
    

#### bun

```bash
bunx prisma db push
```

#### pnpm

```bash
pnpm prisma db push
```

#### yarn

```bash
yarn prisma db push
```

#### npm

```bash
npx prisma db push
```
  

  `db push` will fail because you cannot add a required field to a table with existing content unless you provide a default value.

* Reset **all data** in your database and re-apply migrations.

  
    

#### bun

```bash
bunx prisma migrate reset
```

#### pnpm

```bash
pnpm prisma migrate reset
```

#### yarn

```bash
yarn prisma migrate reset
```

#### npm

```bash
npx prisma migrate reset
```
  

> [!NOTE]
> Note
> 
> Unlike Prisma Migrate, `db push` does not generate migrations that you can modify to preserve data, and is therefore best suited for prototyping in a development environment.

* Continue to evolve your schema until it reaches a relatively stable state.

* Initialize a migration history:

  
    

#### bun

```bash
bunx prisma migrate dev --name initial-state
```

#### pnpm

```bash
pnpm prisma migrate dev --name initial-state
```

#### yarn

```bash
yarn prisma migrate dev --name initial-state
```

#### npm

```bash
npx prisma migrate dev --name initial-state
```
  

  The steps taken to reach the initial prototype are not preserved - `db push` does not generate a history.

* Push your migration history and Prisma schema to source control (e.g. Git).

At this point, the final draft of your prototyping is preserved in a migration and can be pushed to other environments (testing, production, or other members of your team).

## Prototyping with an existing migration history [#prototyping-with-an-existing-migration-history]

The following scenario demonstrates how to use `db push` to prototype a change to a Prisma schema where a migration history already exists.

* Check out the latest Prisma schema and migration history:

  ```prisma title="schema.prisma"
  generator client {
    provider = "prisma-client"
    output   = "./generated"
  }

  datasource db {
    provider = "postgresql"
  }

  model User {
    id       Int      @id @default(autoincrement())
    name     String
    jobTitle String
    posts    Post[]
    profile  Profile?
  }

  model Profile {
    id       Int    @id @default(autoincrement())
    biograpy String // Intentional typo!
    userId   Int    @unique
    user     User   @relation(fields: [userId], references: [id])
  }

  model Post {
    id         Int        @id @default(autoincrement())
    title      String
    published  Boolean    @default(true)
    content    String     @db.VarChar(500)
    authorId   Int
    author     User       @relation(fields: [authorId], references: [id])
    categories Category[]
  }

  model Category {
    id    Int    @id @default(autoincrement())
    name  String @db.VarChar(50)
    posts Post[]

    @@unique([name])
  }
  ```

* Prototype your new feature, which can involve any number of steps. For example, you might:

  * Create a `tags String[]` field, then run `db push`
  * Change the field type to `tags Tag[]` and add a new model named `Tag`, then run `db push`
  * Change your mind and restore the original `tags String[]` field, then call `db push`
  * Make a manual change to the `tags` field in the database - for example, adding a constraint

  After experimenting with several solutions, the final schema change looks like this:

  ```prisma title="schema.prisma"
  model Post {
    id          Int        @id @default(autoincrement())
    title       String
    description String
    published   Boolean    @default(true)
    content     String     @db.VarChar(500)
    authorId    Int
    author      User       @relation(fields: [authorId], references: [id])
    categories  Category[]
    tags        String[]
  }
  ```

* To create a migration that adds the new `tags` field, run the `migrate dev` command:

  
    

#### bun

```bash
bunx prisma migrate dev --name added-tags
```

#### pnpm

```bash
pnpm prisma migrate dev --name added-tags
```

#### yarn

```bash
yarn prisma migrate dev --name added-tags
```

#### npm

```bash
npx prisma migrate dev --name added-tags
```
  

  Prisma Migrate will prompt you to reset because the changes you made manually and with `db push` while prototyping are not part of the migration history:

  ```bash
  √ Drift detected: Your database schema is not in sync with your migration history.

  We need to reset the PostgreSQL database "prototyping" at "localhost:5432".
  ```

> [!WARNING]
> This will result in total data loss.

  

#### bun

```bash
bunx prisma migrate reset
```

#### pnpm

```bash
pnpm prisma migrate reset
```

#### yarn

```bash
yarn prisma migrate reset
```

#### npm

```bash
npx prisma migrate reset
```

* Prisma Migrate replays the existing migration history, generates a new migration based on your schema changes, and applies those changes to the database.

> [!NOTE]
> When using `migrate dev`, if your schema changes mean that seed scripts will no longer work, you can use the `--skip-seed` flag to ignore seed scripts.

At this point, the final result of your prototyping is preserved in a migration, and can be pushed to other environments (testing, production, or other members of your team).

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.

# Seeding (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/seeding)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to seed your database using Prisma ORM's integrated seeding functionality and Prisma Client

Location: ORM > v7 > Prisma Migrate > Workflows > Seeding

Seeding allows you to consistently re-create the same data in your database and can be used to:

* Populate your database with data that is required for your application to start, such as a default language or currency.
* Provide basic data for validating and using your application in a development environment. This is particularly useful if you are using Prisma Migrate, which sometimes requires resetting your development database.

### Watch video: Seeding your database

[How to seed your database with Prisma ORM](https://www.youtube.com/watch?v=mulzjQ4pZaA)

## How to seed your database in Prisma ORM [#how-to-seed-your-database-in-prisma-orm]

Prisma ORM's integrated seeding functionality expects a command in the `"seed"` key in the `migrations` object of your `prisma.config.ts`. This can be any command; `prisma db seed` executes it as given. In this guide and as a default, we recommend writing a seed script inside your project's `prisma/` folder and starting it with the command.

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "tsx prisma/seed.ts",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

## Integrated seeding with Prisma Migrate [#integrated-seeding-with-prisma-migrate]

Database seeding happens when you run `prisma db seed`. With `prisma db seed`, *you* decide when to invoke the seed command. It can be useful for a test setup or to prepare a new development environment, for example.

> [!NOTE]
> Prisma ORM v7 changes
> 
> In Prisma ORM v7, seeding is **only triggered explicitly** by running `npx prisma db seed`. Automatic seeding during `prisma migrate dev` or `prisma migrate reset` has been removed.

## Example seed scripts [#example-seed-scripts]

Here we suggest some specific seed scripts for different situations. You are free to customize these in any way, but can also use them as presented here:

### Seeding your database [#seeding-your-database]

* Create a new file named `seed.ts`. This can be placed anywhere within your project's folder structure. The example below places it in the `/prisma` folder.

* In the `seed.ts` file, import Prisma Client, initialize it and create some records. As an example, take the following Prisma schema with a `User` and `Post` model:

```prisma title="schema.prisma"
model User {
 id    Int    @id @default(autoincrement())
 email String @unique
 name  String
 posts Post[]
}

model Post {
 id        Int     @id @default(autoincrement())
 title     String
 content   String
 published Boolean
 user      User    @relation(fields: [userId], references: [id])
 userId    Int
}
```

Create some new users and posts in your `prisma/seed.ts` file:

> [!NOTE]
> Prisma ORM v7 requirement
> 
> In Prisma ORM v7, `PrismaClient` must be initialized with a driver adapter. The example below uses `@prisma/adapter-pg` with a PostgreSQL connection pool.

```js title="seed.ts"
import "dotenv/config";
import { Pool } from "pg";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../prisma/generated/client";

const connectionString = `${process.env.DATABASE_URL}`;
const pool = new Pool({ connectionString });
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({ adapter });
async function main() {
  const alice = await prisma.user.upsert({
    where: { email: "alice@prisma.io" },
    update: {},
    create: {
      email: "alice@prisma.io",
      name: "Alice",
      posts: {
        create: {
          title: "Check out Prisma with Next.js",
          content: "https://www.prisma.io/nextjs",
          published: true,
        },
      },
    },
  });
  const bob = await prisma.user.upsert({
    where: { email: "bob@prisma.io" },
    update: {},
    create: {
      email: "bob@prisma.io",
      name: "Bob",
      posts: {
        create: [
          {
            title: "Follow Prisma on Twitter",
            content: "https://twitter.com/prisma",
            published: true,
          },
          {
            title: "Follow Nexus on Twitter",
            content: "https://twitter.com/nexusgql",
            published: true,
          },
        ],
      },
    },
  });
  console.log({ alice, bob });
}
main()
  .then(async () => {
    await prisma.$disconnect();
    await pool.end();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    await pool.end();
    process.exit(1);
  });
```

* Add `typescript`, `tsx`, `@types/node`, `@prisma/adapter-pg`, `pg`, `@types/pg` and `dotenv` development dependencies:

  

#### bun

```bash
bun add --dev typescript tsx @types/node @prisma/adapter-pg pg @types/pg dotenv
```

#### pnpm

```bash
pnpm add -D typescript tsx @types/node @prisma/adapter-pg pg @types/pg dotenv
```

#### yarn

```bash
yarn add --dev typescript tsx @types/node @prisma/adapter-pg pg @types/pg dotenv
```

#### npm

```bash
npm install -D typescript tsx @types/node @prisma/adapter-pg pg @types/pg dotenv
```

* Add the `seed` field to your `prisma.config.ts` file:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "tsx prisma/seed.ts", // [!code ++]
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

* To seed the database, run the `db seed` CLI command:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

We're using TypeScript here, but it's possible to do the same thing in vanilla JavaScript. The same steps would be followed, expect with a `prisma/seed.js` file (without types), and calling `node prisma/seed.js` instead of `tsx`.

### Seeding your database via raw SQL queries [#seeding-your-database-via-raw-sql-queries]

You can also make use of raw SQL queries in order to seed the database with data.

While you can use a plain-text `.sql` file (such as a data dump) for that, it is often easier to place those raw queries, if they're of short size, into the `seed.js` file because it saves you the hassle of working out database connection strings and creating a dependency on a binary like `psql`.

To seed additional data to the `schema.prisma` above, add the following to the `seed.js` (or `seed.ts`) file:

```js title="seed.js"
async function rawSql() {
  const result =
    await prisma.$executeRaw`INSERT INTO "User" ("id", "email", "name") VALUES (3, 'foo@example.com', 'Foo') ON CONFLICT DO NOTHING;`;
  console.log({ result });
}
```

and chain this function to the promise calls, such as the following change towards the end of the file:

```js title="seed.js"
main()
  .then(rawSql)
  .then(async () => {
    await prisma.$disconnect();
    await pool.end();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    await pool.end();
    process.exit(1);
  });
```

### Seeding your database via any language (with a Bash script) [#seeding-your-database-via-any-language-with-a-bash-script]

In addition to TypeScript and JavaScript, you can also use a Bash script (`seed.sh`) to seed your database in another language such as Go, or plain SQL.

The following example runs a Go script in the same folder as `seed.sh`:

```bash title="seed.sh"
#!/bin/sh
# -e Exit immediately when a command returns a non-zero status.
# -x Print commands before they are executed
set -ex
# Seeding command go
run ./seed/
```

The following example uses [psql](https://www.postgresql.org/docs/13/app-psql.html) to run a SQL script in the same folder as `seed.sh`:

```bash title="seed.sh"
#!/bin/sh
# -e Exit immediately when a command returns a non-zero status.
# -x Print commands before they are executed
set -ex
# Seeding command
psql file.sql
```

### User-defined arguments [#user-defined-arguments]

`prisma db seed` allows you to define custom arguments in your seed file that you can pass to the `prisma db seed` command. For example, you could define your own arguments to seed different data for different environments or partially seeding data in some tables.

Here is an example seed file that defines a custom argument to seed different data in different environments:

```js title="seed.js"
import { parseArgs } from "node:util";

const options = {
  environment: { type: "string" },
};

async function main() {
  const {
    values: { environment },
  } = parseArgs({ options });

  switch (environment) {
    case "development":
      /** data for your development */
      break;
    case "test":
      /** data for your test environment */
      break;
    default:
      break;
  }
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

You can then provide the `environment` argument when using `prisma db seed` by adding a [delimiter](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02) — `--` —, followed by your custom arguments:

  

#### bun

```bash
bunx prisma db seed -- --environment development
```

#### pnpm

```bash
pnpm prisma db seed -- --environment development
```

#### yarn

```bash
yarn prisma db seed -- --environment development
```

#### npm

```bash
npx prisma db seed -- --environment development
```

## Going further [#going-further]

Here's a non-exhaustive list of other tools you can integrate with Prisma ORM in your development workflow to seed your database:

* [Supabase community project](https://github.com/supabase-community/seed)
* [Replibyte](https://www.replibyte.com/docs/introduction/)

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.

# Squashing migrations (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/squashing-migrations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to squash multiple migration files into a single migration

Location: ORM > v7 > Prisma Migrate > Workflows > Squashing migrations

It is sometimes useful to squash either some or all migration files into a single migration. This guide will describe two scenarios where you may want to do this:

* [Migrating cleanly from a development environment](#migrating-cleanly-from-a-development-environment) by squashing your local migrations into one before merging
* [Creating a clean history in a production environment](#creating-a-clean-history-in-a-production-environment) by squashing all migrations into a single file

In both cases, Prisma Migrate provides the tools for doing this, by using the [`migrate diff`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-diff) command to compare two database schemas and output a single SQL file that takes you from one to the other. The rest of this guide gives detailed instructions on how to carry this out in these two scenarios.

### Migrating cleanly from a development environment [#migrating-cleanly-from-a-development-environment]

Squashing migrations can be useful when developing with a branch-based workflow. During a large local development effort on a feature branch you might generate multiple migrations using `migrate dev`. After the feature is finished, the migration history might contain unnecessary intermediate steps that are unwanted in the final migration history that will be pushed to the `main` branch.

There could be important reasons to avoid applying the intermediate steps in production — they might lose data or be extremely slow / disruptive). Even when this is not the case, you may want to avoid clutter in your production environment's migrations history.

For detailed steps on how to achieve this using `migrate dev`, see the section on [how to migrate cleanly from a development environment](#how-to-migrate-cleanly-from-a-development-environment).

### Creating a clean history in a production environment [#creating-a-clean-history-in-a-production-environment]

Squashing migrations can also be used in a production environment to squash all migration files into one. This can be useful when the production environment has accumulated a longer migration history, and replaying it in new environments has become a burden due to intermediate steps requiring extra time. Since the team is not deriving value from the migration steps (and could get them back from version control history in a pinch) the decision is made to squash the whole history into a single migration.

For detailed steps on how to achieve this using `migrate diff` and `migrate resolve` see the section on [how to create a clean history in a production environment](#how-to-create-a-clean-history-in-a-production-environment).

## Considerations when squashing migrations [#considerations-when-squashing-migrations]

> [!WARNING]
> When squashing migrations, be aware that any manually changed or added SQL in your `migration.sql` files will not be retained. If you have migration files with custom additions such as a view or a trigger, ensure to re-add them after your migrations were squashed.

## How to squash migrations [#how-to-squash-migrations]

This section provides step-by-step instructions on how to squash migrations in the two scenarios discussed above:

* [Migrating cleanly from a development environment](#how-to-migrate-cleanly-from-a-development-environment)
* [Creating a clean history in a production environment](#how-to-create-a-clean-history-in-a-production-environment)

### How to migrate cleanly from a development environment [#how-to-migrate-cleanly-from-a-development-environment]

Before squashing your migrations, make sure you have the following starting conditions:

* The contents of the migrations to be squashed are not yet applied on the production database
* All migrations applied to production are part of the local migration history already
* There is no custom SQL in any of the new migration files that you have added to your branch

> [!NOTE]
> If the migration history on the production database has diverged after you created your feature branch, then you would need to first merge the migrations history and the datamodel changes from production into your local history.

Then follow these steps:

* Reset the contents of your local `./prisma/migrations` folder to match the migration history on the `main` branch
* Create a new migration:

  

#### bun

```bash
bunx prisma migrate dev --name squashed_migrations
```

#### pnpm

```bash
pnpm prisma migrate dev --name squashed_migrations
```

#### yarn

```bash
yarn prisma migrate dev --name squashed_migrations
```

#### npm

```bash
npx prisma migrate dev --name squashed_migrations
```

This creates a single migration that takes you:

* from the state of the `main` branch as described in your reset migration history
* to the state of your local feature as described in your `./prisma/schema.prisma` file
* and outputs this to a new `migration.sql` file in a new directory ending with `squashed_migrations` (specified with the `--name` flag)

This single migration file can now be applied to production using `migrate deploy`.

### How to create a clean history in a production environment [#how-to-create-a-clean-history-in-a-production-environment]

Before squashing your migrations, make sure you have the following starting conditions:

* All migrations in the migration history are applied on the production database
* The datamodel matches the migration history
* The datamodel and the migration history are in sync

Then follow these steps, either on your `main` branch or on a newly checked out branch that gets merged back to `main` before anything else changes there:

* Delete all contents of the `./prisma/migrations` directory

* Create a new empty directory in the `./prisma/migrations` directory. In this guide this will be called `000000000000_squashed_migrations`. Inside this, add a new empty `migration.sql` file.

> [!NOTE]
> We name the migration `000000000000_squashed_migrations` with all the leading zeroes because we want it to be the first migration in the migrations directory. Migrate runs the migrations in the directory in lexicographic (alphabetical) order. This is why it generates migrations with the date and time as a prefix when you use `migrate dev`. You can give the migration another name, as long as it sorts lower than later migrations, for example `0_squashed` or `202207180000_squashed`.

* Create a single migration that takes you:

  * from an empty database
  * to the current state of the production database schema as described in your `./prisma/schema.prisma` file
  * and outputs this to the `migration.sql` file created above

  You can do this using the `migrate diff` command. From the root directory of your project, run the following command:

  

#### bun

```bash
bunx prisma migrate diff \
  --from-empty \
  --to-schema ./prisma/schema.prisma \
  --script > ./prisma/migrations/000000000000_squashed_migrations/migration.sql
```

#### pnpm

```bash
pnpm prisma migrate diff \
  --from-empty \
  --to-schema ./prisma/schema.prisma \
  --script > ./prisma/migrations/000000000000_squashed_migrations/migration.sql
```

#### yarn

```bash
yarn prisma migrate diff \
  --from-empty \
  --to-schema ./prisma/schema.prisma \
  --script > ./prisma/migrations/000000000000_squashed_migrations/migration.sql
```

#### npm

```bash
npx prisma migrate diff \
  --from-empty \
  --to-schema ./prisma/schema.prisma \
  --script > ./prisma/migrations/000000000000_squashed_migrations/migration.sql
```

* Mark this migration as having been applied on production, to prevent it from being run there:

  You can do this using the [`migrate resolve`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-resolve) command to mark the migration in the `000000000000_squashed_migrations` directory as already applied:

  

#### bun

```bash
bunx prisma migrate resolve \
  --applied 000000000000_squashed_migrations
```

#### pnpm

```bash
pnpm prisma migrate resolve \
  --applied 000000000000_squashed_migrations
```

#### yarn

```bash
yarn prisma migrate resolve \
  --applied 000000000000_squashed_migrations
```

#### npm

```bash
npx prisma migrate resolve \
  --applied 000000000000_squashed_migrations
```

You should now have a single migration file that is marked as having been applied on production. New checkouts only get one single migration taking them to the state of the production database schema.

The production database still contains the history of applied migrations in the migrations table. The history of the migrations folder and data models is also still available in source control.

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.

# Troubleshooting (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/troubleshooting)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Troubleshooting issues with Prisma Migrate in a development environment.

Location: ORM > v7 > Prisma Migrate > Workflows > Troubleshooting

This guide describes how to resolve issues with Prisma Migrate in a development environment, which often involves resetting your database. For production-focused troubleshooting, see:

* [Production troubleshooting](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing)
* [Patching / hotfixing production databases](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing)

> [!WARNING]
> This guide **does not apply for MongoDB**.<br />
> Instead of `migrate dev`, [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) is used for [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

## Handling migration history conflicts [#handling-migration-history-conflicts]

A migration history conflict occurs when there are discrepancies between the **migrations folder in the file system*&#x2A; and the **`_prisma_migrations` table in the database**.

#### Causes of migration history conflict in a development environment [#causes-of-migration-history-conflict-in-a-development-environment]

* A migration that has already been applied is later modified
* A migration that has already been applied is missing from the file system

In a development environment, switching between feature branches can result in a history conflict because the `_prisma_migrations` table contains migrations from `branch-1`, and switching to `branch-2` might cause some of those migrations to disappear.

> [!NOTE]
> Note
> 
> You should [never purposefully delete or edit a migration](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/migration-histories#do-not-edit-or-delete-migrations-that-have-been-applied), as this might result in discrepancies between development and production.

#### Fixing a migration history conflict in a development environment [#fixing-a-migration-history-conflict-in-a-development-environment]

If Prisma Migrate detects a migration history conflict when you run `prisma migrate dev`, the CLI will ask to reset the database and reapply the migration history.

## Schema drift [#schema-drift]

Database schema drift occurs when your database schema is out of sync with your migration history - the database schema has 'drifted away' from the source of truth.

#### Causes of schema drift in a development environment [#causes-of-schema-drift-in-a-development-environment]

Schema drift can occur if:

* The database schema was changed *without* using migrations - for example, by using [`prisma db push`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-push) or manually changing the database schema.

> [!NOTE]
> Note
> 
> The [shadow database](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database) is required to detect schema drift, and can therefore only be done in a development environment.

#### Fixing schema drift in a development environment [#fixing-schema-drift-in-a-development-environment]

If you made manual changes to the database that you do not want to keep, or can replicate in the Prisma schema:

* Reset your database:

  

#### bun

```bash
bunx prisma migrate reset
```

#### pnpm

```bash
pnpm prisma migrate reset
```

#### yarn

```bash
yarn prisma migrate reset
```

#### npm

```bash
npx prisma migrate reset
```

* Replicate the changes in the Prisma schema and generate a new migration:

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

If you made manual changes to the database that you want to keep, you can:

* Introspect the database:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

Prisma will update your schema with the changes made directly in the database.

* Generate a new migration to include the introspected changes in your migration history:

  

#### bun

```bash
bunx prisma migrate dev --name introspected_change
```

#### pnpm

```bash
pnpm prisma migrate dev --name introspected_change
```

#### yarn

```bash
yarn prisma migrate dev --name introspected_change
```

#### npm

```bash
npx prisma migrate dev --name introspected_change
```

Prisma Migrate will prompt you to reset, then applies all existing migrations and a new migration based on the introspected changes. Your database and migration history are now in sync, including your manual changes.

## Failed migrations [#failed-migrations]

#### Causes of failed migrations in a development environment [#causes-of-failed-migrations-in-a-development-environment]

A migration might fail if:

* You [modify a migration before running it](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations) and introduce a syntax error
* You add a mandatory (`NOT NULL`) column to a table that already has data
* The migration process stopped unexpectedly
* The database shut down in the middle of the migration process

Each migration in the `_prisma_migrations` table has a `logs` column that stores the error.

#### Fixing failed migrations in a development environment [#fixing-failed-migrations-in-a-development-environment]

The usual way to handle a failed migration in a development environment is to address the root cause and reset the database. For example:

* If you introduced a SQL syntax error by manually editing the database, update the `migration.sql` file that failed and reset the database:

  

#### bun

```bash
bunx prisma migrate reset
```

#### pnpm

```bash
pnpm prisma migrate reset
```

#### yarn

```bash
yarn prisma migrate reset
```

#### npm

```bash
npx prisma migrate reset
```

* If you introduced a change in the Prisma schema that cannot be applied to a database with data (for example, a mandatory column in a table with data):
  * Delete the `migration.sql` file.
  * Modify the schema - for example, add a default value to the mandatory field.
  * Migrate:
    
      

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```
    

Prisma Migrate will prompt you to reset the database and re-apply all migrations.

* If something interrupted the migration process, reset the database:

  

#### bun

```bash
bunx prisma migrate reset
```

#### pnpm

```bash
pnpm prisma migrate reset
```

#### yarn

```bash
yarn prisma migrate reset
```

#### npm

```bash
npx prisma migrate reset
```

## Prisma Migrate and PgBouncer [#prisma-migrate-and-pgbouncer]

You might see the following error if you attempt to run Prisma Migrate commands in an environment that uses PgBouncer for connection pooling:

```bash
Error: undefined: Database error
Error querying the database: db error: ERROR: prepared statement "s0" already exists
```

See [Prisma Migrate and PgBouncer workaround](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/pgbouncer) for further information and a workaround.

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.

# Unsupported database features (Prisma Migrate) (Prisma ORM v7) (/docs/orm/v7/prisma-migrate/workflows/unsupported-database-features)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to include unsupported database features for projects that use Prisma Migrate

Location: ORM > v7 > Prisma Migrate > Workflows > Unsupported database features (Prisma Migrate)

Prisma Migrate uses the Prisma schema to determine what features to create in the database. However, some database features [cannot be represented in the Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/unsupported-database-features) , including but not limited to:

* Stored procedures
* Triggers
* Views

To add an unsupported feature to your database, you must [customize a migration](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations) to include that feature before you apply it.

> [!NOTE]
> Partial indexes are now supported in Prisma Schema Language via the `where` argument on `@@index`, `@@unique`, and `@unique`. See [Configuring partial indexes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#configuring-partial-indexes-with-where) for details. You no longer need to customize migrations for partial indexes.
> 
> The Prisma schema is also able to represent [unsupported field types](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/unsupported-database-features#unsupported-field-types) and [native database functions](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions).

> [!WARNING]
> This guide **does not apply for MongoDB**.<br />
> Instead of `migrate dev`, [`db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema) is used for [MongoDB](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb).

## Customize a migration to include an unsupported feature [#customize-a-migration-to-include-an-unsupported-feature]

To customize a migration to include an unsupported feature:

* Use the `--create-only` flag to generate a new migration without applying it:

  

#### bun

```bash
bunx prisma migrate dev --create-only
```

#### pnpm

```bash
pnpm prisma migrate dev --create-only
```

#### yarn

```bash
yarn prisma migrate dev --create-only
```

#### npm

```bash
npx prisma migrate dev --create-only
```

* Open the generated `migration.sql` file and add the unsupported feature - for example, a trigger function:

```sql title="migration.sql"
CREATE OR REPLACE FUNCTION notify_on_insert()
RETURNS TRIGGER AS $$
BEGIN
  PERFORM pg_notify('new_record', NEW.id::text);
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;
```

* Apply the migration:

  

#### bun

```bash
bunx prisma migrate dev
```

#### pnpm

```bash
pnpm prisma migrate dev
```

#### yarn

```bash
yarn prisma migrate dev
```

#### npm

```bash
npx prisma migrate dev
```

* Commit the modified migration to source control.

## Related pages

- [`Baselining a database`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining): How to initialize a migration history for an existing database that contains important data.
- [`Customizing migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations): How to edit a migration file before applying it to avoid data loss in production.
- [`Development and production`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production): How to use Prisma Migrate commands in development and production environments
- [`Generating down migrations`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/generating-down-migrations): How to generate a down migration SQL file that reverses a given migration file
- [`Native database functions`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions): How to enable PostgreSQL native database functions for projects that use Prisma Migrate.

# Database mapping (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/database-mapping)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to map model and field names to database tables and columns

Location: ORM > v7 > Prisma Schema > Data Model > Database mapping

The [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) includes mechanisms that allow you to define names of certain database objects. You can:

* [Map model and field names to different collection/table and field/column names](#mapping-collectiontable-and-fieldcolumn-names)
* [Define constraint and index names](#constraint-and-index-names)

## Mapping collection/table and field/column names [#mapping-collectiontable-and-fieldcolumn-names]

Sometimes the names used to describe entities in your database might not match the names you would prefer in your generated API. Mapping names in the Prisma schema allows you to influence the naming in your Client API without having to change the underlying database names.

A common approach for naming tables/collections in databases for example is to use plural form and [snake_case](https://en.wikipedia.org/wiki/Snake_case) notation. However, we recommended a different [naming convention (singular form, PascalCase)](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#naming-conventions).

`@map` and `@@map` allow you to [tune the shape of your Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names) by decoupling model and field names from table and column names in the underlying database.

### Map collection / table names [#map-collection--table-names]

As an example, when you [introspect](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) a database with a table named `comments`, the resulting Prisma model will look like this:

```prisma
model comments {
  // Fields
}
```

However, you can still choose `Comment` as the name of the model (e.g. to follow the naming convention) without renaming the underlying `comments` table in the database by using the [`@@map`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) attribute:

```prisma highlight=4;normal
model Comment {
  // Fields

  @@map("comments") // [!code highlight]
}
```

With this modified model definition, Prisma Client automatically maps the `Comment` model to the `comments` table in the underlying database.

### Map field / column names [#map-field--column-names]

You can also [`@map`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#map) a column/field name:

```prisma highlight=2-4;normal
model Comment {
  content String @map("comment_text") // [!code highlight]
  email   String @map("commenter_email") // [!code highlight]
  type    Enum   @map("comment_type") // [!code highlight]

  @@map("comments")
}
```

This way the `comment_text` column is not available under `prisma.comment.comment_text` in the Prisma Client API, but can be accessed via `prisma.comment.content`.

### Map enum names and values [#map-enum-names-and-values]

You can also `@map` an enum value, or `@@map` an enum:

```prisma highlight=3,5;normal
enum Type {
  Blog,
  Twitter @map("comment_twitter") // [!code highlight]

  @@map("comment_source_enum") // [!code highlight]
}
```

In this example:

* `@@map("comment_source_enum")` maps the enum name `Type` to `comment_source_enum` in the database
* `@map("comment_twitter")` maps the enum value `Twitter` to `comment_twitter` in the database

#### Effect on generated TypeScript [#effect-on-generated-typescript]

When you use `@map` on enum values, the generated TypeScript enum uses the **schema names**, not the mapped values:

```prisma
enum Status {
  PENDING  @map("pending")
  APPROVED @map("approved")
}
```

This generates the following TypeScript:

```ts
export const Status = {
  PENDING: "PENDING",
  APPROVED: "APPROVED",
} as const;
```

This means `Status.PENDING` evaluates to `"PENDING"`, not `"pending"`. The mapping is handled at the database level only.

## Constraint and index names [#constraint-and-index-names]

You can optionally use the `map` argument to explicitly define the **underlying constraint and index names** in the Prisma schema for the attributes [`@id`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#id), [`@@id`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference), [`@unique`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#unique), [`@@unique`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference), [`@@index`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#index) and [`@relation`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#relation).

When introspecting a database, the `map` argument will *only* be rendered in the schema if the name *differs* from Prisma ORM's [default constraint naming convention for indexes and constraints](#prisma-orms-default-naming-conventions-for-indexes-and-constraints).

### Use cases for named constraints [#use-cases-for-named-constraints]

Some use cases for explicitly named constraints include:

* Company policy
* Conventions of other tools

### Prisma ORM's default naming conventions for indexes and constraints [#prisma-orms-default-naming-conventions-for-indexes-and-constraints]

Prisma ORM naming convention was chosen to align with PostgreSQL since it is deterministic. It also helps to maximize the amount of times where names do not need to be rendered because many databases out there they already align with the convention.

Prisma ORM always uses the database names of entities when generating the default index and constraint names. If a model is remapped to a different name in the data model via `@@map` or `@map`, the default name generation will still take the name of the *table* in the database as input. The same is true for fields and *columns*.

| Entity            | Convention                           | Example                        |
| ----------------- | ------------------------------------ | ------------------------------ |
| Primary Key       | {tablename}_pkey                   | `User_pkey`                    |
| Unique Constraint | {tablename}_{column_names}_key  | `User_firstName_last_Name_key` |
| Non-Unique Index  | {tablename}_{column_names}_idx  | `User_age_idx`                 |
| Foreign Key       | {tablename}_{column_names}_fkey | `User_childName_fkey`          |

Since most databases have a length limit for entity names, the names will be trimmed if necessary to not violate the database limits. We will shorten the part before the `_suffix` as necessary so that the full name is at most the maximum length permitted.

### Using default constraint names [#using-default-constraint-names]

When no explicit names are provided via `map` arguments Prisma ORM will generate index and constraint names following the [default naming convention](#prisma-orms-default-naming-conventions-for-indexes-and-constraints).

If you introspect a database the names for indexes and constraints will be added to your schema unless they follow Prisma ORM's naming convention. If they do, the names are not rendered to keep the schema more readable. When you migrate such a schema Prisma will infer the default names and persist them in the database.

#### Example [#example]

The following schema defines three constraints (`@id`, `@unique`, and `@relation`) and one index (`@@index`):

```prisma highlight=2,8,11,13;normal
model User {
  id    Int    @id @default(autoincrement()) // [!code highlight]
  name  String @unique
  posts Post[]
}

model Post {
  id         Int    @id @default(autoincrement()) // [!code highlight]
  title      String
  authorName String @default("Anonymous")
  author     User?  @relation(fields: [authorName], references: [name]) // [!code highlight]

  @@index([title, authorName]) // [!code highlight]
}
```

Since no explicit names are provided via `map` arguments Prisma will assume they follow our default naming convention.

The following table lists the name of each constraint and index in the underlying database:

| Constraint or index                | Follows convention | Underlying constraint or index names |
| ---------------------------------- | ------------------ | ------------------------------------ |
| `@id` (on `User` > `id` field)     | Yes                | `User_pk`                            |
| `@@index` (on `Post`)              | Yes                | `Post_title_authorName_idx`          |
| `@id` (on `Post` > `id` field)     | Yes                | `Post_pk`                            |
| `@relation` (on `Post` > `author`) | Yes                | `Post_authorName_fkey`               |

### Using custom constraint / index names [#using-custom-constraint--index-names]

You can use the `map` argument to define **custom constraint and index names** in the underlying database.

#### Example [#example-1]

The following example adds custom names to one `@id` and the `@@index`:

```prisma highlight=2,13;normal
model User {
  id    Int    @id(map: "Custom_Primary_Key_Constraint_Name") @default(autoincrement()) // [!code highlight]
  name  String @unique
  posts Post[]
}

model Post {
  id         Int    @id @default(autoincrement()) // [!code highlight]
  title      String
  authorName String @default("Anonymous")
  author     User?  @relation(fields: [authorName], references: [name]) // [!code highlight]

  @@index([title, authorName], map: "My_Custom_Index_Name") // [!code highlight]
}
```

The following table lists the name of each constraint and index in the underlying database:

| Constraint or index                | Follows convention | Underlying constraint or index names |
| ---------------------------------- | ------------------ | ------------------------------------ |
| `@id` (on `User` > `id` field)     | No                 | `Custom_Primary_Key_Constraint_Name` |
| `@@index` (on `Post`)              | No                 | `My_Custom_Index_Name`               |
| `@id` (on `Post` > `id` field)     | Yes                | `Post_pk`                            |
| `@relation` (on `Post` > `author`) | Yes                | `Post_authorName_fkey`               |

### Related: Naming indexes and primary keys for Prisma Client [#related-naming-indexes-and-primary-keys-for-prisma-client]

Additionally to `map`, the `@@id` and `@@unique` attributes take an optional `name` argument that allows you to customize your Prisma Client API.

On a model like:

```prisma
model User {
  firstName String
  lastName  String

  @@id([firstName, lastName])
}
```

the default API for selecting on that primary key uses a generated combination of the fields:

```ts
const user = await prisma.user.findUnique({
  where: {
    firstName_lastName: {
      firstName: "Paul",
      lastName: "Panther",
    },
  },
});
```

Specifying `@@id([firstName, lastName], name: "fullName")` will change the Prisma Client API to this instead:

```ts highlight=3;edit
const user = await prisma.user.findUnique({
  where: {
    fullName: {
      // [!code highlight]
      firstName: "Paul",
      lastName: "Panther",
    },
  },
});
```

## Related pages

- [`External tables`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables): How to declare and use externally managed tables in Prisma ORM
- [`Indexes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes): How to configure index functionality and add full text indexes
- [`Models`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models): Learn about the concepts for building your data model with Prisma: Models, scalar types, enums, attributes, functions, IDs, default values and more
- [`Multi-schema`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema): How to use Prisma ORM with multiple database schemas
- [`Relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations): A relation is a connection between two models in the Prisma schema. This page explains how you can define one-to-one, one-to-many and many-to-many relations in Prisma

# External tables (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/externally-managed-tables)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to declare and use externally managed tables in Prisma ORM

Location: ORM > v7 > Prisma Schema > Data Model > External tables

## Overview [#overview]

*Externally managed tables* (or *external tables* for short) in Prisma ORM are tables that can be **queried via Prisma Client** but are **ignored by Prisma Migrate**.

Sometimes, you might not want Prisma ORM to manage specific tables—such as ones handled by another team or service.

Some concrete use cases for this are:

* auth services like Clerk or Auth0 that manage specific tables with user and session data
* storage services like Supabase Storage with tables for storing metadata about buckets and objects
* a microservice-based organization where specific teams own specific tables in the database

There may be many other scenarios based on custom organizational constraints or preferences where you may not want Prisma ORM to manage specific tables.

> [!WARNING]
> Externally managed tables are currently in [Preview](https://www.prisma.io/docs/orm/v7/more/releases#preview).

> [!NOTE]
> Externally managed tables are frequently used in combination with [multi-schema](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema) database setups. However, this is not a hard requirement. You can have only a single schema in your database and also declare externally managed tables within it.

> [!WARNING]
> Prisma ORM will not verify that the structure of the tables in the database and the structures of the Prisma models actually match.
> On the one hand, it requires the developer to be thorough when updating the Prisma schema (the safest way to do it is by using `prisma db pull`).
> On the other hand, this flexibility enables you to represent only part of the underlying table in the database (and e.g. not expose *all* its columns).

## Workflow [#workflow]

To use external tables, follow this workflow:

1. Declare the name of the external tables in your [Prisma Config file](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference)
2. Update your Prisma schema (e.g. via `npx prisma db pull`)
3. Re-generate Prisma Client with `npx prisma generate`
4. You can now query the external table using Prisma Client but it will be ignored by Prisma Migrate
5. When the table gets changed (by whoever owns it):
   1. Re-introspect your database using `npx prisma db pull` or manually update the models in your prisma file
   2. Re-generate Prisma Client with `npx prisma generate`

## Prisma Config syntax [#prisma-config-syntax]

You can specify externally managed tables in your [Prisma Config](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference) file via the `tables.external` property:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
  // required when using unstable features
  experimental: {
    externalTables: true, // [!code ++]
  },
  // declare the `users` table and `role` enum as external
  tables: {
    // [!code ++]
    external: ["public.users"], // [!code ++]
  }, // [!code ++]
  enums: {
    // [!code ++]
    external: ["public.role"], // [!code ++]
  }, // [!code ++]
});
```

* Analogous to tables, you can also have externally managed *enums*.
* On PostgreSQL and SQL Server you have to specify the fully qualified table/enum name including the schema name. For example: `public.products` or `auth.users`.
* On MySQL and SQLite, you only have to specify the table name.

## Relationships [#relationships]

Prisma can create and update relationships from tables it manages to externally managed tables.

However, for this Prisma needs to be aware of the structure of those externally managed tables during migration creation.
You can provide a SQL script that Prisma will run on its [shadow database](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database) ahead of all migrations to emulate the external tables and enums during migration creation.

The created placeholder table does not need to have the full structure of the actual table but primary keys need to be present.

If the external table is not referenced by any managed table—that is no managed table contains a foreign key constraint on the external table—you do NOT need to provide any SQL for it in `migrations.initShadowDb`.

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
  // required when using unstable features
  experimental: {
    externalTables: true, // [!code ++]
  },
  // declare a `users` table // [!code ++]
  tables: {
    // [!code ++]
    external: ["public.users"], // [!code ++]
  }, // [!code ++]
  migrations: {
    // [!code ++]
    path: "prisma/migrations", // [!code ++]
    // setup the users table for the shadow database // [!code ++]
    initShadowDb: ` // [!code ++]
      CREATE TABLE public.users (id SERIAL PRIMARY KEY); // [!code ++]
    `, // [!code ++]
  }, // [!code ++]
});
```

Relationships from an external table to a managed table, where the external table contains the foreign key constraint on the managed table, are **NOT** managed by Prisma as that would modify the external table.

## Example [#example]

Assume you have the following Prisma schema which only contains the `posts` table:

```prisma
generator client {
  provider = "prisma-client"
  output   = "./generated"
  // ...
}

datasource db {
  provider = "postgresql"
  // ...
}

model posts {
  id          Int       @id @default(autoincrement())
  created_at  DateTime  @default(now())
  title       String
  content     String?
}
```

You have created that `posts` table already via a prior migration.
You now also have a `users` table and `role` enum in your database which you want to treat as externally managed.

So the tables in your PostgreSQL database in the default `public` schema look like this:

```sql
-- Enum used by users table
CREATE TYPE role AS ENUM ('customer', 'support', 'admin');

-- Users table
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  username VARCHAR(50) NOT NULL UNIQUE,
  email VARCHAR(100) NOT NULL UNIQUE,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  role role
);

-- Posts table
CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  title VARCHAR(200) NOT NULL,
  content TEXT
);
```

### 1. Declaring externally managed tables in Prisma Config [#1-declaring-externally-managed-tables-in-prisma-config]

Enable use of externally managed tables via the `tables.external` property:

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
  experimental: {
    externalTables: true, // [!code ++]
  },
  // declare the `users` table and `role` enum as external
  tables: {
    // [!code ++]
    external: ["public.users"], // [!code ++]
  }, // [!code ++]
  enums: {
    // [!code ++]
    external: ["public.role"], // [!code ++]
  }, // [!code ++]
});
```

### 2. Update the Prisma schema [#2-update-the-prisma-schema]

Next, you need to update your Prisma schema. You can do this either:

* by manually creating the models
* or by using [introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection):

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

The `users` table is now in your Prisma schema:

```prisma
model posts {
  id         Int       @id @default(autoincrement())
  created_at DateTime? @default(now()) @db.Timestamp(6)
  title      String    @db.VarChar(200)
  content    String?
}

model users { // [!code highlight]
  id         Int       @id @default(autoincrement()) // [!code highlight]
  username   String    @unique @db.VarChar(50) // [!code highlight]
  email      String    @unique @db.VarChar(100) // [!code highlight]
  created_at DateTime? @default(now()) @db.Timestamp(6) // [!code highlight]
  role       role // [!code highlight]
} // [!code highlight]

enum role { // [!code highlight]
  customer // [!code highlight]
  support // [!code highlight]
  admin // [!code highlight]
} // [!code highlight]
```

### 3. Re-generate Prisma Client [#3-re-generate-prisma-client]

In order to be able to query the `users` table, you need to re-generate Prisma Client:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

### 4. Query the `users` table using Prisma Client [#4-query-the-users-table-using-prisma-client]

You can now query the external `users` table with Prisma Client:

```ts
await prisma.users.findMany();
```

### 5. Add a relationship [#5-add-a-relationship]

Suppose you now want to add an author relationship from `posts` onto `users`.

First update your Prisma schema.

```prisma
model posts {
  id         Int       @id @default(autoincrement())
  created_at DateTime? @default(now()) @db.Timestamp(6)
  title      String    @db.VarChar(200)
  content    String?
  author     users @relation(fields: [author_id], references: [id]) // [!code ++]
  author_id  Int // [!code ++]
}

model users {
  id         Int       @id @default(autoincrement())
  username   String    @unique @db.VarChar(50)
  email      String    @unique @db.VarChar(100)
  created_at DateTime? @default(now()) @db.Timestamp(6)
  role       role
  posts      posts[] // [!code ++]
}

enum role {
  customer
  support
  admin
}
```

Then add a `migrations.initShadowDb` script so Prisma knows about the `users` table during migrations.

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
  experimental: {
    externalTables: true,
  },
  tables: {
    external: ["public.users"],
  },
  migrations: {
    // [!code ++]
    path: "prisma/migrations", // [!code ++]
    // setup the users table for the shadow database // [!code ++]
    initShadowDb: ` // [!code ++]
      CREATE TABLE public.users (id SERIAL PRIMARY KEY); // [!code ++]
    `, // [!code ++]
  }, // [!code ++]
});
```

Now you can run `prisma migrate dev` command.

## Related pages

- [`Database mapping`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping): Learn how to map model and field names to database tables and columns
- [`Indexes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes): How to configure index functionality and add full text indexes
- [`Models`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models): Learn about the concepts for building your data model with Prisma: Models, scalar types, enums, attributes, functions, IDs, default values and more
- [`Multi-schema`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema): How to use Prisma ORM with multiple database schemas
- [`Relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations): A relation is a connection between two models in the Prisma schema. This page explains how you can define one-to-one, one-to-many and many-to-many relations in Prisma

# Indexes (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/indexes)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to configure index functionality and add full text indexes

Location: ORM > v7 > Prisma Schema > Data Model > Indexes

Prisma ORM allows configuration of database indexes, unique constraints and primary key constraints. Full text indexes in MySQL and MongoDB are available through the `fullTextIndex` preview feature using the `@@fulltext` attribute.

## Index configuration [#index-configuration]

You can configure indexes, unique constraints, and primary key constraints with the following attribute arguments:

* The [`length` argument](#configuring-the-length-of-indexes-with-length-mysql) allows you to specify a maximum length for the subpart of the value to be indexed on `String` and `Bytes` types
  * Available on the `@id`, `@@id`, `@unique`, `@@unique` and `@@index` attributes
  * MySQL only

* The [`sort` argument](#configuring-the-index-sort-order-with-sort) allows you to specify the order that the entries of the constraint or index are stored in the database
  * Available on the `@unique`, `@@unique` and `@@index` attributes in all databases, and on the `@id` and `@@id` attributes in SQL Server

* The [`type` argument](#configuring-the-access-type-of-indexes-with-type-postgresql) allows you to support index access methods other than PostgreSQL's default `BTree` access method
  * Available on the `@@index` attribute
  * PostgreSQL only
  * Supported index access methods: `Hash`, `Gist`, `Gin`, `SpGist` and `Brin`

* The [`clustered` argument](#configuring-if-indexes-are-clustered-or-non-clustered-with-clustered-sql-server) allows you to configure whether a constraint or index is clustered or non-clustered
  * Available on the `@id`, `@@id`, `@unique`, `@@unique` and `@@index` attributes
  * SQL Server only

* The [`map` argument](#configuring-the-name-of-indexes-with-map) allows you to specify a custom name for the index or constraint in the underlying database
  * Available on the `@id`, `@@id`, `@unique`, `@@unique` and `@@index` attributes
  * Supported in all databases

### Configuring the length of indexes with `length` (MySQL) [#configuring-the-length-of-indexes-with-length-mysql]

The `length` argument is specific to MySQL and allows you to define indexes and constraints on columns of `String` and `Byte` types. For these types, MySQL requires you to specify a maximum length for the subpart of the value to be indexed in cases where the full value would exceed MySQL's limits for index sizes. See [the MySQL documentation](https://dev.mysql.com/doc/refman/8.0/en/innodb-limits.html) for more details.

The `length` argument is available on the `@id`, `@@id`, `@unique`, `@@unique` and `@@index` attributes.

As an example, the following data model declares an `id` field with a maximum length of 3000 characters:

```prisma title="schema.prisma" showLineNumbers
model Id {
  id String @id @db.VarChar(3000)
}
```

This is not valid in MySQL because it exceeds MySQL's index storage limit and therefore Prisma ORM rejects the data model. The generated SQL would be rejected by the database.

```sql
CREATE TABLE `Id` (
  `id` VARCHAR(3000) PRIMARY KEY
)
```

The `length` argument allows you to specify that only a subpart of the `id` value represents the primary key. In the example below, the first 100 characters are used:

```prisma title="schema.prisma" showLineNumbers
model Id {
  id String @id(length: 100) @db.VarChar(3000)
}
```

Prisma Migrate is able to create constraints and indexes with the `length` argument if specified in your data model. This means that you can create indexes and constraints on values of Prisma schema type `Byte` and `String`. If you don't specify the argument the index is treated as covering the full value as before.

Introspection will fetch these limits where they are present in your existing database. This allows Prisma ORM to support indexes and constraints that were previously suppressed and results in better support of MySQL databases utilizing this feature.

The `length` argument can also be used on compound primary keys, using the `@@id` attribute, as in the example below:

```prisma title="schema.prisma" showLineNumbers
model CompoundId {
  id_1 String @db.VarChar(3000)
  id_2 String @db.VarChar(3000)

  @@id([id_1(length: 100), id_2(length: 10)])
}
```

A similar syntax can be used for the `@@unique` and `@@index` attributes.

### Configuring the index sort order with `sort` [#configuring-the-index-sort-order-with-sort]

The `sort` argument allows you to specify the order that the entries of the index or constraint are stored in the database. This can have an effect on whether the database is able to use an index for specific queries. The behavior and support varies by database:

* In MySQL/MariaDB, you can specify sort order (`ASC`/`DESC`) directly in unique constraints and indexes
* In PostgreSQL, sort order can only be specified on indexes, not on unique constraints
* In SQL Server, sort order is supported on all constraints and indexes including `@id` and `@@id`

For example, in MySQL/MariaDB, the following table using a descending unique constraint:

```sql
CREATE TABLE `Unique` (
  `unique` INT,
  CONSTRAINT `Unique_unique_key` UNIQUE (`unique` DESC)
)
```

would be introspected as

```prisma title="schema.prisma" showLineNumbers
model Unique {
  unique Int @unique(sort: Desc)
}
```

Note that in PostgreSQL, while you cannot specify sort order on unique constraints directly, you can create a unique index with a sort order that will enforce uniqueness:

```sql
-- PostgreSQL approach
CREATE UNIQUE INDEX "unique_index_desc" ON "Unique" ("unique" DESC);
```

The `sort` argument can also be used on compound indexes:

```prisma title="schema.prisma" showLineNumbers
model CompoundUnique {
  unique_1 Int
  unique_2 Int

  @@unique([unique_1(sort: Desc), unique_2])
}
```

### Example: using `sort` and `length` together [#example-using-sort-and-length-together]

The following example demonstrates the use of the `sort` and `length` arguments to configure indexes and constraints for a `Post` model:

```prisma title="schema.prisma" showLineNumbers
model Post {
  title      String   @db.VarChar(300)
  abstract   String   @db.VarChar(3000)
  slug       String   @unique(sort: Desc, length: 42) @db.VarChar(3000)
  author     String
  created_at DateTime

  @@id([title(length: 100, sort: Desc), abstract(length: 10)])
  @@index([author, created_at(sort: Desc)])
}
```

### Configuring the access type of indexes with `type` (PostgreSQL) [#configuring-the-access-type-of-indexes-with-type-postgresql]

The `type` argument is available for configuring the index type in PostgreSQL with the `@@index` attribute. The index access methods available are `Hash`, `Gist`, `Gin`, `SpGist` and `Brin`, as well as the default `BTree` index access method.

#### Hash [#hash]

The `Hash` type will store the index data in a format that is much faster to search and insert, and that will use less disk space. However, only the `=` and `<>` comparisons can use the index, so other comparison operators such as `<` and `>` will be much slower with `Hash` than when using the default `BTree` type.

As an example, the following model adds an index with a `type` of `Hash` to the `value` field:

```prisma title="schema.prisma" showLineNumbers
model Example {
  id    Int @id
  value Int

  @@index([value], type: Hash)
}
```

This translates to the following SQL commands:

```sql
CREATE TABLE "Example" (
  id INT PRIMARY KEY,
  value INT NOT NULL
);

CREATE INDEX "Example_value_idx" ON "Example" USING HASH (value);
```

#### Generalized Inverted Index (GIN) [#generalized-inverted-index-gin]

The GIN index stores composite values, such as arrays or `JsonB` data. This is useful for speeding up querying whether one object is part of another object. It is commonly used for full-text searches.

An indexed field can define the operator class, which defines the operators handled by the index.

> [!WARNING]
> Indexes using a function (such as `to_tsvector`) to determine the indexed value are not yet supported by Prisma ORM. Indexes defined in this way will not be visible with `prisma db pull`.

As an example, the following model adds a `Gin` index to the `value` field, with `JsonbPathOps` as the class of operators allowed to use the index:

```prisma title="schema.prisma" showLineNumbers
model Example {
  id    Int  @id
  value Json
  //    ^ field type matching the operator class

  @@index([value(ops: JsonbPathOps)], type: Gin)
  //                  ^ operator class      ^ index type
}
```

This translates to the following SQL commands:

```sql
CREATE TABLE "Example" (
  id INT PRIMARY KEY,
  value JSONB NOT NULL
);

CREATE INDEX "Example_value_idx" ON "Example" USING GIN (value jsonb_path_ops);
```

As part of the `JsonbPathOps` the `@>` operator is handled by the index, speeding up queries such as `value @> '{"foo": 2}'`.

##### Supported Operator Classes for GIN [#supported-operator-classes-for-gin]

Prisma ORM generally supports operator classes provided by PostgreSQL in versions 10 and later. If the operator class requires the field type to be of a type Prisma ORM does not yet support, using the `raw` function with a string input allows you to use these operator classes without validation.

The default operator class (marked with ✅) can be omitted from the index definition.

| Operator class | Allowed field type (native types) | Default | Other                         |
| -------------- | --------------------------------- | ------- | ----------------------------- |
| `ArrayOps`     | Any array                         | ✅       | Also available in CockroachDB |
| `JsonbOps`     | `Json` (`@db.JsonB`)              | ✅       | Also available in CockroachDB |
| `JsonbPathOps` | `Json` (`@db.JsonB`)              |         |                               |
| `raw("other")` |                                   |         |                               |

Read more about built-in operator classes in the [official PostgreSQL documentation](https://www.postgresql.org/docs/14/gin-builtin-opclasses.html).

##### CockroachDB [#cockroachdb]

GIN and BTree are the only index types supported by CockroachDB. The operator classes marked to work with CockroachDB are the only ones allowed on that database and supported by Prisma ORM. The operator class cannot be defined in the Prisma Schema Language: the `ops` argument is not necessary or allowed on CockroachDB.

#### Generalized Search Tree (GiST) [#generalized-search-tree-gist]

The GiST index type is used for implementing indexing schemes for user-defined types. By default there are not many direct uses for GiST indexes, but for example the B-Tree index type is built using a GiST index.

As an example, the following model adds a `Gist` index to the `value` field with `InetOps` as the operators that will be using the index:

```prisma title="schema.prisma" showLineNumbers
model Example {
  id    Int    @id
  value String @db.Inet
  //           ^ native type matching the operator class
  //                                   ^ index type
  //                  ^ operator class

  @@index([value(ops: InetOps)], type: Gist)
}
```

This translates to the following SQL commands:

```sql
CREATE TABLE "Example" (
  id INT PRIMARY KEY,
  value INET NOT NULL
);

CREATE INDEX "Example_value_idx" ON "Example" USING GIST (value inet_ops);
```

Queries comparing IP addresses, such as `value > '10.0.0.2'`, will use the index.

##### Supported Operator Classes for GiST [#supported-operator-classes-for-gist]

Prisma ORM generally supports operator classes provided by PostgreSQL in versions 10 and later. If the operator class requires the field type to be of a type Prisma ORM does not yet support, using the `raw` function with a string input allows you to use these operator classes without validation.

| Operator class | Allowed field type (allowed native types) |
| -------------- | ----------------------------------------- |
| `InetOps`      | `String` (`@db.Inet`)                     |
| `raw("other")` |                                           |

Read more about built-in operator classes in the [official PostgreSQL documentation](https://www.postgresql.org/docs/14/gist-builtin-opclasses.html).

#### Space-Partitioned GiST (SP-GiST) [#space-partitioned-gist-sp-gist]

The SP-GiST index is a good choice for many different non-balanced data structures. If the query matches the partitioning rule, it can be very fast.

As with GiST, SP-GiST is important as a building block for user-defined types, allowing implementation of custom search operators directly with the database.

As an example, the following model adds a `SpGist` index to the `value` field with `TextOps` as the operators using the index:

```prisma title="schema.prisma" showLineNumbers
model Example {
  id    Int    @id
  value String
  //    ^ field type matching the operator class

  @@index([value], type: SpGist)
  //                     ^ index type
  //       ^ using the default ops: TextOps
}
```

This translates to the following SQL commands:

```sql
CREATE TABLE "Example" (
  id INT PRIMARY KEY,
  value TEXT NOT NULL
);

CREATE INDEX "Example_value_idx" ON "Example" USING SPGIST (value);
```

Queries such as `value LIKE 'something%'` will be sped up by the index.

##### Supported Operator Classes for SP-GiST [#supported-operator-classes-for-sp-gist]

Prisma ORM generally supports operator classes provided by PostgreSQL in versions 10 and later. If the operator class requires the field type to be of a type Prisma ORM does not yet support, using the `raw` function with a string input allows you to use these operator classes without validation.

The default operator class (marked with ✅) can be omitted from the index definition.

| Operator class | Allowed field type (native types)    | Default | Supported PostgreSQL versions |
| -------------- | ------------------------------------ | ------- | ----------------------------- |
| `InetOps`      | `String` (`@db.Inet`)                | ✅       | 10+                           |
| `TextOps`      | `String` (`@db.Text`, `@db.VarChar`) | ✅       |                               |
| `raw("other")` |                                      |         |                               |

Read more about built-in operator classes from [official PostgreSQL documentation](https://www.postgresql.org/docs/14/spgist-builtin-opclasses.html).

#### Block Range Index (BRIN) [#block-range-index-brin]

The BRIN index type is useful if you have lots of data that does not change after it is inserted, such as date and time values. If your data is a good fit for the index, it can store large datasets in a minimal space.

As an example, the following model adds a `Brin` index to the `value` field with `Int4BloomOps` as the operators that will be using the index:

```prisma title="schema.prisma" showLineNumbers
model Example {
  id    Int @id
  value Int
  //    ^ field type matching the operator class

  @@index([value(ops: Int4BloomOps)], type: Brin)
  //                  ^ operator class      ^ index type
}
```

This translates to the following SQL commands:

```sql
CREATE TABLE "Example" (
  id INT PRIMARY KEY,
  value INT4 NOT NULL
);

CREATE INDEX "Example_value_idx" ON "Example" USING BRIN (value int4_bloom_ops);
```

Queries like `value = 2` will now use the index, which uses a fraction of the space used by the `BTree` or `Hash` indexes.

##### Supported Operator Classes for BRIN [#supported-operator-classes-for-brin]

Prisma ORM generally supports operator classes provided by PostgreSQL in versions 10 and later, and some supported operators are only available from PostgreSQL versions 14 and later. If the operator class requires the field type to be of a type Prisma ORM does not yet support, using the `raw` function with a string input allows you to use these operator classes without validation.

The default operator class (marked with ✅) can be omitted from the index definition.

| Operator class              | Allowed field type (native types)    | Default | Supported PostgreSQL versions |
| --------------------------- | ------------------------------------ | ------- | ----------------------------- |
| `BitMinMaxOps`              | `String` (`@db.Bit`)                 | ✅       |                               |
| `VarBitMinMaxOps`           | `String` (`@db.VarBit`)              | ✅       |                               |
| `BpcharBloomOps`            | `String` (`@db.Char`)                |         | 14+                           |
| `BpcharMinMaxOps`           | `String` (`@db.Char`)                | ✅       |                               |
| `ByteaBloomOps`             | `Bytes` (`@db.Bytea`)                |         | 14+                           |
| `ByteaMinMaxOps`            | `Bytes` (`@db.Bytea`)                | ✅       |                               |
| `DateBloomOps`              | `DateTime` (`@db.Date`)              |         | 14+                           |
| `DateMinMaxOps`             | `DateTime` (`@db.Date`)              | ✅       |                               |
| `DateMinMaxMultiOps`        | `DateTime` (`@db.Date`)              |         | 14+                           |
| `Float4BloomOps`            | `Float` (`@db.Real`)                 |         | 14+                           |
| `Float4MinMaxOps`           | `Float` (`@db.Real`)                 | ✅       |                               |
| `Float4MinMaxMultiOps`      | `Float` (`@db.Real`)                 |         | 14+                           |
| `Float8BloomOps`            | `Float` (`@db.DoublePrecision`)      |         | 14+                           |
| `Float8MinMaxOps`           | `Float` (`@db.DoublePrecision`)      | ✅       |                               |
| `Float8MinMaxMultiOps`      | `Float` (`@db.DoublePrecision`)      |         | 14+                           |
| `InetInclusionOps`          | `String` (`@db.Inet`)                | ✅       | 14+                           |
| `InetBloomOps`              | `String` (`@db.Inet`)                |         | 14+                           |
| `InetMinMaxOps`             | `String` (`@db.Inet`)                |         |                               |
| `InetMinMaxMultiOps`        | `String` (`@db.Inet`)                |         | 14+                           |
| `Int2BloomOps`              | `Int` (`@db.SmallInt`)               |         | 14+                           |
| `Int2MinMaxOps`             | `Int` (`@db.SmallInt`)               | ✅       |                               |
| `Int2MinMaxMultiOps`        | `Int` (`@db.SmallInt`)               |         | 14+                           |
| `Int4BloomOps`              | `Int` (`@db.Integer`)                |         | 14+                           |
| `Int4MinMaxOps`             | `Int` (`@db.Integer`)                | ✅       |                               |
| `Int4MinMaxMultiOps`        | `Int` (`@db.Integer`)                |         | 14+                           |
| `Int8BloomOps`              | `BigInt` (`@db.BigInt`)              |         | 14+                           |
| `Int8MinMaxOps`             | `BigInt` (`@db.BigInt`)              | ✅       |                               |
| `Int8MinMaxMultiOps`        | `BigInt` (`@db.BigInt`)              |         | 14+                           |
| `NumericBloomOps`           | `Decimal` (`@db.Decimal`)            |         | 14+                           |
| `NumericMinMaxOps`          | `Decimal` (`@db.Decimal`)            | ✅       |                               |
| `NumericMinMaxMultiOps`     | `Decimal` (`@db.Decimal`)            |         | 14+                           |
| `OidBloomOps`               | `Int` (`@db.Oid`)                    |         | 14+                           |
| `OidMinMaxOps`              | `Int` (`@db.Oid`)                    | ✅       |                               |
| `OidMinMaxMultiOps`         | `Int` (`@db.Oid`)                    |         | 14+                           |
| `TextBloomOps`              | `String` (`@db.Text`, `@db.VarChar`) |         | 14+                           |
| `TextMinMaxOps`             | `String` (`@db.Text`, `@db.VarChar`) | ✅       |                               |
| `TextMinMaxMultiOps`        | `String` (`@db.Text`, `@db.VarChar`) |         | 14+                           |
| `TimestampBloomOps`         | `DateTime` (`@db.Timestamp`)         |         | 14+                           |
| `TimestampMinMaxOps`        | `DateTime` (`@db.Timestamp`)         | ✅       |                               |
| `TimestampMinMaxMultiOps`   | `DateTime` (`@db.Timestamp`)         |         | 14+                           |
| `TimestampTzBloomOps`       | `DateTime` (`@db.Timestamptz`)       |         | 14+                           |
| `TimestampTzMinMaxOps`      | `DateTime` (`@db.Timestamptz`)       | ✅       |                               |
| `TimestampTzMinMaxMultiOps` | `DateTime` (`@db.Timestamptz`)       |         | 14+                           |
| `TimeBloomOps`              | `DateTime` (`@db.Time`)              |         | 14+                           |
| `TimeMinMaxOps`             | `DateTime` (`@db.Time`)              | ✅       |                               |
| `TimeMinMaxMultiOps`        | `DateTime` (`@db.Time`)              |         | 14+                           |
| `TimeTzBloomOps`            | `DateTime` (`@db.Timetz`)            |         | 14+                           |
| `TimeTzMinMaxOps`           | `DateTime` (`@db.Timetz`)            | ✅       |                               |
| `TimeTzMinMaxMultiOps`      | `DateTime` (`@db.Timetz`)            |         | 14+                           |
| `UuidBloomOps`              | `String` (`@db.Uuid`)                |         | 14+                           |
| `UuidMinMaxOps`             | `String` (`@db.Uuid`)                | ✅       |                               |
| `UuidMinMaxMultiOps`        | `String` (`@db.Uuid`)                |         | 14+                           |
| `raw("other")`              |                                      |         |                               |

Read more about built-in operator classes in the [official PostgreSQL documentation](https://www.postgresql.org/docs/14/brin-builtin-opclasses.html).

### Configuring if indexes are clustered or non-clustered with `clustered` (SQL Server) [#configuring-if-indexes-are-clustered-or-non-clustered-with-clustered-sql-server]

The `clustered` argument is available to configure (non)clustered indexes in SQL Server. It can be used on the `@id`, `@@id`, `@unique`, `@@unique` and `@@index` attributes.

As an example, the following model configures the `@id` to be non-clustered (instead of the clustered default):

```prisma title="schema.prisma" showLineNumbers
model Example {
  id    Int @id(clustered: false)
  value Int
}
```

This translates to the following SQL commands:

```sql
CREATE TABLE [Example] (
  id INT NOT NULL,
  value INT,
  CONSTRAINT [Example_pkey] PRIMARY KEY NONCLUSTERED (id)
)
```

The default value of `clustered` for each attribute is as follows:

| Attribute  | Value   |
| ---------- | ------- |
| `@id`      | `true`  |
| `@@id`     | `true`  |
| `@unique`  | `false` |
| `@@unique` | `false` |
| `@@index`  | `false` |

A table can have at most one clustered index.

### Configuring the name of indexes with `map` [#configuring-the-name-of-indexes-with-map]

The `map` argument allows you to specify a custom name for the index or constraint in the underlying database. This is useful when you want to use a specific naming convention or when the auto-generated name doesn't meet your requirements.

The `map` argument is available on the `@id`, `@@id`, `@unique`, `@@unique` and `@@index` attributes.

As an example, the following model configures a custom name for the index on the `title` field:

```prisma title="schema.prisma" showLineNumbers
model Post {
  id    Int    @id
  title String

  @@index([title], map: "my_custom_index_name")
}
```

This translates to the following SQL command (PostgreSQL example):

```sql
CREATE INDEX "my_custom_index_name" ON "Post" ("title");
```

Without the `map` argument, Prisma would generate a default name like `Post_title_idx`.

The `map` argument can also be used on unique constraints:

```prisma title="schema.prisma" showLineNumbers
model User {
  id    Int    @id
  email String @unique(map: "unique_user_email")
}
```

And on composite indexes and constraints:

```prisma title="schema.prisma" showLineNumbers
model Post {
  id        Int    @id
  title     String
  author    String
  createdAt DateTime

  @@index([author, createdAt], map: "posts_author_date_idx")
  @@unique([title, author], map: "posts_title_author_unique")
}
```

### Configuring partial indexes with `where` [#configuring-partial-indexes-with-where]

The `where` argument allows you to define [partial indexes](https://www.postgresql.org/docs/current/indexes-partial.html) (also known as filtered indexes). A partial index only includes rows that match a specified condition, which reduces the index size and improves both write performance and query performance for the indexed subset of data.

The `where` argument is available on the `@unique`, `@@unique` and `@@index` attributes. It requires the `partialIndexes` Preview feature.

> [!NOTE]
> Partial indexes are supported on **PostgreSQL**, **SQLite**, **SQL Server**, and **CockroachDB**. They are **not** supported on MySQL.

#### Enabling the `partialIndexes` Preview feature [#enabling-the-partialindexes-preview-feature]

To use partial indexes, add the `partialIndexes` feature flag to the `generator` block of your `schema.prisma` file:

```prisma title="schema.prisma" showLineNumbers
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["partialIndexes"]
}
```

#### Raw SQL syntax with `raw()` [#raw-sql-syntax-with-raw]

You can define a partial index with a raw SQL predicate string using the `raw()` function. This approach supports any valid SQL `WHERE` expression that your database accepts:

```prisma title="schema.prisma" showLineNumbers
model User {
  id        Int       @id
  email     String
  status    String
  deletedAt DateTime?

  @@unique([email], where: raw("status = 'active'"))
  @@index([email], where: raw("\"deletedAt\" IS NULL"))
}
```

This generates SQL like:

**PostgreSQL:**

```sql
CREATE UNIQUE INDEX "User_email_key" ON "User" ("email") WHERE (status = 'active');
CREATE INDEX "User_email_idx" ON "User" ("email") WHERE ("deletedAt" IS NULL);
```

**SQLite:**

```sql
CREATE UNIQUE INDEX "User_email_key" ON "User" ("email") WHERE status = 'active';
CREATE INDEX "User_email_idx" ON "User" ("email") WHERE "deletedAt" IS NULL;
```

**SQL Server:**

```sql
CREATE UNIQUE NONCLUSTERED INDEX [User_email_key] ON [dbo].[User]([email]) WHERE ([status]='active');
CREATE NONCLUSTERED INDEX [User_email_idx] ON [dbo].[User]([email]) WHERE ([deletedAt] IS NULL);
```

The `raw()` syntax can be used with any SQL expression your database supports, making it the most flexible option.

#### Object literal syntax (type-safe alternative) [#object-literal-syntax-type-safe-alternative]

You can also define partial indexes using an object literal syntax, which provides type-safety by validating field names and value types against your Prisma schema:

```prisma title="schema.prisma" showLineNumbers
model Post {
  id        Int      @id
  title     String
  published Boolean

  @@index([title], where: { published: true })
  @@unique([title], where: { published: true })
}
```

The object literal syntax supports the following value types:

| Value type       | Example                                  | Notes                                                  |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| `Boolean`        | `{ active: true }`, `{ deleted: false }` | For `Boolean` fields                                   |
| `String`         | `{ status: "active" }`                   | For `String`, `DateTime`, and `Enum` fields            |
| `Number`         | `{ priority: 1 }`, `{ score: 1.5 }`      | For `Int`, `BigInt`, `Float`, and `Decimal` fields     |
| `null`           | `{ deletedAt: null }`                    | Translates to `IS NULL`. Works with any nullable field |
| `{ not: value }` | `{ deletedAt: { not: null } }`           | Negation. Translates to `IS NOT NULL` or `!= value`    |

You can combine multiple conditions in a single object:

```prisma title="schema.prisma" showLineNumbers
model User {
  id        Int       @id
  email     String
  active    Boolean
  deletedAt DateTime?

  @@unique([email], where: { active: true, deletedAt: null })
}
```

> [!NOTE]
> The object literal syntax validates field types. For example, you cannot use a `Boolean` value for a `String` field. For fields with types that are not supported by the object syntax (such as `Unsupported` or composite types), use `raw()` instead.

#### Using `where` with other index arguments [#using-where-with-other-index-arguments]

The `where` argument can be combined with other index arguments such as `name` and `map`:

```prisma title="schema.prisma" showLineNumbers
model User {
  id     Int    @id
  email  String
  status String

  @@unique([email], name: "email_active_unique", map: "idx_email_active", where: raw("status = 'active'"))
}
```

#### Database-specific behavior [#database-specific-behavior]

| Database    | Migrations    | Introspection | Notes                                                                  |
| ----------- | ------------- | ------------- | ---------------------------------------------------------------------- |
| PostgreSQL  | Full support  | Full support  | Full predicate support                                                 |
| SQLite      | Full support  | Full support  | Full predicate support                                                 |
| SQL Server  | Full support  | Full support  | Filtered indexes via `CREATE INDEX`                                    |
| CockroachDB | Create only   | Not supported | Cannot introspect predicate text; predicate modifications not detected |
| MySQL       | Not supported | Not supported | Partial indexes are not supported by the database                      |

> [!WARNING]
> **CockroachDB limitation**: CockroachDB supports creating partial indexes, but it cannot introspect the predicate text from existing indexes. This means that after initial creation, modifications to the `where` clause (adding, changing, or removing a predicate) will not be detected by Prisma Migrate. The differ skips predicate comparison for CockroachDB to prevent false-positive migrations.

#### Introspection [#introspection]

When you run `prisma db pull` on a database that contains partial indexes, Prisma ORM will:

1. Automatically add `"partialIndexes"` to the `previewFeatures` list in your generator block
2. Represent the partial index predicate using the `raw()` syntax with the database's normalized form of the SQL expression

For example, a PostgreSQL partial unique index on a single field will be introspected as:

```prisma title="schema.prisma" showLineNumbers
model User {
  id     Int    @id
  email  String @unique(where: raw("(status = 'active'::text)"))
  status String
}
```

> [!NOTE]
> The introspected `raw()` string reflects the database's normalized form of the SQL expression, which may differ from what you originally wrote. For example, PostgreSQL adds parentheses and explicit type casts (e.g., `'active'::text`), SQL Server wraps column names in brackets and adds parentheses (e.g., `([status]='active')`), while SQLite generally preserves the original expression as-is.

## Full text indexes (MySQL and MongoDB) [#full-text-indexes-mysql-and-mongodb]

The `fullTextIndex` preview feature provides support for introspection and migration of full text indexes in MySQL and MongoDB. This can be configured using the `@@fulltext` attribute. Existing full text indexes in the database are added to your Prisma schema after introspecting with `db pull`, and new full text indexes added in the Prisma schema are created in the database when using Prisma Migrate.

> [!WARNING]
> For now we do not enable the full text search commands in Prisma Client for MongoDB; the progress can be followed in the [MongoDB](https://github.com/prisma/orm/issues/9413) issue.

### Enabling the `fullTextIndex` preview feature [#enabling-the-fulltextindex-preview-feature]

To enable the `fullTextIndex` preview feature, add the `fullTextIndex` feature flag to the `generator` block of the `schema.prisma` file:

```prisma title="schema.prisma" showLineNumbers
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["fullTextIndex"]
}
```

### Examples [#examples]

The following example demonstrates adding a `@@fulltext` index to the `title` and `content` fields of a `Post` model:

```prisma title="schema.prisma" showLineNumbers
model Post {
  id      Int    @id
  title   String @db.VarChar(255)
  content String @db.Text

  @@fulltext([title, content])
}
```

On MongoDB, you can use the `@@fulltext` index attribute (via the `fullTextIndex` preview feature) with the `sort` argument to add fields to your full-text index in ascending or descending order. The following example adds a `@@fulltext` index to the `title` and `content` fields of the `Post` model, and sorts the `title` field in descending order:

```prisma title="schema.prisma" showLineNumbers
generator js {
  provider        = "prisma-client-js"
  previewFeatures = ["fullTextIndex"]
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

model Post {
  id      String @id @map("_id") @db.ObjectId
  title   String
  content String

  @@fulltext([title(sort: Desc), content])
}
```

## Related pages

- [`Database mapping`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping): Learn how to map model and field names to database tables and columns
- [`External tables`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables): How to declare and use externally managed tables in Prisma ORM
- [`Models`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models): Learn about the concepts for building your data model with Prisma: Models, scalar types, enums, attributes, functions, IDs, default values and more
- [`Multi-schema`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema): How to use Prisma ORM with multiple database schemas
- [`Relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations): A relation is a connection between two models in the Prisma schema. This page explains how you can define one-to-one, one-to-many and many-to-many relations in Prisma

# Models (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/models)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn about the concepts for building your data model with Prisma: Models, scalar types, enums, attributes, functions, IDs, default values and more

Location: ORM > v7 > Prisma Schema > Data Model > Models

The data model definition part of the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) defines your application models (also called **Prisma models**). Models:

* Represent the **entities** of your application domain
* Map to the **tables** (relational databases like PostgreSQL) or **collections** (MongoDB) in your database
* Form the foundation of the **queries** available in the generated [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction)
* When used with TypeScript, Prisma Client provides generated **type definitions** for your models and any [variations](https://www.prisma.io/docs/orm/v7/prisma-client/type-safety/operating-against-partial-structures-of-model-types) of them to make database access entirely type safe.

The following schema describes a blogging platform - the data model definition is highlighted:

  

#### Relational databases

```prisma highlight=10-46;normal 
datasource db {
  provider = "postgresql"
}

generator client {
  provider = "prisma-client"
  output   = "./generated"
}

model User { // [!code highlight]
  id      Int      @id @default(autoincrement()) // [!code highlight]
  email   String   @unique // [!code highlight]
  name    String? // [!code highlight]
  role    Role     @default(USER) // [!code highlight]
  posts   Post[] // [!code highlight]
  profile Profile? // [!code highlight]
} // [!code highlight]

model Profile { // [!code highlight]
  id     Int    @id @default(autoincrement()) // [!code highlight]
  bio    String // [!code highlight]
  user   User   @relation(fields: [userId], references: [id]) // [!code highlight]
  userId Int    @unique // [!code highlight]
} // [!code highlight]

model Post { // [!code highlight]
  id         Int        @id @default(autoincrement()) // [!code highlight]
  createdAt  DateTime   @default(now()) // [!code highlight]
  updatedAt  DateTime   @updatedAt // [!code highlight]
  title      String // [!code highlight]
  published  Boolean    @default(false) // [!code highlight]
  author     User       @relation(fields: [authorId], references: [id]) // [!code highlight]
  authorId   Int // [!code highlight]
  categories Category[] // [!code highlight]
} // [!code highlight]

model Category { // [!code highlight]
  id    Int    @id @default(autoincrement()) // [!code highlight]
  name  String // [!code highlight]
  posts Post[] // [!code highlight]
} // [!code highlight]

enum Role { // [!code highlight]
  USER // [!code highlight]
  ADMIN // [!code highlight]
} // [!code highlight]
```

#### MongoDB

```prisma highlight=10-45;normal 
datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User { // [!code highlight]
  id      String   @id @default(auto()) @map("_id") @db.ObjectId // [!code highlight]
  email   String   @unique // [!code highlight]
  name    String? // [!code highlight]
  role    Role     @default(USER) // [!code highlight]
  posts   Post[] // [!code highlight]
  profile Profile? // [!code highlight]
} // [!code highlight]

model Profile { // [!code highlight]
  id     String @id @default(auto()) @map("_id") @db.ObjectId // [!code highlight]
  bio    String // [!code highlight]
  user   User   @relation(fields: [userId], references: [id]) // [!code highlight]
  userId String @unique @db.ObjectId // [!code highlight]
} // [!code highlight]

model Post { // [!code highlight]
  id          String     @id @default(auto()) @map("_id") @db.ObjectId // [!code highlight]
  createdAt   DateTime   @default(now()) // [!code highlight]
  title       String // [!code highlight]
  published   Boolean    @default(false) // [!code highlight]
  author      User       @relation(fields: [authorId], references: [id]) // [!code highlight]
  authorId    String     @db.ObjectId // [!code highlight]
  categoryIDs String[]   @db.ObjectId // [!code highlight]
  categories  Category[] @relation(fields: [categoryIDs], references: [id]) // [!code highlight]
} // [!code highlight]

model Category { // [!code highlight]
  id      String   @id @default(auto()) @map("_id") @db.ObjectId // [!code highlight]
  name    String // [!code highlight]
  postIDs String[] @db.ObjectId // [!code highlight]
  posts   Post[]   @relation(fields: [postIDs], references: [id]) // [!code highlight]
} // [!code highlight]

enum Role { // [!code highlight]
  USER // [!code highlight]
  ADMIN
}
```

The data model definition is made up of:

* [Models](#defining-models) ([`model`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model) primitives) that define a number of fields, including [relations between models](#relation-fields)
* [Enums](#defining-enums) ([`enum`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#enum) primitives) (if your connector supports Enums)
* [Attributes](#defining-attributes) and [functions](#using-functions) that change the behavior of fields and models

The corresponding database looks like this:

![Sample database](https://www.prisma.io/img/orm/sample-database.png)

**A model maps to the underlying structures of the data source.**

* In relational databases like PostgreSQL and MySQL, a `model` maps to a **table**
* In MongoDB, a `model` maps to a **collection**

> **Note**: In the future there might be connectors for non-relational databases and other data sources. For example, for a REST API it would map to a *resource*.

The following query creates a `User` with nested `Post` and `Category` records:

```ts
const user = await prisma.user.create({
  data: {
    email: "ariadne@prisma.io",
    name: "Ariadne",
    posts: {
      create: [
        {
          title: "My first day at Prisma",
          categories: { create: { name: "Office" } },
        },
        {
          title: "How to connect to a SQLite database",
          categories: { create: [{ name: "Databases" }, { name: "Tutorials" }] },
        },
      ],
    },
  },
});
```

Your data model reflects *your* application domain. For example:

* In an **ecommerce** application you probably have models like `Customer`, `Order`, `Item` and `Invoice`.
* In a **social media** application you probably have models like `User`, `Post`, `Photo` and `Message`.

## Introspection and migration [#introspection-and-migration]

There are two ways to define a data model:

* **Write the data model manually and use Prisma Migrate**: You can write your data model manually and map it to your database using [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate). In this case, the data model is the single source of truth for the models of your application.
* **Generate the data model via introspection**: When you have an existing database or prefer migrating your database schema with SQL, you generate the data model by [introspecting](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) your database. In this case, the database schema is the single source of truth for the models of your application.

## Defining models [#defining-models]

Models represent the entities of your application domain. Models are represented by [`model`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model) blocks and define a number of [fields](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-fields). In the example data model above, `User`, `Profile`, `Post` and `Category` are models.

A blogging platform can be extended with the following models:

```prisma
model Comment {
  // Fields
}

model Tag {
  // Fields
}
```

### Mapping model names to tables or collections [#mapping-model-names-to-tables-or-collections]

Prisma model [naming conventions (singular form, PascalCase)](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#naming-conventions) do not always match table names in the database. A common approach for naming tables/collections in databases is to use plural form and [snake_case](https://en.wikipedia.org/wiki/Snake_case) notation - for example: `comments`. When you introspect a database with a table named `comments`, the resulting Prisma model will look like this:

```prisma
model comments {
  // Fields
}
```

However, you can still adhere to the naming convention without renaming the underlying `comments` table in the database by using the [`@@map`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) attribute:

```prisma
model Comment {
  // Fields

  @@map("comments")
}
```

With this model definition, Prisma ORM automatically maps the `Comment` model to the `comments` table in the underlying database.

> **Note**: You can also [`@map`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#map) a column name or enum value, and `@@map` an enum name.

`@map` and `@@map` allow you to [tune the shape of your Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names#using-map-and-map-to-rename-fields-and-models-in-the-prisma-client-api) by decoupling model and field names from table and column names in the underlying database.

## Defining fields [#defining-fields]

The properties of a model are called *fields*, which consist of:

* A &#x2A;*[field name](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-fields)**
* A &#x2A;*[field type](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-fields)**
* Optional &#x2A;*[type modifiers](#type-modifiers)**
* Optional &#x2A;*[attributes](#defining-attributes)**, including [native database type attributes](#native-types-mapping)

A field's type determines its *structure*, and fits into one of two categories:

* [Scalar types](#scalar-fields) (includes [enums](#defining-enums)) that map to columns (relational databases) or document fields (MongoDB) - for example, [`String`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#string) or [`Int`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#int)
* Model types (the field is then called [relation field](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields)) - for example `Post` or `Comment[]`

### Scalar fields [#scalar-fields]

The following example extends the `Comment` and `Tag` models with several scalar types. Some fields include [attributes](#defining-attributes):

  

#### Relational databases

```prisma highlight=2-4,8;normal 
model Comment {
  id      Int    @id @default(autoincrement()) // [!code highlight]
  title   String // [!code highlight]
  content String // [!code highlight]
}

model Tag {
  name String @id // [!code highlight]
}
```

#### MongoDB

```prisma highlight=2-4,8;normal 
model Comment {
  id      String @id @default(auto()) @map("_id") @db.ObjectId // [!code highlight]
  title   String // [!code highlight]
  content String // [!code highlight]
}

model Tag {
  name String @id @map("_id") // [!code highlight]
}
```

See [complete list of scalar field types](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) .

### Relation fields [#relation-fields]

A relation field's type is another model - for example, a post (`Post`) can have multiple comments (`Comment[]`):

  

#### Relational databases

```prisma highlight=4,10;normal 
model Post {
  id       Int       @id @default(autoincrement())
  // Other fields
  comments Comment[] // A post can have many comments // [!code highlight]
}

model Comment {
  id     Int
  // Other fields
  post   Post @relation(fields: [postId], references: [id]) // A comment can have one post // [!code highlight]
  postId Int
}
```

#### MongoDB

```prisma highlight=4,10;normal 
model Post {
  id       String    @id @default(auto()) @map("_id") @db.Objectid
  // Other fields
  comments Comment[] // A post can have many comments // [!code highlight]
}

model Comment {
  id     String @id @default(auto()) @map("_id") @db.Objectid
  // Other fields
  post   Post   @relation(fields: [postId], references: [id]) // A comment can have one post // [!code highlight]
  postId String @db.ObjectId
}
```

Refer to the [relations documentation](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations) for more examples and information about relationships between models.

### Native types mapping [#native-types-mapping]

**Native database type attributes** describe the underlying database type:

```prisma
model Post {
  id      Int    @id
  title   String @db.VarChar(200)
  content String
}
```

Type attributes are:

* Specific to the underlying provider (e.g., PostgreSQL uses `@db.Boolean`, MySQL uses `@db.TinyInt(1)`)
* Written in PascalCase and prefixed by `@db`
* Only added during [introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) if the native type differs from the default

See [native database type attributes](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#model-field-scalar-types) for the complete list.

### Type modifiers [#type-modifiers]

The type of a field can be modified by appending either of two modifiers:

* [`[]`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#-modifier) Make a field a list
* [`?`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#-modifier-1) Make a field optional

> **Note**: You **cannot** combine type modifiers - optional lists are not supported.

#### Lists [#lists]

The following example includes a scalar list and a list of related models:

```prisma
model Post {
  id       Int       @id @default(autoincrement())
  comments Comment[] // A list of comments
  keywords String[]  // A scalar list
}
```

> [!NOTE]
> Scalar lists are only supported if the database connector supports them natively or at a Prisma ORM level.

#### Optional and mandatory fields [#optional-and-mandatory-fields]

```prisma
model Comment {
  id      Int     @id @default(autoincrement())
  title   String       // Required field
  content String?      // Optional field (nullable)
}
```

Fields without `?` are required:

* **Relational databases**: Represented via `NOT NULL` constraints
* **Prisma Client**: TypeScript types enforce these fields at compile time

### Unsupported types [#unsupported-types]

When you introspect a relational database, unsupported data types are added as [`Unsupported`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#unsupported):

```prisma
location    Unsupported("POLYGON")?
```

Fields of type `Unsupported` don't appear in the generated Prisma Client API, but you can still use [raw database access](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries) to query them.

> [!NOTE]
> The MongoDB connector doesn't support `Unsupported` types because it supports all scalar types.

## Defining attributes [#defining-attributes]

Attributes modify the behavior of fields or model blocks. The following example includes three field attributes ([`@id`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#id) , [`@default`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#default) , and [`@unique`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#unique) ) and one block attribute ([`@@unique`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference)):

  

#### Relational databases

```prisma
model User {
  id        Int     @id @default(autoincrement())
  firstName String
  lastName  String
  email     String  @unique
  isAdmin   Boolean @default(false)

  @@unique([firstName, lastName])
}
```

#### MongoDB

```prisma
model User {
  id        String  @id @default(auto()) @map("_id") @db.ObjectId
  firstName String
  lastName  String
  email     String  @unique
  isAdmin   Boolean @default(false)

  @@unique([firstName, lastName])
}
```

Some attributes accept [arguments](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#attribute-argument-types) - for example, `@default` accepts `true` or `false`:

```prisma
isAdmin   Boolean @default(false) // short form of @default(value: false)
```

See [complete list of field and block attributes](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#attributes)

### Defining an ID field [#defining-an-id-field]

An ID uniquely identifies individual records of a model. A model can only have *one* ID:

* In **relational databases**, the ID can be a single field or based on multiple fields. If a model does not have an `@id` or an `@@id`, you must define a mandatory `@unique` field or `@@unique` block instead.
* In **MongoDB**, an ID must be a single field that defines an `@id` attribute and a `@map("_id")` attribute.

#### Defining IDs in relational databases [#defining-ids-in-relational-databases]

In relational databases, an ID can be defined by a single field using the [`@id`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#id) attribute, or multiple fields using the [`@@id`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) attribute.

##### Single field IDs [#single-field-ids]

In the following example, the `User` ID is represented by the `id` integer field:

```prisma highlight=2;normal
model User {
  id      Int      @id @default(autoincrement()) // [!code highlight]
  email   String   @unique
  name    String?
  role    Role     @default(USER)
  posts   Post[]
  profile Profile?
}
```

##### Composite IDs [#composite-ids]

In the following example, the `User` ID is represented by a combination of the `firstName` and `lastName` fields:

```prisma highlight=7;normal
model User {
  firstName String
  lastName  String
  email     String  @unique
  isAdmin   Boolean @default(false)

  @@id([firstName, lastName]) // [!code highlight]
}
```

By default, the name of this field in Prisma Client queries will be `firstName_lastName`.

You can also provide your own name for the composite ID using the [`@@id`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) attribute's `name` field:

```prisma highlight=7;normal
model User {
  firstName String
  lastName  String
  email     String  @unique
  isAdmin   Boolean @default(false)

  @@id(name: "fullName", fields: [firstName, lastName]) // [!code highlight]
}
```

The `firstName_lastName` field will now be named `fullName` instead.

> [!NOTE]
> Refer to the documentation on [working with composite IDs](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-composite-ids-and-constraints) to learn how to interact with a composite ID in Prisma Client.

##### `@unique` fields as unique identifiers [#unique-fields-as-unique-identifiers]

In the following example, users are uniquely identified by a `@unique` field. Because the `email` field functions as a unique identifier for the model (which is required), it must be mandatory:

```prisma highlight=2;normal
model User {
  email   String   @unique // [!code highlight]
  name    String?
  role    Role     @default(USER)
  posts   Post[]
  profile Profile?
}
```

> [!NOTE]
> **Constraint names in relational databases** <br />
> You can optionally define a [custom primary key constraint name](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping#constraint-and-index-names) in the underlying database.

#### Defining IDs in MongoDB [#defining-ids-in-mongodb]

The MongoDB connector has [specific rules for defining an ID field](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#mongodb) that differs from relational databases. An ID must be defined by a single field using the [`@id`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#id) attribute and must include `@map("_id")`.

In the following example, the `User` ID is represented by the `id` string field that accepts an auto-generated `ObjectId`:

```prisma highlight=2;normal
model User {
  id      String   @id @default(auto()) @map("_id") @db.ObjectId // [!code highlight]
  email   String   @unique
  name    String?
  role    Role     @default(USER)
  posts   Post[]
  profile Profile?
}
```

In the following example, the `User` ID is represented by the `id` string field that accepts something other than an `ObjectId` - for example, a unique username:

```prisma highlight=2;normal
model User {
  id      String   @id @map("_id") // [!code highlight]
  email   String   @unique
  name    String?
  role    Role     @default(USER)
  posts   Post[]
  profile Profile?
}
```

> [!WARNING]
> **MongoDB does not support `@@id`**<br />
> MongoDB does not support composite IDs, which means you cannot identify a model with a `@@id` block.

### Defining a default value [#defining-a-default-value]

You can define default values for scalar fields using the [`@default`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#default) attribute:

```prisma
model Post {
  id         Int        @id @default(autoincrement())
  createdAt  DateTime   @default(now())
  title      String
  published  Boolean    @default(false)
  data       Json       @default("{ \"hello\": \"world\" }")
}
```

Default values can be:

* **Static values**: `5` (`Int`), `"Hello"` (`String`), `false` (`Boolean`)
* **Lists**: `[5, 6, 8]` (`Int[]`), `["Hello", "Goodbye"]` (`String[]`)
* **Functions**: [`now()`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#now), [`uuid()`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#uuid), [`cuid()`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#cuid)
* **JSON**: Use escaped strings, e.g., `@default("{ \"hello\": \"world\" }")`

See [attribute functions](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#attribute-functions) for connector support details.

### Defining a unique field [#defining-a-unique-field]

Unique attributes can be defined on a single field using [`@unique`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#unique), or on multiple fields using [`@@unique`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference):

```prisma
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique      // Single field unique
  name  String?
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  authorId Int

  @@unique([authorId, title]) // Composite unique
}
```

You can customize the constraint name with the `name` field: `@@unique(name: "authorTitle", [authorId, title])`

See [working with composite unique identifiers](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-composite-ids-and-constraints) for Prisma Client usage.

#### Composite type unique constraints (MongoDB) [#composite-type-unique-constraints-mongodb]

For MongoDB composite types, you can define unique constraints on nested fields:

```prisma
type Address {
  street String
  number Int
}

model User {
  id      Int     @id
  email   String
  address Address

  @@unique([email, address.number])
}
```

### Defining an index [#defining-an-index]

Define indexes via [`@@index`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#index):

```prisma
model Post {
  id      Int     @id @default(autoincrement())
  title   String
  content String?

  @@index([title, content])
}
```

For MongoDB composite types, use dot notation: `@@index([address.city.name])`

See [custom index names](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping#constraint-and-index-names) for naming customization.

## Defining enums [#defining-enums]

Enums are defined via the [`enum`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#enum) block when [supported by your database](https://www.prisma.io/docs/orm/v7/reference/database-features#misc):

```prisma
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  role  Role    @default(USER)
}

enum Role {
  USER
  ADMIN
}
```

## Defining composite types (MongoDB) [#defining-composite-types-mongodb]

> [!WARNING]
> Composite types are only available on MongoDB.

Composite types (embedded documents) allow embedding records inside other records:

```prisma
model Product {
  id     String  @id @default(auto()) @map("_id") @db.ObjectId
  name   String
  photos Photo[]
}

type Photo {
  height Int
  width  Int
  url    String
}
```

**Supported attributes in composite types:** `@default`, `@map`, native types (`@db.ObjectId`)

**Not supported:** `@unique`, `@id`, `@relation`, `@ignore`, `@updatedAt`

## Using functions [#using-functions]

The Prisma schema supports [functions](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#attribute-functions) for default values:

```prisma
model Post {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  uuid      String   @default(uuid())
}
```

Common functions: `now()`, `uuid()`, `cuid()`, `autoincrement()`, `auto()` (MongoDB ObjectId)

## Relations [#relations]

See [relations documentation](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations) for relationship details.

## Models in Prisma Client [#models-in-prisma-client]

### Queries (CRUD) [#queries-crud]

Every model generates CRUD queries in the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction):

`findMany()` | `findFirst()` | `findUnique()` | `create()` | `update()` | `upsert()` | `delete()` | `createMany()` | `updateMany()` | `deleteMany()`

Access via the lowercase model name property: `prisma.user.create({ ... })`

### Type definitions [#type-definitions]

Prisma Client generates TypeScript types for your models:

```ts
export type User = {
  id: number;
  email: string;
  name: string | null;
};
```

These types ensure type-safe database queries.

## Limitations [#limitations]

Every Prisma model must have at least one unique identifier:

* `@id` or `@@id` for primary key
* `@unique` or `@@unique` for unique constraint

## Related pages

- [`Database mapping`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping): Learn how to map model and field names to database tables and columns
- [`External tables`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables): How to declare and use externally managed tables in Prisma ORM
- [`Indexes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes): How to configure index functionality and add full text indexes
- [`Multi-schema`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema): How to use Prisma ORM with multiple database schemas
- [`Relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations): A relation is a connection between two models in the Prisma schema. This page explains how you can define one-to-one, one-to-many and many-to-many relations in Prisma

# Multi-schema (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/multi-schema)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to use Prisma ORM with multiple database schemas

Location: ORM > v7 > Prisma Schema > Data Model > Multi-schema

## Overview [#overview]

PostgreSQL, CockroachDB, and SQL Server allow you to organize database tables into named groups. These groups are known as *schemas* and act as a *namespace* for logically grouping tables (e.g. to avoid name collisions or to have clearer domain separation) and let you define foreign key constraints across them. To avoid ambiguity, this page will refer to these namespaces as *database schemas*.

This page explains how to:

* include multiple database schemas in your Prisma schema
* apply your schema changes to your database with Prisma Migrate
* introspect an existing database with multiple database schemas
* query across multiple database schemas with Prisma Client

> [!NOTE]
> Multi-schema feature is only supported for PostgreSQL, CockroachDB, and SQL Server. It is not available for SQLite and MySQL because these databases don't have the same concept of *schemas as namespaces*.

## How to include multiple database schemas in your Prisma schema [#how-to-include-multiple-database-schemas-in-your-prisma-schema]

To use multiple database schemas in your Prisma schema file, add the names of your database schemas to an array in the `schemas` field, in the `datasource` block. The following example adds a `"base"` and a `"shop"` schema:

```prisma title="schema.prisma"
generator client {
  provider        = "prisma-client"
  output          = "./generated"
}

datasource db {
  provider = "postgresql"
  schemas  = ["base", "shop"] // [!code ++]
}
```

You do not need to change your connection string. The `schema` value of your connection string is the default database schema that Prisma Client connects to and uses for raw queries. All other Prisma Client queries use the schema of the model or enum that you are querying.

To designate that a model or enum belongs to a specific database schema, add the `@@schema` attribute with the name of the database schema as a parameter. In the following example, the `User` model is part of the `"base"` schema, and the `Order` model and `Size` enum are part of the `"shop"` schema:

```prisma title="schema.prisma"
model User {
  id     Int     @id
  orders Order[]

  @@schema("base") // [!code ++]
}

model Order {
  id      Int  @id
  user    User @relation(fields: [userId], references: [id])
  userId  Int

  @@schema("shop") // [!code ++]
}

enum Size {
  Small
  Medium
  Large

  @@schema("shop") // [!code ++]
}
```

### Tables with the same name in different database schemas [#tables-with-the-same-name-in-different-database-schemas]

If you have tables with the same name in different database schemas, you will need to map the table names to unique model names in your Prisma schema. This avoids name conflicts when you query models in Prisma Client.

For example, consider a situation where the `Config` table in the `base` database schema has the same name as the `Config` table in the `users` database schema. To avoid name conflicts, give the models in your Prisma schema unique names (`BaseConfig` and `UserConfig`) and use the `@@map` attribute to map each model to the corresponding table name:

```prisma title="schema.prisma"
model BaseConfig {
  id Int @id

  @@map("Config")
  @@schema("base")
}

model UserConfig {
  id Int @id

  @@map("Config")
  @@schema("users")
}
```

## How to apply your schema changes with Prisma Migrate [#how-to-apply-your-schema-changes-with-prisma-migrate]

You can use Prisma Migrate (or `prisma db push`) to apply changes to a Prisma schema with multiple database schemas.

As an example, add a `Profile` model to the `base` schema above:

```prisma title="schema.prisma"
model User {
  id      Int      @id
  orders  Order[]
  profile Profile? // [!code ++]

  @@schema("base")
}

model Profile { // [!code ++]
  id     Int    @id @default(autoincrement()) // [!code ++]
  bio    String // [!code ++]
  user   User   @relation(fields: [userId], references: [id]) // [!code ++]
  userId Int    @unique // [!code ++]

  @@schema("base") // [!code ++]
} // [!code ++]

model Order {
  id      Int  @id
  user    User @relation(fields: [userId], references: [id])
  userId  Int

  @@schema("shop")
}

enum Size {
  Small
  Medium
  Large

  @@schema("shop")
}
```

You can then apply this schema change to your database. For example, you can use `migrate dev` to create and apply your schema changes as a migration:

  

#### bun

```bash
bunx prisma migrate dev --name add_profile
```

#### pnpm

```bash
pnpm prisma migrate dev --name add_profile
```

#### yarn

```bash
yarn prisma migrate dev --name add_profile
```

#### npm

```bash
npx prisma migrate dev --name add_profile
```

Note that if you move a model or enum from one schema to another, Prisma ORM deletes the model or enum from the source schema and creates a new one in the target schema.

## How to introspect an existing database with multiple database schemas [#how-to-introspect-an-existing-database-with-multiple-database-schemas]

You can introspect an existing database that has multiple database schemas in the same way that you introspect a database that has a single database schema, using `prisma db pull`:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

This updates your Prisma schema to match the current state of the database.

If you have tables with the same name in different database schemas, Prisma ORM shows a validation error pointing out the conflict. To fix this, [rename the introspected models with the `@map` attribute](#tables-with-the-same-name-in-different-database-schemas).

## How to query across multiple database schemas with Prisma Client [#how-to-query-across-multiple-database-schemas-with-prisma-client]

You can query models in multiple database schemas without any change to your Prisma Client query syntax. For example, the following query finds all orders for a given user, using the Prisma schema above:

```ts
const orders = await prisma.order.findMany({
  where: {
    user: {
      id: 42,
    },
  },
});
```

### Externally managed tables [#externally-managed-tables]

Sometimes, you might not want Prisma ORM to manage specific tables, such as ones handled by another team or service (e.g., Auth0 or Clerk tables). In such cases, you can mark these as **externally managed tables** using the `tables.external` configuration option in your [Prisma Config file](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference#tablesexternal-and-enumsexternal). Learn more about [externally managed tables](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables).

## Related pages

- [`Database mapping`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping): Learn how to map model and field names to database tables and columns
- [`External tables`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables): How to declare and use externally managed tables in Prisma ORM
- [`Indexes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes): How to configure index functionality and add full text indexes
- [`Models`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models): Learn about the concepts for building your data model with Prisma: Models, scalar types, enums, attributes, functions, IDs, default values and more
- [`Relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations): A relation is a connection between two models in the Prisma schema. This page explains how you can define one-to-one, one-to-many and many-to-many relations in Prisma

# Table inheritance (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/table-inheritance)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn about the use cases and patterns for table inheritance in Prisma ORM that enable usage of union types or polymorphic structures in your application.

Location: ORM > v7 > Prisma Schema > Data Model > Table inheritance

## Overview [#overview]

Table inheritance is a software design pattern that allows the modeling of hierarchical relationships between entities. Using table inheritance on the database level can also enable the use of union types in your JavaScript/TypeScript application or share a set of common properties across multiple models.

This page introduces two approaches to table inheritance and explains how to use them with Prisma ORM.

A common use case for table inheritance may be when an application needs to display a *feed* of some kind of *content activities*. A content activity in this case, could be a *video* or an *article*. For example, assume that:

* a content activity always has an `id` and a `url`
* in addition to `id` and a `url`, a video also has a `duration` (modeled as an `Int`)
* in addition to `id` and a `url`, an article also a `body` (modeled as a `String`)

### Use cases [#use-cases]

#### Union types [#union-types]

Union types are a convenient feature in TypeScript that allows developers to work more flexibly with the types in their data model.

In TypeScript, union types look as follows:

```ts no-copy
type Activity = Video | Article;
```

While [it's currently not possible to model union types in the Prisma schema](https://github.com/prisma/orm/issues/2505), you can use them with Prisma ORM by using table inheritance and some additional type definitions.

#### Sharing properties across multiple models [#sharing-properties-across-multiple-models]

If you have a use case where multiple models should share a particular set of properties, you can model this using table inheritance as well.

For example, if both the `Video` and `Article` models from above should have a shared `title` property, you can achieve this with table inheritance as well.

### Example [#example]

In a simple Prisma schema, this would look as follows. Note that we're adding a `User` model as well to illustrate how this can work with relations:

```prisma title="schema.prisma" showLineNumbers
model Video {
  id       Int    @id
  url      String @unique
  duration Int

  user   User @relation(fields: [userId], references: [id])
  userId Int
}

model Article {
  id   Int    @id
  url  String @unique
  body String

  user   User @relation(fields: [userId], references: [id])
  userId Int
}

model User {
  id       Int       @id
  name     String
  videos   Video[]
  articles Article[]
}
```

The following sections show how to model this using table inheritance.

### Single-table vs multi-table inheritance [#single-table-vs-multi-table-inheritance]

Here is a quick comparison of the two main approaches for table inheritance:

* **Single-table inheritance (STI)**: Uses a *single* table to store data of *all* the different entities in one location. In our example, there'd be a single `Activity` table with the `id`, `url` as well as the `duration` and `body` column. It also uses a `type` column that indicates whether an *activity* is a *video* or an *article*.
* **Multi-table inheritance (MTI)**: Uses *multiple* tables to store the data of the different entities separately and links them via foreign keys. In our example, there'd be an `Activity` table with the `id`, `url` column, a `Video` table with the `duration` and a foreign key to `Activity` as well as an `Article` table with the `body` and a foreign key. There is also a `type` column that acts as a discriminator and indicates whether an *activity* is a *video* or an *article*. Note that multi-table inheritance is also sometimes called *delegated types*.

You can learn about the tradeoffs of both approaches [below](#tradeoffs-between-sti-and-mti).

## Single-table inheritance (STI) [#single-table-inheritance-sti]

### Data model [#data-model]

Using STI, the above scenario can be modeled as follows:

```prisma
model Activity {
  id       Int          @id // shared
  url      String       @unique // shared
  duration Int? // video-only
  body     String? // article-only
  type     ActivityType // discriminator

  owner   User @relation(fields: [ownerId], references: [id])
  ownerId Int
}

enum ActivityType {
  Video
  Article
}

model User {
  id         Int        @id @default(autoincrement())
  name       String?
  activities Activity[]
}
```

A few things to note:

* The model-specific properties `duration` and `body` must be marked as optional (i.e., with `?`). That's because a record in the `Activity` table that represents a *video* must not have a value for `body`. Conversely, an `Activity` record representing an *article* can never have a `duration` set.
* The `type` discriminator column indicates whether each record represents a *video* or an *article* item.

### Prisma Client API [#prisma-client-api]

Due to how Prisma ORM generates types and an API for the data model, there will only to be an `Activity` type and the CRUD queries that belong to it (`create`, `update`, `delete`, ...) available to you.

#### Querying for videos and articles [#querying-for-videos-and-articles]

You can now query for only *videos* or *articles* by filtering on the `type` column. For example:

```ts
// Query all videos
const videos = await prisma.activity.findMany({
  where: { type: "Video" },
});

// Query all articles
const articles = await prisma.activity.findMany({
  where: { type: "Article" },
});
```

#### Defining dedicated types [#defining-dedicated-types]

When querying for videos and articles like that, TypeScript will still only recognize an `Activity` type. That can be annoying because even the objects in `videos` will have (optional) `body` and the objects in `articles` will have (optional) `duration` fields.

If you want to have type safety for these objects, you need to define dedicated types for them. You can do this, for example, by using the generated `Activity` type and the TypeScript `Omit` utility type to remove properties from it:

```ts
import { Activity } from "../prisma/generated/client";

type Video = Omit<Activity, "body" | "type">;
type Article = Omit<Activity, "duration" | "type">;
```

In addition, it will be helpful to create mapping functions that convert an object of type `Activity` to the `Video` and `Article` types:

```ts
function activityToVideo(activity: Activity): Video {
  return {
    url: activity.url,
    duration: activity.duration ? activity.duration : -1,
    ownerId: activity.ownerId,
  } as Video;
}

function activityToArticle(activity: Activity): Article {
  return {
    url: activity.url,
    body: activity.body ? activity.body : "",
    ownerId: activity.ownerId,
  } as Article;
}
```

Now you can turn an `Activity` into a more specific type (i.e., `Article` or `Video`) after querying:

```ts
const videoActivities = await prisma.activity.findMany({
  where: { type: "Video" },
});
const videos: Video[] = videoActivities.map(activityToVideo);
```

#### Using Prisma Client extension for a more convenient API [#using-prisma-client-extension-for-a-more-convenient-api]

You can use [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions) to create a more convenient API for the table structures in your database.

## Multi-table inheritance (MTI) [#multi-table-inheritance-mti]

### Data model [#data-model-1]

Using MTI, the above scenario can be modeled as follows:

```prisma
model Activity {
  id   Int          @id @default(autoincrement())
  url  String // shared
  type ActivityType // discriminator

  video   Video? // model-specific 1-1 relation
  article Article? // model-specific 1-1 relation

  owner   User @relation(fields: [ownerId], references: [id])
  ownerId Int
}

model Video {
  id         Int      @id @default(autoincrement())
  duration   Int // video-only
  activityId Int      @unique
  activity   Activity @relation(fields: [activityId], references: [id])
}

model Article {
  id         Int      @id @default(autoincrement())
  body       String // article-only
  activityId Int      @unique
  activity   Activity @relation(fields: [activityId], references: [id])
}

enum ActivityType {
  Video
  Article
}

model User {
  id         Int        @id @default(autoincrement())
  name       String?
  activities Activity[]
}
```

A few things to note:

* A 1-1 relation is needed between `Activity` and `Video` as well as `Activity` and `Article`. This relationship is used to fetch the specific information about a record when needed.
* The model-specific properties `duration` and `body` can be made *required* with this approach.
* The `type` discriminator column indicates whether each record represents a *video* or an *article* item.

### Prisma Client API [#prisma-client-api-1]

This time, you can query for videos and articles directly via the `video` and `article` properties on your `PrismaClient` instance.

#### Querying for videos and articles [#querying-for-videos-and-articles-1]

If you want to access the shared properties, you need to use `include` to fetch the relation to `Activity`.

```ts
// Query all videos
const videos = await prisma.video.findMany({
  include: { activity: true },
});

// Query all articles
const articles = await prisma.article.findMany({
  include: { activity: true },
});
```

Depending on your needs, you may also query the other way around by filtering on the `type` discriminator column:

```ts
// Query all videos
const videoActivities = await prisma.activity.findMany({
  where: { type: 'Video' }
  include: { video: true }
})
```

#### Defining dedicated types [#defining-dedicated-types-1]

While a bit more convenient in terms of types compared to STI, the generated typings likely still won't fit all your needs.

Here's how you can define `Video` and `Article` types by combining Prisma ORM's generated `Video` and `Article` types with the `Activity` type. These combinations create a new type with the desired properties. Note that we're also omitting the `type` discriminator column because that's not needed anymore on the specific types:

```ts
import { Video as VideoDB, Article as ArticleDB, Activity } from "../prisma/generated/client";

type Video = Omit<VideoDB & Activity, "type">;
type Article = Omit<ArticleDB & Activity, "type">;
```

Once these types are defined, you can define mapping functions to convert the types you receive from the queries above into the desired `Video` and `Article` types. Here's the example for the `Video` type:

```ts
import { Prisma, Video as VideoDB, Activity } from "../prisma/generated/client";

type Video = Omit<VideoDB & Activity, "type">;

// Create `VideoWithActivity` typings for the objects returned above
const videoWithActivity = Prisma.validator<Prisma.VideoDefaultArgs>()({
  include: { activity: true },
});
type VideoWithActivity = Prisma.VideoGetPayload<typeof videoWithActivity>;

// Map to `Video` type
function toVideo(a: VideoWithActivity): Video {
  return {
    id: a.id,
    url: a.activity.url,
    ownerId: a.activity.ownerId,
    duration: a.duration,
    activityId: a.activity.id,
  };
}
```

Now you can take the objects returned by the queries above and transform them using `toVideo`:

```ts
const videoWithActivities = await prisma.video.findMany({
  include: { activity: true },
});
const videos: Video[] = videoWithActivities.map(toVideo);
```

#### Using Prisma Client extension for a more convenient API [#using-prisma-client-extension-for-a-more-convenient-api-1]

You can use [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions) to create a more convenient API for the table structures in your database.

## Tradeoffs between STI and MTI [#tradeoffs-between-sti-and-mti]

* **Data model**: The data model may feel more clean with MTI. With STI, you may end up with very wide rows and lots of columns that have `NULL` values in them.
* **Performance**: MTI may come with a performance cost because you need to join the parent and child tables to access *all* properties relevant for a model.
* **Typings**: With Prisma ORM, MTI gives you proper typings for the specific models (i.e., `Article` and `Video` in the examples above) already, while you need to create these from scratch with STI.
* **IDs / Primary keys**: With MTI, records have two IDs (one on the parent and another on the child table) that may not match. You need to consider this in the business logic of your application.

## Third-party solutions [#third-party-solutions]

While Prisma ORM doesn't natively support union types or polymorphism at the moment, you can check out [Zenstack](https://github.com/zenstackhq/zenstack) which is adding an extra layer of features to the Prisma schema. Read their [blog post about polymorphism in Prisma ORM](https://zenstack.dev/blog/polymorphism) to learn more.

## Related pages

- [`Database mapping`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping): Learn how to map model and field names to database tables and columns
- [`External tables`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables): How to declare and use externally managed tables in Prisma ORM
- [`Indexes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes): How to configure index functionality and add full text indexes
- [`Models`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models): Learn about the concepts for building your data model with Prisma: Models, scalar types, enums, attributes, functions, IDs, default values and more
- [`Multi-schema`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema): How to use Prisma ORM with multiple database schemas

# Unsupported database features (Prisma Schema) (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/unsupported-database-features)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to support database features that do not have an equivalent syntax in Prisma Schema Language

Location: ORM > v7 > Prisma Schema > Data Model > Unsupported database features (Prisma Schema)

Not all database functions and features of Prisma ORM's supported databases have a Prisma Schema Language equivalent. Refer to the [database features matrix](https://www.prisma.io/docs/orm/v7/reference/database-features) for a complete list of supported features.

## Native database functions [#native-database-functions]

Prisma Schema Language supports several [functions](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#attribute-functions) that you can use to set the default value of a field. The following example uses the Prisma ORM-level `uuid()` function to set the value of the `id` field:

```prisma
model Post {
  id String @id @default(uuid())
}
```

However, you can also use **native database functions** to define default values with [`dbgenerated(...)`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#dbgenerated) on relational databases (MongoDB does not have the concept of database-level functions). The following example uses the PostgreSQL `gen_random_uuid()` function to populate the `id` field:

```prisma
model User {
  id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
}
```

### When to use a database-level function [#when-to-use-a-database-level-function]

There are two reasons to use a database-level function:

* There is no equivalent Prisma ORM function (for example, `gen_random_bytes` in PostgreSQL).
* You cannot or do not want to rely on functions such `uuid()` and `cuid()`, which are only implemented at a Prisma ORM level and do not manifest in the database.

  Consider the following example, which sets the `id` field to a randomly generated `UUID`:

  ```prisma
  model Post {
    id String @id @default(uuid())
  }
  ```

  The UUID is *only* generated if you use Prisma Client to create the `Post`. If you create posts in any other way, such as a bulk import script written in plain SQL, you must generate the UUID yourself.

### Enable PostgreSQL extensions for native database functions [#enable-postgresql-extensions-for-native-database-functions]

In PostgreSQL, some native database functions are part of an extension. For example, in PostgreSQL versions 12.13 and earlier, the `gen_random_uuid()` function is part of the [`pgcrypto`](https://www.postgresql.org/docs/10/pgcrypto.html) extension.

To use a PostgreSQL extension, you must first install it on the file system of your database server.

You can then activate the extension by installing it via a [customized migration](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/customizing-migrations). Add the following SQL to your migration file:

```sql
CREATE EXTENSION IF NOT EXISTS pgcrypto;
```

If your project uses [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate), you must [install the extension as part of a migration](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/native-database-functions) . Do not install the extension manually, because it is also required by the shadow database.

Prisma Migrate returns the following error if the extension is not available:

```
Migration `20210221102106_failed_migration` failed to apply cleanly to a temporary database.
Database error: Error querying the database: db error: ERROR: type "pgcrypto" does not exist
```

## Unsupported field types [#unsupported-field-types]

Some database types of relational databases, such as `polygon` or `geometry`, do not have a Prisma Schema Language equivalent. Use the [`Unsupported`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#unsupported) field type to represent the field in your Prisma schema:

```prisma highlight=3;normal
model Star {
  id       Int                    @id @default(autoincrement())
  position Unsupported("circle")? @default(dbgenerated("'<(10,4),11>'::circle")) // [!code highlight]
}
```

The `prisma migrate dev` and `prisma db push` command will both create a `position` field of type `circle` in the database. However, the field will not be available in the generated Prisma Client.

## Unsupported database features [#unsupported-database-features]

Some features, like SQL views, cannot be represented in the Prisma schema. If your project uses [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate), you must [include unsupported features as part of a migration](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/unsupported-database-features) .

> [!NOTE]
> Partial indexes are now supported in Prisma Schema Language via the `where` argument on `@@index`, `@@unique`, and `@unique`. See [Configuring partial indexes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes#configuring-partial-indexes-with-where) for details.

## Related pages

- [`Database mapping`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping): Learn how to map model and field names to database tables and columns
- [`External tables`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables): How to declare and use externally managed tables in Prisma ORM
- [`Indexes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes): How to configure index functionality and add full text indexes
- [`Models`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models): Learn about the concepts for building your data model with Prisma: Models, scalar types, enums, attributes, functions, IDs, default values and more
- [`Multi-schema`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema): How to use Prisma ORM with multiple database schemas

# Views (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/views)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to include views in your Prisma schema

Location: ORM > v7 > Prisma Schema > Data Model > Views

Database views allow you to name and store queries. In relational databases, views are [stored SQL queries](https://www.postgresql.org/docs/current/sql-createview.html) that might include columns in multiple tables, or calculated values such as aggregates. In MongoDB, views are queryable objects where the contents are defined by an [aggregation pipeline](https://www.mongodb.com/docs/manual/core/aggregation-pipeline) on other collections.

The `views` preview feature allows you to represent views in your Prisma schema with the `view` keyword. To use views in Prisma ORM, follow these steps:

1. [Enable the `views` preview feature](#enable-the-views-preview-feature)
2. [Create a view in the underlying database](#create-a-view-in-the-underlying-database), either directly or as a [manual addition to a Prisma Migrate migration file](#use-views-with-prisma-migrate-and-db-push), or use an existing view
3. [Represent the view in your Prisma schema](#add-views-to-your-prisma-schema)
4. [Query the view in Prisma Client](#query-views-in-prisma-client)

> [!WARNING]
> Support for views is currently a [Preview](https://www.prisma.io/docs/orm/v7/more/releases#preview) feature. You can add a view to your Prisma schema with the `view` keyword or introspect the views in your database schema with `db pull`. You cannot yet apply views in your schema to your database with Prisma Migrate and `db push` unless the changes are added manually to your migration file using the `--create-only` flag. <br /><br />For updates on progress with this feature, follow [our GitHub issue](https://github.com/prisma/orm/issues/17335).

## Enable the `views` preview feature [#enable-the-views-preview-feature]

Support for views is currently in an early preview. To enable the `views` preview feature, add the `views` feature flag to the `previewFeatures` field of the `generator` block in your Prisma Schema:

```prisma title="schema.prisma" highlight=3;add showLineNumbers
generator client {
  provider        = "prisma-client"
  output          = "./generated"
  previewFeatures = ["views"] // [!code ++]
}
```

Please leave feedback about this preview feature in our dedicated preview feature [feedback issue](https://github.com/prisma/orm/issues/17335) for `views`.

## Create a view in the underlying database [#create-a-view-in-the-underlying-database]

Currently, you cannot apply views that you define in your Prisma schema to your database with Prisma Migrate or `db push`. Instead, you must first create the view in the underlying database, either manually or [as part of a migration](#use-views-with-prisma-migrate-and-db-push).

For example, take the following Prisma schema with a `User` model and a related `Profile` model:

  

#### Relational databases

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

model Profile {
  id     Int    @id @default(autoincrement())
  bio    String
  user   User   @relation(fields: [userId], references: [id])
  userId Int    @unique
}
```

#### MongoDB

```prisma
model User {
  id      String   @id @default(auto()) @map("_id") @db.ObjectId
  email   String   @unique
  name    String?
  profile Profile?
}

model Profile {
  id     String @id @default(auto()) @map("_id") @db.ObjectId
  bio    String
  User   User   @relation(fields: [userId], references: [id])
  userId String @unique @db.ObjectId
}
```

Next, take a `UserInfo` view in the underlying database that combines the `email` and `name` fields from the `User` model and the `bio` field from the `Profile` model.

For a relational database, the SQL statement to create this view is:

```sql
CREATE VIEW "UserInfo" AS
    SELECT u.id, email, name, bio
    FROM "User" u
    LEFT JOIN "Profile" p ON u.id = p."userId";
```

For MongoDB, you can [create a view](https://www.mongodb.com/docs/manual/core/views/join-collections-with-view/) with the following command:

```ts
db.createView("UserInfo", "User", [
  {
    $lookup: {
      from: "Profile",
      localField: "_id",
      foreignField: "userId",
      as: "ProfileData",
    },
  },
  {
    $project: {
      _id: 1,
      email: 1,
      name: 1,
      bio: "$ProfileData.bio",
    },
  },
  { $unwind: "$bio" },
]);
```

## Use views with Prisma Migrate and `db push` [#use-views-with-prisma-migrate-and-db-push]

If you apply changes to your Prisma schema with Prisma Migrate or `db push`, Prisma ORM does not create or run any SQL related to views.

To include views in a migration, run `migrate dev --create-only` and then manually add the SQL for views to your migration file. Alternatively, you can create views manually in the database.

## Add views to your Prisma schema [#add-views-to-your-prisma-schema]

To add a view to your Prisma schema, use the `view` keyword.

You can represent the `UserInfo` view from the example above in your Prisma schema as follows:

  

#### Relational databases

```prisma
view UserInfo {
  id    Int
  email String
  name  String
  bio   String
}
```

#### MongoDB

```prisma
view UserInfo {
  id    String @map("_id") @db.ObjectId
  email String
  name  String
  bio   String
}
```

### Write by hand [#write-by-hand]

A `view` block is comprised of two main pieces:

* The `view` block definition
* The view's field definitions

These two pieces allow you to define the name of your view in the generated Prisma Client and the columns present in your view's query results.

#### Define a `view` block [#define-a-view-block]

To define the `UserInfo` view from the example above, begin by using the `view` keyword to define a `view` block in your schema named `UserInfo`:

```prisma
view UserInfo {
  // Fields
}
```

#### Define fields [#define-fields]

The properties of a view are called *fields*, which consist of:

* A field name
* A field type

The fields of the `UserInfo` example view can be defined as follows:

  

#### Relational databases

```prisma highlight=2-5;normal 
view UserInfo {
  id    Int // [!code highlight]
  email String // [!code highlight]
  name  String // [!code highlight]
  bio   String // [!code highlight]
}
```

#### MongoDB

```prisma highlight=2-5;normal 
view UserInfo {
  id    String @map("_id") @db.ObjectId // [!code highlight]
  email String // [!code highlight]
  name  String // [!code highlight]
  bio   String // [!code highlight]
}
```

Each *field* of a `view` block represents a column in the query results of the view in the underlying database.

### Use introspection [#use-introspection]

> [!WARNING]
> Currently views can only be introspected with PostgreSQL, MySQL, SQL Server and CockroachDB databases. If you are using another database provider, your views must be added manually.

If you have an existing view or views defined in your database, [introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection) will automatically generate `view` blocks in your Prisma schema that represent those views.

Assuming the example `UserInfo` view exists in your underlying database, running the following command will generate a `view` block in your Prisma schema representing that view:

  

#### bun

```bash
bunx prisma db pull
```

#### pnpm

```bash
pnpm prisma db pull
```

#### yarn

```bash
yarn prisma db pull
```

#### npm

```bash
npx prisma db pull
```

The resulting `view` block will be defined as follows:

```prisma
view UserInfo {
  id    Int?
  email String?
  name  String?
  bio   String?
}
```

> [!WARNING]
> Please note for now `db pull` will only introspect views in your schema when using PostgreSQL, MySQL, SQL Server or CockroachDB. Support for this workflow will be extended to other database providers.

#### The `views` directory [#the-views-directory]

Introspection of a database with one or more existing views will also create a new `views` directory within your `prisma` directory. This directory will contain a subdirectory named after your database's schema which contains a `.sql` file for each view that was introspected in that schema. Each file will be named after an individual view and will contain the query the related view defines.

For example, after introspecting a database with the default `public` schema using the model used above you will find a `prisma/views/public/UserInfo.sql` file was created with the following contents:

```sql
SELECT
  u.id,
  u.email,
  u.name,
  p.bio
FROM
  (
    "User" u
    LEFT JOIN "Profile" p ON ((u.id = p."userId"))
  );
```

## Query views in Prisma Client [#query-views-in-prisma-client]

> [!NOTE]
> Be sure to run `prisma generate` after updating your Prisma schema so that the `view` definitions become part of your Prisma Client API.

You can query views in Prisma Client in the same way that you query models. For example, the following query finds all users with a `name` of `'Alice'` in the `UserInfo` view defined above.

```ts
const userinfo = await prisma.userInfo.findMany({
  where: {
    name: "Alice",
  },
});
```

> [!NOTE]
> Write-queries (create/update/delete) are not supported on `views`.

## Special types of views [#special-types-of-views]

This section describes how to use Prisma ORM with updatable and materialized views in your database.

### Updatable views [#updatable-views]

Some databases support *updatable views* (e.g. [PostgreSQL](https://www.postgresql.org/docs/current/sql-createview.html#SQL-CREATEVIEW-UPDATABLE-VIEWS), [MySQL](https://dev.mysql.com/doc/refman/8.0/en/view-updatability.html), and [SQL Server](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql?view=sql-server-ver16#updatable-views)). Updatable views allow creating, updating, or deleting entries if the underlying database supports such operations.

Prisma ORM does not allow any mutations (create, update, delete) on views, regardless of the database's capabilities. This change provides guardrails to ensure that views are treated consistently as read-only entities within Prisma Client. As a result, methods to perform writes such as `create`, `update`, `delete`, or `upsert` are not generated for `view` blocks in your Prisma Client API.

If you need to modify data represented by a view, you must perform the write operations directly on the underlying tables or use raw SQL queries.

### Materialized views [#materialized-views]

Some databases support materialized views, e.g. [PostgreSQL](https://www.postgresql.org/docs/current/rules-materializedviews.html), [CockroachDB](https://www.cockroachlabs.com/docs/stable/views.html#materialized-views), [MongoDB](https://www.mongodb.com/docs/manual/core/materialized-views/), and [SQL Server](https://learn.microsoft.com/en-us/sql/relational-databases/views/create-indexed-views?view=sql-server-ver16) (where they're called "indexed views").

Materialized views persist the result of the view query for faster access and only update it on demand.

Currently, Prisma ORM does not support materialized views. However, when you [manually create a view](#create-a-view-in-the-underlying-database), you can also create a materialized view with the corresponding command in the underlying database. You can then use Prisma Client's [TypedSQL functionality](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql) to execute the command and refresh the view manually.

In the future Prisma Client might support marking individual views as materialized and add a Prisma Client method to refresh the materialized view. Please comment on our [`views` feedback issue](https://github.com/prisma/orm/issues/17335) with your use case.

## Limitations [#limitations]

Prisma ORM treats all `view` blocks as *read-only* representations of database queries rather than true tables. Because of this, several limitations apply to ensure Prisma Client remains consistent with the behavior of the underlying database.

### No identifiers [#no-identifiers]

Views are virtual tables and do not have inherent primary keys. Hence, you cannot define `@id`, `@@id` attributes on a `view` block.

### No indexes [#no-indexes]

Because views are virtual tables, they cannot have indexes. Therefore, `@index` and `@@index` cannot be defined on `view` blocks.

### Unsafe `@unique` attributes [#unsafe-unique-attributes]

While Prisma ORM lets you place `@unique` and `@@unique` attributes on views, the underlying database and Prisma do not enforce those constraints. Multiple rows can therefore share the same value for a supposedly unique field.

Neither the database nor Prisma ORM enforce the unique constraint expressed by that attribute.

The purpose of the `@unique` attribute in this case is only to enable relationships across views as well as `findUnique` queries and cursor-based pagination in Prisma Client.

### Disabled write queries [#disabled-write-queries]

All write operations (`create`, `update`, `delete`, `upsert`) are disabled and not generated in the Prisma Client.

## Related pages

- [`Database mapping`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping): Learn how to map model and field names to database tables and columns
- [`External tables`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables): How to declare and use externally managed tables in Prisma ORM
- [`Indexes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes): How to configure index functionality and add full text indexes
- [`Models`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models): Learn about the concepts for building your data model with Prisma: Models, scalar types, enums, attributes, functions, IDs, default values and more
- [`Multi-schema`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema): How to use Prisma ORM with multiple database schemas

# Data sources (Prisma ORM v7) (/docs/orm/v7/prisma-schema/overview/data-sources)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Data sources enable Prisma to connect to your database. This page explains how to configure data sources in your Prisma schema

Location: ORM > v7 > Prisma Schema > Overview > Data sources

A data source determines how Prisma ORM connects to your database, and is represented by the [`datasource`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#datasource) block in the Prisma schema. Connection details (such as the database URL) are configured in [Prisma Config](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference). The following data source uses the `postgresql` provider:

```prisma
datasource db {
  provider = "postgresql"
}
```

A Prisma schema can only have *one* data source. However, you can:

* [Override the database connection when creating your `PrismaClient`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference)
* [Specify a different **database** for Prisma Migrate's shadow database if you are working with cloud-hosted development databases](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database#cloud-hosted-shadow-databases-must-be-created-manually)

## Securing database connections [#securing-database-connections]

Some data source `provider`s allow you to configure your connection with SSL/TLS **by specifying certificate locations in your connection configuration**.

* [Configuring an SSL connection with PostgreSQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#common-patterns)
* [Configuring an SSL connection with MySQL](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#common-patterns)
* [Configure a TLS connection with Microsoft SQL Server](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server#connection-details)

See the database-specific documentation above for examples of SSL/TLS connection configuration in Prisma Config.

## Related pages

- [`Generators`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators): Generators in your Prisma schema specify what assets are generated when the `prisma generate` command is invoked. This page explains how to configure generators
- [`Schema location`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/location): Documentation regarding proper location of Prisma Schema including default naming and multiple files.

# Generators (Prisma ORM v7) (/docs/orm/v7/prisma-schema/overview/generators)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Generators in your Prisma schema specify what assets are generated when the `prisma generate` command is invoked. This page explains how to configure generators

Location: ORM > v7 > Prisma Schema > Overview > Generators

A Prisma schema can have one or more generators, represented by the [`generator`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#generator) block:

```prisma
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}
```

A generator determines which assets are created when you run the `prisma generate` command.

The default generator for Prisma Client is `prisma-client`, which outputs plain TypeScript code and *requires* a custom `output` path (read more about it in [the blog post on generating into `node_modules`](https://www.prisma.io/blog/why-prisma-orm-generates-code-into-node-modules-and-why-it-ll-change)).

Alternatively, you can configure any npm package that complies with our generator specification.

## `prisma-client` [#prisma-client]

The `prisma-client` generator outputs plain TypeScript that runs across JavaScript environments (such as ESM, Bun, Deno, ...).

It generates Prisma Client into a custom directory in your application's codebase that's specified via the `output` field on the `generator` block. This gives you full visibility and control over the generated code. It also [splits](#importing-types) the generated Prisma Client library into multiple files.

Here are the main differences compared to `prisma-client-js`:

* Requires an `output` path; no "magic" generation into `node_modules` any more
* Doesn't load `.env` at runtime; use `dotenv` or set environment variables manually instead
* Supports ESM and CommonJS via the `moduleFormat` field
* More flexible thanks to additional [fields](#field-reference)
* Outputs plain TypeScript that's bundled just like the rest of your application code

The `prisma-client` generator is the default generator.

### Getting started [#getting-started]

Follow these steps to use the new `prisma-client` generator in your project.

#### 1. Configure the `prisma-client` generator in `schema.prisma` [#1-configure-the-prisma-client-generator-in-schemaprisma]

Update your [`generator`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators) block:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"            // Required // [!code ++]
  output   = "../src/generated/prisma"  // Required // [!code ++]
}
```

The **`output` option is required** and tells Prisma ORM where to put the generated Prisma Client code. You can choose any location suitable for your project structure. For instance, if you have the following layout:

```txt
.
├── package.json
├── prisma
│   └── schema.prisma
├── src
│   └── index.ts
└── tsconfig.json
```

Then `../src/generated/prisma` places the generated code in `src/generated/prisma` relative to `schema.prisma`.

#### 2. Generate Prisma Client [#2-generate-prisma-client]

Generate Prisma Client by running:

  

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```

This generates the code for Prisma Client (including the query engine binary) into the specified `output` folder.

#### 3. Use Prisma Client in your application [#3-use-prisma-client-in-your-application]

#### Importing Prisma Client [#importing-prisma-client]

After generating the Prisma Client, import it from the path you specified:

```ts title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg"; // or the adapter for your database
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
const prisma = new PrismaClient({ adapter });
```

Prisma Client is now ready to use in your project.

#### Importing generated model types [#importing-generated-model-types]

If you're importing types generated for your models, you can do so as follows:

```ts title="src/index.ts"
import { UserModel, PostModel } from "./generated/prisma/models";
```

#### Importing generated enum types [#importing-generated-enum-types]

If you're importing types generated for your enums, you can do so as follows:

```ts title="src/index.ts"
import { Role, User } from "./generated/prisma/enums";
```

#### Importing in browser environments [#importing-in-browser-environments]

If you need to access generated types in your frontend code, you can import them as follows:

```ts title="src/index.ts"
import { Role } from "./generated/prisma/browser";
```

Note that `./generated/prisma/browser` does not expose a `PrismaClient`.

### Field reference [#field-reference]

Use the following options in the `generator client { ... }` block. Only `output` is required. The other fields have defaults or are inferred from your environment and `tsconfig.json`.

```prisma title="schema.prisma"
generator client {
  // Required
  provider = "prisma-client"
  output   = "../src/generated/prisma"

  // Optional
  engineType             = "client"
  runtime                = "nodejs"
  moduleFormat           = "esm"
  generatedFileExtension = "ts"
  importFileExtension    = "ts"
}
```

Below are the options for the `prisma-client` generator:

| **Option**               | **Default**               | **Description**                                                                                                                                                        |
| ------------------------ | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `output` (**required**)  |                           | Directory where Prisma Client is generated, e.g. `../src/generated/prisma`.                                                                                            |
| `runtime`                | `nodejs`                  | Target runtime environment. <br />Supported values: <br />`nodejs`, `deno`, `bun`, `workerd` (alias `cloudflare`), `vercel-edge` (alias `edge-light`), `react-native`. |
| `moduleFormat`           | Inferred from environment | Module format (`esm` or `cjs`). Determines whether `import.meta.url` or `__dirname` is used.                                                                           |
| `generatedFileExtension` | `ts`                      | File extension for generated TypeScript files (`ts`, `mts`, `cts`).                                                                                                    |
| `importFileExtension`    | Inferred from environment | File extension used in **import statements**. Can be `ts`, `mts`, `cts`, `js`, `mjs`, `cjs`, or empty (for bare imports).                                              |

> [!NOTE]
> `nodejs`, `deno`, and `bun` all map to the same internal codepath but are preserved as separate user-facing values for clarity.

> [!NOTE]
> **If you use `tsx` as your TypeScript runner** and see `Cannot find module './internal/class.js'` errors at runtime, set `importFileExtension = "ts"` in your generator block:
> 
> ```prisma
> generator client {
>   provider            = "prisma-client"
>   output              = "../src/generated/prisma"
>   importFileExtension = "ts"
> }
> ```
>
> This happens because the generated client uses `.js` extensions in its import statements (ESM convention), but `tsx` cannot resolve `.js` imports to the corresponding `.ts` files on disk. Setting `importFileExtension = "ts"` ensures the generated imports match what `tsx` expects.

### Importing types [#importing-types]

The new `prisma-client` generator creates individual `.ts` files which allow for a more fine granular import of types. This can improve compile and typecheck performance and be useful for tree-shaking, too.
You can still use the top level barrel files that export all types through a single import.

The overall structure of the generated output looks like this:

```
generated/
└── prisma
    ├── browser.ts
    ├── client.ts
    ├── commonInputTypes.ts
    ├── enums.ts
    ├── internal
    │   ├── ...
    ├── models
    │   ├── Post.ts
    │   └── User.ts
    └── models.ts
```

#### `client.ts` [#clientts]

For use in your server code.

* Provides access to the `PrismaClient` instance and all model and utility types.
* Provides best compatibility with the `prisma-client-js` generated output.
* Contains transitive dependencies on server only-packages, so cannot be used in browser contexts.

Example:

```ts title="src/index.ts"
import { Prisma, type Post, PrismaClient } from "./generated/prisma/client";
```

#### `browser.ts` [#browserts]

For using types in your frontend (i.e. code that runs in the browser).

* Contains no transitive dependencies on Node.js or other server-only packages.
* Contains no real `PrismaClient` constructor.
* Contains all model and enum types and values.
* Provides access to various utilities like `Prisma.JsonNull` and `Prisma.Decimal`.

Example:

```ts title="src/index.ts"
import { Prisma, type Post } from "./generated/prisma/browser";
```

#### `enums.ts` [#enumsts]

Isolated access to user defined enum types and values.

* Contains no transitive dependencies and is very slim.
* Can be used on backend and frontend.
* Prefer this for optimal tree shaking and typecheck performance when accessing enums.

Example:

```ts title="src/index.ts"
import { MyEnum } from "./generated/prisma/enums";
```

#### `models.ts` [#modelsts]

Isolated access to all model types.

* Can be used on backend and frontend.
* Contains all models including their derived utility types like `<ModelName>WhereInput` or `<ModelName>UpdateInput>`.

> [!NOTE]
> Plain model types are exposed here as `<ModelName>Model` (e.g. `PostModel`). This is in contrast to the exposed name in `client.ts` and `browser.ts` which is simply `<ModelName>` (e.g. `Post`).
> 
> This is necessary due to internal constraints to avoid potential naming conflicts with internal types.

Example:

```ts title="src/index.ts"
import type {
  UserModel,
  PostModel,
  PostWhereInput,
  UserUpdateInput,
} from "./generated/prisma/models";
```

#### `models/<ModelName>.ts` [#modelsmodelnamets]

Isolated access to the types for an individual model.

* Can be used on backend and frontend.
* Contains the models including its derived utility types like `<ModelName>WhereInput` or `<ModelName>UpdateInput>`.

> [!NOTE]
> The plain model type is exposed here as `<ModelName>Model` (e.g. `PostModel`).

Example:

```ts title="src/index.ts"
import type { UserModel, UserWhereInput, UserUpdateInput } from "./generated/prisma/models/User";
```

#### `commonInputTypes.ts` [#commoninputtypests]

Provides shared utility types that you should rarely directly need.

Example:

```ts
import type { IntFilter } from "./generated/prisma/commonInputTypes";
```

#### `internal/*` [#internal]

> [!WARNING]
> Do not directly import from these files! They are not part of the stable API of the generated code and can change at any time in breaking ways.
> 
> Usually anything you might need from there is exposed via `browser.ts` or `client.ts` under the `Prisma` namespace.

### Breaking changes from `prisma-client-js` [#breaking-changes-from-prisma-client-js]

* Requires an `output` path on the `generator` block
* No `Prisma.validator` function; you can use TypeScript native [`satisfies`](https://www.prisma.io/blog/satisfies-operator-ur8ys8ccq7zb) keyword instead

### Examples [#examples]

To see what the new `prisma-client` generator looks like in practice, check out our minimal and [ready-to-run examples](https://github.com/prisma/prisma-examples):

| Example                                                                                                                                                            | Framework      | Bundler           | Runtime                                          | Monorepo  |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------- | ----------------- | ------------------------------------------------ | --------- |
| [`nextjs-starter-webpack`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/nextjs-starter-webpack)                                   | Next.js 15     | Webpack           | Node.js                                          | n/a       |
| [`nextjs-starter-turbopack`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/nextjs-starter-turbopack)                               | Next.js 15     | Turbopack (alpha) | Node.js                                          | n/a       |
| [`nextjs-starter-webpack-monorepo`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/nextjs-starter-webpack-monorepo)                 | Next.js 15     | Webpack           | Node.js                                          | pnpm      |
| [`nextjs-starter-webpack-with-middleware`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/nextjs-starter-webpack-with-middleware)   | Next.js 15     | Webpack           | Node.js (main pages), `vercel-edge` (middleware) | n/a       |
| [`nextjs-starter-webpack-turborepo`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/nextjs-starter-webpack-turborepo)               | Next.js 15     | Webpack           | Node.js                                          | turborepo |
| [`react-router-starter-nodejs`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/react-router-starter-nodejs)                         | React Router 7 | Vite 6            | Node.js                                          | n/a       |
| [`react-router-starter-cloudflare-workerd`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/react-router-starter-cloudflare-workerd) | React Router 7 |                   |                                                  | n/a       |
| [`nuxt3-starter-nodejs`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/nuxt3-starter-nodejs)                                       | Nuxt 3         | Vite 6            | Node.js                                          | n/a       |
| [`nuxt4-starter-nodejs`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/nuxt4-starter-nodejs)                                       | Nuxt 4         | Vite 7            | Node.js                                          | n/a       |
| [`bun`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/deno-deploy)                                                                 | None           | None              | Deno 2                                           | n/a       |
| [`deno`](https://github.com/prisma/prisma-examples/tree/latest/generator-prisma-client/deno-deploy)                                                                | None           | None              | Deno 2                                           | n/a       |

## `prisma-client-js` (Deprecated) [#prisma-client-js-deprecated]

> [!WARNING]
> Deprecated
> 
> The `prisma-client-js` generator is deprecated. We recommend using [`prisma-client`](#prisma-client) for new projects and updating existing projects when possible.

The `prisma-client-js` generator requires the `@prisma/client` npm package and generates Prisma Client into `node_modules`.

### Field reference [#field-reference-1]

The generator for Prisma's JavaScript Client accepts multiple additional properties:

* `previewFeatures`: [Preview features](https://www.prisma.io/docs/orm/v7/reference/preview-features/client-preview-features) to include
* `binaryTargets`: Engine binary targets for `prisma-client-js` (for example, `debian-openssl-1.1.x` if you are deploying to Ubuntu 18+, or `native` if you are working locally)

```prisma title="prisma/schema.prisma"
generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["sample-preview-feature"]
  binaryTargets   = ["debian-openssl-1.1.x"] // defaults to `"native"`
}
```

## Community generators [#community-generators]

> [!NOTE]
> Existing generators or new ones should not be affected if you are using a [multi-file Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/location#multi-file-prisma-schema), unless a generator reads the schema manually.

The following is a list of community created generators.

* [`prisma-dbml-generator`](https://notiz.dev/blog/prisma-dbml-generator/): Transforms the Prisma schema into [Database Markup Language](https://dbml.dbdiagram.io/home/) (DBML) which allows for an easy visual representation
* [`prisma-docs-generator`](https://github.com/pantharshit00/prisma-docs-generator): Generates an individual API reference for Prisma Client
* [`prisma-json-schema-generator`](https://github.com/valentinpalkovic/prisma-json-schema-generator): Transforms the Prisma schema in [JSON schema](https://json-schema.org/)
* [`prisma-json-types-generator`](https://github.com/arthurfiorette/prisma-json-types-generator): Enhances `prisma-client-js` (or `prisma-client`) to provide strongly typed JSON fields for all databases, based on your schema. It improves code generation, Intellisense, and more, without affecting runtime code.
* [`typegraphql-prisma`](https://github.com/MichalLytek/typegraphql-prisma#readme): Generates [TypeGraphQL](https://typegraphql.com/) CRUD resolvers for Prisma models
* [`typegraphql-prisma-nestjs`](https://github.com/EndyKaufman/typegraphql-prisma-nestjs#readme): Fork of [`typegraphql-prisma`](https://github.com/MichalLytek/typegraphql-prisma), which also generates CRUD resolvers for Prisma models but for NestJS
* [`prisma-typegraphql-types-gen`](https://github.com/YassinEldeeb/prisma-tgql-types-gen): Generates [TypeGraphQL](https://typegraphql.com/) class types and enums from your prisma type definitions, the generated output can be edited without being overwritten by the next gen and has the ability to correct you when you mess up the types with your edits.
* [`nexus-prisma`](https://github.com/prisma/nexus-prisma/): Allows for projecting Prisma models to GraphQL via [GraphQL Nexus](https://nexusjs.org/docs/)
* [`prisma-nestjs-graphql`](https://github.com/unlight/prisma-nestjs-graphql): Generates object types, inputs, args, etc. from the Prisma Schema for usage with `@nestjs/graphql` module
* [`prisma-appsync`](https://github.com/maoosi/prisma-appsync): Generates a full-blown GraphQL API for [AWS AppSync](https://aws.amazon.com/appsync/)
* [`prisma-kysely`](https://github.com/valtyr/prisma-kysely): Generates type definitions for Kysely, a TypeScript SQL query builder. This can be useful to perform queries against your database from an edge runtime, or to write more complex SQL queries not possible in Prisma without dropping type safety.
* [`prisma-generator-nestjs-dto`](https://github.com/vegardit/prisma-generator-nestjs-dto): Generates DTO and Entity classes with relation `connect` and `create` options for use with [NestJS Resources](https://docs.nestjs.com/recipes/crud-generator) and [@nestjs/swagger](https://www.npmjs.com/package/@nestjs/swagger)
* [`prisma-erd-generator`](https://github.com/keonik/prisma-erd-generator): Generates an entity relationship diagram
* [`prisma-generator-plantuml-erd`](https://github.com/dbgso/prisma-generator-plantuml-erd/tree/main/packages/generator): Generator to generate ER diagrams for PlantUML. Markdown and Asciidoc documents can also be generated by activating the option.
* [`prisma-class-generator`](https://github.com/kimjbstar/prisma-class-generator): Generates classes from your Prisma Schema that can be used as DTO, Swagger Response, TypeGraphQL and so on.
* [`zod-prisma`](https://github.com/CarterGrimmeisen/zod-prisma): Creates Zod schemas from your Prisma models.
* [`prisma-pothos-types`](https://github.com/hayes/pothos/tree/main/packages/plugin-prisma): Makes it easier to define Prisma-based object types, and helps solve n+1 queries for relations. It also has integrations for the Relay plugin to make defining nodes and connections easy and efficient.
* [`prisma-generator-pothos-codegen`](https://github.com/Cauen/prisma-generator-pothos-codegen): Auto generate input types (for use as args) and auto generate decoupled type-safe base files makes it easy to create customizable objects, queries and mutations for [Pothos](https://pothos-graphql.dev/) from Prisma schema. Optionally generate all crud at once from the base files.
* [`prisma-joi-generator`](https://github.com/omar-dulaimi/prisma-joi-generator): Generate full Joi schemas from your Prisma schema.
* [`prisma-yup-generator`](https://github.com/omar-dulaimi/prisma-yup-generator): Generate full Yup schemas from your Prisma schema.
* [`prisma-class-validator-generator`](https://github.com/omar-dulaimi/prisma-class-validator-generator): Emit TypeScript models from your Prisma schema with class validator validations ready.
* [`prisma-zod-generator`](https://github.com/omar-dulaimi/prisma-zod-generator): Emit Zod schemas from your Prisma schema.
* [`prisma-trpc-generator`](https://github.com/omar-dulaimi/prisma-trpc-generator): Emit fully implemented tRPC routers.
* [`prisma-json-server-generator`](https://github.com/omar-dulaimi/prisma-json-server-generator): Emit a JSON file that can be run with json-server.
* [`prisma-trpc-shield-generator`](https://github.com/omar-dulaimi/prisma-trpc-shield-generator): Emit a tRPC shield from your Prisma schema.
* [`prisma-custom-models-generator`](https://github.com/omar-dulaimi/prisma-custom-models-generator): Emit custom models from your Prisma schema, based on Prisma recommendations.
* [`nestjs-prisma-graphql-crud-gen`](https://github.com/mk668a/nestjs-prisma-graphql-crud-gen): Generate CRUD resolvers from GraphQL schema with NestJS and Prisma.
* [`prisma-generator-dart`](https://github.com/FredrikBorgstrom/abcx3/tree/master/libs/prisma-generator-dart): Generates Dart/Flutter class files with to- and fromJson methods.
* [`prisma-generator-graphql-typedef`](https://github.com/mavvy22/prisma-generator-graphql-typedef): Generates graphql schema.
* [`prisma-markdown`](https://github.com/samchon/prisma-markdown): Generates markdown document composed with ERD diagrams and their descriptions. Supports pagination of ERD diagrams through `@namespace` comment tag.
* [`prisma-models-graph`](https://github.com/dangchinh25/prisma-models-graph): Generates a bi-directional models graph for schema without strict relationship defined in the schema, works via a custom schema annotation.
* [`prisma-generator-fake-data`](https://github.com/luisrudge/prisma-generator-fake-data): Generates realistic-looking fake data for your Prisma models that can be used in unit/integration tests, demos, and more.
* [`prisma-generator-drizzle`](https://github.com/farreldarian/prisma-generator-drizzle): A Prisma generator for generating Drizzle schema with ease.
* [`prisma-generator-express`](https://github.com/multipliedtwice/prisma-generator-express): Generates Express CRUD and Router generator function.
* [`prismabox`](https://github.com/m1212e/prismabox): Generates versatile [typebox](https://github.com/sinclairzx81/typebox) schema from your Prisma models.
* [`prisma-generator-typescript-interfaces`](https://github.com/mogzol/prisma-generator-typescript-interfaces): Generates zero-dependency TypeScript interfaces from your Prisma schema.
* [`prisma-openapi`](https://github.com/nitzano/prisma-openapi): Generates OpenAPI schema from Prisma models.
* [`@lexmata/prisma-ent-generator`](https://github.com/Lexmata/prisma-ent-generator): Generates Go [Ent](https://entgo.io/) schema files from your Prisma schema.
* [`@lexmata/prisma-python-generator`](https://github.com/Lexmata/prisma-python-generator): Generates Python [Pydantic](https://docs.pydantic.dev/) model classes from your Prisma schema.
* [`@pegasusheavy/nestjs-prisma-graphql`](https://github.com/quinnjr/nestjs-prisma-graphql): Generates NestJS GraphQL types from your Prisma schema. ESM-first with support for Prisma 7+.

## Related pages

- [`Data sources`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/data-sources): Data sources enable Prisma to connect to your database. This page explains how to configure data sources in your Prisma schema
- [`Schema location`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/location): Documentation regarding proper location of Prisma Schema including default naming and multiple files.

# Overview of Prisma Schema (Prisma ORM v7) (/docs/orm/v7/prisma-schema/overview)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

The Prisma schema is the main method of configuration when using Prisma. It is typically called schema.prisma and contains your database connection and data model

Location: ORM > v7 > Prisma Schema > Overview of Prisma Schema

The Prisma Schema (or *schema* for short) is the main method of configuration for your Prisma ORM setup. It consists of the following parts:

* [**Data sources**](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/data-sources): Specify the details of the data sources Prisma ORM should connect to (e.g. a PostgreSQL database)
* [**Generators**](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators): Specifies what clients should be generated based on the data model (e.g. Prisma Client)
* [**Data model definition**](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models): Specifies your application [models](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#defining-models) (the shape of the data per data source) and their [relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations)

It is typically a single file called `schema.prisma` (or multiple files with `.prisma` file extension) that is stored in a defined but customizable [location](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/location). You can also [organize your Prisma schema in multiple files](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/location#multi-file-prisma-schema) if you prefer that.

See the [Prisma schema API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) <span class="api" /> for detailed information about each section of the schema.

Whenever a `prisma` command is invoked, the CLI typically reads some information from the schema, e.g.:

* `prisma generate`: Reads *all* above mentioned information from the Prisma schema to generate the correct data source client code (e.g. Prisma Client).
* `prisma migrate dev`: Reads the data sources and data model definition to create a new migration.

You can also [use environment variables](#accessing-environment-variables-from-the-schema) inside the schema to provide configuration options when a CLI command is invoked.

## Example [#example]

The following is an example of a Prisma Schema that specifies:

* A data source (PostgreSQL or MongoDB)
* A generator (Prisma Client)
* A data model definition with two models (with one relation) and one `enum`
* Several [native data type attributes](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#native-types-mapping) (`@db.VarChar(255)`, `@db.ObjectId`)

  

#### Relational Databases

```prisma
datasource db {
  provider = "postgresql"
}

generator client {
  provider = "prisma-client"
  output   = "./generated"
}

model User {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  email     String   @unique
  name      String?
  role      Role     @default(USER)
  posts     Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  published Boolean  @default(false)
  title     String   @db.VarChar(255)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

enum Role {
  USER
  ADMIN
}
```

#### MongoDB

```prisma
datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id        String   @id @default(auto()) @map("_id") @db.ObjectId
  createdAt DateTime @default(now())
  email     String   @unique
  name      String?
  role      Role     @default(USER)
  posts     Post[]
}

model Post {
  id        String   @id @default(auto()) @map("_id") @db.ObjectId
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  published Boolean  @default(false)
  title     String
  author    User     @relation(fields: [authorId], references: [id])
  authorId  String   @db.ObjectId
}

enum Role {
  USER
  ADMIN
}
```

## Syntax [#syntax]

Prisma Schema files are written in Prisma Schema Language (PSL). See the [data sources](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/data-sources), [generators](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators), [data model definition](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models) and [Prisma Schema API reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) pages for details and examples.

### VS Code [#vs-code]

Syntax highlighting for PSL is available via a [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) (which also lets you auto-format the contents of your Prisma schema and indicates syntax errors with red squiggly lines). Learn more about [setting up Prisma ORM in your editor](https://www.prisma.io/docs/orm/v7/more/dev-environment/editor-setup).

### GitHub [#github]

PSL code snippets on GitHub can be rendered with syntax highlighting as well by using the `.prisma` file extension or annotating fenced code blocks in Markdown with `prisma`:

````mdx
```prisma
model User {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  email     String   @unique
  name      String?
}
```
````

## Accessing environment variables from the schema [#accessing-environment-variables-from-the-schema]

You can use environment variables to provide configuration options when a CLI command is invoked, or a Prisma Client query is run.

Hardcoding URLs directly in your schema is possible but is discouraged because it poses a security risk. Using environment variables in the schema allows you to **keep secrets out of the schema** which in turn **improves the portability of the schema** by allowing you to use it in different environments.

Environment variables can be accessed using the `env()` function:

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

You can use the `env()` function in the following places:

* A datasource url
* Generator binary targets

See [Environment variables](https://www.prisma.io/docs/orm/v7/more/dev-environment/environment-variables) for more information about how to use an `.env` file during development.

## Comments [#comments]

There are three types of comments that are supported in Prisma Schema Language:

* `// comment`: This comment is for the reader's clarity and is not present in the abstract syntax tree (AST) of the schema.
* `/// comment`: These comments will show up in the abstract syntax tree (AST) of the schema as descriptions to AST nodes. Tools can then use these comments to provide additional information. All comments are attached to the next available node - [free-floating comments](https://github.com/prisma/orm/issues/3544) are not supported and are not included in the AST.
* `/* block comment */`: These comments will show up in the abstract syntax tree, similarly to `///` comments.

Here are some different examples:

```prisma
/// This comment will get attached to the `User` node in the AST
model User {
  /// This comment will get attached to the `id` node in the AST
  id     Int   @default(autoincrement())
  // This comment is just for you
  weight Float /// This comment gets attached to the `weight` node
}

// This comment is just for you. It will not
// show up in the AST.

/// This comment will get attached to the
/// Customer node.
model Customer {
  /**
   * ...and so will this comment
   */
}
```

## Auto formatting [#auto-formatting]

Prisma ORM supports formatting `.prisma` files automatically. There are two ways to format `.prisma` files:

* Run the [`prisma format`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#format) <span class="api" /> command.
* Install the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) and invoke the [VS Code format action](https://code.visualstudio.com/docs/editor/codebasics#_formatting) - manually or on save.

There are no configuration options - [formatting rules](#formatting-rules) are fixed (similar to Golang's `gofmt` but unlike Javascript's `prettier`):

### Formatting rules [#formatting-rules]

#### Configuration blocks are aligned by their = sign [#configuration-blocks-are-aligned-by-theirsign]

```prisma
block _ {
  key      = "value"
  key2     = 1
  long_key = true
}
```

#### Field definitions are aligned into columns separated by 2 or more spaces [#field-definitions-are-aligned-into-columns-separated-by-2-or-more-spaces]

```prisma
block _ {
  id          String       @id
  first_name  LongNumeric  @default
}
```

#### Empty lines resets block alignment and formatting rules [#empty-lines-resets-block-alignment-and-formatting-rules]

```prisma
block _ {
  key   = "value"
  key2  = 1
  key10 = true

  long_key   = true
  long_key_2 = true
}
```

```prisma
block _ {
  id  String  @id
              @default

  first_name  LongNumeric  @default
}
```

#### Multiline field attributes keep the alignment of the rest of the field attributes [#multiline-field-attributes-keep-the-alignment-of-the-rest-of-the-field-attributes]

```prisma
block _ {
  id          String       @id
                           @default
  first_name  LongNumeric  @default
}
```

#### Block attributes are sorted to the end of the block [#block-attributes-are-sorted-to-the-end-of-the-block]

```prisma
block _ {
  key   = "value"

  @@attribute
}
```

## Related pages

- [`PostgreSQL extensions`](https://www.prisma.io/docs/orm/v7/prisma-schema/postgresql-extensions): How to install and manage PostgreSQL extensions with Prisma ORM using customized migrations, and how to use them in Prisma Client
- [`What is introspection?`](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection): Learn how you can introspect your database to generate a data model into your Prisma schema

# Schema location (Prisma ORM v7) (/docs/orm/v7/prisma-schema/overview/location)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Documentation regarding proper location of Prisma Schema including default naming and multiple files.

Location: ORM > v7 > Prisma Schema > Overview > Schema location

The default name for the Prisma Schema is a single file `schema.prisma` in your `prisma` folder. When your schema is named like this, the Prisma CLI will detect it automatically.

## Prisma Schema location [#prisma-schema-location]

The Prisma CLI looks for the Prisma Schema in the following locations, in the following order:

1. The location specified by the [`--schema` flag](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference), which is available when you `introspect`, `generate`, `migrate`, and `studio`:

   ```bash
   prisma generate --schema=./alternative/schema.prisma
   ```

2. The location specified in the `prisma.config.ts` file:

   ```ts title="prisma.config.ts"
   import { defineConfig } from "prisma/config";

   export default defineConfig({
     schema: "prisma/",
     ...
   });
   ```

3. Default locations:
   * `./prisma/schema.prisma`
   * `./schema.prisma`

The Prisma CLI outputs the path of the schema that will be used. The following example shows the terminal output for `prisma db pull`:

```text
Environment variables loaded from .env
Prisma Schema loaded from prisma/schema.prisma

Introspecting based on datasource defined in prisma/schema.prisma …

✔ Introspected 4 models and wrote them into prisma/schema.prisma in 239ms

Run prisma generate to generate Prisma Client.
```

## Multi-file Prisma schema [#multi-file-prisma-schema]

### Watch video: Multi-file Prisma schema

[How to organize and use a multi-file Prisma schema](https://www.youtube.com/watch?v=yGgoP2KK8Bo)

If you prefer splitting your Prisma schema into multiple files, you can have a setup that looks as follows:

```
prisma/
├── migrations
├── models
│   ├── posts.prisma
│   ├── users.prisma
│   └── ... other `.prisma` files
└── schema.prisma
```

### Usage [#usage]

When using a multi-file Prisma schema, you must always explicitly specify the location of the directory that contains your schema files (including the main `schema.prisma` file with your `generator` block).

You can do this in two ways:

* pass the `--schema` option to your Prisma CLI command (e.g. `prisma migrate dev --schema ./prisma`)
* set the `schema` property in [`prisma.config.ts`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference#schema) (for Prisma ORM v7):

  ```ts title="prisma.config.ts"
  import { defineConfig, env } from "prisma/config";
  import "dotenv/config";

  export default defineConfig({
    schema: "prisma/",
    migrations: {
      path: "prisma/migrations",
      seed: "tsx prisma/seed.ts",
    },
    datasource: {
      url: env("DATABASE_URL"),
    },
  });
  ```

> [!NOTE]
> We recommend using the [Prisma Config file](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference#schema) to specify the location of your Prisma schema. This is the most flexible way to specify the location of your Prisma schema alongside other configuration options.

> [!WARNING]
> The `schema.prisma` file (which contains your `generator` block) must be located in the same directory that you specify in your schema configuration. For example, if you configure `schema: 'prisma'`, your `schema.prisma` file must be at `prisma/schema.prisma`, not in a subdirectory like `prisma/models/schema.prisma`.

You must also place the `migrations` directory at the same level as your `schema.prisma` file.

For example, assuming `schema.prisma` defines the `generator` block, here's the correct directory structure:

```
# All files must be inside the `prisma/` directory
# `migrations` and `schema.prisma` must be at the same level
prisma/
├── migrations
├── models
│   ├── posts.prisma
│   └── users.prisma
└── schema.prisma  # Contains generator block
```

> [!NOTE]
> If your schema files are in a `prisma/` directory (as shown above), the Prisma CLI commands like `prisma generate` and `prisma migrate dev` will work without additional configuration, as `./prisma/schema.prisma` is a default location.

### Tips for multi-file Prisma Schema [#tips-for-multi-file-prisma-schema]

We've found that a few patterns work well with this feature and will help you get the most out of it:

* Organize your files by domain: group related models into the same file. For example, keep all user-related models in `user.prisma` while post-related models go in `post.prisma`.
* Use clear naming conventions: schema files should be named clearly and succinctly. Use names like `user.prisma` and `post.prisma` and not `myModels.prisma` or `CommentFeaturesSchema.prisma`.
* Have an obvious "main" schema file: while you can now have as many schema files as you want, you'll still need a place where you define your `generator` block. We recommend having a single schema file that's obviously the "main" file so that this block is easy to find. `main.prisma`, `schema.prisma`, and `base.prisma` are a few we've seen that work well.

## Related pages

- [`Data sources`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/data-sources): Data sources enable Prisma to connect to your database. This page explains how to configure data sources in your Prisma schema
- [`Generators`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators): Generators in your Prisma schema specify what assets are generated when the `prisma generate` command is invoked. This page explains how to configure generators

# Prisma Error Reference (Prisma ORM v7) (/docs/orm/v7/reference/errors)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Common Prisma ORM errors and how to troubleshoot them

Location: ORM > v7 > Reference > Prisma Error Reference

This section provides information about common errors you might encounter when using Prisma ORM and how to resolve them.

## Error Categories [#error-categories]

### Prisma Client Errors [#prisma-client-errors]

* [**Connection Pool Issues**](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool) - Troubleshoot connection pooling problems

### Prisma Migrate Errors [#prisma-migrate-errors]

* [**Migration Overview**](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/mental-model) - Understanding migration concepts
* [**Shadow Database Issues**](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/shadow-database) - Troubleshoot shadow database problems
* [**Baselining Issues**](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/baselining) - Issues with baseline migrations

### MongoDB Errors [#mongodb-errors]

* [**Replica Set Configuration**](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb) - MongoDB replica set requirements

## Full Error Reference [#full-error-reference]

For a complete list of error codes and their meanings, see the [Error Reference](https://www.prisma.io/docs/orm/v7/reference/error-reference).

## Related pages

- [`Config API`](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference): Complete reference for prisma.config.ts configuration options
- [`Connection URLs`](https://www.prisma.io/docs/orm/v7/reference/connection-urls): Learn about the format and syntax Prisma ORM uses for defining database connection URLs for PostgreSQL, MySQL and SQLite
- [`Database Features`](https://www.prisma.io/docs/orm/v7/reference/database-features): Database features supported in Prisma ORM
- [`Environment Variables`](https://www.prisma.io/docs/orm/v7/reference/environment-variables-reference): Reference for Prisma environment variables
- [`Error Reference`](https://www.prisma.io/docs/orm/v7/reference/error-reference): Prisma Client, Migrate, and Introspection error codes

# Prisma CLI Preview features (Prisma ORM v7) (/docs/orm/v7/reference/preview-features/cli-preview-features)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma CLI features that are currently in Preview.

Location: ORM > v7 > Reference > Preview Features > Prisma CLI Preview features

When we release a new Prisma CLI feature, it often starts in Preview so that you can test it and submit your feedback. After we improve the feature with your feedback and are satisfied with the internal test results, we promote the feature to general availability.

For more information, see [ORM releases and maturity levels](https://www.prisma.io/docs/orm/v7/more/releases).

## Currently active Preview features [#currently-active-preview-features]

There are currently no [Preview](https://www.prisma.io/docs/orm/v7/more/releases#preview) features for Prisma CLI.

## Preview features promoted to general availability [#preview-features-promoted-to-general-availability]

In the list below, you can find a history of Prisma CLI features that were in Preview and are now in general availability. The features are sorted by the most recent version in which they were promoted to general availability.

| Features                                                                                                                                   | Released in Preview                                         | Released in general availability                            |
| ------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | ----------------------------------------------------------- |
| [`prisma migrate diff`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing#fixing-failed-migrations-with-migrate-diff-and-db-execute) | [3.9.0](https://github.com/prisma/orm/releases/tag/3.9.0)   | [3.13.0](https://github.com/prisma/orm/releases/tag/3.13.0) |
| [`prisma db execute`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/patching-and-hotfixing#fixing-failed-migrations-with-migrate-diff-and-db-execute)   | [3.9.0](https://github.com/prisma/orm/releases/tag/3.9.0)   | [3.13.0](https://github.com/prisma/orm/releases/tag/3.13.0) |
| [`prisma db push`](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/prototyping-your-schema)                                                               | [2.10.0](https://github.com/prisma/orm/releases/tag/2.10.0) | [2.22.0](https://github.com/prisma/orm/releases/tag/2.22.0) |
| [`prisma migrate`](https://www.prisma.io/docs/orm/v7/prisma-migrate)                                                                                                 | [2.13.0](https://github.com/prisma/orm/releases/tag/2.13.0) | [2.19.0](https://github.com/prisma/orm/releases/tag/2.19.0) |

## Related pages

- [`Prisma Client & Prisma schema`](https://www.prisma.io/docs/orm/v7/reference/preview-features/client-preview-features): Prisma Client and Prisma schema features that are currently in Preview

# Prisma Client & Prisma schema (Prisma ORM v7) (/docs/orm/v7/reference/preview-features/client-preview-features)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma Client and Prisma schema features that are currently in Preview

Location: ORM > v7 > Reference > Preview Features > Prisma Client & Prisma schema

When we release a new Prisma Client or Prisma schema feature, it often starts in Preview so that you can test it and submit your feedback. After we improve the feature with your feedback and are satisfied with the internal test results, we promote the feature to general availability.

For more information, see [ORM releases and maturity levels](https://www.prisma.io/docs/orm/v7/more/releases).

## Currently active Preview features [#currently-active-preview-features]

The following [Preview](https://www.prisma.io/docs/orm/v7/more/releases#preview) feature flags are available for Prisma Client and Prisma schema:

| Feature                                                                    | Released into Preview                                       |                           Feedback issue                           |
| -------------------------------------------------------------------------- | :---------------------------------------------------------- | :----------------------------------------------------------------: |
| [`views`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/views)                          | [4.9.0](https://github.com/prisma/orm/releases/tag/4.9.0)   |    [Submit feedback](https://github.com/prisma/orm/issues/17335)   |
| `relationJoins`                                                            | [5.7.0](https://github.com/prisma/orm/releases/tag/5.7.0)   | [Submit feedback](https://github.com/prisma/orm/discussions/22288) |
| `nativeDistinct`                                                           | [5.7.0](https://github.com/prisma/orm/releases/tag/5.7.0)   | [Submit feedback](https://github.com/prisma/orm/discussions/22287) |
| `typedSql`                                                                 | [5.19.0](https://github.com/prisma/orm/releases/tag/5.19.0) | [Submit feedback](https://github.com/prisma/orm/discussions/25106) |
| `strictUndefinedChecks`                                                    | [5.20.0](https://github.com/prisma/orm/releases/tag/5.20.0) | [Submit feedback](https://github.com/prisma/orm/discussions/25271) |
| [`fullTextSearchPostgres`](https://www.prisma.io/docs/orm/v6/prisma-client/queries/full-text-search) | [6.0.0](https://github.com/prisma/orm/releases/tag/6.0.0)   |    [Submit feedback](https://github.com/prisma/orm/issues/25773)   |
| `shardKeys`                                                                | [6.10.0](https://pris.ly/release/6.10.0)                    |      [Submit feedback](https://github.com/prisma/orm/issues/)      |
| [`partialIndexes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes)               | [7.4.0](https://pris.ly/release/7.4.0)                      |    [Submit feedback](https://github.com/prisma/orm/issues/6974)    |

To enable a Preview feature, [add the feature flag to the `generator` block](#enabling-a-prisma-client-preview-feature) in your `schema.prisma` file. [Share your feedback on all Preview features on GitHub](https://github.com/prisma/orm/issues/3108).

## Enabling a Prisma Client Preview feature [#enabling-a-prisma-client-preview-feature]

To enable a Prisma Client Preview feature:

1. Add the Preview feature flag to the `generator` block:

   ```prisma
   generator client {
     provider        = "prisma-client"
     output          = "./generated"
     previewFeatures = ["relationJoins"]
   }
   ```

2. Re-generate Prisma Client:

   
     

#### bun

```bash
bunx prisma generate
```

#### pnpm

```bash
pnpm prisma generate
```

#### yarn

```bash
yarn prisma generate
```

#### npm

```bash
npx prisma generate
```
   

3. If you are using Visual Studio Code and the Preview feature is not available in your `.ts` file after generating Prisma Client, run the **TypeScript: Restart TS server** command.

## Preview features promoted to General Availability [#preview-features-promoted-to-general-availability]

In the list below, you can find a history of Prisma Client and Prisma schema features that were in Preview and are now in general availability. The features are sorted by the most recent version in which they were promoted to general availability.

| Feature                                                                                                                       | Released into Preview                                                                                                                                                                                                                                                                                                                                                                                           | Released into General Availability                                                                                                              |
| ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| [`driverAdapters`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers#driver-adapters)                                | [5.4.0](https://github.com/prisma/orm/releases/tag/5.4.0)                                                                                                                                                                                                                                                                                                                                                       | [6.16.0](https://github.com/prisma/orm/releases/tag/6.16.0)                                                                                     |
| [`multiSchema`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema)                                                                | [4.3.0](https://github.com/prisma/orm/releases/tag/4.3.0)                                                                                                                                                                                                                                                                                                                                                       | [6.13.0](https://github.com/prisma/orm/releases/tag/6.13.0)                                                                                     |
| [`prismaSchemaFolder`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/location#multi-file-prisma-schema)                                      | [5.15.0](https://github.com/prisma/orm/releases/tag/5.15.0)                                                                                                                                                                                                                                                                                                                                                     | [6.7.0](https://pris.ly/release/6.7.0)                                                                                                          |
| `omitApi`                                                                                                                     | [5.13.0](https://github.com/prisma/orm/releases/tag/5.13.0)                                                                                                                                                                                                                                                                                                                                                     | [6.2.0](https://github.com/prisma/orm/releases/tag/6.2.0)                                                                                       |
| `jsonProtocol`                                                                                                                | [4.11.0](https://github.com/prisma/orm/releases/tag/4.11.0)                                                                                                                                                                                                                                                                                                                                                     | [5.0.0](https://github.com/prisma/orm/releases/tag/5.0.0)                                                                                       |
| [`extendedWhereUnique`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#filter-on-non-unique-fields-with-userwhereuniqueinput)      | [4.5.0](https://github.com/prisma/orm/releases/tag/4.5.0)                                                                                                                                                                                                                                                                                                                                                       | [5.0.0](https://github.com/prisma/orm/releases/tag/5.0.0)                                                                                       |
| [`fieldReference`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#compare-columns-in-the-same-table)                               | [4.3.0](https://github.com/prisma/orm/releases/tag/4.3.0)                                                                                                                                                                                                                                                                                                                                                       | [5.0.0](https://github.com/prisma/orm/releases/tag/5.0.0)                                                                                       |
| [`clientExtensions`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions)                                                                 | [4.7.0](https://github.com/prisma/orm/releases/tag/4.7.0)                                                                                                                                                                                                                                                                                                                                                       | [4.16.0](https://github.com/prisma/orm/releases/tag/4.16.0)                                                                                     |
| [`filteredRelationCount`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#filter-the-relation-count)           | [4.3.0](https://github.com/prisma/orm/releases/tag/4.3.0)                                                                                                                                                                                                                                                                                                                                                       | [4.16.0](https://github.com/prisma/orm/releases/tag/4.16.0)                                                                                     |
| [`tracing`](https://www.prisma.io/docs/orm/v7/prisma-client/observability-and-logging/opentelemetry-tracing)                                            | [4.2.0](https://github.com/prisma/orm/releases/tag/4.2.0)                                                                                                                                                                                                                                                                                                                                                       | [6.1.0](https://github.com/prisma/orm/releases/tag/6.1.0)                                                                                       |
| [`orderByNulls`](https://www.prisma.io/docs/orm/v6/prisma-client/queries/filtering-and-sorting#sort-with-null-records-first-or-last)                    | [4.1.0](https://github.com/prisma/orm/releases/tag/4.1.0)                                                                                                                                                                                                                                                                                                                                                       | [4.16.0](https://github.com/prisma/orm/releases/tag/4.16.0)                                                                                     |
| [`referentialIntegrity`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode)                                            | [3.1.1](https://github.com/prisma/orm/releases/tag/3.1.1)                                                                                                                                                                                                                                                                                                                                                       | [4.7.0](https://github.com/prisma/orm/releases/tag/4.7.0)                                                                                       |
| [`interactiveTransactions`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#interactive-transactions)                              | [2.29.0](https://github.com/prisma/orm/releases/tag/2.29.0)                                                                                                                                                                                                                                                                                                                                                     | [4.7.0](https://github.com/prisma/orm/releases/tag/4.7.0)<br />with Prisma Accelerate [5.1.1](https://github.com/prisma/orm/releases/tag/5.1.1) |
| [`extendedIndexes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes)                                                                 | [3.5.0](https://github.com/prisma/orm/releases/tag/3.5.0)                                                                                                                                                                                                                                                                                                                                                       | [4.0.0](https://github.com/prisma/orm/releases/tag/4.0.0)                                                                                       |
| [`filterJson`](https://www.prisma.io/docs/orm/v7/prisma-client/special-fields-and-types/working-with-json-fields#filter-on-a-json-field-simple)         | [2.23.0](https://github.com/prisma/orm/releases/tag/2.23.0)                                                                                                                                                                                                                                                                                                                                                     | [4.0.0](https://github.com/prisma/orm/releases/tag/4.0.0)                                                                                       |
| [`improvedQueryRaw`](https://www.prisma.io/docs/orm/v7/prisma-client/using-raw-sql/raw-queries#raw-query-type-mapping)                                  | [3.14.0](https://github.com/prisma/orm/releases/tag/3.14.0)                                                                                                                                                                                                                                                                                                                                                     | [4.0.0](https://github.com/prisma/orm/releases/tag/4.0.0)                                                                                       |
| [`cockroachdb`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#cockroachdb)                                             | [3.9.0](https://github.com/prisma/orm/releases/tag/3.9.0)<br />migrations in [3.11.0](https://github.com/prisma/orm/releases/tag/3.11.0)                                                                                                                                                                                                                                                                        | [3.14.0](https://github.com/prisma/orm/releases/tag/3.14.0)                                                                                     |
| [`mongodb`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mongodb)                                                                | [2.27.0](https://github.com/prisma/orm/releases/tag/2.27.0)<br />introspection in [3.2.0](https://github.com/prisma/orm/releases/tag/3.2.0)<br />embedded docs in [3.4.0](https://github.com/prisma/orm/releases/tag/3.4.0)<br />raw queries in [3.9.0](https://github.com/prisma/orm/releases/tag/3.9.0)<br />filters/ordering in embedded docs in [3.11.0](https://github.com/prisma/orm/releases/tag/3.11.0) | [3.12.0](https://github.com/prisma/orm/releases/tag/3.12.0)                                                                                     |
| [`microsoftSqlServer`](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server)                                                  | [2.10.0](https://github.com/prisma/orm/releases/tag/2.10.0)                                                                                                                                                                                                                                                                                                                                                     | [3.0.1](https://github.com/prisma/orm/releases/tag/3.0.1)                                                                                       |
| [`namedConstraints`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping#constraint-and-index-names)                            | [2.29.0](https://github.com/prisma/orm/releases/tag/2.29.0)                                                                                                                                                                                                                                                                                                                                                     | [3.0.1](https://github.com/prisma/orm/releases/tag/3.0.1)                                                                                       |
| [`referentialActions`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions)                                        | [2.26.0](https://github.com/prisma/orm/releases/tag/2.26.0)                                                                                                                                                                                                                                                                                                                                                     | [3.0.1](https://github.com/prisma/orm/releases/tag/3.0.1)                                                                                       |
| [`orderByAggregateGroup`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#order-by-aggregate-group)            | [2.21.0](https://github.com/prisma/orm/releases/tag/2.21.0)                                                                                                                                                                                                                                                                                                                                                     | [3.0.1](https://github.com/prisma/orm/releases/tag/3.0.1)                                                                                       |
| [`orderByRelation`](https://www.prisma.io/docs/orm/v6/prisma-client/queries/filtering-and-sorting#sort-by-relation)                                     | [2.16.0](https://github.com/prisma/orm/releases/tag/2.16.0)<br />aggregates in [2.19.0](https://github.com/prisma/orm/releases/tag/2.19.0)                                                                                                                                                                                                                                                                      | [3.0.1](https://github.com/prisma/orm/releases/tag/3.0.1)                                                                                       |
| [`selectRelationCount`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#count-relations)                       | [2.20.0](https://github.com/prisma/orm/releases/tag/2.20.0)                                                                                                                                                                                                                                                                                                                                                     | [3.0.1](https://github.com/prisma/orm/releases/tag/3.0.1)                                                                                       |
| `napi`                                                                                                                        | [2.20.0](https://github.com/prisma/orm/releases/tag/2.20.0)                                                                                                                                                                                                                                                                                                                                                     | [3.0.1](https://github.com/prisma/orm/releases/tag/3.0.1)                                                                                       |
| [`groupBy`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#groupby)                                                                | [2.14.0](https://github.com/prisma/orm/releases/tag/2.14.0)                                                                                                                                                                                                                                                                                                                                                     | [2.20.0](https://github.com/prisma/orm/releases/tag/2.20.0)                                                                                     |
| [`createMany`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#createmany)                                                          | [2.16.0](https://github.com/prisma/orm/releases/tag/2.16.0)                                                                                                                                                                                                                                                                                                                                                     | [2.20.0](https://github.com/prisma/orm/releases/tag/2.20.0)                                                                                     |
| [`nativeTypes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#native-types-mapping)                                                 | [2.11.0](https://github.com/prisma/orm/releases/tag/2.11.0)                                                                                                                                                                                                                                                                                                                                                     | [2.17.0](https://github.com/prisma/orm/releases/tag/2.17.0)                                                                                     |
| [`uncheckedScalarInputs`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#create-a-single-record-and-multiple-related-records) | [2.11.0](https://github.com/prisma/orm/releases/tag/2.11.0)                                                                                                                                                                                                                                                                                                                                                     | [2.15.0](https://github.com/prisma/orm/releases/tag/2.15.0)                                                                                     |
| [`transactionApi`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#the-transaction-api)                                            | [2.1.0](https://github.com/prisma/orm/releases/tag/2.1.0)                                                                                                                                                                                                                                                                                                                                                       | [2.11.0](https://github.com/prisma/orm/releases/tag/2.11.0)                                                                                     |
| [`connectOrCreate`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#connectorcreate)                                                | [2.1.0](https://github.com/prisma/orm/releases/tag/2.1.0)                                                                                                                                                                                                                                                                                                                                                       | [2.11.0](https://github.com/prisma/orm/releases/tag/2.11.0)                                                                                     |
| [`atomicNumberOperations`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#atomic-number-operations)                                | [2.6.0](https://github.com/prisma/orm/releases/tag/2.6.0)                                                                                                                                                                                                                                                                                                                                                       | [2.10.0](https://github.com/prisma/orm/releases/tag/2.10.0)                                                                                     |
| [`insensitiveFilters` (PostgreSQL)](https://www.prisma.io/docs/orm/v6/prisma-client/queries/filtering-and-sorting#case-insensitive-filtering)           | [2.5.0](https://github.com/prisma/orm/releases/tag/2.5.0)                                                                                                                                                                                                                                                                                                                                                       | [2.8.0](https://github.com/prisma/orm/releases/tag/2.8.0)                                                                                       |
| [`aggregateApi`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/aggregation-grouping-summarizing#aggregate)                                    | [2.2.0](https://github.com/prisma/orm/releases/tag/2.2.0)                                                                                                                                                                                                                                                                                                                                                       | [2.5.0](https://github.com/prisma/orm/releases/tag/2.5.0)                                                                                       |
| [`distinct`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#distinct)                                                              | [2.3.0](https://github.com/prisma/orm/releases/tag/2.3.0)                                                                                                                                                                                                                                                                                                                                                       | [2.5.0](https://github.com/prisma/orm/releases/tag/2.5.0)                                                                                       |

## Related pages

- [`Prisma CLI Preview features`](https://www.prisma.io/docs/orm/v7/reference/preview-features/cli-preview-features): Prisma CLI features that are currently in Preview.

# Shared Prisma Client extensions (Prisma ORM v7) (/docs/orm/v7/prisma-client/client-extensions/shared-extensions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Share extensions or import shared extensions into your Prisma project

Location: ORM > v7 > Prisma Client > Client Extensions > Shared Prisma Client extensions

> [!NOTE]
> Using Prisma 8?
> 
> Prisma 8 replaces Client extensions with [extensions](https://www.prisma.io/docs/orm/extensions) that add database capabilities and [middleware](https://www.prisma.io/docs/orm/middleware/how-middleware-works) that wraps every query. Browse both in the [extension directory](https://www.prisma.io/extensions).

You can share your [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions) with other users, either as packages or as modules, and import extensions that other users create into your project.

If you would like to build a shareable extension, we also recommend using the [`prisma-client-extension-starter`](https://github.com/prisma/prisma-client-extension-starter) template.

To explore examples of Prisma's official Client extensions and those made by the community, visit [Shared packages & examples](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/extension-examples).

## Install a shared, packaged extension [#install-a-shared-packaged-extension]

In your project, you can install any Prisma Client extension that another user has published to `npm`. To do so, run the following command:

  

#### bun

```bash
bun add prisma-extension-<package-name>
```

#### pnpm

```bash
pnpm add prisma-extension-<package-name>
```

#### yarn

```bash
yarn add prisma-extension-<package-name>
```

#### npm

```bash
npm install prisma-extension-<package-name>
```

For example, if the package name for an available extension is `prisma-extension-find-or-create`, you could install it as follows:

  

#### bun

```bash
bun add prisma-extension-find-or-create
```

#### pnpm

```bash
pnpm add prisma-extension-find-or-create
```

#### yarn

```bash
yarn add prisma-extension-find-or-create
```

#### npm

```bash
npm install prisma-extension-find-or-create
```

To import the `find-or-create` extension from the example above, and wrap your client instance with it, you could use the following code. This example assumes that the extension name is `findOrCreate`.

```ts
import findOrCreate from "prisma-extension-find-or-create";
import { PrismaClient } from "../generated/prisma/client";
const prisma = new PrismaClient();
const xprisma = prisma.$extends(findOrCreate);
const user = await xprisma.user.findOrCreate();
```

When you call a method in an extension, use the constant name from your `$extends` statement, not `prisma`. In the above example, `xprisma.user.findOrCreate` works, but `prisma.user.findOrCreate` does not, because the original `prisma` is not modified.

## Create a shareable extension [#create-a-shareable-extension]

When you want to create extensions other users can use, and that are not tailored just for your schema, Prisma ORM provides utilities to allow you to create shareable extensions.

To create a shareable extension:

1. Define the extension as a module using `Prisma.defineExtension`
2. Use one of the methods that begin with the `$all` prefix such as [`$allModels`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model#add-a-custom-method-to-all-models-in-your-schema) or [`$allOperations`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query#modify-all-prisma-client-operations)

### Define an extension [#define-an-extension]

Use the `Prisma.defineExtension` method to make your extension shareable. You can use it to package the extension to either separate your extensions into a separate file or share it with other users as an npm package.

The benefit of `Prisma.defineExtension` is that it provides strict type checks and auto completion for authors of extension in development and users of shared extensions.

### Use a generic method [#use-a-generic-method]

Extensions that contain methods under `$allModels` apply to every model instead of a specific one. Similarly, methods under `$allOperations` apply to a client instance as a whole and not to a named component, e.g. `result` or `query`.

You do not need to use the `$all` prefix with the [`client`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/client) component, because the `client` component always applies to the client instance.

For example, a generic extension might take the following form:

```ts
export default Prisma.defineExtension({
  name: "prisma-extension-find-or-create", //Extension name
  model: {
    $allModels: {
      // new method
      findOrCreate(/* args */) {
        /* code for the new method */
        return query(args);
      },
    },
  },
});
```

Refer to the following pages to learn the different ways you can modify Prisma Client operations:

* [Modify all Prisma Client operations](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query#modify-all-prisma-client-operations)
* [Modify a specific operation in all models of your schema](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query#modify-a-specific-operation-in-all-models-of-your-schema)
* [Modify all operations in all models of your schema](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query#modify-all-operations-in-all-models-of-your-schema)

### Publishing the shareable extension to npm [#publishing-the-shareable-extension-to-npm]

You can then share the extension on `npm`. When you choose a package name, we recommend that you use the `prisma-extension-<package-name>` convention, to make it easier to find and install.

### Call a client-level method from your packaged extension [#call-a-client-level-method-from-your-packaged-extension]

> [!WARNING]
> There's currently a limitation for extensions that reference a `PrismaClient` and call a client-level method, like the example below.
> 
> If you trigger the extension from inside a [transaction](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions) (interactive or batched), the extension code will issue the queries in a new connection and ignore the current transaction context.
> 
> Learn more in this issue on GitHub: [Client extensions that require use of a client-level method silently ignore transactions](https://github.com/prisma/orm/issues/20678).

In the following situations, you need to refer to a Prisma Client instance that your extension wraps:

* When you want to use a [client-level method](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#client-methods), such as `$queryRaw`, in your packaged extension.
* When you want to chain multiple `$extends` calls in your packaged extension.

However, when someone includes your packaged extension in their project, your code cannot know the details of the Prisma Client instance.

You can refer to this client instance as follows:

```ts
Prisma.defineExtension((client) => {
  // The Prisma Client instance that the extension user applies the extension to
  return client.$extends({
    name: "prisma-extension-<extension-name>",
  });
});
```

For example:

```ts
export default Prisma.defineExtension((client) => {
  return client.$extends({
    name: "prisma-extension-find-or-create",
    query: {
      $allModels: {
        async findOrCreate({ args, query, operation }) {
          return (await client.$transaction([query(args)]))[0];
        },
      },
    },
  });
});
```

### Advanced type safety: type utilities for defining generic extensions [#advanced-type-safety-type-utilities-for-defining-generic-extensions]

You can improve the type-safety of your shared extensions using [type utilities](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/type-utilities).

## Related pages

- [`Add custom fields and methods to query results`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/result): Extend the functionality of Prisma Client, result component
- [`Add custom methods to your models`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/model): Extend the functionality of Prisma Client, model component
- [`Add methods to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/client): Extend the functionality of Prisma Client, client component
- [`Create custom Prisma Client queries`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/query): Extend the functionality of Prisma Client, query component
- [`Shared packages & examples`](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions/extension-examples): Explore the Prisma Client extensions that have been built by Prisma and its community

# Fine-Grained Authorization (Permit) (Prisma ORM v7) (/docs/orm/v7/prisma-client/client-extensions/shared-extensions/permit-rbac)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to implement RBAC, ABAC, and ReBAC authorization in your Prisma applications

Location: ORM > v7 > Prisma Client > Client Extensions > Shared Extensions > Fine-Grained Authorization (Permit)

> [!NOTE]
> Quick summary
> 
> This page explains how to implement fine-grained authorization (FGA) in Prisma ORM applications using the `@permitio/permit-prisma` extension. It introduces the access control models supported by Permit.io (RBAC, ABAC, and ReBAC) and helps you choose the right model for your database operations.

Prisma ORM does not include built-in authorization. This guide shows how to implement fine-grained authorization in your Prisma applications using the `@permitio/permit-prisma` extension.

Fine-grained authorization (FGA) controls which records a user can read or modify. Without it, your application might expose sensitive data or allow unauthorized modifications.

## Access control models [#access-control-models]

This extension supports three access control models from Permit.io:

### Role-based Access Control (RBAC) [#role-based-access-control-rbac]

**What it is**: Users are assigned roles (Admin, Editor, Viewer) with predefined permissions to perform actions on resource types.

**Example**: An "Editor" role can update any document in the system.

**Best for**: Simple permission structures where access is determined by job function or user level.

### Attribute-Based Access Control (ABAC) [#attribute-based-access-control-abac]

**What it is**: Access decisions based on attributes of users, resources, or environment.

**Examples**:

* Allow access if `user.department == document.department`
* Allow updates if `document.status == "DRAFT"`

**How it works with the extension**: When `enableAttributeSync` is on, resource attributes are automatically synced to Permit.io for policy evaluation.

**Best for**: Dynamic rules that depend on context or data properties.

### Relationship-Based Access Control (ReBAC) [#relationship-based-access-control-rebac]

**What it is**: Permissions based on relationships between users and specific resource instances.

**Example**: A user is an "Owner" of document-123 but just a "Viewer" of document-456.

**How it works with the extension**:

* Resource instances are synced to Permit.io (with `enableResourceSync: true`)
* Permission checks include the specific resource instance ID

**Best for**: Collaborative applications where users need different permissions on different instances of the same resource type.

### Choosing the right model [#choosing-the-right-model]

* **RBAC**: When you need simple, role-based access control
* **ABAC**: When decisions depend on data properties or contextual information
* **ReBAC**: When users need different permissions on different instances

## Usage [#usage]

### Prerequisites [#prerequisites]

Before implementing fine-grained authorization with Prisma, make sure you have:

* A Prisma application with existing models and queries
* Basic understanding of authorization concepts
* Node.js and npm installed

### Installation [#installation]

Install the extension alongside Prisma Client:

  

#### bun

```bash
bun add @permitio/permit-prisma @prisma/client@7
```

#### pnpm

```bash
pnpm add @permitio/permit-prisma @prisma/client@7
```

#### yarn

```bash
yarn add @permitio/permit-prisma @prisma/client@7
```

#### npm

```bash
npm install @permitio/permit-prisma @prisma/client@7
```

You'll also need to sign up for a [Permit account](https://app.permit.io) to define your authorization policies.

> **Note:**\
> Ensure that the Permit PDP container is running. It is recommended to run it using Docker for better performance, security, and availability. For instructions, refer to the Permit documentation: [Deploy Permit to Production](https://docs.permit.io/how-to/deploy/deploy-to-production/) and [PDP Overview](https://docs.permit.io/concepts/pdp/overview/).

## Basic setup [#basic-setup]

First, extend your Prisma Client with the Permit extension:

```typescript
import { PrismaClient } from "@prisma/client";
import { createPermitClientExtension } from "@permitio/permit-prisma";

const prisma = new PrismaClient().$extends(
  createPermitClientExtension({
    permitConfig: {
      token: process.env.PERMIT_API_KEY, // Your Permit API key
      pdp: "http://localhost:7766", // PDP address (local or cloud)
    },
    enableAutomaticChecks: true, // Automatically enforce permissions
  }),
);
```

## Implementing RBAC (Role-Based Access Control) [#implementing-rbac-role-based-access-control]

RBAC uses roles to determine access permissions. For example, "Admin" roles can perform all actions while "Viewer" roles can only read data.

1. **Define resources and actions in Permit.io dashboard**:
   * Create resources matching your Prisma models (e.g., "document")
   * Define actions (e.g., "create", "read", "update", "delete")
   * Create roles with permission sets (e.g., "admin", "editor", "viewer")
2. **Set the active user in your code**:

```typescript
// Set the current user context before performing operations
prisma.$permit.setUser("john@example.com");

// All subsequent operations will be checked against this user's permissions
const documents = await prisma.document.findMany();
```

## Implementing ABAC (Attribute-Based Access Control) [#implementing-abac-attribute-based-access-control]

ABAC extends access control by considering user attributes, resource attributes, and context.

1. **Configure the extension for ABAC**:

```typescript
const prisma = new PrismaClient().$extends(
  createPermitClientExtension({
    permitConfig: { token: process.env.PERMIT_API_KEY, pdp: "http://localhost:7766" },
    enableAutomaticChecks: true,
  }),
);
```

2. **Set user with attributes:**

```typescript
prisma.$permit.setUser({
  key: "doctor@hospital.com",
  attributes: { department: "cardiology" },
});

// Will succeed only if user department matches record department (per policy)
const records = await prisma.medicalRecord.findMany({
  where: { department: "cardiology" },
});
```

## Implementing ReBAC (Relationship-Based Access Control) [#implementing-rebac-relationship-based-access-control]

ReBAC models permissions based on relationships between users and specific resource instances.

1. **Configure the extension for ReBAC**:

```typescript
const prisma = new PrismaClient().$extends(
  createPermitClientExtension({
    permitConfig: { token: process.env.PERMIT_API_KEY, pdp: "http://localhost:7766" },
    accessControlModel: "rebac",
    enableAutomaticChecks: true,
    enableResourceSync: true, // Sync resource instances with Permit.io
    enableDataFiltering: true, // Filter queries by permissions
  }),
);
```

2. \*\* Access instance-specific resources:\*\*

```typescript
prisma.$permit.setUser("owner@example.com");

// Will only succeed if the user has permission on this specific file
const file = await prisma.file.findUnique({
  where: { id: "file-123" },
});
```

## Manual permission checks [#manual-permission-checks]

For more control, you can perform explicit permission checks:

```typescript
// Check if user can update a document
const canUpdate = await prisma.$permit.check(
  "john@example.com", // user
  "update", // action
  "document", // resource
);

if (canUpdate) {
  await prisma.document.update({
    where: { id: "doc-123" },
    data: { title: "Updated Title" },
  });
}

// Or enforce permissions (throws if denied)
await prisma.$permit.enforceCheck("john@example.com", "delete", {
  type: "document",
  key: "doc-123",
});
```

## Common use cases [#common-use-cases]

Here are some common scenarios where fine-grained authorization is valuable:

* **Multi-tenant applications**: Isolate data between different customers
* **Healthcare applications**: Ensure patient data is only accessible to authorized staff
* **Collaborative platforms**: Grant different permissions on shared resources
* **Content management systems**: Control who can publish, edit, or view content

## Summary [#summary]

By integrating the `@permitio/permit-prisma` extension with your Prisma ORM application, you can implement authorization policies that protect your data and ensure users only access what they're permitted to see. The extension supports all major authorization models (RBAC, ABAC, ReBAC) and provides both automatic and manual permission enforcement.

## Next steps [#next-steps]

* [Create a free Permit.io account](https://app.permit.io)
* [View the full extension documentation](https://github.com/permitio/permit-prisma)

# Deploy to Cloudflare Workers & Pages (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn the things you need to know in order to deploy an app that uses Prisma Client for talking to a database to a Cloudflare Worker or to Cloudflare Pages

Location: ORM > v7 > Prisma Client > Deployment > Edge > Deploy to Cloudflare Workers & Pages

> [!NOTE]
> Quick summary
> 
> This page covers everything you need to know to deploy an app with Prisma ORM to a [Cloudflare Worker](https://developers.cloudflare.com/workers/) or to [Cloudflare Pages](https://developers.cloudflare.com/pages).

**Questions answered in this page**

* How to deploy Prisma to Cloudflare Workers?
* Which drivers work on Workers/Pages?
* How to configure DATABASE_URL and envs?

## General considerations when deploying to Cloudflare Workers [#general-considerations-when-deploying-to-cloudflare-workers]

This section covers *general* things you need to be aware of when deploying to Cloudflare Workers or Pages and are using Prisma ORM, regardless of the database provider you use.

### Using Prisma Postgres [#using-prisma-postgres]

You can use Prisma Postgres and deploy to Cloudflare Workers.

After you create a Worker, run:

  

#### bun

```bash
bunx --bun prisma@prev init --db
```

#### pnpm

```bash
pnpm dlx prisma@prev init --db
```

#### yarn

```bash
yarn dlx prisma@prev init --db
```

#### npm

```bash
npx prisma@prev init --db
```

Enter a name for your project and choose a database region.

This command:

* Connects your CLI to your [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=orm) account. If you're not logged in or don't have an account, your browser will open to guide you through creating a new account or signing into your existing one.
* Creates a `prisma` directory containing a `schema.prisma` file for your database models.
* Creates a `.env` file with your `DATABASE_URL`.

### Using an edge-compatible driver [#using-an-edge-compatible-driver]

When deploying a Cloudflare Worker that uses Prisma ORM, you need to use an [edge-compatible driver](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/overview#edge-compatibility-of-database-drivers) and its respective [driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers#driver-adapters) for Prisma ORM.

The edge-compatible drivers for Cloudflare Workers and Pages are:

* [Neon Serverless](https://neon.tech/docs/serverless/serverless-driver) uses HTTP to access the database
* [PlanetScale Serverless](https://planetscale.com/docs/tutorials/planetscale-serverless-driver) uses HTTP to access the database
* [`node-postgres`](https://node-postgres.com/) (`pg`) uses Cloudflare's `connect()` (TCP) to access the database
* [`@libsql/client`](https://github.com/tursodatabase/libsql-client-ts) is used to access Turso databases via HTTP
* [Cloudflare D1](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare) is used to access D1 databases

There's [also work being done](https://github.com/sidorares/node-mysql2/pull/2289) on the `node-mysql2` driver which will enable access to traditional MySQL databases from Cloudflare Workers and Pages in the future as well.

For hosted Prisma Postgres, use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver). For another database, choose a driver that supports Cloudflare Workers and use its Prisma driver adapter.

### Setting your database connection URL as an environment variable [#setting-your-database-connection-url-as-an-environment-variable]

First, ensure that your `datasource` block in your Prisma schema is configured correctly. Database connection URLs are configured in `prisma.config.ts`:

```prisma
datasource db {
  provider = "postgresql" // this might also be `mysql` or another value depending on your database
}
```

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

#### Development [#development]

When using your Worker in **development**, you can configure your database connection via the [`.dev.vars` file](https://developers.cloudflare.com/workers/configuration/secrets/#local-development-with-secrets) locally.

Assuming you use the `DATABASE_URL` environment variable from above, you can set it inside `.dev.vars` as follows:

```bash title=".dev.vars"
DATABASE_URL="your-database-connection-string"
```

In the above snippet, `your-database-connection-string` is a placeholder that you need to replace with the value of your own connection string, for example:

```bash title=".dev.vars"
DATABASE_URL="postgresql://admin:mypassword42@somehost.aws.com:5432/mydb"
```

Note that the `.dev.vars` file is not compatible with `.env` files which are typically used by Prisma ORM.

This means that you need to make sure that Prisma ORM gets access to the environment variable when needed, e.g. when running a Prisma CLI command like `prisma migrate dev`.

There are several options for achieving this:

* Run your Prisma CLI commands using [`dotenv`](https://www.npmjs.com/package/dotenv-cli) to specify from where the CLI should read the environment variable, for example:
  ```bash
  dotenv -e .dev.vars -- npx prisma migrate dev
  ```
* Create a script in `package.json` that reads `.dev.vars` via [`dotenv`](https://www.npmjs.com/package/dotenv-cli). You can then execute `prisma` commands as follows: `npm run env -- npx prisma migrate dev`. Here's a reference for the script:
  ```js title="package.json"
  "scripts":  { "env": "dotenv -e .dev.vars" }
  ```
* Duplicate the `DATABASE_URL` and any other relevant env vars into a new file called `.env` which can then be used by Prisma ORM.

> [!NOTE]
> If you're using an approach that requires `dotenv`, you need to have the [`dotenv-cli`](https://www.npmjs.com/package/dotenv-cli) package installed. You can do this e.g. by using this command to install the package locally in your project: `npm install -D dotenv-cli`.

#### Production [#production]

When deploying your Worker to **production**, you'll need to set the database connection using the `wrangler` CLI:

  

#### bun

```bash
bunx wrangler secret put DATABASE_URL
```

#### pnpm

```bash
pnpm dlx wrangler secret put DATABASE_URL
```

#### yarn

```bash
yarn dlx wrangler secret put DATABASE_URL
```

#### npm

```bash
npx wrangler secret put DATABASE_URL
```

The command is interactive and will ask you to enter the value for the `DATABASE_URL` env var as the next step in the terminal.

> [!NOTE]
> This command requires you to be authenticated, and will ask you to log in to your Cloudflare account in case you are not.

### Size limits on free accounts [#size-limits-on-free-accounts]

Cloudflare has a [size limit of 3 MB for Workers on the free plan](https://developers.cloudflare.com/workers/platform/limits/). If your application bundle with Prisma ORM exceeds that size, we recommend upgrading to a paid Worker plan.

### Deploying a Next.js app to Cloudflare Pages with `@cloudflare/next-on-pages` [#deploying-a-nextjs-app-to-cloudflare-pages-with-cloudflarenext-on-pages]

Cloudflare offers an option to run Next.js apps on Cloudflare Pages with [`@cloudflare/next-on-pages`](https://github.com/cloudflare/next-on-pages), see the [Cloudflare Pages Next.js guide](https://developers.cloudflare.com/pages/framework-guides/nextjs/ssr/get-started/) for instructions.

Based on some testing, we found the following:

* You can deploy using the PlanetScale or Neon Serverless Driver.
* Traditional PostgreSQL deployments using `pg` don't work because `pg` itself currently does not work with `@cloudflare/next-on-pages` (see [`next-on-pages` issue #605](https://github.com/cloudflare/next-on-pages/issues/605)).

Feel free to reach out to us on [Discord](https://pris.ly/discord?utm_source=docs\&utm_medium=inline_text) if you find that anything has changed about this.

## Database-specific considerations & examples [#database-specific-considerations--examples]

This section provides database-specific instructions for deploying a Cloudflare Worker with Prisma ORM.

### Prerequisites [#prerequisites]

As a prerequisite for the following section, you need to have a Cloudflare Worker running locally and the Prisma CLI installed.

If you don't have that yet, you can run these commands:

  

#### bun

```bash
bunx create-cloudflare prisma-cloudflare-worker-example --type hello-world
cd prisma-cloudflare-worker-example
bun add prisma@prev --dev&& bun add @prisma/client@7
bunx --bun prisma init --output ../generated/prisma
```

#### pnpm

```bash
pnpm create cloudflare prisma-cloudflare-worker-example --type hello-world
cd prisma-cloudflare-worker-example
pnpm add prisma@prev --save-dev&& pnpm add @prisma/client@7
pnpm prisma init --output ../generated/prisma
```

#### yarn

```bash
yarn create cloudflare prisma-cloudflare-worker-example --type hello-world
cd prisma-cloudflare-worker-example
yarn add prisma@prev --dev&& yarn add @prisma/client@7
yarn prisma init --output ../generated/prisma
```

#### npm

```bash
npm create cloudflare@latest prisma-cloudflare-worker-example -- --type hello-world
cd prisma-cloudflare-worker-example
npm install prisma@prev --save-dev && npm install @prisma/client@7
npx prisma init --output ../generated/prisma
```

You'll further need a database instance of your database provider of choice available. Refer to the respective documentation of the provider for setting up that instance.

We'll use the default `User` model for the example below:

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

### PostgreSQL (traditional) [#postgresql-traditional]

If you are using a traditional PostgreSQL database that's accessed via TCP and the `pg` driver, you need to:

* use the `@prisma/adapter-pg` database adapter (learn more in [Using driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters))
* set `nodejs_compat` in `wrangler.jsonc` (see the [Cloudflare docs](https://developers.cloudflare.com/workers/runtime-apis/nodejs/))

#### 1. Configure Prisma schema & database connection [#1-configure-prisma-schema--database-connection]

> [!NOTE]
> If you don't have a project to deploy, follow the instructions in the [Prerequisites](#prerequisites) to bootstrap a basic Cloudflare Worker with Prisma ORM in it.

First, ensure that the database connection is configured properly. Database connection URLs are configured in `prisma.config.ts`:

```prisma title="schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider = "postgresql"
}
```

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Next, you need to set the `DATABASE_URL` environment variable to the value of your database connection string. You'll do this in a file called `.dev.vars` used by Cloudflare:

```bash title=".dev.vars"
DATABASE_URL="postgresql://admin:mypassword42@somehost.aws.com:5432/mydb"
```

Because the Prisma CLI by default is only compatible with `.env` files, you can adjust your `package.json` with the following script that loads the env vars from `.dev.vars`. You can then use this script to load the env vars before executing a `prisma` command.

Add this script to your `package.json`:

```js title="package.json" highlight=5;add
{
  // ...
  "scripts": {
    // ....
    "env": "dotenv -e .dev.vars"
  },
  // ...
}
```

Now you can execute Prisma CLI commands as follows while ensuring that the command has access to the env vars in `.dev.vars`:

  

#### bun

```bash
bun run env npx prisma
```

#### pnpm

```bash
pnpm run env npx prisma
```

#### yarn

```bash
yarn env npx prisma
```

#### npm

```bash
npm run env -- npx prisma
```

#### 2. Install dependencies [#2-install-dependencies]

Next, install the required packages:

  

#### bun

```bash
bun add @prisma/adapter-pg
```

#### pnpm

```bash
pnpm add @prisma/adapter-pg
```

#### yarn

```bash
yarn add @prisma/adapter-pg
```

#### npm

```bash
npm install @prisma/adapter-pg
```

#### 3. Set `nodejs_compat` in `wrangler.jsonc` [#3-set-nodejs_compat-in-wranglerjsonc]

In your `wrangler.jsonc` file, add the following lines:

```json title="wrangler.jsonc"
{
  "compatibility_flags": [
    "nodejs_compat"
  ],
  "compatibility_date": "2026-08-23"
}
```

#### 4. Migrate your database schema (if applicable) [#4-migrate-your-database-schema-if-applicable]

If you ran `npx prisma init` above, you need to migrate your database schema to create the `User` table that's defined in your Prisma schema (if you already have all the tables you need in your database, you can skip this step):

  

#### bun

```bash
bun run env npx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm run env npx prisma migrate dev --name init
```

#### yarn

```bash
yarn env npx prisma migrate dev --name init
```

#### npm

```bash
npm run env -- npx prisma migrate dev --name init
```

#### 5. Use Prisma Client in your Worker to send a query to the database [#5-use-prisma-client-in-your-worker-to-send-a-query-to-the-database]

Here is a sample code snippet that you can use to instantiate `PrismaClient` and send a query to your database:

```ts
import { PrismaClient } from "./generated/client";
import { PrismaPg } from "@prisma/adapter-pg";

export default {
  async fetch(request, env, ctx) {
    const adapter = new PrismaPg({ connectionString: env.DATABASE_URL });
    const prisma = new PrismaClient({ adapter });

    const users = await prisma.user.findMany();
    const result = JSON.stringify(users);
    ctx.waitUntil(prisma.$disconnect());
    return new Response(result);
  },
};
```

#### 6. Run the Worker locally [#6-run-the-worker-locally]

To run the Worker locally, you can run the `wrangler dev` command:

  

#### bun

```bash
bunx wrangler dev
```

#### pnpm

```bash
pnpm dlx wrangler dev
```

#### yarn

```bash
yarn dlx wrangler dev
```

#### npm

```bash
npx wrangler dev
```

#### 7. Set the `DATABASE_URL` environment variable and deploy the Worker [#7-set-the-database_url-environment-variable-and-deploy-the-worker]

To deploy the Worker, you first need to set the `DATABASE_URL` environment variable [via the `wrangler` CLI](https://developers.cloudflare.com/workers/configuration/secrets/#secrets-on-deployed-workers):

  

#### bun

```bash
bunx wrangler secret put DATABASE_URL
```

#### pnpm

```bash
pnpm dlx wrangler secret put DATABASE_URL
```

#### yarn

```bash
yarn dlx wrangler secret put DATABASE_URL
```

#### npm

```bash
npx wrangler secret put DATABASE_URL
```

The command is interactive and will ask you to enter the value for the `DATABASE_URL` env var as the next step in the terminal.

> [!NOTE]
> This command requires you to be authenticated, and will ask you to log in to your Cloudflare account in case you are not.

Then deploy the Worker:

  

#### bun

```bash
bunx wrangler deploy
```

#### pnpm

```bash
pnpm dlx wrangler deploy
```

#### yarn

```bash
yarn dlx wrangler deploy
```

#### npm

```bash
npx wrangler deploy
```

The command will output the URL where you can access the deployed Worker.

### PlanetScale [#planetscale]

If you are using a PlanetScale database, you need to:

* use the `@prisma/adapter-planetscale` database adapter (learn more in [PlanetScale](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale))
* manually remove the conflicting `cache` field:

  ```ts
  export default {
    async fetch(request, env, ctx) {
      const adapter = new PrismaPlanetScale({
        url: env.DATABASE_URL,
        // see https://github.com/cloudflare/workerd/issues/698
        fetch(url, init) {
          delete init["cache"];
          return fetch(url, init);
        },
      });
      const prisma = new PrismaClient({ adapter });

      // ...
    },
  };
  ```

#### 1. Configure Prisma schema & database connection [#1-configure-prisma-schema--database-connection-1]

> [!NOTE]
> If you don't have a project to deploy, follow the instructions in the [Prerequisites](#prerequisites) to bootstrap a basic Cloudflare Worker with Prisma ORM in it.

First, ensure that the database connection is configured properly. Database connection URLs are configured in `prisma.config.ts`:

```prisma title="schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider     = "mysql"
  relationMode = "prisma" // required for PlanetScale (as by default foreign keys are disabled)
}
```

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Next, you need to set the `DATABASE_URL` environment variable to the value of your database connection string. You'll do this in a file called `.dev.vars` used by Cloudflare:

```bash title=".dev.vars"
DATABASE_URL="mysql://32qxa2r7hfl3102wrccj:password@us-east.connect.psdb.cloud/demo-cf-worker-ps?sslaccept=strict"
```

Because the Prisma CLI by default is only compatible with `.env` files, you can adjust your `package.json` with the following script that loads the env vars from `.dev.vars`. You can then use this script to load the env vars before executing a `prisma` command.

Add this script to your `package.json`:

```js title="package.json" highlight=5;add
{
  // ...
  "scripts": {
    // ....
    "env": "dotenv -e .dev.vars"
  },
  // ...
}
```

Now you can execute Prisma CLI commands as follows while ensuring that the command has access to the env vars in `.dev.vars`:

  

#### bun

```bash
bun run env npx prisma
```

#### pnpm

```bash
pnpm run env npx prisma
```

#### yarn

```bash
yarn env npx prisma
```

#### npm

```bash
npm run env -- npx prisma
```

#### 2. Install dependencies [#2-install-dependencies-1]

Next, install the required packages:

  

#### bun

```bash
bun add @prisma/adapter-planetscale
```

#### pnpm

```bash
pnpm add @prisma/adapter-planetscale
```

#### yarn

```bash
yarn add @prisma/adapter-planetscale
```

#### npm

```bash
npm install @prisma/adapter-planetscale
```

#### 3. Migrate your database schema (if applicable) [#3-migrate-your-database-schema-if-applicable]

If you ran `npx prisma init` above, you need to migrate your database schema to create the `User` table that's defined in your Prisma schema (if you already have all the tables you need in your database, you can skip this step):

  

#### bun

```bash
bun run env npx prisma db push
```

#### pnpm

```bash
pnpm run env npx prisma db push
```

#### yarn

```bash
yarn env npx prisma db push
```

#### npm

```bash
npm run env -- npx prisma db push
```

#### 4. Use Prisma Client in your Worker to send a query to the database [#4-use-prisma-client-in-your-worker-to-send-a-query-to-the-database]

Here is a sample code snippet that you can use to instantiate `PrismaClient` and send a query to your database:

```ts
import { PrismaClient } from "./generated/client";
import { PrismaPlanetScale } from "@prisma/adapter-planetscale";

export default {
  async fetch(request, env, ctx) {
    const adapter = new PrismaPlanetScale({
      url: env.DATABASE_URL,
      // see https://github.com/cloudflare/workerd/issues/698
      fetch(url, init) {
        delete init["cache"];
        return fetch(url, init);
      },
    });
    const prisma = new PrismaClient({ adapter });

    const users = await prisma.user.findMany();
    const result = JSON.stringify(users);
    ctx.waitUntil(prisma.$disconnect());
    return new Response(result);
  },
};
```

#### 6. Run the Worker locally [#6-run-the-worker-locally-1]

To run the Worker locally, you can run the `wrangler dev` command:

  

#### bun

```bash
bunx wrangler dev
```

#### pnpm

```bash
pnpm dlx wrangler dev
```

#### yarn

```bash
yarn dlx wrangler dev
```

#### npm

```bash
npx wrangler dev
```

#### 7. Set the `DATABASE_URL` environment variable and deploy the Worker [#7-set-the-database_url-environment-variable-and-deploy-the-worker-1]

To deploy the Worker, you first need to set the `DATABASE_URL` environment variable [via the `wrangler` CLI](https://developers.cloudflare.com/workers/configuration/secrets/#secrets-on-deployed-workers):

  

#### bun

```bash
bunx wrangler secret put DATABASE_URL
```

#### pnpm

```bash
pnpm dlx wrangler secret put DATABASE_URL
```

#### yarn

```bash
yarn dlx wrangler secret put DATABASE_URL
```

#### npm

```bash
npx wrangler secret put DATABASE_URL
```

The command is interactive and will ask you to enter the value for the `DATABASE_URL` env var as the next step in the terminal.

> [!NOTE]
> This command requires you to be authenticated, and will ask you to log in to your Cloudflare account in case you are not.

Then deploy the Worker:

  

#### bun

```bash
bunx wrangler deploy
```

#### pnpm

```bash
pnpm dlx wrangler deploy
```

#### yarn

```bash
yarn dlx wrangler deploy
```

#### npm

```bash
npx wrangler deploy
```

The command will output the URL where you can access the deployed Worker.

### Neon [#neon]

If you are using a Neon database, you need to:

* use the `@prisma/adapter-neon` database adapter (learn more in [Using driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters))

#### 1. Configure Prisma schema & database connection [#1-configure-prisma-schema--database-connection-2]

> [!NOTE]
> If you don't have a project to deploy, follow the instructions in the [Prerequisites](#prerequisites) to bootstrap a basic Cloudflare Worker with Prisma ORM in it.

First, ensure that the database connection is configured properly. Database connection URLs are configured in `prisma.config.ts`:

```prisma title="schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider = "postgresql"
}
```

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Next, you need to set the `DATABASE_URL` environment variable to the value of your database connection string. You'll do this in a file called `.dev.vars` used by Cloudflare:

```bash title=".dev.vars"
DATABASE_URL="postgresql://janedoe:password@ep-nameless-pond-a23b1mdz.eu-central-1.aws.neon.tech/neondb?sslmode=require"
```

Because the Prisma CLI by default is only compatible with `.env` files, you can adjust your `package.json` with the following script that loads the env vars from `.dev.vars`. You can then use this script to load the env vars before executing a `prisma` command.

Add this script to your `package.json`:

```js title="package.json" highlight=5;add
{
  // ...
  "scripts": {
    // ....
    "env": "dotenv -e .dev.vars"
  },
  // ...
}
```

Now you can execute Prisma CLI commands as follows while ensuring that the command has access to the env vars in `.dev.vars`:

  

#### bun

```bash
bun run env npx prisma
```

#### pnpm

```bash
pnpm run env npx prisma
```

#### yarn

```bash
yarn env npx prisma
```

#### npm

```bash
npm run env -- npx prisma
```

#### 2. Install dependencies [#2-install-dependencies-2]

Next, install the required packages:

  

#### bun

```bash
bun add @prisma/adapter-neon
```

#### pnpm

```bash
pnpm add @prisma/adapter-neon
```

#### yarn

```bash
yarn add @prisma/adapter-neon
```

#### npm

```bash
npm install @prisma/adapter-neon
```

#### 3. Migrate your database schema (if applicable) [#3-migrate-your-database-schema-if-applicable-1]

If you ran `npx prisma init` above, you need to migrate your database schema to create the `User` table that's defined in your Prisma schema (if you already have all the tables you need in your database, you can skip this step):

  

#### bun

```bash
bun run env npx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm run env npx prisma migrate dev --name init
```

#### yarn

```bash
yarn env npx prisma migrate dev --name init
```

#### npm

```bash
npm run env -- npx prisma migrate dev --name init
```

#### 5. Use Prisma Client in your Worker to send a query to the database [#5-use-prisma-client-in-your-worker-to-send-a-query-to-the-database-1]

Here is a sample code snippet that you can use to instantiate `PrismaClient` and send a query to your database:

```ts
import { PrismaClient } from "./generated/client";
import { PrismaNeon } from "@prisma/adapter-neon";

export default {
  async fetch(request, env, ctx) {
    const adapter = new PrismaNeon({ connectionString: env.DATABASE_URL });
    const prisma = new PrismaClient({ adapter });

    const users = await prisma.user.findMany();
    const result = JSON.stringify(users);
    ctx.waitUntil(prisma.$disconnect());
    return new Response(result);
  },
};
```

#### 6. Run the Worker locally [#6-run-the-worker-locally-2]

To run the Worker locally, you can run the `wrangler dev` command:

  

#### bun

```bash
bunx wrangler dev
```

#### pnpm

```bash
pnpm dlx wrangler dev
```

#### yarn

```bash
yarn dlx wrangler dev
```

#### npm

```bash
npx wrangler dev
```

#### 7. Set the `DATABASE_URL` environment variable and deploy the Worker [#7-set-the-database_url-environment-variable-and-deploy-the-worker-2]

To deploy the Worker, you first need to set the `DATABASE_URL` environment variable [via the `wrangler` CLI](https://developers.cloudflare.com/workers/configuration/secrets/#secrets-on-deployed-workers):

  

#### bun

```bash
bunx wrangler secret put DATABASE_URL
```

#### pnpm

```bash
pnpm dlx wrangler secret put DATABASE_URL
```

#### yarn

```bash
yarn dlx wrangler secret put DATABASE_URL
```

#### npm

```bash
npx wrangler secret put DATABASE_URL
```

The command is interactive and will ask you to enter the value for the `DATABASE_URL` env var as the next step in the terminal.

> [!NOTE]
> This command requires you to be authenticated, and will ask you to log in to your Cloudflare account in case you are not.

Then deploy the Worker:

  

#### bun

```bash
bunx wrangler deploy
```

#### pnpm

```bash
pnpm dlx wrangler deploy
```

#### yarn

```bash
yarn dlx wrangler deploy
```

#### npm

```bash
npx wrangler deploy
```

The command will output the URL where you can access the deployed Worker.

### Cloudflare D1 [#cloudflare-d1]

> [!NOTE]
> Using Cloudflare D1
> 
> For step-by-step instructions on using Prisma ORM with [Cloudflare D1](https://developers.cloudflare.com/d1/) (schema setup, migrations, and deploying your Worker), see the dedicated [Cloudflare D1 deployment guide](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-d1).

## Related pages

- [`Deploy to Deno Deploy`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-deno-deploy)
- [`Deploy to Vercel Edge Functions & Middleware`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-vercel): Learn the things you need to know in order to deploy an Edge function that uses Prisma Client for talking to a database
- [`Deploying edge functions with Prisma ORM`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/overview): Learn how to deploy your Prisma-backed apps to edge functions like Cloudflare Workers or Vercel Edge Functions

# Deploy to Deno Deploy (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/edge/deploy-to-deno-deploy)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Location: ORM > v7 > Prisma Client > Deployment > Edge > Deploy to Deno Deploy

With this guide, you can learn how to build and deploy a REST API to [Deno Deploy](https://deno.com/deploy). The application uses Prisma ORM to manage tasks in a [Prisma Postgres](https://www.prisma.io/docs/postgres) database.

This guide covers Deno CLI, Deno Deploy, Prisma Client with the Postgres adapter, and Prisma Postgres.

## Prerequisites [#prerequisites]

* A free [Prisma Data Platform](https://console.prisma.io/login?utm_source=docs\&utm_medium=content\&utm_content=orm) account
* A free [Deno Deploy](https://deno.com/deploy) account
* [Deno](https://docs.deno.com/runtime/#install-deno) v2.0 or later installed
* (Recommended) [Deno extension for VS Code](https://docs.deno.com/runtime/reference/vscode/)

## 1. Set up your application [#1-set-up-your-application]

Create a new directory and initialize your Prisma project:

  

#### bun

```bash
mkdir prisma-deno-deploy
cd prisma-deno-deploy
deno run -A npm 
# couldn't auto-convert command:prisma@prev init --db
```

#### pnpm

```bash
mkdir prisma-deno-deploy
cd prisma-deno-deploy
deno run -A npm undefined
# couldn't auto-convert command:prisma@prev init --db
```

#### yarn

```bash
mkdir prisma-deno-deploy
cd prisma-deno-deploy
deno run -A npm undefined
# couldn't auto-convert command:prisma@prev init --db
```

#### npm

```bash
mkdir prisma-deno-deploy
cd prisma-deno-deploy
deno run -A npm:prisma@prev init --db
```

Enter a name for your project and choose a database region.

This command:

* Connects to the [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=orm) (opens browser for authentication)
* Creates a `prisma/schema.prisma` file for your database models
* Creates a `.env` file with your `DATABASE_URL`
* Creates a `prisma.config.ts` configuration file

## 2. Configure Deno [#2-configure-deno]

Create a `deno.json` file with the following configuration:

```json title="deno.json"
{
  "nodeModulesDir": "auto",
  "compilerOptions": {
    "lib": ["deno.window"],
    "types": ["node"]
  },
  "imports": {
    "@prisma/adapter-pg": "npm:@prisma/adapter-pg@^7.0.0",
    "@prisma/client": "npm:@prisma/client@7",
    "prisma": "npm:prisma@prev"
  },
  "tasks": {
    "dev": "deno run -A --env=.env --watch index.ts",
    "db:generate": "deno run -A --env=.env npm:prisma@prev generate",
    "db:push": "deno run -A --env=.env npm:prisma@prev db push",
    "db:migrate": "deno run -A --env=.env npm:prisma@prev migrate dev",
    "db:studio": "deno run -A --env=.env npm:prisma@prev studio"
  }
}
```

> [!NOTE]
> The `nodeModulesDir: "auto"` setting is required for Prisma to work correctly with Deno. The `compilerOptions` ensure TypeScript understands Deno globals and npm packages. The import map allows you to use clean import paths like `@prisma/adapter-pg` instead of `npm:@prisma/adapter-pg`.

Install the dependencies:

```bash
deno install
deno install --allow-scripts
```

## 3. Define your data model [#3-define-your-data-model]

Edit `prisma/schema.prisma` to add the Deno runtime and a `Task` model:

```prisma title="prisma/schema.prisma" highlight=4;add
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
  runtime  = "deno"
}

datasource db {
  provider = "postgresql"
}

model Task {
  id          Int      @id @default(autoincrement())
  title       String
  description String?
  completed   Boolean  @default(false)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}
```

## 4. Push the schema to your database [#4-push-the-schema-to-your-database]

Apply the schema to your database and generate Prisma Client:

```bash
deno task db:push
```

This command:

1. Creates the `Task` table in your Prisma Postgres database
2. Generates the Prisma Client with full type safety

> [!NOTE]
> If you see TypeScript errors in your IDE after generating, restart the Deno language server (`Cmd/Ctrl + Shift + P` → "Deno: Restart Language Server") to refresh the types.

## 5. Create your application [#5-create-your-application]

Create `index.ts` with a REST API for managing tasks:

```ts title="index.ts"
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "./generated/prisma/client.ts";

// Initialize Prisma Client with the Postgres adapter
const connectionString = Deno.env.get("DATABASE_URL")!;
const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

// Helper to create JSON responses
function json(data: unknown, status = 200): Response {
  return new Response(JSON.stringify(data, null, 2), {
    status,
    headers: { "Content-Type": "application/json" },
  });
}

// Request handler
async function handler(request: Request): Promise<Response> {
  const url = new URL(request.url);
  const path = url.pathname;
  const method = request.method;

  try {
    // GET /tasks - List all tasks
    if (method === "GET" && path === "/tasks") {
      const tasks = await prisma.task.findMany({
        orderBy: { createdAt: "desc" },
      });
      return json(tasks);
    }

    // POST /tasks - Create a new task
    if (method === "POST" && path === "/tasks") {
      const body = await request.json();
      const task = await prisma.task.create({
        data: {
          title: body.title,
          description: body.description,
        },
      });
      return json(task, 201);
    }

    // GET /tasks/:id - Get a specific task
    const taskMatch = path.match(/^\/tasks\/(\d+)$/);
    if (taskMatch) {
      const id = parseInt(taskMatch[1]);

      if (method === "GET") {
        const task = await prisma.task.findUnique({ where: { id } });
        if (!task) return json({ error: "Task not found" }, 404);
        return json(task);
      }

      // PATCH /tasks/:id - Update a task
      if (method === "PATCH") {
        const body = await request.json();
        const task = await prisma.task.update({
          where: { id },
          data: body,
        });
        return json(task);
      }

      // DELETE /tasks/:id - Delete a task
      if (method === "DELETE") {
        await prisma.task.delete({ where: { id } });
        return json({ message: "Task deleted" });
      }
    }

    // GET / - API info
    if (method === "GET" && path === "/") {
      return json({
        name: "Prisma + Deno Task API",
        version: "1.0.0",
        endpoints: {
          "GET /tasks": "List all tasks",
          "POST /tasks": "Create a task",
          "GET /tasks/:id": "Get a task",
          "PATCH /tasks/:id": "Update a task",
          "DELETE /tasks/:id": "Delete a task",
        },
      });
    }

    return json({ error: "Not found" }, 404);
  } catch (error) {
    console.error(error);
    return json({ error: "Internal server error" }, 500);
  }
}

// Start the server
Deno.serve({ port: 8000 }, handler);
```

This creates a full CRUD API with the following endpoints:

| Method | Endpoint     | Description         |
| ------ | ------------ | ------------------- |
| GET    | `/`          | API info            |
| GET    | `/tasks`     | List all tasks      |
| POST   | `/tasks`     | Create a new task   |
| GET    | `/tasks/:id` | Get a specific task |
| PATCH  | `/tasks/:id` | Update a task       |
| DELETE | `/tasks/:id` | Delete a task       |

## 6. Test your application locally [#6-test-your-application-locally]

Start the development server:

```bash
deno task dev
```

Test the API with curl:

```bash
# Get API info
curl http://localhost:8000/

# Create a task
curl -X POST http://localhost:8000/tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Learn Prisma", "description": "Complete the Deno guide"}'

# List all tasks
curl http://localhost:8000/tasks

# Update a task (mark as completed)
curl -X PATCH http://localhost:8000/tasks/1 \
  -H "Content-Type: application/json" \
  -d '{"completed": true}'

# Delete a task
curl -X DELETE http://localhost:8000/tasks/1
```

You should see JSON responses for each request. The task ID will increment with each new task created.

## 7. Create a GitHub repository [#7-create-a-github-repository]

You need a GitHub repository to deploy to Deno Deploy.

Create a `.gitignore` file:

```text title=".gitignore"
.env
node_modules/
generated/
deno.lock
```

Initialize and push your repository:

```bash
git init -b main
git remote add origin https://github.com/<username>/prisma-deno-deploy
git add .
git commit -m "Initial commit"
git push -u origin main
```

## 8. Deploy to Deno Deploy [#8-deploy-to-deno-deploy]

1. Go to [https://dash.deno.com/](https://dash.deno.com/)
2. Click **New Project** and select your GitHub repository
3. Configure the deployment:
   * **Framework preset**: No Preset
   * **Install command**: `deno install`
   * **Build command**: `deno run -A npm:prisma@prev generate`
   * **Entrypoint**: `index.ts`
4. Click **Create & Deploy**

The first deployment will fail because you need to add the database connection string.

### Add environment variables [#add-environment-variables]

1. Go to your project's **Settings** > **Environment Variables**
2. Add a new variable:
   * **Key**: `DATABASE_URL`
   * **Value**: Your Prisma Postgres connection string (copy from your `.env` file)
3. Click **Save**

Trigger a new deployment by clicking **Redeploy** or pushing a new commit.

## 9. Test your deployed API [#9-test-your-deployed-api]

Once deployed, test your API at your Deno Deploy URL:

```bash
# Replace with your actual Deno Deploy URL
curl https://your-project.deno.dev/

# Create a task
curl -X POST https://your-project.deno.dev/tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Deploy to production"}'

# List tasks
curl https://your-project.deno.dev/tasks
```

## Summary [#summary]

You successfully deployed a REST API to Deno Deploy using:

* **Deno** as the runtime with native TypeScript support
* **Prisma ORM** with the Postgres adapter for type-safe database access
* **Prisma Postgres** as the managed database

Your project structure should look like this:

```
prisma-deno-deploy/
├── deno.json
├── index.ts
├── prisma/
│   └── schema.prisma
├── prisma.config.ts
├── generated/
│   └── prisma/
│       └── ...
└── .env
```

### Next steps [#next-steps]

* Add authentication using [Deno KV](https://docs.deno.com/deploy/reference/deno_kv/) for sessions
* Add request validation with [Zod](https://zod.dev/)
* Explore [Prisma Client extensions](https://www.prisma.io/docs/orm/v7/prisma-client/client-extensions) for custom functionality
* Set up [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) for schema versioning in production

## Related pages

- [`Deploy to Cloudflare Workers & Pages`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare): Learn the things you need to know in order to deploy an app that uses Prisma Client for talking to a database to a Cloudflare Worker or to Cloudflare Pages
- [`Deploy to Vercel Edge Functions & Middleware`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-vercel): Learn the things you need to know in order to deploy an Edge function that uses Prisma Client for talking to a database
- [`Deploying edge functions with Prisma ORM`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/overview): Learn how to deploy your Prisma-backed apps to edge functions like Cloudflare Workers or Vercel Edge Functions

# Deploy to Vercel Edge Functions & Middleware (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/edge/deploy-to-vercel)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn the things you need to know in order to deploy an Edge function that uses Prisma Client for talking to a database

Location: ORM > v7 > Prisma Client > Deployment > Edge > Deploy to Vercel Edge Functions & Middleware

This page covers everything you need to know to deploy an app that uses Prisma Client for talking to a database in [Vercel Edge Middleware](https://vercel.com/docs/functions/edge-middleware) or a [Vercel Function](https://vercel.com/docs/functions) deployed to the [Vercel Edge Runtime](https://vercel.com/docs/functions/runtimes/edge-runtime).

**Questions answered in this page**

* How to deploy Prisma on Vercel Edge?
* Which database drivers are supported?
* How to configure env and postinstall?

Vercel supports both Node.js and edge runtimes for Vercel Functions. The Node.js runtime is the default and recommended for most use cases.

> [!NOTE]
> By default, Vercel Functions use the Node.js runtime. You can explicitly set the runtime if needed:
> 
> ```typescript
> export const runtime = "edge"; // 'nodejs' is the default
>
> export function GET(request: Request) {
>   return new Response(`I am a Vercel Function!`, {
>     status: 200,
>   });
> }
> ```

## General considerations when deploying to Vercel Edge Functions & Edge Middleware [#general-considerations-when-deploying-to-vercel-edge-functions--edge-middleware]

### Using Prisma Postgres [#using-prisma-postgres]

You can use Prisma Postgres in Vercel's edge runtime. Follow this guide for an end-to-end tutorial on [deploying an application to Vercel using Prisma Postgres](https://www.prisma.io/docs/guides/v7/frameworks/nextjs).

### Using an edge-compatible driver [#using-an-edge-compatible-driver]

Vercel's Edge Runtime currently only supports a limited set of database drivers:

* [Neon Serverless](https://neon.tech/docs/serverless/serverless-driver) uses HTTP to access the database (also compatible with [Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres))
* [PlanetScale Serverless](https://planetscale.com/docs/tutorials/planetscale-serverless-driver) uses HTTP to access the database
* [`@libsql/client`](https://github.com/tursodatabase/libsql-client-ts) is used to access Turso databases

Note that [`node-postgres`](https://node-postgres.com/) (`pg`) is currently *not* supported on Vercel Edge Functions.

When deploying a Vercel Edge Function that uses Prisma ORM, you need to use one of these [edge-compatible drivers](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/overview#edge-compatibility-of-database-drivers) and its respective [driver adapter](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers#driver-adapters) for Prisma ORM.

> [!NOTE]
> For hosted Prisma Postgres, use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver). For another database, choose a driver that supports Vercel Edge Functions and use its Prisma driver adapter.

### Setting your database connection URL as an environment variable [#setting-your-database-connection-url-as-an-environment-variable]

First, ensure that your `datasource` block in your Prisma schema is configured correctly. Database connection URLs are configured in `prisma.config.ts`:

```prisma
datasource db {
  provider = "postgresql" // this might also be `mysql` or another value depending on your database
}
```

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

#### Development [#development]

When in **development**, you can configure your database connection via the `DATABASE_URL` environment variable (e.g. [using `.env` files](https://www.prisma.io/docs/orm/v7/more/dev-environment/environment-variables)).

#### Production [#production]

When deploying your Edge Function to **production**, you'll need to set the database connection using the `vercel` CLI:

  

#### bun

```bash
bunx vercel env add DATABASE_URL
```

#### pnpm

```bash
pnpm dlx vercel env add DATABASE_URL
```

#### yarn

```bash
yarn dlx vercel env add DATABASE_URL
```

#### npm

```bash
npx vercel env add DATABASE_URL
```

This command is interactive and will ask you to select environments and provide the value for the `DATABASE_URL` in subsequent steps.

Alternatively, you can configure the environment variable [via the UI](https://vercel.com/docs/projects/environment-variables#creating-environment-variables) of your project in the Vercel Dashboard.

### Generate Prisma Client in `postinstall` hook [#generate-prisma-client-in-postinstall-hook]

In your `package.json`, you should add a `"postinstall"` section as follows:

```js title="package.json" showLineNumbers
{
  // ...,
  "postinstall": "prisma generate"
}
```

### Size limits on free accounts [#size-limits-on-free-accounts]

Vercel has a [size limit of 1 MB on free accounts](https://vercel.com/docs/functions/limitations). If your application bundle with Prisma ORM exceeds that size, use an engine-less Prisma Client with a compatible driver adapter or upgrade to a plan with a larger limit.

## Database-specific considerations & examples [#database-specific-considerations--examples]

This section provides database-specific instructions for deploying a Vercel Edge Functions with Prisma ORM.

### Prerequisites [#prerequisites]

As a prerequisite for the following section, you need to have a Vercel Edge Function (which typically comes in the form of a Next.js API route) running locally and the Prisma and Vercel CLIs installed.

If you don't have that yet, you can run these commands to set up a Next.js app from scratch (following the instructions of the [Vercel Functions Quickstart](https://vercel.com/docs/functions/quickstart)):

  

#### bun

```bash
bun add --global vercel
```

#### pnpm

```bash
pnpm add -g vercel
```

#### yarn

```bash
yarn global add vercel
```

#### npm

```bash
npm install -g vercel
```

  

#### bun

```bash
bunx create-next-app@latest
```

#### pnpm

```bash
pnpm dlx create-next-app@latest
```

#### yarn

```bash
yarn dlx create-next-app@latest
```

#### npm

```bash
npx create-next-app@latest
```

  

#### bun

```bash
bun add prisma@prev --dev&& bun add @prisma/client@7
```

#### pnpm

```bash
pnpm add prisma@prev --save-dev&& pnpm add @prisma/client@7
```

#### yarn

```bash
yarn add prisma@prev --dev&& yarn add @prisma/client@7
```

#### npm

```bash
npm install prisma@prev --save-dev && npm install @prisma/client@7
```

  

#### bun

```bash
bunx --bun prisma init --output ../app/generated/prisma
```

#### pnpm

```bash
pnpm prisma init --output ../app/generated/prisma
```

#### yarn

```bash
yarn prisma init --output ../app/generated/prisma
```

#### npm

```bash
npx prisma init --output ../app/generated/prisma
```

We'll use the default `User` model for the example below:

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

### Vercel Postgres [#vercel-postgres]

If you are using Vercel Postgres, you need to:

* use the `@prisma/adapter-neon` database adapter because Vercel Postgres uses [Neon](https://neon.tech/) under the hood
* be aware that Vercel by default calls the pooled connection string `POSTGRES_PRISMA_URL` while the direct, non-pooled connection string is exposed as `POSTGRES_URL_NON_POOLING`. Configure `prisma.config.ts` so that the Prisma CLI uses the direct connection string:

  ```ts title="prisma.config.ts"
  import { defineConfig, env } from "prisma/config";

  export default defineConfig({
    schema: "prisma/schema.prisma",
    datasource: {
      url: env("POSTGRES_URL_NON_POOLING"), // direct connection for Prisma CLI
    },
  });
  ```

#### 1. Configure Prisma schema & database connection [#1-configure-prisma-schema--database-connection]

> [!NOTE]
> If you don't have a project to deploy, follow the instructions in the [Prerequisites](#prerequisites) to bootstrap a basic Next.js app with Prisma ORM in it.

First, ensure that the database connection is configured properly. Database connection URLs are configured in `prisma.config.ts`:

```prisma title="schema.prisma" showLineNumbers
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider = "postgresql"
}
```

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("POSTGRES_URL_NON_POOLING"), // direct connection for Prisma CLI
  },
});
```

Next, you need to set the `POSTGRES_PRISMA_URL` and `POSTGRES_URL_NON_POOLING` environment variable to the values of your database connection.

If you ran `npx prisma init`, you can use the `.env` file that was created by this command to set these:

```bash title=".env"
POSTGRES_PRISMA_URL="postgres://user:password@host-pooler.region.postgres.vercel-storage.com:5432/name?pgbouncer=true&connect_timeout=15"
POSTGRES_URL_NON_POOLING="postgres://user:password@host.region.postgres.vercel-storage.com:5432/name"
```

#### 2. Install dependencies [#2-install-dependencies]

Next, install the required packages:

  

#### bun

```bash
bun add @prisma/adapter-neon
```

#### pnpm

```bash
pnpm add @prisma/adapter-neon
```

#### yarn

```bash
yarn add @prisma/adapter-neon
```

#### npm

```bash
npm install @prisma/adapter-neon
```

#### 3. Configure `postinstall` hook [#3-configure-postinstall-hook]

Next, add a new key to the `scripts` section in your `package.json`:

```js title="package.json"
{
  // ...
  "scripts": {
    // ...
    "postinstall": "prisma generate" // [!code ++]
  }
}
```

#### 4. Migrate your database schema (if applicable) [#4-migrate-your-database-schema-if-applicable]

If you ran `npx prisma init` above, you need to migrate your database schema to create the `User` table that's defined in your Prisma schema (if you already have all the tables you need in your database, you can skip this step):

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

#### 5. Use Prisma Client in your Vercel Edge Function to send a query to the database [#5-use-prisma-client-in-your-vercel-edge-function-to-send-a-query-to-the-database]

If you created the project from scratch, you can create a new edge function as follows.

First, create a new API route, e.g. by using these commands:

```bash
mkdir src/app/api
mkdir src/app/api/edge
touch src/app/api/edge/route.ts
```

Here is a sample code snippet that you can use to instantiate `PrismaClient` and send a query to your database in the new `app/api/edge/route.ts` file you just created:

```ts title="app/api/edge/route.ts" showLineNumbers
import { NextResponse } from "next/server";
import { PrismaClient } from "./generated/client";
import { PrismaNeon } from "@prisma/adapter-neon";

export const runtime = "nodejs"; // can also be set to 'edge'

export async function GET(request: Request) {
  const adapter = new PrismaNeon({ connectionString: process.env.POSTGRES_PRISMA_URL });
  const prisma = new PrismaClient({ adapter });

  const users = await prisma.user.findMany();

  return NextResponse.json(users, { status: 200 });
}
```

#### 6. Run the Edge Function locally [#6-run-the-edge-function-locally]

Run the app with the following command:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

You can now access the Edge Function via `http://localhost:3000/api/edge`.

#### 7. Set the `POSTGRES_PRISMA_URL` environment variable and deploy the Edge Function [#7-set-the-postgres_prisma_url-environment-variable-and-deploy-the-edge-function]

Run the following command to deploy your project with Vercel:

  

#### bun

```bash
bunx vercel deploy
```

#### pnpm

```bash
pnpm dlx vercel deploy
```

#### yarn

```bash
yarn dlx vercel deploy
```

#### npm

```bash
npx vercel deploy
```

Note that once the project was created on Vercel, you will need to set the `POSTGRES_PRISMA_URL` environment variable (and if this was your first deploy, it likely failed). You can do this either via the Vercel UI or by running the following command:

  

#### bun

```bash
bunx vercel env add POSTGRES_PRISMA_URL
```

#### pnpm

```bash
pnpm dlx vercel env add POSTGRES_PRISMA_URL
```

#### yarn

```bash
yarn dlx vercel env add POSTGRES_PRISMA_URL
```

#### npm

```bash
npx vercel env add POSTGRES_PRISMA_URL
```

At this point, you can get the URL of the deployed application from the Vercel Dashboard and access the edge function via the `/api/edge` route.

### PlanetScale [#planetscale]

If you are using a PlanetScale database, you need to:

* use the `@prisma/adapter-planetscale` database adapter (learn more in [PlanetScale](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale))

#### 1. Configure Prisma schema & database connection [#1-configure-prisma-schema--database-connection-1]

> [!NOTE]
> If you don't have a project to deploy, follow the instructions in the [Prerequisites](#prerequisites) to bootstrap a basic Next.js app with Prisma ORM in it.

First, ensure that the database connection is configured properly. Database connection URLs are configured in `prisma.config.ts`:

```prisma title="schema.prisma" showLineNumbers
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider     = "mysql"
  relationMode = "prisma" // required for PlanetScale (as by default foreign keys are disabled)
}
```

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Next, you need to set the `DATABASE_URL` environment variable in your `.env` file that's used both by Prisma and Next.js to read your env vars:

```bash title=".env"
DATABASE_URL="mysql://32qxa2r7hfl3102wrccj:password@us-east.connect.psdb.cloud/demo-cf-worker-ps?sslaccept=strict"
```

#### 2. Install dependencies [#2-install-dependencies-1]

Next, install the required packages:

  

#### bun

```bash
bun add @prisma/adapter-planetscale
```

#### pnpm

```bash
pnpm add @prisma/adapter-planetscale
```

#### yarn

```bash
yarn add @prisma/adapter-planetscale
```

#### npm

```bash
npm install @prisma/adapter-planetscale
```

#### 3. Configure `postinstall` hook [#3-configure-postinstall-hook-1]

Next, add a new key to the `scripts` section in your `package.json`:

```js title="package.json"
{
  // ...
  "scripts": {
    // ...
    "postinstall": "prisma generate" // [!code ++]
  }
}
```

#### 4. Migrate your database schema (if applicable) [#4-migrate-your-database-schema-if-applicable-1]

If you ran `npx prisma init` above, you need to migrate your database schema to create the `User` table that's defined in your Prisma schema (if you already have all the tables you need in your database, you can skip this step):

  

#### bun

```bash
bunx prisma db push
```

#### pnpm

```bash
pnpm prisma db push
```

#### yarn

```bash
yarn prisma db push
```

#### npm

```bash
npx prisma db push
```

#### 5. Use Prisma Client in an Edge Function to send a query to the database [#5-use-prisma-client-in-an-edge-function-to-send-a-query-to-the-database]

If you created the project from scratch, you can create a new edge function as follows.

First, create a new API route, e.g. by using these commands:

```bash
mkdir src/app/api
mkdir src/app/api/edge
touch src/app/api/edge/route.ts
```

Here is a sample code snippet that you can use to instantiate `PrismaClient` and send a query to your database in the new `app/api/edge/route.ts` file you just created:

```ts title="app/api/edge/route.ts" showLineNumbers
import { NextResponse } from "next/server";
import { PrismaClient } from "./generated/client";
import { PrismaPlanetScale } from "@prisma/adapter-planetscale";

export const runtime = "nodejs"; // can also be set to 'edge'

export async function GET(request: Request) {
  const adapter = new PrismaPlanetScale({ url: process.env.DATABASE_URL });
  const prisma = new PrismaClient({ adapter });

  const users = await prisma.user.findMany();

  return NextResponse.json(users, { status: 200 });
}
```

#### 6. Run the Edge Function locally [#6-run-the-edge-function-locally-1]

Run the app with the following command:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

You can now access the Edge Function via `http://localhost:3000/api/edge`.

#### 7. Set the `DATABASE_URL` environment variable and deploy the Edge Function [#7-set-the-database_url-environment-variable-and-deploy-the-edge-function]

Run the following command to deploy your project with Vercel:

  

#### bun

```bash
bunx vercel deploy
```

#### pnpm

```bash
pnpm dlx vercel deploy
```

#### yarn

```bash
yarn dlx vercel deploy
```

#### npm

```bash
npx vercel deploy
```

Note that once the project was created on Vercel, you will need to set the `DATABASE_URL` environment variable (and if this was your first deploy, it likely failed). You can do this either via the Vercel UI or by running the following command:

  

#### bun

```bash
bunx vercel env add DATABASE_URL
```

#### pnpm

```bash
pnpm dlx vercel env add DATABASE_URL
```

#### yarn

```bash
yarn dlx vercel env add DATABASE_URL
```

#### npm

```bash
npx vercel env add DATABASE_URL
```

At this point, you can get the URL of the deployed application from the Vercel Dashboard and access the edge function via the `/api/edge` route.

### Neon [#neon]

If you are using a Neon database, you need to:

* use the `@prisma/adapter-neon` database adapter (learn more in [Using driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql#using-driver-adapters))

#### 1. Configure Prisma schema & database connection [#1-configure-prisma-schema--database-connection-2]

> [!NOTE]
> If you don't have a project to deploy, follow the instructions in the [Prerequisites](#prerequisites) to bootstrap a basic Next.js app with Prisma ORM in it.

First, ensure that the database connection is configured properly. Database connection URLs are configured in `prisma.config.ts`:

```prisma title="schema.prisma" showLineNumbers
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider = "postgresql"
}
```

```ts title="prisma.config.ts"
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DATABASE_URL"),
  },
});
```

Next, you need to set the `DATABASE_URL` environment variable in your `.env` file that's used both by Prisma and Next.js to read your env vars:

```bash title=".env"
DATABASE_URL="postgresql://janedoe:password@ep-nameless-pond-a23b1mdz.eu-central-1.aws.neon.tech/neondb?sslmode=require"
```

#### 2. Install dependencies [#2-install-dependencies-2]

Next, install the required packages:

  

#### bun

```bash
bun add @prisma/adapter-neon
```

#### pnpm

```bash
pnpm add @prisma/adapter-neon
```

#### yarn

```bash
yarn add @prisma/adapter-neon
```

#### npm

```bash
npm install @prisma/adapter-neon
```

#### 3. Configure `postinstall` hook [#3-configure-postinstall-hook-2]

Next, add a new key to the `scripts` section in your `package.json`:

```js title="package.json"
{
  // ...
  "scripts": {
    // ...
    "postinstall": "prisma generate" // [!code ++]
  }
}
```

#### 4. Migrate your database schema (if applicable) [#4-migrate-your-database-schema-if-applicable-2]

If you ran `npx prisma init` above, you need to migrate your database schema to create the `User` table that's defined in your Prisma schema (if you already have all the tables you need in your database, you can skip this step):

  

#### bun

```bash
bunx prisma migrate dev --name init
```

#### pnpm

```bash
pnpm prisma migrate dev --name init
```

#### yarn

```bash
yarn prisma migrate dev --name init
```

#### npm

```bash
npx prisma migrate dev --name init
```

#### 5. Use Prisma Client in an Edge Function to send a query to the database [#5-use-prisma-client-in-an-edge-function-to-send-a-query-to-the-database-1]

If you created the project from scratch, you can create a new edge function as follows.

First, create a new API route, e.g. by using these commands:

```bash
mkdir src/app/api
mkdir src/app/api/edge
touch src/app/api/edge/route.ts
```

Here is a sample code snippet that you can use to instantiate `PrismaClient` and send a query to your database in the new `app/api/edge/route.ts` file you just created:

```ts title="app/api/edge/route.ts" showLineNumbers
import { NextResponse } from "next/server";
import { PrismaClient } from "./generated/client";
import { PrismaNeon } from "@prisma/adapter-neon";

export const runtime = "nodejs"; // can also be set to 'edge'

export async function GET(request: Request) {
  const adapter = new PrismaNeon({ connectionString: process.env.DATABASE_URL });
  const prisma = new PrismaClient({ adapter });

  const users = await prisma.user.findMany();

  return NextResponse.json(users, { status: 200 });
}
```

#### 6. Run the Edge Function locally [#6-run-the-edge-function-locally-2]

Run the app with the following command:

  

#### bun

```bash
bun run dev
```

#### pnpm

```bash
pnpm run dev
```

#### yarn

```bash
yarn dev
```

#### npm

```bash
npm run dev
```

You can now access the Edge Function via `http://localhost:3000/api/edge`.

#### 7. Set the `DATABASE_URL` environment variable and deploy the Edge Function [#7-set-the-database_url-environment-variable-and-deploy-the-edge-function-1]

Run the following command to deploy your project with Vercel:

  

#### bun

```bash
bunx vercel deploy
```

#### pnpm

```bash
pnpm dlx vercel deploy
```

#### yarn

```bash
yarn dlx vercel deploy
```

#### npm

```bash
npx vercel deploy
```

Note that once the project was created on Vercel, you will need to set the `DATABASE_URL` environment variable (and if this was your first deploy, it likely failed). You can do this either via the Vercel UI or by running the following command:

  

#### bun

```bash
bunx vercel env add DATABASE_URL
```

#### pnpm

```bash
pnpm dlx vercel env add DATABASE_URL
```

#### yarn

```bash
yarn dlx vercel env add DATABASE_URL
```

#### npm

```bash
npx vercel env add DATABASE_URL
```

At this point, you can get the URL of the deployed application from the Vercel Dashboard and access the edge function via the `/api/edge` route.

## Using Prisma ORM with Vercel Fluid [#using-prisma-orm-with-vercel-fluid]

[Fluid compute](https://vercel.com/fluid) is Vercel's compute model for dynamic workloads such as streaming data and AI APIs. Vercel's Fluid compute [supports both edge and Node.js runtimes](https://vercel.com/docs/fluid-compute#available-runtime-support). A common challenge in traditional serverless platforms is leaked database connections when functions are suspended and pools can't close idle connections. Fluid provides [`attachDatabasePool`](https://vercel.com/blog/the-real-serverless-compute-to-database-connection-problem-solved) to ensure idle connections are released before a function is suspended.

Use `attachDatabasePool` together with [Prisma's driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers) to safely manage connections in Fluid:

```ts
import { Pool } from "pg";
import { attachDatabasePool } from "@vercel/functions";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "./generated/client";

const pool = new Pool({ connectionString: process.env.POSTGRES_URL });

attachDatabasePool(pool);

const prisma = new PrismaClient({
  adapter: new PrismaPg(pool),
});
```

## Related pages

- [`Deploy to Cloudflare Workers & Pages`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare): Learn the things you need to know in order to deploy an app that uses Prisma Client for talking to a database to a Cloudflare Worker or to Cloudflare Pages
- [`Deploy to Deno Deploy`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-deno-deploy)
- [`Deploying edge functions with Prisma ORM`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/overview): Learn how to deploy your Prisma-backed apps to edge functions like Cloudflare Workers or Vercel Edge Functions

# Deploying edge functions with Prisma ORM (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/edge/overview)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy your Prisma-backed apps to edge functions like Cloudflare Workers or Vercel Edge Functions

Location: ORM > v7 > Prisma Client > Deployment > Edge > Deploying edge functions with Prisma ORM

You can deploy an application that uses Prisma ORM to the edge. Depending on which edge function provider and which database you use, there are different considerations and things to be aware of.

**Questions answered in this page**

* Which database drivers work on edge?
* How do driver adapters affect connections?
* When to use the Prisma Postgres serverless driver?

Here is a brief overview of all the edge function providers that are currently supported by Prisma ORM:

| Provider / Product     | Supported natively with Prisma ORM                   | Supported with the Prisma Postgres serverless driver |
| ---------------------- | ---------------------------------------------------- | ---------------------------------------------------- |
| Vercel Edge Functions  | ✅ (Preview; only compatible drivers)                 | ✅                                                    |
| Vercel Edge Middleware | ✅ (Preview; only compatible drivers)                 | ✅                                                    |
| Cloudflare Workers     | ✅ (Preview; only compatible drivers)                 | ✅                                                    |
| Cloudflare Pages       | ✅ (Preview; only compatible drivers)                 | ✅                                                    |
| Deno Deploy            | [Not yet](https://github.com/prisma/orm/issues/2452) | ✅                                                    |

Deploying edge functions that use Prisma ORM on Cloudflare and Vercel is currently in [Preview](https://www.prisma.io/docs/orm/v7/more/releases#preview).

## Edge-compatibility of database drivers [#edge-compatibility-of-database-drivers]

### Why are there limitations around database drivers in edge functions? [#why-are-there-limitations-around-database-drivers-in-edge-functions]

Edge functions typically don't use the standard Node.js runtime. For example, Vercel Edge Functions and Cloudflare Workers are running code in [V8 isolates](https://v8docs.nodesource.com/node-0.8/d5/dda/classv8_1_1_isolate.html). Deno Deploy is using the [Deno](https://deno.com/) JavaScript runtime. As a consequence, these edge functions only have access to a small subset of the standard Node.js APIs and also have constrained computing resources (CPU and memory).

In particular, the constraint of not being able to freely open TCP connections makes it difficult to talk to a traditional database from an edge function. While Cloudflare has introduced a [`connect()`](https://developers.cloudflare.com/workers/runtime-apis/tcp-sockets/) API that enables limited TCP connections, this still only enables database access using specific database drivers that are compatible with that API.

> [!NOTE]
> For hosted Prisma Postgres, use the [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver). For another database, choose an edge-compatible driver and its Prisma driver adapter.

### Which database drivers are edge-compatible? [#which-database-drivers-are-edge-compatible]

Here is an overview of the different database drivers and their compatibility with different edge function offerings:

* [Neon Serverless](https://neon.tech/docs/serverless/serverless-driver) uses HTTP to access the database. It works with Cloudflare Workers and Vercel Edge Functions.
* [PlanetScale Serverless](https://planetscale.com/docs/tutorials/planetscale-serverless-driver) uses HTTP to access the database. It works with Cloudflare Workers and Vercel Edge Functions.
* [`node-postgres`](https://node-postgres.com/) (`pg`) uses Cloudflare's `connect()` (TCP) to access the database. It is only compatible with Cloudflare Workers, not with Vercel Edge Functions.
* [`@libsql/client`](https://github.com/tursodatabase/libsql-client-ts) is used to access Turso databases. It works with Cloudflare Workers and Vercel Edge Functions.
* [Cloudflare D1](https://developers.cloudflare.com/d1/) is used to access D1 databases. It is only compatible with Cloudflare Workers, not with Vercel Edge Functions.
* The [Prisma Postgres serverless driver](https://www.prisma.io/docs/postgres/database/serverless-driver) uses HTTP and WebSockets. It is supported on Cloudflare Workers, Vercel Edge Functions, and other runtimes with `fetch` and `WebSocket` APIs.

There's [also work being done](https://github.com/sidorares/node-mysql2/pull/2289) on the `node-mysql2` driver which will enable access to traditional MySQL databases from Cloudflare Workers and Pages in the future as well.

You can use all of these drivers with Prisma ORM using the respective [driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers).

Depending on which deployment provider and database/driver you use, there may be special considerations. Please take a look at the deployment docs for your respective scenario to make sure you can deploy your application successfully:

* Cloudflare
  * [PostgreSQL (traditional)](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare#postgresql-traditional)
  * [PlanetScale](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare#planetscale)
  * [Neon](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare#neon)
  * [Cloudflare D1](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-d1)
  * [Prisma Postgres](https://developers.cloudflare.com/workers/tutorials/using-prisma-postgres-with-workers)
* Vercel
  * [Vercel Postgres](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-vercel#vercel-postgres)
  * [Neon](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-vercel#neon)
  * [PlanetScale](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-vercel#planetscale)
  * [Prisma Postgres](https://www.prisma.io/docs/guides/v7/frameworks/nextjs)

If you want to deploy an app using Turso, you can follow the instructions in [Using driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite#using-driver-adapters).

## Related pages

- [`Deploy to Cloudflare Workers & Pages`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare): Learn the things you need to know in order to deploy an app that uses Prisma Client for talking to a database to a Cloudflare Worker or to Cloudflare Pages
- [`Deploy to Deno Deploy`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-deno-deploy)
- [`Deploy to Vercel Edge Functions & Middleware`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-vercel): Learn the things you need to know in order to deploy an Edge function that uses Prisma Client for talking to a database

# Deploy to AWS Lambda (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-aws-lambda)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy your Prisma ORM-backed applications to AWS Lambda with AWS SAM, Serverless Framework, or SST

Location: ORM > v7 > Prisma Client > Deployment > Serverless > Deploy to AWS Lambda

> [!NOTE]
> Quick summary
> 
> This guide explains how to avoid common issues when deploying a project using Prisma ORM to [AWS Lambda](https://aws.amazon.com/lambda/).

**Questions answered in this page**

* How to deploy Prisma to AWS Lambda?
* Which binaryTargets should I configure?
* How to handle connection pooling on Lambda?

While a deployment framework is not required to deploy to AWS Lambda, this guide covers deploying with:

* [AWS Serverless Application Model (SAM)](https://aws.amazon.com/serverless/sam/) is an open-source framework from AWS that can be used in the creation of serverless applications. AWS SAM includes the [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-reference.html#serverless-sam-cli), which you can use to build, test, and deploy your application.

* [Serverless Framework](https://www.serverless.com/framework) provides a CLI that helps with workflow automation and AWS resource provisioning. Prisma ORM works with the Serverless Framework without extra configuration, but a few changes to your project improve deployment and performance. There is also additional configuration that is needed if you are using the [`serverless-webpack`](https://www.npmjs.com/package/serverless-webpack) or [`serverless-bundle`](https://www.npmjs.com/package/serverless-bundle) libraries.

* [SST](https://sst.dev/) provides tools to define, test, debug, and deploy applications. Prisma ORM works well with SST but must be configured so that your schema is correctly packaged by SST.

## General considerations when deploying to AWS Lambda [#general-considerations-when-deploying-to-aws-lambda]

This section covers changes you will need to make to your application, regardless of framework. After following these steps, follow the steps for your framework.

* [Deploying with AWS SAM](#deploying-with-aws-sam)
* [Deploying with the Serverless Framework](#deploying-with-the-serverless-framework)
* [Deploying with SST](#deploying-with-sst)

### Connection pooling [#connection-pooling]

In a Function as a Service (FaaS) environment, each function invocation typically creates a new database connection. Unlike a continuously running Node.js server, these connections aren't maintained between executions. For better performance in serverless environments, implement connection pooling to reuse existing database connections rather than creating new ones for each function call.

You can use [Prisma Postgres](https://www.prisma.io/docs/postgres), which has built-in connection pooling, to solve this issue. For other solutions, see the [connection management guide for serverless environments](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections#serverless-environments-faas).

## Deploying with AWS SAM [#deploying-with-aws-sam]

### Loading environment variables [#loading-environment-variables]

AWS SAM does not directly support loading values from a `.env` file. You will have to use one of AWS's services to store and retrieve these parameters. [The practical guide to surviving AWS SAM](https://medium.com/bip-xtech/a-practical-guide-to-surviving-aws-sam-d8ab141b3d25) describes your options and how to store and retrieve values in Parameters, SSM, Secrets Manager, and more.

## Deploying with the Serverless Framework [#deploying-with-the-serverless-framework]

### Loading environment variables via a `.env` file [#loading-environment-variables-via-a-env-file]

Your functions will need the `DATABASE_URL` environment variable to access the database. The `serverless-dotenv-plugin` will allow you to use your `.env` file in your deployments.

First, make sure that the plugin is installed:

  

#### bun

```bash
bun add --dev serverless-dotenv-plugin
```

#### pnpm

```bash
pnpm add -D serverless-dotenv-plugin
```

#### yarn

```bash
yarn add --dev serverless-dotenv-plugin
```

#### npm

```bash
npm install -D serverless-dotenv-plugin
```

Then, add `serverless-dotenv-plugin` to your list of plugins in `serverless.yml`:

```yaml title="serverless.yml"
plugins:
  - serverless-dotenv-plugin
```

The environment variables in your `.env` file will now be automatically loaded on package or deployment.

```bash
serverless package
```

```bash
Running "serverless" from node_modules
DOTENV: Loading environment variables from .env:
         - DATABASE_URL

Packaging deployment-example-sls for stage dev (us-east-1)
.
```

## Deploying with SST [#deploying-with-sst]

### Working with environment variables [#working-with-environment-variables]

While SST supports `.env` files, [it is not recommended](https://v2.sst.dev/config#should-i-use-configsecret-or-env-for-secrets). SST recommends using `Config` to access these environment variables in a secure way.

The SST guide [available here](https://v2.sst.dev/config#overview) is a step-by-step guide to get started with `Config`. Assuming you have created a new secret called `DATABASE_URL` and have [bound that secret to your app](https://v2.sst.dev/config#bind-the-config), you can set up `PrismaClient` with the following:

```ts title="prisma.ts" showLineNumbers
import { PrismaClient } from "./generated/client";
import { Config } from "sst/node/config";
import { PrismaPg } from "@prisma/adapter-pg";
const globalForPrisma = global as unknown as { prisma: PrismaClient };

const adapter = new PrismaPg({ connectionString });

export const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({ adapter });

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

export default prisma;
```

## Related pages

- [`Deploy to Azure Functions`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-azure-functions): Learn how to deploy a Prisma Client based REST API to Azure Functions and connect to an Azure SQL database
- [`Deploy to Netlify`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-netlify): Learn how to deploy Node.js and TypeScript applications that are using Prisma Client to Netlify
- [`Deploy to Vercel`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-vercel): Learn how to deploy a Next.js application based on Prisma Client to Vercel

# Deploy to Azure Functions (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-azure-functions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy a Prisma Client based REST API to Azure Functions and connect to an Azure SQL database

Location: ORM > v7 > Prisma Client > Deployment > Serverless > Deploy to Azure Functions

This guide explains how to avoid common issues when deploying a Node.js-based function app to Azure using [Azure Functions](https://azure.microsoft.com/en-us/products/functions/).

Azure Functions is a serverless deployment platform. You do not need to maintain infrastructure to deploy your code. With Azure Functions, the fundamental building block is the [function app](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=blob\&pivots=programming-language-typescript). A function app provides an execution context in Azure in which your functions run. It is comprised of one or more individual functions that Azure manages, deploys, and scales together. You can organize and collectively manage multiple functions as a single logical unit.

## Prerequisites [#prerequisites]

* An existing function app project with Prisma ORM

## Things to know [#things-to-know]

While Prisma ORM works well with Azure functions, there are a few things to take note of before deploying your application.

### Connection pooling [#connection-pooling]

Generally, when you use a FaaS (Function as a Service) environment to interact with a database, every function invocation can result in a new connection to the database. This is not a problem with a constantly running Node.js server. Therefore, it is beneficial to pool DB connections to get better performance. To solve this issue, you can use [Prisma Postgres](https://www.prisma.io/docs/postgres). For other solutions, see the [connection management guide for serverless environments](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections#serverless-environments-faas).

## Summary [#summary]

For more insight into Prisma Client's API, explore the function handlers and check out the [Prisma Client API Reference](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference)

## Related pages

- [`Deploy to AWS Lambda`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-aws-lambda): Learn how to deploy your Prisma ORM-backed applications to AWS Lambda with AWS SAM, Serverless Framework, or SST
- [`Deploy to Netlify`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-netlify): Learn how to deploy Node.js and TypeScript applications that are using Prisma Client to Netlify
- [`Deploy to Vercel`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-vercel): Learn how to deploy a Next.js application based on Prisma Client to Vercel

# Deploy to Netlify (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-netlify)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy Node.js and TypeScript applications that are using Prisma Client to Netlify

Location: ORM > v7 > Prisma Client > Deployment > Serverless > Deploy to Netlify

This guide covers the steps you will need to take in order to deploy your application that uses Prisma ORM to [Netlify](https://www.netlify.com/).

Netlify is a cloud platform for continuous deployment, static sites, and serverless functions. Netlify integrates with GitHub for automatic deployments upon commits. When you follow the steps below, you will use that approach to create a CI/CD pipeline that deploys your application from a GitHub repository.

## Prerequisites [#prerequisites]

Before you can follow this guide, you will need to set up your application to begin deploying to Netlify. We recommend the ["Get started with Netlify"](https://docs.netlify.com/get-started/) guide for a quick overview and ["Deploy functions"](https://docs.netlify.com/functions/deploy/?fn-language=ts) for an in-depth look at your deployment options.

## Store environment variables in Netlify [#store-environment-variables-in-netlify]

We recommend keeping `.env` files in your `.gitignore` in order to prevent leakage of sensitive connection strings. Instead, you can use the Netlify CLI to [import values into netlify directly](https://docs.netlify.com/environment-variables/get-started/#import-variables-with-the-netlify-cli).

Assuming you have a file like the following:

```text title=".env"
# Connect to DB
DATABASE_URL="postgresql://postgres:__PASSWORD__@__HOST__:__PORT__/__DB_NAME__"
```

You can upload the file as environment variables using the `env:import` command:

```bash no-break-terminal
netlify env:import .env
```

```bash
site: my-very-very-cool-site
---------------------------------------------------------------------------------.
                         Imported environment variables                          |
---------------------------------------------------------------------------------|
     Key      |                              Value                               |
--------------|------------------------------------------------------------------|
 DATABASE_URL | postgresql://postgres:__PASSWORD__@__HOST__:__PORT__/__DB_NAME__ |
---------------------------------------------------------------------------------'
```

**If you are not using an `.env` file**

If you are storing your database connection string and other environment variables in a different method, you will need to manually upload your environment variables to Netlify. These options are [discussed in Netlify's documentation](https://docs.netlify.com/environment-variables/get-started/) and one method, uploading via the UI, is described below.

1. Open the Netlify admin UI for the site. You can use Netlify CLI as follows:
   ```bash
   netlify open --admin
   ```
2. Click **Site settings**:
   ![Netlify admin UI](https://www.prisma.io/img/orm/prisma-client/deployment/serverless/images/500-06-deploy-to-netlify-site-settings.png)
3. Navigate to **Build & deploy** in the sidebar on the left and select **Environment**.
4. Click **Edit variables** and create a variable with the key `DATABASE_URL` and set its value to your database connection string.
   ![Netlify environment variables](https://www.prisma.io/img/orm/prisma-client/deployment/serverless/images/500-07-deploy-to-netlify-environment-variables-settings.png)
5. Click **Save**.

Now start a new Netlify build and deployment so that the new build can use the newly uploaded environment variables.

```bash
netlify deploy
```

You can now test the deployed application.

## Connection pooling [#connection-pooling]

When you use a Function-as-a-Service provider, like Netlify, it is beneficial to pool database connections for performance reasons. This is because every function invocation may result in a new connection to your database which can quickly run out of open connections.

You can use [Prisma Postgres](https://www.prisma.io/docs/postgres), which has built-in connection pooling, to reduce your Prisma Client bundle size, and to avoid cold starts.

For more information on connection management for serverless environments, refer to our [connection management guide](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections#serverless-environments-faas).

## Related pages

- [`Deploy to AWS Lambda`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-aws-lambda): Learn how to deploy your Prisma ORM-backed applications to AWS Lambda with AWS SAM, Serverless Framework, or SST
- [`Deploy to Azure Functions`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-azure-functions): Learn how to deploy a Prisma Client based REST API to Azure Functions and connect to an Azure SQL database
- [`Deploy to Vercel`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-vercel): Learn how to deploy a Next.js application based on Prisma Client to Vercel

# Deploy to Vercel (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-vercel)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy a Next.js application based on Prisma Client to Vercel

Location: ORM > v7 > Prisma Client > Deployment > Serverless > Deploy to Vercel

This guide takes you through the steps to set up and deploy a serverless application that uses Prisma to [Vercel](https://vercel.com/).

Vercel is a cloud platform that hosts static sites, serverless, and edge functions. You can integrate a Vercel project with a GitHub repository to allow you to deploy automatically when you make new commits.

We created an [example application](https://github.com/prisma/deployment-example-vercel) using Next.js you can use as a reference when deploying an application using Prisma to Vercel.

While our examples use Next.js, you can deploy other applications to Vercel. See [Using Express with Vercel](https://vercel.com/guides/using-express-with-vercel) and [Nuxt on Vercel](https://vercel.com/docs/frameworks/nuxt) as examples of other options.

## Build configuration [#build-configuration]

### Updating Prisma Client during Vercel builds [#updating-prisma-client-during-vercel-builds]

Vercel will automatically cache dependencies on deployment. For most applications, this will not cause any issues. However, for Prisma ORM, it may result in an outdated version of Prisma Client on a change in your Prisma schema. To avoid this issue, add `prisma generate` to the `postinstall` script of your application:

```json title="package.json" showLineNumbers
{
  ...
  "scripts": {
    "postinstall": "prisma generate" // [!code ++]
  }
  ...
}
```

This will re-generate Prisma Client at build time so that your deployment always has an up-to-date client. Another option to avoid an outdated Prisma Client is to check your client into version control. This way each deployment is guaranteed to include the correct Prisma Client.

> [!NOTE]
> If you see `prisma: command not found` errors during your deployment to Vercel, you are missing `prisma` in your dependencies. By default, `prisma` is a dev dependency and may need to be moved to be a standard dependency.

### CI/CD workflows [#cicd-workflows]

In a more sophisticated CI/CD environment, you may additionally want to update the database schema with any migrations you have performed during local development. You can do this using the [`prisma migrate deploy`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-deploy) command.

In that case, you could create a custom build command in your `package.json` (e.g. called `vercel-build`) that looks as follows:

```json title="package.json"
{
  ...
  "scripts" {
    "vercel-build": "prisma generate && prisma migrate deploy && next build", // [!code ++]
  }
  ...
}
```

You can invoke this script inside your CI/CD pipeline using the following command:

  

#### bun

```bash
bun run vercel-build
```

#### pnpm

```bash
pnpm run vercel-build
```

#### yarn

```bash
yarn vercel-build
```

#### npm

```bash
npm run vercel-build
```

## Add a separate database for preview deployments [#add-a-separate-database-for-preview-deployments]

By default, your application will have a single *production* environment associated with the `main` git branch of your repository. If you open a pull request to change your application, Vercel creates a new *preview* environment.

Vercel uses the `DATABASE_URL` environment variable you define when you import the project for both the production and preview environments. This causes problems if you create a pull request with a database schema migration because the pull request will change the schema of the production database.

To prevent this, use a *second* hosted database to handle preview deployments. Once you have that connection string, you can add a `DATABASE_URL` for your preview environment using the Vercel dashboard:

1. Click the **Settings** tab of your Vercel project.

2. Click **Environment variables**.

3. Add an environment variable with a key of `DATABASE_URL` and select only the **Preview** environment option:

   ![Add an environment variable for the preview environment](https://www.prisma.io/img/orm/prisma-client/deployment/serverless/images/300-60-deploy-to-vercel-preview-environment-variable.png)

4. Set the value to the connection string of your second database:

   ```bash
   postgresql://dbUsername:dbPassword@myhost:5432/mydb
   ```

5. Click **Save**.

## Connection pooling [#connection-pooling]

When you use a Function-as-a-Service provider, like Vercel Serverless functions, every invocation may result in a new connection to your database. This can cause your database to quickly run out of open connections and cause your application to stall. For this reason, pooling connections to your database is essential.

You can use [Prisma Postgres](https://www.prisma.io/docs/postgres), which has built-in connection pooling, to reduce your Prisma Client bundle size, and to avoid cold starts.

For more information on connection management for serverless environments, refer to our [connection management guide](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections#serverless-environments-faas).

## Using Prisma ORM with Vercel Fluid [#using-prisma-orm-with-vercel-fluid]

[Fluid compute](https://vercel.com/fluid) is Vercel's compute model for dynamic workloads such as streaming data and AI APIs. Vercel's Fluid compute [supports both edge and Node.js runtimes](https://vercel.com/docs/fluid-compute#available-runtime-support). A common challenge in traditional serverless platforms is leaked database connections when functions are suspended and pools can't close idle connections. Fluid provides [`attachDatabasePool`](https://vercel.com/blog/the-real-serverless-compute-to-database-connection-problem-solved) to ensure idle connections are released before a function is suspended.

Use `attachDatabasePool` together with [Prisma's driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers) to safely manage connections in Fluid:

```ts
import { Pool } from "pg";
import { attachDatabasePool } from "@vercel/functions";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "./generated/client";

const pool = new Pool({ connectionString: process.env.POSTGRES_URL });

attachDatabasePool(pool);

export const prisma = new PrismaClient({
  adapter: new PrismaPg(pool),
});
```

## Related pages

- [`Deploy to AWS Lambda`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-aws-lambda): Learn how to deploy your Prisma ORM-backed applications to AWS Lambda with AWS SAM, Serverless Framework, or SST
- [`Deploy to Azure Functions`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-azure-functions): Learn how to deploy a Prisma Client based REST API to Azure Functions and connect to an Azure SQL database
- [`Deploy to Netlify`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/serverless/deploy-to-netlify): Learn how to deploy Node.js and TypeScript applications that are using Prisma Client to Netlify

# Deploy to Fly.io (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-flyio)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy a Node.js server that uses Prisma ORM to Fly.io

Location: ORM > v7 > Prisma Client > Deployment > Traditional > Deploy to Fly.io

This guide explains how to deploy a Node.js server that uses Prisma ORM and PostgreSQL to Fly.io.

The [Prisma Render deployment example](https://github.com/prisma/prisma-examples/tree/latest/deployment-platforms/render) contains an Express.js application with REST endpoints and a simple frontend. This app uses Prisma Client to fetch, create, and delete records from its database.
This guide will show you how to deploy the same application, without modification, on Fly.io.

## About Fly.io [#about-flyio]

[fly.io](https://fly.io/) is a cloud application platform that lets you deploy and scale full-stack applications that start on request, on machines near your users. For this example, it's helpful to know:

* Fly.io lets you deploy long-running, "serverful" full-stack applications in [35 regions around the world](https://fly.io/docs/reference/regions/). By default, applications are configured to [auto-stop](https://fly.io/docs/launch/autostop-autostart/) when not in use, and auto-start as needed as requests come in.
* Fly.io natively supports a wide variety of [languages and frameworks](https://fly.io/docs/languages-and-frameworks/), including Node.js and Bun. In this guide, we'll use the Node.js runtime.
* Fly.io can [launch apps directly from GitHub](https://fly.io/speedrun). When run from the CLI, `fly launch` will automatically configure applications hosted on GitHub to deploy on push.

## Prerequisites [#prerequisites]

* Sign up for a [Fly.io](https://fly.io/docs/getting-started/launch/) account

## Get the example code [#get-the-example-code]

Download the [example code](https://github.com/prisma/prisma-examples/tree/latest/deployment-platforms/render) to your local machine.

```bash
curl https://codeload.github.com/prisma/prisma-examples/tar.gz/latest | tar -xz --strip=2 prisma-examples-latest/deployment-platforms/render
cd render
```

## Understand the example [#understand-the-example]

Before deploying, review the example code.

### Web application [#web-application]

The logic for the Express app is in two files:

* `src/index.js`: The API. The endpoints use Prisma Client to fetch, create, and delete data from the database.
* `public/index.html`: The web frontend. The frontend calls a few of the API endpoints.

### Prisma schema and migrations [#prisma-schema-and-migrations]

The Prisma components of this app are in three files:

* `prisma/schema.prisma`: The data model of this app. This example defines two models, `User` and `Post`. The format of this file follows the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview).
* `prisma/migrations/<migration name>/migration.sql`: The SQL commands that construct this schema in a PostgreSQL database. You can auto-generate migration files like this one by running [`prisma migrate dev`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/mental-model#what-is-prisma-migrate).
* `prisma/seed.js`: defines some test users and postsPrisma, used to [seed the database](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/seeding) with starter data.

## Deploy the example [#deploy-the-example]

### 1. Run `fly launch` and accept the defaults [#1-run-fly-launch-and-accept-the-defaults]

Your web service will be live at its `fly.dev` URL as soon as the deploy completes. Optionally [scale](https://fly.io/docs/launch/scale-count/) the size, number, and placement of machines as desired. [`fly console`](https://fly.io/docs/flyctl/console/) can be used to ssh into a new or existing machine.

More information can be found on in the [fly.io documentation](https://fly.io/docs/js/prisma/).

## Related pages

- [`Deploy to Heroku`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-heroku): Learn how to deploy a Node.js server that uses Prisma ORM to Heroku
- [`Deploy to Koyeb`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-koyeb): Learn how to deploy a Node.js server that uses Prisma ORM to Koyeb Serverless Platform
- [`Deploy to Railway`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-railway): Learn how to deploy an app that uses Prisma ORM and Prisma Postgres to Railway
- [`Deploy to Render`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-render): Learn how to deploy a Node.js server that uses Prisma ORM to Render
- [`Deploy to Sevalla`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-sevalla): Learn how to deploy a Node.js server that uses Prisma ORM to Sevalla

# Deploy to Heroku (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-heroku)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy a Node.js server that uses Prisma ORM to Heroku

Location: ORM > v7 > Prisma Client > Deployment > Traditional > Deploy to Heroku

In this guide, you will set up and deploy a Node.js server that uses Prisma ORM with PostgreSQL to [Heroku](https://www.heroku.com). The application exposes a REST API and uses Prisma Client to handle fetching, creating, and deleting records from a database.

Heroku is a cloud platform as a service (PaaS). In contrast to the popular serverless deployment model, with Heroku, your application is constantly running even if no requests are made to it. This has several benefits due to the connection limits of a PostgreSQL database. For more information, check out the [general deployment documentation](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-prisma)

Typically Heroku integrates with a Git repository for automatic deployments upon commits. You can deploy to Heroku from a GitHub repository or by pushing your source to a [Git repository that Heroku creates per app](https://devcenter.heroku.com/articles/git). This guide uses the latter approach whereby you push your code to the app's repository on Heroku, which triggers a build and deploys the application.

The application has the following components:

* **Backend**: Node.js REST API built with Express.js with resource endpoints that use Prisma Client to handle database operations against a PostgreSQL database (e.g., hosted on Heroku).
* **Frontend**: Static HTML page to interact with the API.

![Heroku deployment architecture diagram showing a Node.js backend with Prisma Client, static frontend, and PostgreSQL database.](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/heroku-architecture.png)

The focus of this guide is showing how to deploy projects using Prisma ORM to Heroku. The starting point will be the [Prisma Heroku example](https://github.com/prisma/prisma-examples/tree/latest/deployment-platforms/heroku), which contains an Express.js server with a couple of preconfigured REST endpoints and a simple frontend.

> **Note:** The various **checkpoints** throughout the guide allowing you to validate whether you performed the steps correctly.

## A note on deploying GraphQL servers to Heroku [#a-note-on-deploying-graphql-servers-to-heroku]

While the example uses REST, the same principles apply to a GraphQL server, with the main difference being that you typically have a single GraphQL API endpoint rather than a route for every resource as with REST.

## Prerequisites [#prerequisites]

* [Heroku](https://www.heroku.com) account.
* [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) installed.
* Node.js installed.
* PostgreSQL CLI `psql` installed.

> **Note:** Heroku doesn't provide a free plan, so billing information is required.

## Prisma ORM workflow [#prisma-orm-workflow]

At the core of Prisma ORM is the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) – a declarative configuration where you define your data model and other Prisma ORM-related configuration. The Prisma schema is also a single source of truth for both Prisma Client and Prisma Migrate.

In this guide, you will use [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) to create the database schema. Prisma Migrate is based on the Prisma schema and works by generating `.sql` migration files that are executed against the database.

Migrate comes with two primary workflows:

* Creating migrations and applying during local development with `prisma migrate dev`
* Applying generated migration to production with `prisma migrate deploy`

For brevity, the guide does not cover how migrations are created with `prisma migrate dev`. Rather, it focuses on the production workflow and uses the Prisma schema and SQL migration that are included in the example code.

You will use Heroku's [release phase](https://devcenter.heroku.com/articles/release-phase) to run the `prisma migrate deploy` command so that the migrations are applied before the application starts.

To learn more about how migrations are created with Prisma Migrate, check out the [start from scratch guide](https://www.prisma.io/docs/v7/prisma-orm/quickstart/postgresql)

## 1. Download the example and install dependencies [#1-download-the-example-and-install-dependencies]

Open your terminal and navigate to a location of your choice. Create the directory that will hold the application code and download the example code:

```bash
mkdir prisma-heroku
cd prisma-heroku
curl https://codeload.github.com/prisma/prisma-examples/tar.gz/latest | tar -xz --strip=3 prisma-examples-latest/deployment-platforms/heroku
```

**Checkpoint:** `ls -1` should show:

```bash
ls -1
Procfile
README.md
package.json
prisma
public
src
```

Install the dependencies:

  

#### bun

```bash
bun install
```

#### pnpm

```bash
pnpm install
```

#### yarn

```bash
yarn install
```

#### npm

```bash
npm install
```

> **Note:** The `Procfile` tells Heroku the command needed to start the application, i.e. `npm start`, and the command to run during the release phase, i.e., `npx prisma migrate deploy`

## 2. Create a Git repository for the application [#2-create-a-git-repository-for-the-application]

In the previous step, you downloaded the code. In this step, you will create a repository from the code so that you can push it to Heroku for deployment.

To do so, run `git init` from the source code folder:

```bash
git init
> Initialized empty Git repository in /Users/alice/prisma-heroku/.git/
```

To use the `main` branch as the default branch, run the following command:

```bash
git branch -M main
```

With the repository initialized, add and commit the files:

```bash
git add .
git commit -m 'Initial commit'
```

**Checkpoint:** `git log -1` should show the commit:

```bash
git log -1
commit 895534590fdd260acee6396e2e1c0438d1be7fed (HEAD -> main)
```

## 3. Heroku CLI login [#3-heroku-cli-login]

Make sure you're logged in to Heroku with the CLI:

```bash
heroku login
```

This will allow you to deploy to Heroku from the terminal.

**Checkpoint:** `heroku auth:whoami` should show your username:

```bash
heroku auth:whoami
> your-email
```

## 4. Create a Heroku app [#4-create-a-heroku-app]

To deploy an application to Heroku, you need to create an app. You can do so with the following command:

```bash
heroku apps:create your-app-name
```

> **Note:** Use a unique name of your choice instead of `your-app-name`.

**Checkpoint:** You should see the URL and the repository for your Heroku app:

```bash
heroku apps:create your-app-name
> Creating ⬢ your-app-name... done
> https://your-app-name.herokuapp.com/ | https://git.heroku.com/your-app-name.git
```

Creating the Heroku app will add the git remote Heroku created to your local repository. Pushing commits to this remote will trigger a deploy.

**Checkpoint:** `git remote -v` should show the Heroku git remote for your application:

```bash
heroku https://git.heroku.com/your-app-name.git (fetch)
heroku https://git.heroku.com/your-app-name.git (push)
```

If you don't see the heroku remote, use the following command to add it:

```bash
heroku git:remote --app your-app-name
```

## 5. Add a PostgreSQL database to your application [#5-add-a-postgresql-database-to-your-application]

Heroku allows your to provision a PostgreSQL database as part of an application.

Create the database with the following command:

```bash
heroku addons:create heroku-postgresql:hobby-dev
```

**Checkpoint:** To verify the database was created you should see the following:

```bash
Creating heroku-postgresql:hobby-dev on ⬢ your-app-name... free
Database has been created and is available
 ! This database is empty. If upgrading, you can transfer
 ! data from another database with pg:copy
Created postgresql-parallel-73780 as DATABASE_URL
```

> **Note:** Heroku automatically sets the `DATABASE_URL` environment variable when the app is running on Heroku. Prisma ORM uses this environment variable because it's declared in the *datasource* block of the Prisma schema (`prisma/schema.prisma`) with `env("DATABASE_URL")`.

## 6. Push to deploy [#6-push-to-deploy]

Deploy the app by pushing the changes to the Heroku app repository:

```bash
git push heroku main
```

This will trigger a build and deploy your application to Heroku. Heroku will also run the `npx prisma migrate deploy` command which executes the migrations to create the database schema before deploying the app (as defined in the `release` step of the `Procfile`).

**Checkpoint:** `git push` will emit the logs from the build and release phase and display the URL of the deployed app:

```bash
remote: -----> Launching...
remote:  !     Release command declared: this new release will not be available until the command succeeds.
remote:        Released v5
remote:        https://your-app-name.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
remote: Running release command...
remote:
remote: Prisma schema loaded from prisma/schema.prisma
remote: Datasource "db": PostgreSQL database "your-db-name", schema "public" at "your-db-host.compute-1.amazonaws.com:5432"
remote:
remote: 1 migration found in prisma/migrations
remote:
remote: The following migration have been applied:
remote:
remote: migrations/
remote:   └─ 20210310152103_init/
remote:     └─ migration.sql
remote:
remote: All migrations have been successfully applied.
remote: Waiting for release.... done.
```

> **Note:** Heroku will also set the `PORT` environment variable to which your application is bound.

## 7. Test your deployed application [#7-test-your-deployed-application]

You can use the static frontend to interact with the API you deployed via the preview URL.

Open up the preview URL in your browser, the URL should like this: `https://APP_NAME.herokuapp.com`. You should see the following:

![Deployed Prisma app frontend in browser showing Check API status, Seed data, and Load feed buttons.](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/heroku-deployed.png)

The buttons allow you to make requests to the REST API and view the response:

* **Check API status**: Will call the REST API status endpoint that returns `{"up":true}`.
* **Seed data**: Will seed the database with a test `user` and `post`. Returns the created users.
* **Load feed**: Will load all `users` in the database with their related `profiles`.

For more insight into Prisma Client's API, look at the route handlers in the `src/index.js` file.

You can view the application's logs with the `heroku logs --tail` command:

```bash
2020-07-07T14:39:07.396544+00:00 app[web.1]:
2020-07-07T14:39:07.396569+00:00 app[web.1]: > prisma-heroku@1.0.0 start /app
2020-07-07T14:39:07.396569+00:00 app[web.1]: > node src/index.js
2020-07-07T14:39:07.396570+00:00 app[web.1]:
2020-07-07T14:39:07.657505+00:00 app[web.1]: 🚀 Server ready at: http://localhost:12516
2020-07-07T14:39:07.657526+00:00 app[web.1]: ⭐️ See sample requests: http://pris.ly/e/ts/rest-express#3-using-the-rest-api
2020-07-07T14:39:07.842546+00:00 heroku[web.1]: State changed from starting to up
```

## Heroku specific notes [#heroku-specific-notes]

There are some implementation details relating to Heroku that this guide addresses and are worth reiterating:

* **Port binding**: web servers bind to a port so that they can accept connections. When deploying to Heroku The `PORT` environment variable is set by Heroku. Ensure you bind to `process.env.PORT` so that your application can accept requests once deployed. A common pattern is to try binding to try `process.env.PORT` and fallback to a preset port as follows:

```js
const PORT = process.env.PORT || 3000;
const server = app.listen(PORT, () => {
  console.log(`app running on port ${PORT}`);
});
```

* **Database URL**: As part of Heroku's provisioning process, a `DATABASE_URL` config var is added to your app’s configuration. This contains the URL your app uses to access the database. Ensure that your `schema.prisma` file uses `env("DATABASE_URL")` so that Prisma Client can successfully connect to the database.

- **Disable SSL certificate validation**: When using the `PrismaPg` adapter with `DATABASE_URL`, make sure to disable SSL certificate validation in line with [Heroku's guidelines](https://devcenter.heroku.com/articles/heroku-postgresql#connecting-to-heroku-postgres). Failing to do so can result in a `P1010 DriverAdapterError: DatabaseAccessDenied` error. You can handle this conditionally based on whether the database is local or hosted on Heroku:

```js
const isSecureDb = !process.env.DATABASE_URL.includes("@127.0.0.1");

export const db = new PrismaClient({
  adapter: new PrismaPg({
    connectionString: process.env.DATABASE_URL + (isSecureDb ? `?sslmode=no-verify` : ""),
  }),
});
```

## Summary [#summary]

You have deployed a Node.js app with Prisma ORM to Heroku.

You can find the source code for the example in [this GitHub repository](https://github.com/prisma/prisma-examples/tree/latest/deployment-platforms/heroku).

For more insight into Prisma Client's API, look at the route handlers in the `src/index.js` file.

## Related pages

- [`Deploy to Fly.io`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-flyio): Learn how to deploy a Node.js server that uses Prisma ORM to Fly.io
- [`Deploy to Koyeb`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-koyeb): Learn how to deploy a Node.js server that uses Prisma ORM to Koyeb Serverless Platform
- [`Deploy to Railway`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-railway): Learn how to deploy an app that uses Prisma ORM and Prisma Postgres to Railway
- [`Deploy to Render`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-render): Learn how to deploy a Node.js server that uses Prisma ORM to Render
- [`Deploy to Sevalla`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-sevalla): Learn how to deploy a Node.js server that uses Prisma ORM to Sevalla

# Deploy to Koyeb (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-koyeb)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy a Node.js server that uses Prisma ORM to Koyeb Serverless Platform

Location: ORM > v7 > Prisma Client > Deployment > Traditional > Deploy to Koyeb

In this guide, you will set up and deploy a Node.js server that uses Prisma ORM with PostgreSQL to [Koyeb](https://www.koyeb.com/). The application exposes a REST API and uses Prisma Client to handle fetching, creating, and deleting records from a database.

Koyeb is a serverless platform for deploying apps globally. It runs Docker containers, web apps, and APIs with git-based deployment, TLS encryption, native autoscaling, a global edge network, and built-in service mesh and discovery.

When using the [Koyeb git-driven deployment](https://www.koyeb.com/docs/build-and-deploy/build-from-git) method, each time you push code changes to a GitHub repository a new build and deployment of the application are automatically triggered on the Koyeb Serverless Platform.
This guide uses the latter approach whereby you push your code to the app's repository on GitHub.

The application has the following components:

* **Backend**: Node.js REST API built with Express.js with resource endpoints that use Prisma Client to handle database operations against a PostgreSQL database (e.g., hosted on Heroku).
* **Frontend**: Static HTML page to interact with the API.

![Koyeb deployment architecture diagram showing a Node.js backend with Prisma Client, static frontend, and PostgreSQL database.](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/koyeb-architecture.png)

The focus of this guide is showing how to deploy projects using Prisma ORM to Koyeb. The starting point will be the [Prisma Koyeb example](https://github.com/koyeb/example-prisma), which contains an Express.js server with a couple of preconfigured REST endpoints and a simple frontend.

> **Note:** The various **checkpoints** throughout the guide allow you to validate whether you performed the steps correctly.

## Prerequisites [#prerequisites]

* Hosted PostgreSQL database and a URL from which it can be accessed, e.g. `postgresql://username:password@your_postgres_db.cloud.com/db_identifier` (you can use Supabase, which offers a [free plan](https://dev.to/prisma/set-up-a-free-postgresql-database-on-supabase-to-use-with-prisma-3pk6)).
* [GitHub](https://github.com) account with an empty public repository we will use to push the code.
* [Koyeb](https://www.koyeb.com) account.
* Node.js installed.

## Prisma ORM workflow [#prisma-orm-workflow]

At the core of Prisma ORM is the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview) – a declarative configuration where you define your data model and other Prisma ORM-related configuration. The Prisma schema is also a single source of truth for both Prisma Client and Prisma Migrate.

In this guide, you will create the database schema with [Prisma Migrate](https://www.prisma.io/docs/orm/v7/prisma-migrate) to create the database schema. Prisma Migrate is based on the Prisma schema and works by generating `.sql` migration files that are executed against the database.

Migrate comes with two primary workflows:

* Creating migrations and applying them during local development with `prisma migrate dev`
* Applying generated migration to production with `prisma migrate deploy`

For brevity, the guide does not cover how migrations are created with `prisma migrate dev`. Rather, it focuses on the production workflow and uses the Prisma schema and SQL migration that are included in the example code.

You will use Koyeb's [build step](https://www.koyeb.com/docs/build-and-deploy/build-from-git#the-buildpack-build-process) to run the `prisma migrate deploy` command so that the migrations are applied before the application starts.

To learn more about how migrations are created with Prisma Migrate, check out the [start from scratch guide](https://www.prisma.io/docs/v7/prisma-orm/quickstart/postgresql)

## 1. Download the example and install dependencies [#1-download-the-example-and-install-dependencies]

Open your terminal and navigate to a location of your choice. Create the directory that will hold the application code and download the example code:

```bash
mkdir prisma-on-koyeb
cd prisma-on-koyeb
curl https://github.com/koyeb/example-prisma/tarball/main/latest | tar xz  --strip=1
```

**Checkpoint:** Executing the `tree` command should show the following directories and files:

```bash
.
├── README.md
├── package.json
├── prisma
│   ├── migrations
│   │   ├── 20210310152103_init
│   │   │   └── migration.sql
│   │   └── migration_lock.toml
│   └── schema.prisma
├── public
│   └── index.html
└── src
    └── index.js

5 directories, 8 files
```

Install the dependencies:

  

#### bun

```bash
bun install
```

#### pnpm

```bash
pnpm install
```

#### yarn

```bash
yarn install
```

#### npm

```bash
npm install
```

## 2. Initialize a Git repository and push the application code to GitHub [#2-initialize-a-git-repository-and-push-the-application-code-to-github]

In the previous step, you downloaded the code. In this step, you will create a repository from the code so that you can push it to a GitHub repository for deployment.

To do so, run `git init` from the source code folder:

```bash
git init
> Initialized empty Git repository in /Users/edouardb/prisma-on-koyeb/.git/
```

With the repository initialized, add and commit the files:

```bash
git add .
git commit -m 'Initial commit'
```

**Checkpoint:** `git log -1` should show the commit:

```bash
git log -1
commit 895534590fdd260acee6396e2e1c0438d1be7fed (HEAD -> main)
```

Then, push the code to your GitHub repository by adding the remote

```bash
git remote add origin git@github.com:<YOUR_GITHUB_USERNAME>/<YOUR_GITHUB_REPOSITORY_NAME>.git
git push -u origin main
```

## 3. Deploy the application on Koyeb [#3-deploy-the-application-on-koyeb]

On the [Koyeb Control Panel](https://app.koyeb.com), click the **Create App** button.

You land on the Koyeb App creation page where you are asked for information about the application to deploy such as the deployment method to use, the repository URL, the branch to deploy, the build and run commands to execute.

Pick GitHub as the deployment method and select the GitHub repository containing your application and set the branch to deploy to `main`.

> **Note:** If this is your first time using Koyeb, you will be prompted to install the Koyeb app in your GitHub account.

In the **Environment variables** section, create a new environment variable `DATABASE_URL` that is type Secret. In the value field, click **Create Secret**, name your secret `prisma-pg-url` and set the PostgreSQL database connection string as the secret value which should look as follows: `postgresql://__USER__:__PASSWORD__@__HOST__/__DATABASE__`.
[Koyeb Secrets](https://www.koyeb.com/docs/reference/secrets) allow you to securely store and retrieve sensitive information like API tokens, database connection strings. They enable you to secure your code by removing hardcoded credentials and let you pass environment variables securely to your applications.

Last, give your application a name and click the **Create App** button.

**Checkpoint:** Open the deployed app by clicking on the screenshot of the deployed app. Once the page loads, click on the **Check API status** button, which should return: `{"up":true}`

![Koyeb app creation interface showing environment variables configuration and Create App button.](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/koyeb-app-creation.png)

Koyeb will build and deploy the application. Additional commits to your GitHub repository will trigger a new build and deployment on Koyeb.

**Checkpoint:** Once the build and deployment are completed, you can access your application by clicking the App URL ending with koyeb.app in the Koyeb control panel. Once on the app page loads, Once the page loads, click on the **Check API status** button, which should return: `{"up":true}`

## 4. Test your deployed application [#4-test-your-deployed-application]

You can use the static frontend to interact with the API you deployed via the preview URL.

Open up the preview URL in your browser, the URL should like this: `https://APP_NAME-ORG_NAME.koyeb.app`. You should see the following:

![Deployed Prisma app frontend in browser showing Check API status, Seed data, and Load feed buttons.](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/koyeb-deployed.png)

The buttons allow you to make requests to the REST API and view the response:

* **Check API status**: Will call the REST API status endpoint that returns `{"up":true}`.
* **Seed data**: Will seed the database with a test `user` and `post`. Returns the created users.
* **Load feed**: Will load all `users` in the database with their related `profiles`.

For more insight into Prisma Client's API, look at the route handlers in the `src/index.js` file.

You can view the application's logs clicking the `Runtime logs` tab on your app service from the Koyeb control panel:

```bash
node-72d14691	stdout	> prisma-koyeb@1.0.0 start
node-72d14691	stdout	> node src/index.js
node-72d14691	stdout	🚀 Server ready at: http://localhost:8080
node-72d14691	stdout	⭐️ See sample requests: http://pris.ly/e/ts/rest-express#3-using-the-rest-api
```

## Koyeb specific notes [#koyeb-specific-notes]

### Build [#build]

By default, for applications using the Node.js runtime, if the `package.json` contains a `build` script, Koyeb automatically executes it after the dependencies installation.
In the example, the `build` script is used to run `prisma generate && prisma migrate deploy && next build`.

### Deployment [#deployment]

By default, for applications using the Node.js runtime, if the `package.json` contains a `start` script, Koyeb automatically executes it to launch the application.
In the example, the `start` script is used to run `node src/index.js`.

### Database migrations and deployments [#database-migrations-and-deployments]

In the example you deployed, migrations are applied using the `prisma migrate deploy` command during the Koyeb build (as defined in the `build` script in `package.json`).

### Additional notes [#additional-notes]

In this guide, we kept pre-set values for the region, instance size, and horizontal scaling. You can customize them according to your needs.

> **Note:** The Ports section is used to let Koyeb know which port your application is listening to and properly route incoming HTTP requests. A default `PORT` environment variable is set to `8080` and incoming HTTP requests are routed to the `/` path when creating a new application.
> If your application is listening on another port, you can define another port to route incoming HTTP requests.

## Summary [#summary]

You have deployed a Node.js app with Prisma ORM to Koyeb.

You can find the source code for the example in [this GitHub repository](https://github.com/koyeb/example-prisma).

For more insight into Prisma Client's API, look at the route handlers in the `src/index.js` file.

## Related pages

- [`Deploy to Fly.io`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-flyio): Learn how to deploy a Node.js server that uses Prisma ORM to Fly.io
- [`Deploy to Heroku`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-heroku): Learn how to deploy a Node.js server that uses Prisma ORM to Heroku
- [`Deploy to Railway`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-railway): Learn how to deploy an app that uses Prisma ORM and Prisma Postgres to Railway
- [`Deploy to Render`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-render): Learn how to deploy a Node.js server that uses Prisma ORM to Render
- [`Deploy to Sevalla`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-sevalla): Learn how to deploy a Node.js server that uses Prisma ORM to Sevalla

# Deploy to Railway (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-railway)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy an app that uses Prisma ORM and Prisma Postgres to Railway

Location: ORM > v7 > Prisma Client > Deployment > Traditional > Deploy to Railway

This guide explains how to deploy an app that uses Prisma ORM and Prisma Postgres to [Railway](https://railway.com?utm_medium=integration\&utm_source=docs\&utm_campaign=prisma). The app exposes a REST API and uses Prisma Client to query a Prisma Postgres database. Your app will run on Railway and connect to a managed Prisma Postgres database.

Railway is a deployment platform that provides instant deployments, built-in observability, and scaling. It supports code repositories and container images from popular registries. Railway handles configuration management, environment variables, and provides private networking between services.

To get a pre-wired Next.js Project with Prisma ORM, Prisma Postgres, and Railway, use the [Official Prisma Railway Template](https://railway.com/deploy/prisma-postgres?utm_medium=integration\&utm_source=docs\&utm_campaign=prisma).

This template provisions a Prisma Postgres database and links it to your Next.js application when you deploy.

## Prerequisites [#prerequisites]

You need:

* A [Railway account](https://railway.com?utm_medium=integration\&utm_source=docs\&utm_campaign=prisma)
* A GitHub repository with your application code.

> [!NOTE]
> If you don't have a project ready, you can use our [example Prisma project](https://github.com/prisma/prisma-examples/tree/latest/deployment-platforms/railway). It's a simple Hono application that uses Prisma ORM and includes a REST API, a frontend for testing endpoints, and a defined Prisma schema with migrations.

## Deploy your application [#deploy-your-application]

### 1. Create a new Railway project [#1-create-a-new-railway-project]

1. Go to the [Railway dashboard](https://railway.com/dashboard?utm_medium=integration\&utm_source=docs\&utm_campaign=prisma)
2. Click **Create a New Project**
3. Select **GitHub Repo**
4. Click **Configure GitHub App** and authorize Railway
5. Select your repository

Your application is now deploying to Railway, but it won't properly run without a database connection.

In the next section, you'll configure a database and set the `DATABASE_URL` environment variable in Railway.

![Railway deploying application](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/railway-deploying.png)

## Configure your database [#configure-your-database]

### 1. Get your database connection string [#1-get-your-database-connection-string]

You'll need a Prisma Postgres connection string. There are two ways to obtain one:

* Create a new database on [Prisma Data Platform](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=orm)
* Run `npx create-db&#x60; for a temporary database &#x2A;(no account required)*

### 2. Add the database URL to Railway [#2-add-the-database-url-to-railway]

1. In your Railway project, open your service
2. Go to the **Variables** tab
3. Click **New Variable**
4. Set the name to `DATABASE_URL`
5. Paste your database connection string as the value
6. Click **Deploy** to redeploy your application with the new environment variable

![Railway environment variables setup](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/railway-env-vars.png)

### 3. Access your application [#3-access-your-application]

Once the deployment completes with the database URL configured:

1. Navigate to the **Settings** tab
2. Under **Networking**, click **Generate Domain**
3. Your application will be available at the generated URL

![Railway networking settings](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/railway-networking.png)

Open the generated URL to see your deployed app.

If you used the example project, you should see three api endpoints already set up:

* Check API status (`/api`)
* Load feed (`/api/feed`)
* Seed data (`/api/seed`)

![Railway deployed application](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/railway-final-product.png)

If you see any errors:

* Wait a minute and refresh
* Ensure `DATABASE_URL` is set
* Check the service logs
* Redeploy

To learn more about the various features Railway offers for your application, visit the [Railway documentation](https://docs.railway.app?utm_medium=integration\&utm_source=docs\&utm_campaign=prisma).

## Related pages

- [`Deploy to Fly.io`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-flyio): Learn how to deploy a Node.js server that uses Prisma ORM to Fly.io
- [`Deploy to Heroku`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-heroku): Learn how to deploy a Node.js server that uses Prisma ORM to Heroku
- [`Deploy to Koyeb`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-koyeb): Learn how to deploy a Node.js server that uses Prisma ORM to Koyeb Serverless Platform
- [`Deploy to Render`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-render): Learn how to deploy a Node.js server that uses Prisma ORM to Render
- [`Deploy to Sevalla`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-sevalla): Learn how to deploy a Node.js server that uses Prisma ORM to Sevalla

# Deploy to Render (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-render)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy a Node.js server that uses Prisma ORM to Render

Location: ORM > v7 > Prisma Client > Deployment > Traditional > Deploy to Render

This guide explains how to deploy a Node.js server that uses Prisma ORM and PostgreSQL to Render.

**Questions answered in this page**

* How to deploy Prisma apps on Render?
* How to run migrations before start?
* What Render settings are recommended?

The [Prisma Render deployment example](https://github.com/prisma/prisma-examples/tree/latest/deployment-platforms/render) contains an Express.js application with REST endpoints and a simple frontend. This app uses Prisma Client to fetch, create, and delete records from its database.

## About Render [#about-render]

[Render](https://render.com) is a cloud application platform for deploying and scaling full-stack applications. For this example, it's helpful to know:

* Render lets you deploy long-running, "serverful" full-stack applications. You can configure Render services to [autoscale](https://docs.render.com/scaling) based on CPU and/or memory usage. This is one of several [deployment paradigms](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/deploy-prisma) you can choose from.
* Render natively supports [common runtimes](https://docs.render.com/language-support), including Node.js and Bun. In this guide, we'll use the Node.js runtime.
* Render [integrates with Git repos](https://docs.render.com/github) for automatic deployments upon commits. You can deploy to Render from GitHub, GitLab, or Bitbucket. In this guide, we'll deploy from a Git repository.

## Prerequisites [#prerequisites]

* Sign up for a [Render](https://render.com) account

## Get the example code [#get-the-example-code]

Download the [example code](https://github.com/prisma/prisma-examples/tree/latest/deployment-platforms/render) to your local machine.

```bash
curl https://codeload.github.com/prisma/prisma-examples/tar.gz/latest | tar -xz --strip=2 prisma-examples-latest/deployment-platforms/render
cd render
```

## Understand the example [#understand-the-example]

Before deploying, review the example code.

### Web application [#web-application]

The logic for the Express app is in two files:

* `src/index.js`: The API. The endpoints use Prisma Client to fetch, create, and delete data from the database.
* `public/index.html`: The web frontend. The frontend calls a few of the API endpoints.

### Prisma schema and migrations [#prisma-schema-and-migrations]

The Prisma components of this app are in two files:

* `prisma/schema.prisma`: The data model of this app. This example defines two models, `User` and `Post`. The format of this file follows the [Prisma schema](https://www.prisma.io/docs/orm/v7/prisma-schema/overview).
* `prisma/migrations/<migration name>/migration.sql`: The SQL commands that construct this schema in a PostgreSQL database. You can auto-generate migration files like this one by running [`prisma migrate dev`](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/mental-model#what-is-prisma-migrate).

### Render Blueprint [#render-blueprint]

The `render.yaml` file is a [Render blueprint](https://docs.render.com/infrastructure-as-code). Blueprints are Render's Infrastructure as Code format. You can use a Blueprint to programmatically create and modify services on Render.

A `render.yaml` defines the services that will be spun up on Render by a Blueprint. In this `render.yaml`, we see:

* **A web service that uses a Node runtime**: This is the Express app.
* **A PostgreSQL database**: This is the database that the Express app uses.

The format of this file follows the [Blueprint specification](https://docs.render.com/blueprint-spec).

### How Render deploys work with Prisma Migrate [#how-render-deploys-work-with-prisma-migrate]

In general, you want all your database migrations to run before your web app is started. Otherwise, the app may hit errors when it queries a database that doesn't have the expected tables and rows.

You can use the Pre-Deploy Command setting in a Render deploy to run any commands, such as database migrations, before the app is started.

For more details about the Pre-Deploy Command, see [Render's deploy guide](https://docs.render.com/deploys#deploy-steps).

In our example code, the `render.yaml` shows the web service's build command, pre-deploy command, and start command. Notably, `npx prisma migrate deploy` (the pre-deploy command) will run before `npm run start` (the start command).

| **Command**        | **Value**                        |
| :----------------- | :------------------------------- |
| Build Command      | `npm install --production=false` |
| Pre-Deploy Command | `npx prisma migrate deploy`      |
| Start Command      | `npm run start`                  |

## Deploy the example [#deploy-the-example]

### 1. Initialize your Git repository [#1-initialize-your-git-repository]

1. Download [the example code](https://github.com/prisma/prisma-examples/tree/latest/deployment-platforms/render) to your local machine.
2. Create a new Git repository on GitHub, GitLab, or BitBucket.
3. Upload the example code to your new repository.

### 2. Deploy manually [#2-deploy-manually]

1. In the Render Dashboard, click **New** > **PostgreSQL**. Provide a database name, and select a plan. (The Free plan works for this demo.)
2. After your database is ready, look up its [internal URL](https://docs.render.com/postgresql-creating-connecting#internal-connections).
3. In the Render Dashboard, click **New** > **Web Service** and connect the Git repository that contains the example code.
4. Provide the following values during service creation:

| **Setting**                                                  | **Value**                                              |
| :----------------------------------------------------------- | :----------------------------------------------------- |
| Language                                                     | `Node`                                                 |
| Build Command                                                | `npm install --production=false`                       |
| Pre-Deploy Command (Note: this may be in the "Advanced" tab) | `npx prisma migrate deploy`                            |
| Start Command                                                | `npm run start`                                        |
| Environment Variables                                        | Set `DATABASE_URL` to the internal URL of the database |

Your web service will be live at its `onrender.com` URL as soon as the build finishes.

### 3. (optional) Deploy with Infrastructure as Code [#3-optional-deploy-with-infrastructure-as-code]

You can also deploy the example using the Render Blueprint. Follow Render's [Blueprint setup guide](https://render.com/docs/infrastructure-as-code#setup) and use the `render.yaml` in the example.

## Bonus: Seed the database [#bonus-seed-the-database]

Prisma ORM includes a framework for [seeding the database](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/seeding) with starter data. In our example, `prisma/seed.js` defines some test users and posts.

To add these users to the database, we can either:

1. Add the seed script to our Pre-Deploy Command, or
2. Manually run the command on our server via an SSH shell

### Method 1: Pre-Deploy Command [#method-1-pre-deploy-command]

If you manually deployed your Render services:

1. In the Render dashboard, navigate to your web service.
2. Select **Settings**.
3. Set the Pre-Deploy Command to: `npx prisma migrate deploy; npx prisma db seed`

If you deployed your Render services using the Blueprint:

1. In your `render.yaml` file, change the `preDeployCommand` to: `npx prisma migrate deploy; npx prisma db seed`
2. Commit the change to your Git repo.

### Method 2: SSH [#method-2-ssh]

Render allows you to SSH into your web service.

1. Follow [Render's SSH guide](https://docs.render.com/ssh) to connect to your server.
2. In the shell, run: `npx prisma db seed`

## Related pages

- [`Deploy to Fly.io`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-flyio): Learn how to deploy a Node.js server that uses Prisma ORM to Fly.io
- [`Deploy to Heroku`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-heroku): Learn how to deploy a Node.js server that uses Prisma ORM to Heroku
- [`Deploy to Koyeb`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-koyeb): Learn how to deploy a Node.js server that uses Prisma ORM to Koyeb Serverless Platform
- [`Deploy to Railway`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-railway): Learn how to deploy an app that uses Prisma ORM and Prisma Postgres to Railway
- [`Deploy to Sevalla`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-sevalla): Learn how to deploy a Node.js server that uses Prisma ORM to Sevalla

# Deploy to Sevalla (Prisma ORM v7) (/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-sevalla)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to deploy a Node.js server that uses Prisma ORM to Sevalla

Location: ORM > v7 > Prisma Client > Deployment > Traditional > Deploy to Sevalla

This guide explains how to deploy a Node.js server that uses Prisma ORM and PostgreSQL to [Sevalla](https://sevalla.com). The app exposes a REST API and uses Prisma Client to query a PostgreSQL database. Both the app and database will be hosted on Sevalla.

Sevalla is a developer-focused PaaS that hosts applications, databases, object storage, and static sites.

It supports Git-based deployments, Dockerfiles, and Procfiles and runs on Google Kubernetes Engine with global delivery via Cloudflare.

For this example, it's helpful to know:

* Sevalla supports long-running “serverful” applications with built-in autoscaling and flexible pod sizes.
* Git-based deployments are integrated with GitHub, GitLab, and Bitbucket.
* PostgreSQL, MySQL, MariaDB, Redis, and Valkey databases are natively supported.
* Applications and databases can be securely connected through private networking with automatic environment variable injection.

## Prerequisites [#prerequisites]

You need:

* A [Sevalla account](https://sevalla.com) (comes with $50 in free credits)
* A GitHub repository with your application code.

> **Note:** If you don't have a project ready, you can use our [example Prisma project](https://github.com/sevalla-templates/express-prisma-demo). It's a simple Express.js application that uses Prisma ORM and includes a REST API, a frontend for testing endpoints, a defined Prisma schema with migrations, and an optional database seeding script.

## Create an app on Sevalla [#create-an-app-on-sevalla]

First, create a new application on your Sevalla dashboard. Click **Applications** on the sidebar and then click the **Create an app** button, as shown below.

![Sevalla app creation interface](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/sevalla-app-creation.png)

Next, select your Git repository. Sevalla supports deploying from both private and public repositories. If you're using our example project, you don't need to fork it. Enter the URL `https://github.com/sevalla-templates/express-prisma-demo`.

![Choose repository interface in Sevalla](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/sevalla-choose-repository.png)

Choose the appropriate branch (usually `main` or `master`), set your application's name, select the desired deployment region, and pick your pod size. (You can start with 0.5 CPU / 1GB RAM using your free credits)

![Name application interface in Sevalla](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/sevalla-name-application.png)

Click **Create**, but skip the deploy step for now, so it does not fail since we have not added the database.

## Set up the database on Sevalla [#set-up-the-database-on-sevalla]

On your Sevalla dashboard, click **Databases** > **Add database**. Select **PostgreSQL** (or your preferred configured database type), and then provide a database name, username, and password, or use the default generated details.

![Create database interface in Sevalla](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/sevalla-create-database.png)

Next, give the database a recognizable name for easy identification within your Sevalla dashboard. Ensure you select the **same region** as your application, choose an appropriate database size, and click **Create**.

Once your database has been created, scroll down to the **Connected Applications** section and click **Add Connection**.

Select the application you created previously and enable "Add environment variables". Make sure the variable name is set to `DATABASE_URL` (if it defaults to `DB_URL`, change it accordingly).

![App internal connection interface in Sevalla](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/sevalla-app-internal-connection.png)

Finally, click **Add connection**. This securely links your application to your database and configures the necessary environment variable.

## Trigger deployment [#trigger-deployment]

Now that your application and database are connected, return to your application's **Deployment** tab and click **Deploy**.

> **Note:** Sevalla automatically builds your application using Nixpacks, detecting your project's `package.json` and `start` script. If you'd rather use a Dockerfile or Buildpacks, navigate to **Settings** > **Build**, and click **Update Settings** under the **Build environment** section to customize your build method.

## Seed the database (optional) [#seed-the-database-optional]

If your project includes a seed script (typically located at `prisma/seed.js`), you can populate your database with initial or demo data after deploying your application.

To do this, navigate to your application's **Web Terminal** (under **Applications*&#x2A; > &#x2A;*\[Your App]** > **Web Terminal**) and run the following command:

  

#### bun

```bash
bunx prisma db seed
```

#### pnpm

```bash
pnpm prisma db seed
```

#### yarn

```bash
yarn prisma db seed
```

#### npm

```bash
npx prisma db seed
```

This is what the web terminal looks like:

![Sevalla web terminal interface](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/sevalla-web-terminal.png)

Once this is done, you can manage and interact with your database directly via Sevalla's built-in interactive studio. As shown below, we can see the seeded data:

![Sevalla database studio interface](https://www.prisma.io/img/orm/prisma-client/deployment/traditional/images/sevalla-database-studio.png)

You have deployed a Node.js application using Prisma ORM to Sevalla, with the app and database connected over private networking.

## Related pages

- [`Deploy to Fly.io`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-flyio): Learn how to deploy a Node.js server that uses Prisma ORM to Fly.io
- [`Deploy to Heroku`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-heroku): Learn how to deploy a Node.js server that uses Prisma ORM to Heroku
- [`Deploy to Koyeb`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-koyeb): Learn how to deploy a Node.js server that uses Prisma ORM to Koyeb Serverless Platform
- [`Deploy to Railway`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-railway): Learn how to deploy an app that uses Prisma ORM and Prisma Postgres to Railway
- [`Deploy to Render`](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/traditional/deploy-to-render): Learn how to deploy a Node.js server that uses Prisma ORM to Render

# Query optimization (Prisma ORM v7) (/docs/orm/v7/prisma-client/queries/advanced/query-optimization-performance)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to identify and optimize query performance with Prisma

Location: ORM > v7 > Prisma Client > Queries > Advanced > Query optimization

This page covers identifying and optimizing query performance with Prisma ORM.

## Query Insights [#query-insights]

[Query Insights](https://www.prisma.io/docs/query-insights) is built into Prisma Postgres and shows you which queries are slow, how expensive they are, and what to fix. It works out of the box for raw SQL, but to see Prisma ORM operations (model name, action, query shape) you need one extra step.

### Enabling Prisma ORM attribution [#enabling-prisma-orm-attribution]

Install `@prisma/sqlcommenter-query-insights`:

```bash
npm install @prisma/sqlcommenter-query-insights
```

Then pass it to the `comments` option in your `PrismaClient` constructor:

```ts
import { prismaQueryInsights } from "@prisma/sqlcommenter-query-insights";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient({
  adapter: myAdapter, // driver adapter or Accelerate URL required
  comments: [prismaQueryInsights()],
});
```

This adds a SQL comment to every query containing the model, action, and parameterized query shape. Query Insights uses these annotations to trace SQL back to the exact Prisma call that generated it, even when a single Prisma call produces multiple SQL statements.

#### Let your AI agent handle setup [#let-your-ai-agent-handle-setup]

Copy this prompt into your AI coding assistant:

```
Install and configure @prisma/sqlcommenter-query-insights in my project so I can
see Prisma ORM queries in Query Insights. Docs: https://www.prisma.io/docs/query-insights
```

## Debugging performance issues [#debugging-performance-issues]

Common causes of slow queries:

* Over-fetching data
* Missing indexes
* Not caching repeated queries
* Full table scans

Use [Query Insights](https://www.prisma.io/docs/query-insights) to identify which queries are affected and what to change.

## Using bulk queries [#using-bulk-queries]

It is generally more performant to read and write large amounts of data in bulk - for example, inserting `50,000` records in batches of `1000` rather than as `50,000` separate inserts. `PrismaClient` supports the following bulk queries:

* [`createMany()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#createmany)
* [`createManyAndReturn()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#createmanyandreturn)
* [`deleteMany()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#deletemany)
* [`updateMany()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#updatemany)
* [`updateManyAndReturn()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#updatemanyandreturn)
* [`findMany()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#findmany)

## Reuse `PrismaClient` or use connection pooling to avoid database connection pool exhaustion [#reuse-prismaclient-or-use-connection-pooling-to-avoid-database-connection-pool-exhaustion]

Creating multiple instances of `PrismaClient` can exhaust your database connection pool, especially in serverless or edge environments, potentially slowing down other queries. Learn more in the [serverless challenge](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections#the-serverless-challenge).

For applications with a traditional server, instantiate `PrismaClient` once and reuse it throughout your app instead of creating multiple instances. For example, instead of:

```ts title="query.ts"
async function getPosts() {
  const prisma = new PrismaClient();
  await prisma.post.findMany();
}

async function getUsers() {
  const prisma = new PrismaClient();
  await prisma.user.findMany();
}
```

Define a single `PrismaClient` instance in a dedicated file and re-export it for reuse:

```ts title="db.ts"
export const prisma = new PrismaClient();
```

Then import the shared instance:

```ts title="query.ts"
import { prisma } from "db.ts";

async function getPosts() {
  await prisma.post.findMany();
}

async function getUsers() {
  await prisma.user.findMany();
}
```

For serverless development environments with frameworks that use HMR (Hot Module Replacement), ensure you properly handle a [single instance of Prisma in development](https://www.prisma.io/docs/orm/v7/more/troubleshooting/nextjs#best-practices-for-using-prisma-client-in-development).

## Solving the n+1 problem [#solving-the-n1-problem]

The n+1 problem occurs when looping through query results and performing one additional query **per result**.

### Using `findUnique()` with the fluent API [#using-findunique-with-the-fluent-api]

Prisma's dataloader automatically batches `findUnique()` queries in the same tick. Use the fluent API to return related data:

```ts
// Instead of findMany per user, use:
return context.prisma.user
  .findUnique({ where: { id: parent.id } })
  .posts();
```

### Using JOINs with `relationLoadStrategy` [#using-joins-with-relationloadstrategy]

```ts
const posts = await prisma.post.findMany({
  relationLoadStrategy: "join",
  where: { authorId: parent.id },
});
```

* All criteria of the `where` filter are on scalar fields (unique or non-unique) of the same model you're querying.
* All criteria use the `equal` filter, whether that's via the shorthand or explicit syntax `(where: { field: <val>, field1: { equals: <val> } })`.
* No boolean operators or relation filters are present.

Automatic batching of `findUnique()` is particularly useful in a **GraphQL context**. GraphQL runs a separate resolver function for every field, which can make it difficult to optimize a nested query.

For example - the following GraphQL runs the `allUsers` resolver to get all users, and the `posts` resolver **once per user** to get each user's posts (n+1):

```js
query {
  allUsers {
    id,
    posts {
      id
    }
  }
}
```

The `allUsers` query uses `user.findMany(..)` to return all users:

```ts highlight=7;normal
const Query = objectType({
  name: "Query",
  definition(t) {
    t.nonNull.list.nonNull.field("allUsers", {
      type: "User",
      resolve: (_parent, _args, context) => {
        return context.prisma.user.findMany();
      },
    });
  },
});
```

This results in a single SQL query:

```js
{
  timestamp: 2021-02-19T09:43:06.332Z,
  query: 'SELECT `dev`.`User`.`id`, `dev`.`User`.`email`, `dev`.`User`.`name` FROM `dev`.`User` WHERE 1=1 LIMIT ? OFFSET ?',
  params: '[-1,0]',
  duration: 0,
  target: 'quaint::connector::metrics'
}
```

However, the resolver function for `posts` is then invoked **once per user**. This results in a `findMany()&#x60; query **✘ per user** rather than a single `findMany()` to return all posts by all users (expand CLI output to see queries).

```ts highlight=10-13;normal;
const User = objectType({
  name: "User",
  definition(t) {
    t.nonNull.int("id");
    t.string("name");
    t.nonNull.string("email");
    t.nonNull.list.nonNull.field("posts", {
      type: "Post",
      resolve: (parent, _, context) => {
        return context.prisma.post.findMany({
          where: { authorId: parent.id || undefined },
        });
      },
    });
  },
});
```

```json
{
  timestamp: 2021-02-19T09:43:06.343Z,
  query: 'SELECT `dev`.`Post`.`id`, `dev`.`Post`.`createdAt`, `dev`.`Post`.`updatedAt`, `dev`.`Post`.`title`, `dev`.`Post`.`content`, `dev`.`Post`.`published`, `dev`.`Post`.`viewCount`, `dev`.`Post`.`authorId` FROM `dev`.`Post` WHERE `dev`.`Post`.`authorId` = ? LIMIT ? OFFSET ?',
  params: '[1,-1,0]',
  duration: 0,
  target: 'quaint::connector::metrics'
}
{
  timestamp: 2021-02-19T09:43:06.347Z,
  query: 'SELECT `dev`.`Post`.`id`, `dev`.`Post`.`createdAt`, `dev`.`Post`.`updatedAt`, `dev`.`Post`.`title`, `dev`.`Post`.`content`, `dev`.`Post`.`published`, `dev`.`Post`.`viewCount`, `dev`.`Post`.`authorId` FROM `dev`.`Post` WHERE `dev`.`Post`.`authorId` = ? LIMIT ? OFFSET ?',
  params: '[3,-1,0]',
  duration: 0,
  target: 'quaint::connector::metrics'
}
{
  timestamp: 2021-02-19T09:43:06.348Z,
  query: 'SELECT `dev`.`Post`.`id`, `dev`.`Post`.`createdAt`, `dev`.`Post`.`updatedAt`, `dev`.`Post`.`title`, `dev`.`Post`.`content`, `dev`.`Post`.`published`, `dev`.`Post`.`viewCount`, `dev`.`Post`.`authorId` FROM `dev`.`Post` WHERE `dev`.`Post`.`authorId` = ? LIMIT ? OFFSET ?',
  params: '[2,-1,0]',
  duration: 0,
  target: 'quaint::connector::metrics'
}
{
  timestamp: 2021-02-19T09:43:06.348Z,
  query: 'SELECT `dev`.`Post`.`id`, `dev`.`Post`.`createdAt`, `dev`.`Post`.`updatedAt`, `dev`.`Post`.`title`, `dev`.`Post`.`content`, `dev`.`Post`.`published`, `dev`.`Post`.`viewCount`, `dev`.`Post`.`authorId` FROM `dev`.`Post` WHERE `dev`.`Post`.`authorId` = ? LIMIT ? OFFSET ?',
  params: '[4,-1,0]',
  duration: 0,
  target: 'quaint::connector::metrics'
}
{
  timestamp: 2021-02-19T09:43:06.348Z,
  query: 'SELECT `dev`.`Post`.`id`, `dev`.`Post`.`createdAt`, `dev`.`Post`.`updatedAt`, `dev`.`Post`.`title`, `dev`.`Post`.`content`, `dev`.`Post`.`published`, `dev`.`Post`.`viewCount`, `dev`.`Post`.`authorId` FROM `dev`.`Post` WHERE `dev`.`Post`.`authorId` = ? LIMIT ? OFFSET ?',
  params: '[5,-1,0]',
  duration: 0,
  target: 'quaint::connector::metrics'
}
// And so on
```

#### Solution 1: Batching queries with the fluent API [#solution-1-batching-queries-with-the-fluent-api]

Use `findUnique()` in combination with [the fluent API](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#fluent-api) (`.posts()&#x60;) as shown to return a user's posts. Even though the resolver is called once per user, the Prisma dataloader in Prisma Client **✔ batches the `findUnique()` queries**.

> [!NOTE]
> It may seem counterintuitive to use a `prisma.user.findUnique(...).posts()` query to return posts instead of `prisma.posts.findMany()` - particularly as the former results in two queries rather than one.
> 
> The **only** reason you need to use the fluent API (`user.findUnique(...).posts()`) to return posts is that the dataloader in Prisma Client batches `findUnique()` queries and does not currently [batch `findMany()` queries](https://github.com/prisma/orm/issues/1477).
> 
> When the dataloader batches `findMany()` queries or your query has the `relationStrategy` set to `join`, you no longer need to use `findUnique()` with the fluent API in this way.

```ts highlight=13-18;add|10-12;delete
const User = objectType({
  name: "User",
  definition(t) {
    t.nonNull.int("id");
    t.string("name");
    t.nonNull.string("email");
    t.nonNull.list.nonNull.field("posts", {
      type: "Post",
      resolve: (parent, _, context) => {
        return context.prisma.post.findMany({
          // [!code --]
          where: { authorId: parent.id || undefined }, // [!code --]
        }); // [!code --]
        return context.prisma.user // [!code ++]
          .findUnique({
            // [!code ++]
            where: { id: parent.id || undefined }, // [!code ++]
          }) // [!code ++]
          .posts(); // [!code ++]
      }, // [!code ++]
    });
  },
});
```

```json
{
  timestamp: 2021-02-19T09:59:46.340Z,
  query: 'SELECT `dev`.`User`.`id`, `dev`.`User`.`email`, `dev`.`User`.`name` FROM `dev`.`User` WHERE 1=1 LIMIT ? OFFSET ?',
  params: '[-1,0]',
  duration: 0,
  target: 'quaint::connector::metrics'
}
{
  timestamp: 2021-02-19T09:59:46.350Z,
  query: 'SELECT `dev`.`User`.`id` FROM `dev`.`User` WHERE `dev`.`User`.`id` IN (?,?,?) LIMIT ? OFFSET ?',
  params: '[1,2,3,-1,0]',
  duration: 0,
  target: 'quaint::connector::metrics'
}
{
  timestamp: 2021-02-19T09:59:46.350Z,
  query: 'SELECT `dev`.`Post`.`id`, `dev`.`Post`.`createdAt`, `dev`.`Post`.`updatedAt`, `dev`.`Post`.`title`, `dev`.`Post`.`content`, `dev`.`Post`.`published`, `dev`.`Post`.`viewCount`, `dev`.`Post`.`authorId` FROM `dev`.`Post` WHERE `dev`.`Post`.`authorId` IN (?,?,?) LIMIT ? OFFSET ?',
  params: '[1,2,3,-1,0]',
  duration: 0,
  target: 'quaint::connector::metrics'
}
```

If the `posts` resolver is invoked once per user, the dataloader in Prisma Client groups `findUnique()` queries with the same parameters and selection set. Each group is optimized into a single `findMany()`.

#### Solution 2: Using JOINs to perform queries [#solution-2-using-joins-to-perform-queries]

You can perform the query with a [database join](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview) by setting `relationLoadStrategy` to `"join"`, ensuring that only **one** query is executed against the database.

```ts
const User = objectType({
  name: "User",
  definition(t) {
    t.nonNull.int("id");
    t.string("name");
    t.nonNull.string("email");
    t.nonNull.list.nonNull.field("posts", {
      type: "Post",
      resolve: (parent, _, context) => {
        return context.prisma.post.findMany({
          relationLoadStrategy: "join",
          where: { authorId: parent.id || undefined },
        });
      },
    });
  },
});
```

### Avoiding n+1 in loops [#avoiding-n1-in-loops]

Don't loop with separate queries:

```ts
// BAD: n+1 queries
const users = await prisma.user.findMany({});
users.forEach(async (usr) => {
  const posts = await prisma.post.findMany({ where: { authorId: usr.id } });
});
```

Use `include` or `in` filter instead:

```ts
// GOOD: 2 queries with include
const usersWithPosts = await prisma.user.findMany({
  include: { posts: true },
});

// GOOD: 2 queries with in filter
const users = await prisma.user.findMany({});
const posts = await prisma.post.findMany({
  where: { authorId: { in: users.map(u => u.id) } },
});

// BEST: 1 query with join
const posts = await prisma.post.findMany({
  relationLoadStrategy: "join",
  where: { authorId: { in: users.map(u => u.id) } },
});
```

This is not an efficient way to query. Instead, you can:

* Use nested reads ([`include`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#include) ) to return users and related posts
* Use the [`in`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#in) filter
* Set the [`relationLoadStrategy`](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview) to `"join"`

#### Solving n+1 with `include` [#solving-n1-with-include]

You can use `include` to return each user's posts. This only results in **two** SQL queries - one to get users, and one to get posts. This is known as a [nested read](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-reads).

```ts
const usersWithPosts = await prisma.user.findMany({
  include: {
    posts: true,
  },
});
```

```sql
SELECT "public"."User"."id", "public"."User"."email", "public"."User"."name" FROM "public"."User" WHERE 1=1 OFFSET $1
SELECT "public"."Post"."id", "public"."Post"."title", "public"."Post"."authorId" FROM "public"."Post" WHERE "public"."Post"."authorId" IN ($1,$2,$3,$4) OFFSET $5
```

#### Solving n+1 with `in` [#solving-n1-with-in]

If you have a list of user IDs, you can use the `in` filter to return all posts where the `authorId` is `in` that list of IDs:

```ts
const users = await prisma.user.findMany({});

const userIds = users.map((x) => x.id);

const posts = await prisma.post.findMany({
  where: {
    authorId: {
      in: userIds,
    },
  },
});
```

```sql
SELECT "public"."User"."id", "public"."User"."email", "public"."User"."name" FROM "public"."User" WHERE 1=1 OFFSET $1
SELECT "public"."Post"."id", "public"."Post"."createdAt", "public"."Post"."updatedAt", "public"."Post"."title", "public"."Post"."content", "public"."Post"."published", "public"."Post"."authorId" FROM "public"."Post" WHERE "public"."Post"."authorId" IN ($1,$2,$3,$4) OFFSET $5
```

#### Solving n+1 with `relationLoadStrategy: "join"` [#solving-n1-with-relationloadstrategy-join]

You can perform the query with a [database join](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#relation-load-strategies-preview) by setting `relationLoadStrategy` to `"join"`, ensuring that only **one** query is executed against the database.

```ts
const users = await prisma.user.findMany({});

const userIds = users.map((x) => x.id);

const posts = await prisma.post.findMany({
  relationLoadStrategy: "join",
  where: {
    authorId: {
      in: userIds,
    },
  },
});
```

# Connection management (Prisma ORM v7) (/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-management)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

This page explains how database connections are handled with Prisma Client and how to manually connect and disconnect your database

Location: ORM > v7 > Prisma Client > Setup and Configuration > Database Connections > Connection management

> [!NOTE]
> Quick summary
> 
> This page explains how Prisma Client manages database connections, including how and when to use the `$connect()` and `$disconnect()` methods, connection pooling behavior, and best practices for both long-running and serverless environments.

`PrismaClient` connects and disconnects from your data source using the following two methods:

* [`$connect()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference)
* [`$disconnect()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference)

In most cases, you **do not need to explicitly call these methods**. `PrismaClient` automatically connects when you run your first query, creates a [connection pool](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool), and disconnects when the Node.js process ends.

See the [connection management guide](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections) for information about managing connections for different deployment paradigms (long-running processes and serverless functions).

**Questions answered in this page**

* When should I call $connect and $disconnect?
* How does Prisma manage connection pools?
* How to handle connections in serverless?

## `$connect()` [#connect]

It is not necessary to call [`$connect()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference) thanks to the *lazy connect* behavior: The `PrismaClient` instance connects lazily when the first request is made to the API (`$connect()` is called for you under the hood).

### Calling `$connect()` explicitly [#calling-connect-explicitly]

If you need the first request to respond instantly and cannot wait for a lazy connection to be established, you can explicitly call `prisma.$connect()` to establish a connection to the data source:

```ts
const prisma = new PrismaClient();

// run inside `async` function
await prisma.$connect();
```

## `$disconnect()` [#disconnect]

When you call [`$disconnect()`](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference) , Prisma Client:

1. Runs the [`beforeExit` hook](#exit-hooks)
2. Closes all connections in the pool

In a long-running application such as a GraphQL API, which constantly serves requests, it does not make sense to `$disconnect()` after each request - it takes time to establish a connection, and doing so as part of each request will slow down your application.

> [!NOTE]
> To avoid too *many* connections in a long-running application, we recommend that you [use a single instance of `PrismaClient` across your application](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction#use-prisma-client-to-send-queries-to-your-database).

### Calling `$disconnect()` explicitly [#calling-disconnect-explicitly]

In most long-running or serverless apps you should **not** call `$disconnect()` after each request, so connections can be reused. In some situations it **does** make sense to call it explicitly, for example when creating a temporary `PrismaClient` and then immediately releasing its resources (e.g. in [Cloudflare Workers](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare), where `ctx.waitUntil(prisma.$disconnect())` is recommended).

Another scenario is a script that:

1. Runs **infrequently** (for example, a scheduled job to send emails each night), which means it does not benefit from a long-running connection to the database *and*
2. Exists in the context of a **long-running application**, such as a background service. If the application never shuts down, Prisma Client never disconnects.

The following script creates a new instance of `PrismaClient`, performs a task, and then disconnects - which closes the connection pool:

```ts
import { PrismaClient } from "../prisma/generated/client";

const prisma = new PrismaClient();
const emailService = new EmailService();

async function main() {
  const allUsers = await prisma.user.findMany();
  const emails = allUsers.map((x) => x.email);

  await emailService.send(emails, "Hello!");
}

main()
  .then(async () => {
    await prisma.$disconnect();  //[!code highlight]
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect(); //[!code highlight]
    process.exit(1);
  });
```

If the above script runs multiple times in the context of a long-running application *without* calling `$disconnect()`, a new connection pool is created with each new instance of `PrismaClient`.

## Exit hooks [#exit-hooks]

The `beforeExit` hook runs when Prisma ORM is triggered externally (e.g. via a `SIGINT` signal) to shut down, and allows you to run code *before* Prisma Client disconnects - for example, to issue queries as part of a graceful shutdown of a service:

```ts
const prisma = new PrismaClient();

prisma.$on("beforeExit", async () => {
  console.log("beforeExit hook");
  // PrismaClient still available
  await prisma.message.create({
    data: {
      message: "Shutting down server",
    },
  });
});
```

## Related pages

- [`Configure Prisma Client with PgBouncer`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/pgbouncer): Configure Prisma Client with PgBouncer and other poolers: when to use pgbouncer=true, required transaction mode, prepared statements, and Prisma Migrate workarounds
- [`Connection pool`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool): Prisma Client uses a connection pool (from the database driver or driver adapter) to store and manage database connections.

# Connection pool (Prisma ORM v7) (/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Prisma Client uses a connection pool (from the database driver or driver adapter) to store and manage database connections.

Location: ORM > v7 > Prisma Client > Setup and Configuration > Database Connections > Connection pool

> [!NOTE]
> Quick summary
> 
> This page explains how Prisma ORM manages database connections using a connection pool, and how you can configure limits and timeouts for optimal performance.

Prisma Client uses a **connection pool** of database connections (managed by the database driver when using [driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers)). The pool is created when Prisma Client opens the *first* connection to the database, which can happen in one of two ways:

* By [explicitly calling `$connect()`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-management#connect) *or*
* By running the first query, which calls `$connect()` under the hood

Relational database connectors use Prisma ORM's own connection pool, and the MongoDB connectors uses the [MongoDB driver connection pool](https://github.com/mongodb/specifications/blob/master/source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.rst).

**Questions answered in this page**

* How do I size Prisma's connection pool?
* How do I set pool timeouts and limits?
* When should I use PgBouncer with Prisma?

## Relational databases [#relational-databases]

Starting with Prisma ORM v7, relational datasources instantiate Prisma Client with [driver adapters](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers) by default. Driver adapters rely on the Node.js driver you supply, so connection pooling defaults (and configuration) now come from the driver itself.

Use the tables below to translate Prisma ORM v6 connection URL parameters to the Prisma ORM v7 driver adapter fields alongside their defaults.

### Prisma ORM v7 driver adapter defaults [#prisma-orm-v7-driver-adapter-defaults]

The following tables document the default connection pool settings for each driver adapter.

> [!NOTE]
> Prisma timeouts
> 
> Prisma ORM also has its own configurable timeouts that are separate from the database driver timeouts. If you see a timeout error and are unsure whether it comes from the driver or from Prisma Client, see the [Prisma Client timeouts and transaction options documentation](https://www.prisma.io/docs/orm/v7/prisma-client/queries/transactions#transaction-isolation-level).

#### PostgreSQL (using the `pg` driver adapter) [#postgresql-using-the-pg-driver-adapter]

Here are the default connection pool settings for the `pg` driver adapter:

| Behavior            | v6 URL parameter               | v6 default                         | v7 `pg` config field      | v7 default       |
| ------------------- | ------------------------------ | ---------------------------------- | ------------------------- | ---------------- |
| Pool size           | `connection_limit`             | `num_cpus::get_physical() * 2 + 1` | `max`                     | `10`             |
| Acquire timeout     | `pool_timeout`                 | `10s`                              | `connectionTimeoutMillis` | `0` (no timeout) |
| Connection timeout  | `connect_timeout`              | `5s`                               | `connectionTimeoutMillis` | `0` (no timeout) |
| Idle timeout        | `max_idle_connection_lifetime` | `300s`                             | `idleTimeoutMillis`       | `10s`            |
| Connection lifetime | `max_connection_lifetime`      | `0` (no timeout)                   | `maxLifetimeSeconds`      | `0` (no timeout) |

**Example: Matching Prisma ORM v6 defaults with the `pg` driver adapter**

If you want to preserve the same timeout behavior you had in Prisma ORM v6, pass the following configuration when instantiating the driver adapter:

```ts
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL,
  // Match Prisma ORM v6 defaults:
  connectionTimeoutMillis: 5_000, // v6 connect_timeout was 5s
  idleTimeoutMillis: 300_000, // v6 max_idle_connection_lifetime was 300s
});
```

> [!NOTE]
> See the [node-postgres pool documentation](https://node-postgres.com/apis/pool) for details on every available option.

#### MySQL or MariaDB (using the `mariadb` driver) [#mysql-or-mariadb-using-the-mariadb-driver]

Here are the default connection pool settings for the `mariadb` driver adapter:

| Behavior           | v6 URL parameter               | v6 default                         | v7 `mariadb` config field | v7 default |
| ------------------ | ------------------------------ | ---------------------------------- | ------------------------- | ---------- |
| Pool size          | `connection_limit`             | `num_cpus::get_physical() * 2 + 1` | `connectionLimit`         | `10`       |
| Acquire timeout    | `pool_timeout`                 | `10s`                              | `acquireTimeout`          | `10s`      |
| Connection timeout | `connect_timeout`              | `5s`                               | `connectTimeout`          | `1s`       |
| Idle timeout       | `max_idle_connection_lifetime` | `300s`                             | `idleTimeout`             | `1800s`    |

**Example: Matching Prisma ORM v6 defaults with the `mariadb` driver adapter**

If you want to preserve the same timeout behavior you had in Prisma ORM v6, pass the following configuration when instantiating the driver adapter:

```ts
import { PrismaMariaDb } from "@prisma/adapter-mariadb";

const adapter = new PrismaMariaDb({
  host: "localhost",
  port: 3306,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  // Match Prisma ORM v6 defaults:
  connectTimeout: 5_000, // v6 connect_timeout was 5s
  idleTimeout: 300, // v6 max_idle_connection_lifetime was 300s (note: in seconds, not ms)
});
```

> [!NOTE]
> Refer to the [MariaDB Connector/Node.js pool options](https://mariadb.com/docs/connectors/mariadb-connector-nodejs/connector-nodejs-promise-api#pool-options) for configuration and tuning guidance.

#### SQL Server (using the `mssql` driver) [#sql-server-using-the-mssql-driver]

Here are the default connection pool settings for the `mssql` driver adapter:

| Behavior           | v6 URL parameter               | v6 default                         | v7 `mssql` config field  | v7 default |
| ------------------ | ------------------------------ | ---------------------------------- | ------------------------ | ---------- |
| Pool size          | `connection_limit`             | `num_cpus::get_physical() * 2 + 1` | `pool.max`               | `10`       |
| Connection timeout | `connect_timeout`              | `5s`                               | `connectionTimeout`      | `15s`      |
| Idle timeout       | `max_idle_connection_lifetime` | `300s`                             | `pool.idleTimeoutMillis` | `30s`      |

**Example: Matching Prisma ORM v6 defaults with the `mssql` driver adapter**

If you want to preserve the same timeout behavior you had in Prisma ORM v6, pass the following configuration when instantiating the driver adapter:

```ts
import { PrismaMssql } from "@prisma/adapter-mssql";

const adapter = new PrismaMssql({
  server: "localhost",
  port: 1433,
  database: "mydb",
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  // Match Prisma ORM v6 defaults:
  connectionTimeout: 5_000, // v6 connect_timeout was 5s
  pool: {
    idleTimeoutMillis: 300_000, // v6 max_idle_connection_lifetime was 300s
  },
});
```

> [!NOTE]
> See the [`node-mssql` pool docs](https://tediousjs.github.io/node-mssql/#general-same-for-all-drivers) for details on these fields.

## MongoDB [#mongodb]

The MongoDB connector does not use the Prisma ORM connection pool. The connection pool is managed internally by the MongoDB driver and [configured via connection string parameters](https://www.mongodb.com/docs/manual/reference/connection-string-options/#connection-pool-options).

## External connection poolers [#external-connection-poolers]

The pool size cannot exceed what the underlying database can support. Configure pool size and timeouts via your [driver adapter](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool) (see the tables above). This is a particular challenge in serverless environments, where each function manages an instance of `PrismaClient` and its own connection pool.

Consider introducing [an external connection pooler like PgBouncer](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections#pgbouncer) to prevent your application or functions from exhausting the database connection limit.

## Manual database connection handling [#manual-database-connection-handling]

When using Prisma Client with a driver adapter, database connections are managed by the driver and its pool. They are not exposed to the developer and it is not possible to manually access individual connections.

## Related pages

- [`Configure Prisma Client with PgBouncer`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/pgbouncer): Configure Prisma Client with PgBouncer and other poolers: when to use pgbouncer=true, required transaction mode, prepared statements, and Prisma Migrate workarounds
- [`Connection management`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-management): This page explains how database connections are handled with Prisma Client and how to manually connect and disconnect your database

# Database connections (Prisma ORM v7) (/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Learn how to manage database connections and configure connection pools

Location: ORM > v7 > Prisma Client > Setup and Configuration > Database connections

Databases can handle a limited number of concurrent connections. Each connection requires RAM, which means that increasing the database connection limit without scaling available resources:

* ✔ might allow more processes to connect *but*
* ✘ significantly affects **database performance**, and can result in the database being **shut down** due to **exhaustion of system resources**

The way your application **manages connections** also impacts performance. This guide describes how to approach connection management in [serverless environments](#serverless-environments-faas) and [long-running processes](#long-running-processes).

> [!WARNING]
> This guide focuses on **relational databases** and how to configure and tune the Prisma ORM connection pool (MongoDB uses the MongoDB driver connection pool).

## Long-running processes [#long-running-processes]

Examples of long-running processes include Node.js applications hosted on a service like Heroku or a virtual machine. Use the following checklist as a guide to connection management in long-running environments:

* Configure [pool size and timeouts](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool) for your driver adapter (defaults and options are adapter-specific)
* Make sure you have [**one** global instance of `PrismaClient`](#prismaclient-in-long-running-applications)

### `PrismaClient` in long-running applications [#prismaclient-in-long-running-applications]

In **long-running** applications, we recommend that you:

* ✔ Create **one** instance of `PrismaClient` and re-use it across your application
* ✔ Assign `PrismaClient` to a global variable *in dev environments only* to [prevent hot reloading from creating new instances](#prevent-hot-reloading-from-creating-new-instances-of-prismaclient)

#### Re-using a single `PrismaClient` instance [#re-using-a-single-prismaclient-instance]

To re-use a single instance, create a module that exports a `PrismaClient` object:

```ts title="client.ts"
import { PrismaClient } from "../prisma/generated/client";

let prisma = new PrismaClient();

export default prisma;
```

The object is [cached](https://nodejs.org/api/modules.html#modules_caching) the first time the module is imported. Subsequent requests return the cached object rather than creating a new `PrismaClient`:

```ts title="app.ts"
import prisma from "./client";

async function main() {
  const allUsers = await prisma.user.findMany();
}

main();
```

You do not have to replicate the example above exactly - the goal is to make sure `PrismaClient` is cached. For example, you can [instantiate `PrismaClient` in the `context` object](https://github.com/prisma/prisma-examples/blob/9f1a6b9e7c25b9e1851bd59b273046158d748995/typescript/graphql-express/src/context.ts#L9) that you [pass into an Express app](https://github.com/prisma/prisma-examples/blob/9f1a6b9e7c25b9e1851bd59b273046158d748995/typescript/graphql-express/src/server.ts#L12).

#### Do not explicitly `$disconnect()` [#do-not-explicitly-disconnect]

You [do not need to explicitly `$disconnect()`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-management#calling-disconnect-explicitly) in the context of a long-running application that is continuously serving requests. Opening a new connection takes time and can slow down your application if you disconnect after each query.

#### Prevent hot reloading from creating new instances of `PrismaClient` [#prevent-hot-reloading-from-creating-new-instances-of-prismaclient]

Frameworks like [Next.js](https://nextjs.org/) support hot reloading of changed files, which enables you to see changes to your application without restarting. However, if the framework refreshes the module responsible for exporting `PrismaClient`, this can result in **additional, unwanted instances of `PrismaClient` in a development environment**.

As a workaround, you can store `PrismaClient` as a global variable in development environments only, as global variables are not reloaded:

```ts title="client.ts"
import { PrismaClient } from "../prisma/generated/client";

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };

export const prisma = globalForPrisma.prisma || new PrismaClient();

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
```

The way that you import and use Prisma Client does not change:

```ts title="app.ts"
import { prisma } from "./client";

async function main() {
  const allUsers = await prisma.user.findMany();
}

main();
```

## Connections Created per CLI Command [#connections-created-per-cli-command]

In local tests with Postgres, MySQL, and SQLite, each Prisma CLI command typically uses a single connection. The table below shows the ranges observed in these tests. Your environment *may* produce slightly different results.

| Command                                                                   | Connections | Description                                      |
| ------------------------------------------------------------------------- | ----------- | ------------------------------------------------ |
| [`migrate status`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-status) | 1           | Checks the status of migrations                  |
| [`migrate dev`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-dev)       | 1–4         | Applies pending migrations in development        |
| [`migrate diff`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-diff)     | 1–2         | Compares database schema with migration history  |
| [`migrate reset`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-reset)   | 1–2         | Resets the database and reapplies migrations     |
| [`migrate deploy`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#migrate-deploy) | 1–2         | Applies pending migrations in production         |
| [`db pull`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-pull)               | 1           | Pulls the database schema into the Prisma schema |
| [`db push`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-push)               | 1–2         | Pushes the Prisma schema to the database         |
| [`db execute`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-execute)         | 1           | Executes raw SQL commands                        |
| [`db seed`](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#db-seed)               | 1           | Seeds the database with initial data             |

## Serverless environments (FaaS) [#serverless-environments-faas]

Examples of serverless environments include Node.js functions hosted on AWS Lambda, Vercel or Netlify Functions. Use the following checklist as a guide to connection management in serverless environments:

* Familiarize yourself with the [serverless connection management challenge](#the-serverless-challenge)
* Configure [pool size and timeouts](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool) for your driver adapter (defaults and options are adapter-specific)
* [Instantiate `PrismaClient` outside the handler](#instantiate-prismaclient-outside-the-handler) and do not explicitly `$disconnect()`
* Configure [function concurrency](#concurrency-limits) and handle [idle connections](#zombie-connections)

### The serverless challenge [#the-serverless-challenge]

In a serverless environment, each function creates **its own instance** of `PrismaClient`, and each client instance has its own connection pool.

Consider the following example, where a single AWS Lambda function uses `PrismaClient` to connect to a database. The `connection_limit` is **3**:

![An AWS Lambda function connecting to a database.](https://www.prisma.io/img/orm/prisma-client/setup-and-configuration/databases-connections/serverless-connections.png)

A traffic spike causes AWS Lambda to spawn two additional lambdas to handle the increased load. Each lambda creates an instance of `PrismaClient`, each with a `connection_limit` of **3**, which results in a maximum of **9** connections to the database:

![Three AWS Lambda function connecting to a database.](https://www.prisma.io/img/orm/prisma-client/setup-and-configuration/databases-connections/serverless-connections-2.png)

Many *concurrent functions* responding to a traffic spike 📈 can exhaust the database connection limit very quickly. Furthermore, any functions that are **paused** keep their connections open by default and block them from being used by another function.

1. Configure a small pool size for your [driver adapter](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool) (adapter-specific; start small when not using a pooler)
2. If you need more connections per function, consider using an [external connection pooler like PgBouncer](#external-connection-poolers)

### `PrismaClient` in serverless environments [#prismaclient-in-serverless-environments]

#### Instantiate `PrismaClient` outside the handler [#instantiate-prismaclient-outside-the-handler]

Instantiate `PrismaClient` [outside the scope of the function handler](https://github.com/prisma/e2e-tests/blob/5d1041d3f19245d3d237d959eca94d1d796e3a52/platforms/serverless-lambda/index.ts#L3) to increase the chances of reuse. As long as the handler remains 'warm' (in use), the connection is potentially reusable:

```ts highlight=3;normal
import { PrismaClient } from "../prisma/generated/client";

const client = new PrismaClient();

export async function handler() {
  /* ... */
}
```

#### Do not explicitly `$disconnect()` [#do-not-explicitly-disconnect-1]

You [do not need to explicitly `$disconnect()`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-management#calling-disconnect-explicitly) at the end of a function, as there is a possibility that the container might be reused. Opening a new connection takes time and slows down your function's ability to process requests. In some cases (e.g. [Cloudflare Workers](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/edge/deploy-to-cloudflare)), calling `$disconnect()` when releasing a temporary client is recommended. See the [connection management caveat](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-management#calling-disconnect-explicitly).

### Other serverless considerations [#other-serverless-considerations]

#### Container reuse [#container-reuse]

There is no guarantee that subsequent nearby invocations of a function will hit the same container - for example, AWS can choose to create a new container at any time.

Code should assume the container to be stateless and create a connection only if it does not exist - Prisma Client JS already implements this logic.

#### Zombie connections [#zombie-connections]

Containers that are marked "to be removed" and are not being reused still **keep a connection open** and can stay in that state for some time (unknown and not documented from AWS). This can lead to sub-optimal utilization of the database connections.

A potential solution is to **clean up idle connections** ([`serverless-mysql`](https://github.com/jeremydaly/serverless-mysql) implements this idea, but cannot be used with Prisma ORM).

#### Concurrency limits [#concurrency-limits]

Depending on your serverless concurrency limit (the number of serverless functions running in parallel), you might still exhaust your database's connection limit. This can happen when too many functions are invoked concurrently, each with its own connection pool, which eventually exhausts the database connection limit. To prevent this, you can [set your serverless concurrency limit](https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html) to a number lower than the maximum connection limit of your database divided by the number of connections used by each function invocation (as you might want to be able to connect from another client for other purposes).

## Optimizing the connection pool [#optimizing-the-connection-pool]

If Prisma Client cannot obtain a connection from the pool before the adapter's acquire timeout, you will see connection pool timeout exceptions in your log. A connection pool timeout can occur if:

* Many users are accessing your app simultaneously
* You send a large number of queries in parallel (for example, using `await Promise.all()`)

Pool size, acquire timeout, and other pool behavior are **configured per driver adapter**. There are no connection URL parameters for these in Prisma ORM v7. See the [connection pool reference](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool) for each adapter's pool settings (e.g. `max`, `connectionTimeoutMillis` for `pg`) and the underlying driver documentation. Tune the pool so that:

* Your database can support the total number of concurrent connections (pool size × number of instances)
* Timeouts and queue behavior match your workload (e.g. avoid exhausting system resources if the queue grows unbounded)

## External connection poolers [#external-connection-poolers]

Connection poolers like PgBouncer prevent your application from exhausting the database's connection limit.

To keep Prisma Client on the pooled connection while allowing Prisma CLI commands (for example, migrations or introspection) to connect directly, define two environment variables:

```bash title=".env"
# Connection URL to your database using PgBouncer.
DATABASE_URL="postgres://root:password@127.0.0.1:54321/postgres?pgbouncer=true"

# Direct connection URL to the database used for Prisma CLI commands. # [!code ++]
DIRECT_URL="postgres://root:password@127.0.0.1:5432/postgres" # [!code ++]
```

Configure `prisma.config.ts` to point to the direct connection string. Prisma CLI commands always read from this configuration.

```ts title="prisma.config.ts" showLineNumbers
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DIRECT_URL"),
  },
});
```

At runtime, instantiate Prisma Client with a driver adapter (for example, `@prisma/adapter-pg`) that uses the pooled connection string:

```ts title="src/db/client.ts" showLineNumbers
import { PrismaClient } from "../prisma/generated/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
export const prisma = new PrismaClient({ adapter });
```

### PgBouncer [#pgbouncer]

PostgreSQL only supports a certain amount of concurrent connections, and this limit can be reached quite fast when the service usage goes up – especially in [serverless environments](#serverless-environments-faas).

[PgBouncer](https://www.pgbouncer.org/) holds a connection pool to the database and proxies incoming client connections by sitting between Prisma Client and the database. This reduces the number of processes a database has to handle at any given time. PgBouncer passes on a limited number of connections to the database and queues additional connections for delivery when connections become available. To use PgBouncer, see [Configure Prisma Client with PgBouncer](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/pgbouncer).

### AWS RDS Proxy [#aws-rds-proxy]

Due to the way AWS RDS Proxy pins connections, [it does not provide any connection pooling benefits](https://www.prisma.io/docs/orm/v7/prisma-client/deployment/caveats-when-deploying-to-aws-platforms#aws-rds-proxy) when used together with Prisma Client.

## Related pages

- [`Configuring error formatting`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/error-formatting): This page explains how to configure the formatting of errors when using Prisma Client
- [`Custom model and field names`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/custom-model-and-field-names): Learn how you can decouple the naming of Prisma models from database tables to improve the ergonomics of the generated Prisma Client API
- [`Database polyfills`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/database-polyfills): Prisma Client provides features that are not achievable with relational databases. These features are referred to as "polyfills" and explained on this page.
- [`Generating Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client): Learn when and how to run prisma generate, configure the generator output, and import the generated client in your app.
- [`Introduction to Prisma Client`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction): Learn how to set up and configure Prisma Client in your project

# Configure Prisma Client with PgBouncer (Prisma ORM v7) (/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/pgbouncer)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Configure Prisma Client with PgBouncer and other poolers: when to use pgbouncer=true, required transaction mode, prepared statements, and Prisma Migrate workarounds

Location: ORM > v7 > Prisma Client > Setup and Configuration > Database Connections > Configure Prisma Client with PgBouncer

An external connection pooler like PgBouncer holds a connection pool to the database, and proxies incoming client connections by sitting between Prisma Client and the database. This reduces the number of processes a database has to handle at any given time.

Usually, this works transparently, but some connection poolers only support a limited set of functionality. One common feature that external connection poolers do not support are named prepared statements, which Prisma ORM uses. For these cases, Prisma ORM can be configured to behave differently.

**Questions answered in this page**

* How do I configure Prisma with PgBouncer?
* Do I need `pgbouncer=true`, and if so, when?
* How does Prisma Migrate work with PgBouncer?

> [!NOTE]
> If you don't want to run your own pooler, [Prisma Accelerate](https://www.prisma.io/accelerate?utm_source=docs\&utm_campaign=pgbouncer-help) provides connection pooling for all databases supported by Prisma ORM with little setup. To get started, open the [Prisma Console](https://console.prisma.io?utm_source=docs\&utm_campaign=pgbouncer-help).

## PgBouncer [#pgbouncer]

### Set PgBouncer to transaction mode [#set-pgbouncer-to-transaction-mode]

For Prisma Client to work reliably, PgBouncer must run in [**Transaction mode**](https://www.pgbouncer.org/features.html).

Transaction mode offers a connection for every transaction – a requirement for the Prisma Client to work with PgBouncer.

### Add `pgbouncer=true` for PgBouncer versions below `1.21.0` [#add-pgbouncertrue-for-pgbouncer-versions-below-1210]

> [!WARNING]
> We recommend **not** setting `pgbouncer=true` in the database connection string if you're using [PgBouncer `1.21.0`](https://github.com/prisma/orm/issues/21531#issuecomment-1919059472) or later.

To use Prisma Client with PgBouncer, add the `?pgbouncer=true` flag to the PostgreSQL connection URL:

```shell
postgresql://USER:PASSWORD@HOST:PORT/DATABASE?pgbouncer=true
```

> [!NOTE]
> `PORT` specified for PgBouncer pooling is sometimes different from the default `5432` port. Check your database provider docs for the correct port number.

### Configure `max_prepared_statements` in PgBouncer to be greater than zero [#configure-max_prepared_statements-in-pgbouncer-to-be-greater-than-zero]

Prisma uses prepared statements, and setting [`max_prepared_statements`](https://www.pgbouncer.org/config.html) to a value greater than `0` enables PgBouncer to use those prepared statements.

> [!NOTE]
> `PORT` specified for PgBouncer pooling is sometimes different from the default `5432` port. Check your database provider docs for the correct port number.

### Prisma Migrate and PgBouncer workaround [#prisma-migrate-and-pgbouncer-workaround]

Prisma Migrate uses **database transactions** to check out the current state of the database and the migrations table. However, the Schema Engine is designed to use a **single connection to the database**, and does not support connection pooling with PgBouncer. If you attempt to run Prisma Migrate commands in any environment that uses PgBouncer for connection pooling, you might see the following error:

```bash
Error: undefined: Database error
Error querying the database: db error: ERROR: prepared statement "s0" already exists
```

To work around this issue, configure a **direct** connection for Prisma CLI commands in `prisma.config.ts`, while Prisma Client continues to use the PgBouncer URL via a driver adapter.

```bash title=".env"
# PgBouncer (pooled) connection string used by Prisma Client.
DATABASE_URL="postgres://USER:PASSWORD@HOST:PORT/DATABASE?pgbouncer=true"

# Direct database connection string used by Prisma CLI. # [!code ++]
DIRECT_URL="postgres://USER:PASSWORD@HOST:PORT/DATABASE" # [!code ++]
```

```ts title="prisma.config.ts" showLineNumbers
import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DIRECT_URL"),
  },
});
```

```ts title="src/db/client.ts" showLineNumbers
import { PrismaClient } from "../prisma/generated/client";
import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
export const prisma = new PrismaClient({ adapter });
```

With this setup, PgBouncer stays in the path for runtime traffic, while Prisma CLI commands (`prisma migrate dev`, `prisma db push`, `prisma db pull`, and so on) always use the direct connection string defined in `prisma.config.ts`.

### PgBouncer with different database providers [#pgbouncer-with-different-database-providers]

There are sometimes minor differences in how to connect directly to a Postgres database that depend on the provider hosting the database.

Below are links to information on how to set up these connections with providers who have setup steps not covered here in our documentation:

* [Connecting directly to a PostgreSQL database hosted on Digital Ocean](https://github.com/prisma/orm/issues/6157)
* [Connecting directly to a PostgreSQL database hosted on ScaleGrid](https://github.com/prisma/orm/issues/6701#issuecomment-824387959)

## Supabase Supavisor [#supabase-supavisor]

Supabase's Supavisor behaves similarly to [PgBouncer](#pgbouncer). You can add `?pgbouncer=true` to your connection pooled connection string available via your [Supabase database settings](https://supabase.com/dashboard/project/_/settings/database).

## Other external connection poolers [#other-external-connection-poolers]

Although Prisma ORM does not have explicit support for other connection poolers, if the limitations are similar to the ones of [PgBouncer](#pgbouncer) you can usually also use `pgbouncer=true` in your connection string to put Prisma ORM in a mode that works with them as well.

## Related pages

- [`Connection management`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-management): This page explains how database connections are handled with Prisma Client and how to manually connect and disconnect your database
- [`Connection pool`](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool): Prisma Client uses a connection pool (from the database driver or driver adapter) to store and manage database connections.

# Relations (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/relations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

A relation is a connection between two models in the Prisma schema. This page explains how you can define one-to-one, one-to-many and many-to-many relations in Prisma

Location: ORM > v7 > Prisma Schema > Data Model > Relations

A relation is a *connection* between two models in the Prisma schema. For example, there is a one-to-many relation between `User` and `Post` because one user can have many blog posts:

```prisma
model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int  // Foreign key connecting Post to User
  title    String
}
```

At a Prisma ORM level, the `User` / `Post` relation consists of:

* **Relation fields** (`author` and `posts`): Define connections at Prisma ORM level, do not exist in the database
* **Relation scalar field** (`authorId`): The foreign key that exists in the database

## Relations in the database [#relations-in-the-database]

### Relational databases [#relational-databases]

In SQL, you use a *foreign key* to create a relation between two tables:

* A foreign key column (`authorId`) in `Post` references the primary key (`id`) in `User`

```prisma
author     User        @relation(fields: [authorId], references: [id])
```

> [!NOTE]
> Relations in the Prisma schema represent relationships that exist between tables in the database.

### MongoDB [#mongodb]

MongoDB uses a normalized data model design where documents reference each other by ID:

```json
// User document
{ "_id": { "$oid": "60d5922d00581b8f0062e3a8" }, "name": "Ella" }

// Post documents referencing the user
{ "_id": "...", "title": "How to make sushi", "authorId": { "$oid": "60d5922d00581b8f0062e3a8" } }
```

If using `ObjectId`, add `@db.ObjectId` to both the model ID and relation scalar field:

```prisma
model Post {
  id       String @id @default(auto()) @map("_id") @db.ObjectId
  author   User   @relation(fields: [authorId], references: [id])
  authorId String @db.ObjectId
}
```

## Relations in Prisma Client [#relations-in-prisma-client]

### Create records with nested relations [#create-records-with-nested-relations]

```ts
const userAndPosts = await prisma.user.create({
  data: {
    posts: {
      create: [{ title: "Prisma Day 2020" }, { title: "How to write a Prisma schema" }],
    },
  },
});
```

### Retrieve records with related data [#retrieve-records-with-related-data]

```ts
const getAuthor = await prisma.user.findUnique({
  where: { id: "20" },
  include: { posts: true },
});
```

### Connect existing records [#connect-existing-records]

```ts
await prisma.user.update({
  where: { id: 20 },
  data: {
    posts: { connect: { id: 4 } },
  },
});
```

## Types of relations [#types-of-relations]

There are three different types (or [cardinalities](https://en.wikipedia.org/wiki/Cardinality_\(data_modeling\))) of relations in Prisma ORM:

* [One-to-one](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-one-relations) (also called 1-1 relations)
* [One-to-many](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-many-relations) (also called 1-n relations)
* [Many-to-many](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations) (also called m-n relations)

The following Prisma schema includes every type of relation:

* one-to-one: `User` ↔ `Profile`
* one-to-many: `User` ↔ `Post`
* many-to-many: `Post` ↔ `Category`

  

#### Relational databases

```prisma
model User {
  id      Int      @id @default(autoincrement())
  posts   Post[]
  profile Profile?
}

model Profile {
  id     Int  @id @default(autoincrement())
  user   User @relation(fields: [userId], references: [id])
  userId Int  @unique // relation scalar field (used in the `@relation` attribute above)
}

model Post {
  id         Int        @id @default(autoincrement())
  author     User       @relation(fields: [authorId], references: [id])
  authorId   Int // relation scalar field  (used in the `@relation` attribute above)
  categories Category[]
}

model Category {
  id    Int    @id @default(autoincrement())
  posts Post[]
}
```

#### MongoDB

```prisma
model User {
  id      String   @id @default(auto()) @map("_id") @db.ObjectId
  posts   Post[]
  profile Profile?
}

model Profile {
  id     String @id @default(auto()) @map("_id") @db.ObjectId
  user   User   @relation(fields: [userId], references: [id])
  userId String @unique @db.ObjectId // relation scalar field (used in the `@relation` attribute above)
}

model Post {
  id          String     @id @default(auto()) @map("_id") @db.ObjectId
  author      User       @relation(fields: [authorId], references: [id])
  authorId    String     @db.ObjectId // relation scalar field  (used in the `@relation` attribute above)
  categories  Category[] @relation(fields: [categoryIds], references: [id])
  categoryIds String[]   @db.ObjectId
}

model Category {
  id      String   @id @default(auto()) @map("_id") @db.ObjectId
  posts   Post[]   @relation(fields: [postIds], references: [id])
  postIds String[] @db.ObjectId
}
```

> [!NOTE]
> This schema is the same as the [example data model](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models) but has all [scalar fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#scalar-fields) removed (except for the required [relation scalar fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#relation-fields)) so you can focus on the [relation fields](#relation-fields).

> [!NOTE]
> This example uses [implicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations). These relations do not require the `@relation` attribute unless you need to [disambiguate relations](#disambiguating-relations).

Notice that the syntax is slightly different between relational databases and MongoDB - particularly for [many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations).

For relational databases, the following entity relationship diagram represents the database that corresponds to the sample Prisma schema:

![The sample schema as an entity relationship diagram](https://www.prisma.io/img/orm/prisma-schema/data-model/relations/sample-schema.png)

For MongoDB, Prisma ORM uses a [normalized data model design](https://www.mongodb.com/docs/manual/data-modeling/), which means that documents reference each other by ID in a similar way to relational databases. See [the MongoDB section](#mongodb) for more details.

### Implicit and explicit many-to-many relations [#implicit-and-explicit-many-to-many-relations]

Many-to-many relations in relational databases can be modelled in two ways:

* [explicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#explicit-many-to-many-relations), where the relation table is represented as an explicit model in your Prisma schema
* [implicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations), where Prisma ORM manages the relation table and it does not appear in the Prisma schema.

Implicit many-to-many relations require both models to have a single `@id`. Be aware of the following:

* You cannot use a [multi-field ID](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference)
* You cannot use a `@unique` in place of an `@id`

To use either of these features, you must set up an explicit many-to-many instead.

The implicit many-to-many relation still manifests in a relation table in the underlying database. However, Prisma ORM manages this relation table.

If you use an implicit many-to-many relation instead of an explicit one, it makes the [Prisma Client API](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/introduction) simpler (because, for example, you have one fewer level of nesting inside of [nested writes](https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries#nested-writes)).

If you're not using Prisma Migrate but obtain your data model from [introspection](https://www.prisma.io/docs/orm/v7/prisma-schema/introspection), you can still make use of implicit many-to-many relations by following Prisma ORM's [conventions for relation tables](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#relation-table-conventions).

## Relation fields [#relation-fields]

Relation fields are fields on a Prisma model whose type is another model (not a scalar type). Every relation needs exactly two relation fields, one on each model.

```prisma
model User {
  id    Int    @id @default(autoincrement())
  posts Post[] // relation field
}

model Post {
  id       Int    @id @default(autoincrement())
  author   User   @relation(fields: [authorId], references: [id]) // annotated relation field
  authorId Int    // relation scalar field (foreign key)
}
```

**Key concepts:**

* `posts` and `author` are relation fields (exist at Prisma ORM level only)
* `authorId` is the relation scalar field (exists in the database as foreign key)

### Annotated relation fields [#annotated-relation-fields]

Relations annotated with `@relation` attribute (one-to-one, one-to-many, and many-to-many for MongoDB) represent the side that stores the foreign key:

```prisma
author     User    @relation(fields: [authorId], references: [id])
authorId   Int     // relation scalar field
```

The `references` argument names the field on the other model that the relation scalar field points to. In the example above, `authorId` on `Post` holds the value of `id` on `User`, so `fields` lists the field on this model and `references` lists the field it points to on the related model.

Both arguments are lists because a relation can span more than one field. When the related model has a composite ID or a composite unique constraint, `fields` and `references` each list the same number of fields in the same order, for example `@relation(fields: [firstName, lastName], references: [firstName, lastName])`. The fields in `references` must be the related model's `@id` or a `@unique` field, or together form its `@@id` or `@@unique`. MongoDB does not support `@@id`, so on MongoDB the referenced fields are an `@id`, a `@unique`, or a `@@unique`. See the [`@relation` reference](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#relation) for every argument the attribute accepts.

**Naming convention:** Relation scalar fields typically use the pattern `fieldName` + `Id` (e.g., `author` → `authorId`).

## The `@relation` attribute [#the-relation-attribute]

The `@relation` attribute is required when:

* Defining one-to-one or one-to-many relations
* Disambiguating multiple relations between the same models
* Defining [self-relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/self-relations)
* Defining many-to-many relations for MongoDB

> [!NOTE]
> [Implicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations) in relational databases do not require `@relation`.

## Disambiguating relations [#disambiguating-relations]

When you have two relations between the same models, use the `name` argument in `@relation` to disambiguate:

```prisma
model User {
  id           Int     @id @default(autoincrement())
  writtenPosts Post[]  @relation("WrittenPosts")
  pinnedPost   Post?   @relation("PinnedPost")
}

model Post {
  id         Int     @id @default(autoincrement())
  author     User    @relation("WrittenPosts", fields: [authorId], references: [id])
  authorId   Int
  pinnedBy   User?   @relation("PinnedPost", fields: [pinnedById], references: [id])
  pinnedById Int?    @unique
}
```

The `name` must be the same on both sides of the relation.

## Related pages

- [`Database mapping`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/database-mapping): Learn how to map model and field names to database tables and columns
- [`External tables`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/externally-managed-tables): How to declare and use externally managed tables in Prisma ORM
- [`Indexes`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/indexes): How to configure index functionality and add full text indexes
- [`Models`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models): Learn about the concepts for building your data model with Prisma: Models, scalar types, enums, attributes, functions, IDs, default values and more
- [`Multi-schema`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/multi-schema): How to use Prisma ORM with multiple database schemas

# Many-to-many relations (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to define and work with many-to-many relations in Prisma.

Location: ORM > v7 > Prisma Schema > Data Model > Relations > Many-to-many relations

Many-to-many (m-n) relations connect zero or more records on one side to zero or more on the other. They can be [implicit](#implicit-many-to-many-relations) (Prisma manages the relation table) or [explicit](#explicit-many-to-many-relations) (you define the relation table).

## Relational databases [#relational-databases]

Use [implicit](#implicit-many-to-many-relations) m-n unless you need to store additional metadata in the relation table.

### Explicit many-to-many relations [#explicit-many-to-many-relations]

The relation table is represented as a model in the schema:

```prisma
model Post {
  id         Int                 @id @default(autoincrement())
  title      String
  categories CategoriesOnPosts[]
}

model Category {
  id    Int                 @id @default(autoincrement())
  name  String
  posts CategoriesOnPosts[]
}

model CategoriesOnPosts {
  post       Post     @relation(fields: [postId], references: [id])
  postId     Int
  category   Category @relation(fields: [categoryId], references: [id])
  categoryId Int
  assignedAt DateTime @default(now())
  assignedBy String
  @@id([postId, categoryId])
}
```

The relation table can store additional fields like `assignedAt` and `assignedBy`.

#### Querying explicit many-to-many [#querying-explicit-many-to-many]

```ts
// Create post with new category
const post = await prisma.post.create({
  data: {
    title: "How to be Bob",
    categories: {
      create: [
        {
          assignedBy: "Bob",
          category: { create: { name: "New category" } },
        },
      ],
    },
  },
});

// Connect to existing categories
await prisma.post.create({
  data: {
    title: "My Post",
    categories: {
      create: [
        { assignedBy: "Bob", category: { connect: { id: 9 } } },
        { assignedBy: "Bob", category: { connect: { id: 22 } } },
      ],
    },
  },
});

// Query posts by category
const posts = await prisma.post.findMany({
  where: { categories: { some: { category: { name: "New Category" } } } },
});
```

### Implicit many-to-many relations [#implicit-many-to-many-relations]

Prisma manages the relation table automatically:

```prisma
model Post {
  id         Int        @id @default(autoincrement())
  title      String
  categories Category[]
}

model Category {
  id    Int    @id @default(autoincrement())
  name  String
  posts Post[]
}
```

#### Querying implicit many-to-many [#querying-implicit-many-to-many]

```ts
// Create post with categories
const post = await prisma.post.create({
  data: {
    title: "How to become a butterfly",
    categories: {
      create: [{ name: "Magic" }, { name: "Butterflies" }],
    },
  },
});

// Get posts with categories
const posts = await prisma.post.findMany({
  include: { categories: true },
});
```

#### Rules for implicit m-n [#rules-for-implicit-m-n]

* Both models must have a single `@id` (no composite IDs or `@unique`)
* No `@relation` attribute needed (unless disambiguating)
* Cannot use `fields`, `references`, `onUpdate`, or `onDelete` in `@relation`

#### Relation table conventions [#relation-table-conventions]

For `prisma db pull` to recognize implicit m-n tables:

* Table name: `_CategoryToPost` (underscore + model names alphabetically + `To`)
* Columns: `A` (FK to first model alphabetically) and `B` (FK to second)
* Unique index on both columns, non-unique index on `B`

### Configuring relation table name [#configuring-relation-table-name]

Use `@relation("MyRelationTable")` on both sides to customize the table name.

## MongoDB [#mongodb]

MongoDB requires explicit ID arrays on both sides:

```prisma
model Post {
  id          String     @id @default(auto()) @map("_id") @db.ObjectId
  categoryIDs String[]   @db.ObjectId
  categories  Category[] @relation(fields: [categoryIDs], references: [id])
}

model Category {
  id      String   @id @default(auto()) @map("_id") @db.ObjectId
  name    String
  postIDs String[] @db.ObjectId
  posts   Post[]   @relation(fields: [postIDs], references: [id])
}
```

### Querying MongoDB m-n [#querying-mongodb-m-n]

```ts
// Find posts by category IDs
const posts = await prisma.post.findMany({
  where: { categoryIDs: { hasSome: [id1, id2] } },
});

// Find posts by category name
const posts = await prisma.post.findMany({
  where: { categories: { some: { name: { contains: "Servers" } } } },
});
```

## Related pages

- [`One-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-many-relations): How to define and work with one-to-many relations in Prisma.
- [`One-to-one relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-one-relations): How to define and work with one-to-one relations in Prisma.
- [`Referential actions`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions): Referential actions let you define the update and delete behavior of related models on the database level
- [`Relation mode`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode): Manage relations between records with relation modes in Prisma
- [`Self-relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/self-relations): How to define and work with self-relations in Prisma.

# One-to-many relations (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/relations/one-to-many-relations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to define and work with one-to-many relations in Prisma.

Location: ORM > v7 > Prisma Schema > Data Model > Relations > One-to-many relations

One-to-many (1-n) relations connect one record on one side to zero or more records on the other side:

```prisma
model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int
}
```

This expresses:

* A user can have zero or more posts
* A post must always have an author

You can also reference a field other than the primary key. The referenced field on the parent model must be unique, so mark it with `@unique` (an `@id` field is already unique). To reference several fields at once, they must together form a `@@id` or `@@unique`; see [Multi-field relations](#multi-field-relations-relational-databases-only).

```prisma
model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  posts Post[]
}

model Post {
  id          Int    @id @default(autoincrement())
  authorEmail String
  author      User   @relation(fields: [authorEmail], references: [email])
}
```

## Multi-field relations (relational databases only) [#multi-field-relations-relational-databases-only]

```prisma
model User {
  firstName String
  lastName  String
  post      Post[]
  @@id([firstName, lastName])
}

model Post {
  id              Int    @id @default(autoincrement())
  author          User   @relation(fields: [authorFirstName, authorLastName], references: [firstName, lastName])
  authorFirstName String
  authorLastName  String
}
```

## 1-n in the database [#1-n-in-the-database]

The difference between 1-1 and 1-n is that in a 1-1 relation the foreign key must have a `UNIQUE` constraint. Without `UNIQUE`, multiple records can point to the same parent, making it 1-n.

## Required vs optional relation fields [#required-vs-optional-relation-fields]

The annotated relation field and relation scalar can be either optional or mandatory. The list side is always mandatory.

**Optional 1-n** (can create Post without User):

```prisma
model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int   @id @default(autoincrement())
  author   User? @relation(fields: [authorId], references: [id])
  authorId Int?
}
```

**Mandatory 1-n** (must assign User when creating Post):

```prisma
model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int
}
```

## Related pages

- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations): How to define and work with many-to-many relations in Prisma.
- [`One-to-one relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-one-relations): How to define and work with one-to-one relations in Prisma.
- [`Referential actions`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions): Referential actions let you define the update and delete behavior of related models on the database level
- [`Relation mode`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode): Manage relations between records with relation modes in Prisma
- [`Self-relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/self-relations): How to define and work with self-relations in Prisma.

# One-to-one relations (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/relations/one-to-one-relations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to define and work with one-to-one relations in Prisma.

Location: ORM > v7 > Prisma Schema > Data Model > Relations > One-to-one relations

One-to-one (1-1) relations connect at most **one** record on each side. In this example, `User` and `Profile` have a 1-1 relation:

```prisma
model User {
  id      Int      @id @default(autoincrement())
  profile Profile?
}

model Profile {
  id     Int  @id @default(autoincrement())
  user   User @relation(fields: [userId], references: [id])
  userId Int  @unique // Foreign key with unique constraint
}
```

This expresses:

* A user can have zero or one profile
* A profile must always be connected to exactly one user

You can also reference a non-ID field with `@unique`:

```prisma
model Profile {
  id        Int    @id @default(autoincrement())
  user      User   @relation(fields: [userEmail], references: [email])
  userEmail String @unique
}
```

## Multi-field relations (relational databases only) [#multi-field-relations-relational-databases-only]

```prisma
model User {
  firstName String
  lastName  String
  profile   Profile?
  @@id([firstName, lastName])
}

model Profile {
  id            Int    @id @default(autoincrement())
  user          User   @relation(fields: [userFirstName, userLastName], references: [firstName, lastName])
  userFirstName String
  userLastName  String
  @@unique([userFirstName, userLastName])
}
```

## 1-1 in the database [#1-1-in-the-database]

In SQL, a 1-1 relation requires a `UNIQUE` constraint on the foreign key. Without this, it becomes a 1-n relation.

For MongoDB, documents reference each other by ID:

```json
// User
{ "_id": { "$oid": "60d58e130011041800d209e1" }, "name": "Bob" }
// Profile
{ "_id": "...", "bio": "I like drawing.", "userId": { "$oid": "60d58e130011041800d209e1" } }
```

## Required and optional 1-1 relation fields [#required-and-optional-1-1-relation-fields]

The side *without* a relation scalar must be optional:

```prisma
model User {
  id      Int      @id @default(autoincrement())
  profile Profile? // No relation scalar - must be optional
}
```

The side *with* a relation scalar can be required or optional:

**Mandatory 1-1** (cannot create User without Profile):

```prisma
model User {
  id        Int     @id @default(autoincrement())
  profile   Profile @relation(fields: [profileId], references: [id])
  profileId Int     @unique
}
```

**Optional 1-1** (can create User without Profile):

```prisma
model User {
  id        Int      @id @default(autoincrement())
  profile   Profile? @relation(fields: [profileId], references: [id])
  profileId Int?     @unique
}
```

## Choosing which side stores the foreign key [#choosing-which-side-stores-the-foreign-key]

In 1-1 relations, you can choose which side holds the `@relation` attribute and foreign key. Both approaches are valid:

**Option 1:** Foreign key on `Profile`

```prisma
model User {
  id      Int      @id @default(autoincrement())
  profile Profile?
}

model Profile {
  id     Int  @id @default(autoincrement())
  user   User @relation(fields: [userId], references: [id])
  userId Int  @unique
}
```

**Option 2:** Foreign key on `User`

```prisma
model User {
  id        Int      @id @default(autoincrement())
  profile   Profile? @relation(fields: [profileId], references: [id])
  profileId Int?     @unique
}

model Profile {
  id   Int   @id @default(autoincrement())
  user User?
}
```

## Related pages

- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations): How to define and work with many-to-many relations in Prisma.
- [`One-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-many-relations): How to define and work with one-to-many relations in Prisma.
- [`Referential actions`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions): Referential actions let you define the update and delete behavior of related models on the database level
- [`Relation mode`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode): Manage relations between records with relation modes in Prisma
- [`Self-relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/self-relations): How to define and work with self-relations in Prisma.

# Referential actions (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/relations/referential-actions)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Referential actions let you define the update and delete behavior of related models on the database level

Location: ORM > v7 > Prisma Schema > Data Model > Relations > Referential actions

Referential actions determine what happens to a record when your application deletes or updates a related record. They are defined in the [`@relation`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#relation) attribute and map to foreign key constraints in the database.

In the following example, `onDelete: Cascade` means that deleting a `User` record will also delete all related `Post` records.

```prisma title="schema.prisma" highlight=4;normal showLineNumbers
model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id], onDelete: Cascade)
  authorId Int
}

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}
```

If you do not specify a referential action, Prisma ORM [uses a default](#referential-action-defaults).

**Questions answered in this page**

* What do referential actions do?
* Which defaults apply if none are set?
* How do actions map to my database?
* How do I fix cascade cycles on SQL Server?
* Do MongoDB self-relations require NoAction?
* How do I handle multiple cascade paths?

## Available referential actions [#available-referential-actions]

Prisma ORM supports five referential actions:

* **[`Cascade`](#cascade)** - Deletes/updates cascade to related records
* **[`Restrict`](#restrict)** - Prevents deletion/update if related records exist
* **[`NoAction`](#noaction)** - Similar to Restrict, behavior varies by database
* **[`SetNull`](#setnull)** - Sets foreign key to NULL (requires optional relation)
* **[`SetDefault`](#setdefault)** - Sets foreign key to default value

### Referential action defaults [#referential-action-defaults]

If you do not specify a referential action, Prisma ORM uses the following defaults:

| Clause     | Optional relations | Mandatory relations |
| :--------- | :----------------- | :------------------ |
| `onDelete` | `SetNull`          | `Restrict`          |
| `onUpdate` | `Cascade`          | `Cascade`           |

## Caveats [#caveats]

The following caveats apply:

* Referential actions are **not** supported on [implicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations). To use referential actions, you must define an explicit many-to-many relation and define your referential actions on the [join table](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/troubleshooting-relations#how-to-use-a-relation-table-with-a-many-to-many-relationship).
* Certain combinations of referential actions and required/optional relations are incompatible. For example, using `SetNull` on a required relation will lead to database errors when deleting referenced records because the non-nullable constraint would be violated. See [this GitHub issue](https://github.com/prisma/orm/issues/7909) for more information.

## Types of referential actions [#types-of-referential-actions]

The following table shows which referential action each database supports.

| Database      | Cascade | Restrict | NoAction | SetNull | SetDefault |
| :------------ | :------ | :------- | :------- | :------ | :--------- |
| PostgreSQL    | ✔️      | ✔️       | ✔️       | ✔️⌘     | ✔️         |
| MySQL/MariaDB | ✔️      | ✔️       | ✔️       | ✔️      | ❌ (✔️†)    |
| SQLite        | ✔️      | ✔️       | ✔️       | ✔️      | ✔️         |
| SQL Server    | ✔️      | ❌‡       | ✔️       | ✔️      | ✔️         |
| CockroachDB   | ✔️      | ✔️       | ✔️       | ✔️      | ✔️         |
| MongoDB       | ✔️      | ✔️       | ✔️       | ✔️      | ❌          |

* † See [special cases for MySQL](#mysqlmariadb).
* ⌘ See [special cases for PostgreSQL](#postgresql).
* ‡ See [special cases for SQL Server](#sql-server).

### Special cases for referential actions [#special-cases-for-referential-actions]

Referential actions are part of the ANSI SQL standard. However, there are special cases where some relational databases diverge from the standard.

#### MySQL/MariaDB [#mysqlmariadb]

MySQL/MariaDB, and the underlying InnoDB storage engine, does not support `SetDefault`. The exact behavior depends on the database version:

* In MySQL versions 8 and later, and MariaDB versions 10.5 and later, `SetDefault` effectively acts as an alias for `NoAction`. You can define tables using the `SET DEFAULT` referential action, but a foreign key constraint error is triggered at runtime.
* In MySQL versions 5.6 and later, and MariaDB versions before 10.5, attempting to create a table definition with the `SET DEFAULT` referential action fails with a syntax error.

For this reason, when you set `mysql` as the database provider, Prisma ORM warns users to replace `SetDefault` referential actions in the Prisma schema with another action.

#### PostgreSQL [#postgresql]

PostgreSQL is the only database supported by Prisma ORM that allows you to define a `SetNull` referential action that refers to a non-nullable field. However, this raises a foreign key constraint error when the action is triggered at runtime.

For this reason, when you set `postgres` as the database provider in the (default) `foreignKeys` relation mode, Prisma ORM warns users to mark as optional any fields that are included in a `@relation` attribute with a `SetNull` referential action. For all other database providers, Prisma ORM rejects the schema with a validation error.

#### SQL Server [#sql-server]

[`Restrict`](#restrict) is not available for SQL Server databases, but you can use [`NoAction`](#noaction) instead.

### `Cascade` [#cascade]

* `onDelete: Cascade` Deleting a referenced record will trigger the deletion of referencing record.
* `onUpdate: Cascade` Updates the relation scalar fields if the referenced scalar fields of the dependent record are updated.

#### Example usage [#example-usage]

```prisma title="schema.prisma" highlight=4;add showLineNumbers
model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade) // [!code ++]
  authorId Int
}

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}
```

**Result:** If a `User` record is deleted, their posts are deleted too. If the user's `id` is updated, the corresponding `authorId` is also updated.

### `Restrict` [#restrict]

* `onDelete: Restrict` Prevents the deletion if any referencing records exist.
* `onUpdate: Restrict` Prevents the identifier of a referenced record from being changed.

#### Example usage [#example-usage-1]

```prisma title="schema.prisma" highlight=4;add showLineNumbers
model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id], onDelete: Restrict, onUpdate: Restrict) // [!code ++]
  authorId Int
}

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}
```

**Result:** `User`s with posts cannot be deleted. The `User`'s `id` cannot be changed.

> [!WARNING]
> The `Restrict` action is **not** available on [Microsoft SQL Server](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server) and triggers a schema validation error. Instead, you can use [`NoAction`](#noaction), which produces the same result and is compatible with SQL Server.

### `NoAction` [#noaction]

The `NoAction` action is similar to `Restrict`, the difference between the two is dependent on the database being used:

* **PostgreSQL**: `NoAction` allows the check (if a referenced row on the table exists) to be deferred until later in the transaction. See [the PostgreSQL docs](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-FK) for more information.
* **MySQL**: `NoAction` behaves exactly the same as `Restrict`. See [the MySQL docs](https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html#foreign-key-referential-actions) for more information.
* **SQLite**: When a related primary key is modified or deleted, no action is taken. See [the SQLite docs](https://www.sqlite.org/foreignkeys.html#fk_actions) for more information.
* **SQL Server**: When a referenced record is deleted or modified, an error is raised. See [the SQL Server docs](https://learn.microsoft.com/en-us/sql/relational-databases/tables/graph-edge-constraints?view=sql-server-ver15#on-delete-referential-actions-on-edge-constraints) for more information.
* **MongoDB**: When a record is modified or deleted, nothing is done to any related records.

> [!WARNING]
> If you are [managing relations in Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode#emulate-relations-in-prisma-orm-with-the-prisma-relation-mode) rather than using foreign keys in the database, you should be aware that currently Prisma ORM only implements the referential actions. Foreign keys also create constraints, which make it impossible to manipulate data in a way that would violate these constraints: instead of executing the query, the database responds with an error. These constraints will not be created if you emulate referential integrity in Prisma Client, so if you set the referential action to `NoAction` there will be no checks to prevent you from breaking the referential integrity.

#### Example usage [#example-usage-2]

```prisma title="schema.prisma" highlight=4;add showLineNumbers
model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id], onDelete: NoAction, onUpdate: NoAction) // [!code ++]
  authorId Int
}

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}
```

**Result:** `User`s with posts cannot be deleted. The `User`'s `id` cannot be changed.

### `SetNull` [#setnull]

* `onDelete: SetNull` The scalar field of the referencing object will be set to `NULL`.

* `onUpdate: SetNull` When updating the identifier of a referenced object, the scalar fields of the referencing objects will be set to `NULL`.

`SetNull` will only work on optional relations. On required relations, a runtime error will be thrown since the scalar fields cannot be null.

```prisma title="schema.prisma" highlight=4;add showLineNumbers
model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User?  @relation(fields: [authorId], references: [id], onDelete: SetNull, onUpdate: SetNull) // [!code ++]
  authorId Int?
}

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}
```

**Result:** When deleting or updating a `User`, the `authorId` is set to `NULL` for all their posts.

### `SetDefault` [#setdefault]

* `onDelete: SetDefault` The scalar field of the referencing object will be set to the fields default value.

* `onUpdate: SetDefault` The scalar field of the referencing object will be set to the fields default value.

These require setting a default for the relation scalar field with [`@default`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#default). If no defaults are provided for any of the scalar fields, a runtime error will be thrown.

```prisma title="schema.prisma" highlight=4,5;add showLineNumbers
model Post {
  id             Int     @id @default(autoincrement())
  title          String
  authorUsername String? @default("anonymous") // [!code ++]
  author         User?   @relation(fields: [authorUsername], references: [username], onDelete: SetDefault, onUpdate: SetDefault) // [!code ++]
}

model User {
  username String @id
  posts    Post[]
}
```

**Result:** When deleting or updating a `User`, their posts' `authorUsername` is set to the default value ('anonymous').

## Special rules for SQL Server and MongoDB [#special-rules-for-sql-server-and-mongodb]

> [!NOTE]
> Quick summary
> 
> This section explains special rules and common issues when using referential actions with SQL Server and MongoDB, including how to avoid cycles and multiple cascade paths.

**SQL Server** doesn't allow cascading referential actions if the relation chain causes a cycle or multiple cascade paths. The server will return an error when executing the SQL.

**MongoDB** requires `NoAction` for self-referential relations or cycles between three models to prevent infinite loops. MongoDB uses `relationMode = "prisma"` by default, meaning Prisma ORM manages [referential integrity](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode).

Prisma ORM validates your data model *before* generating SQL, highlighting problematic relations to help you fix these issues early.

### Self-relation (SQL Server and MongoDB) [#self-relation-sql-server-and-mongodb]

The following model describes a self-relation where an `Employee` can have a manager and managees, referencing entries of the same model.

```prisma
model Employee {
  id        Int        @id @default(autoincrement())
  manager   Employee?  @relation(name: "management", fields: [managerId], references: [id])
  managees  Employee[] @relation(name: "management")
  managerId Int?
}
```

This will result in the following error:

```bash wrap
Error parsing attribute "@relation": A self-relation must have `onDelete` and `onUpdate` referential actions set to `NoAction` in one of the @relation attributes. (Implicit default `onDelete`: `SetNull`, and `onUpdate`: `Cascade`)
```

By not defining any actions, Prisma ORM will use the following default values depending if the underlying [scalar fields](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/models#scalar-fields) are set to be optional or required.

| Clause     | All of the scalar fields are optional | At least one scalar field is required |
| :--------- | :------------------------------------ | :------------------------------------ |
| `onDelete` | `SetNull`                             | `NoAction`                            |
| `onUpdate` | `Cascade`                             | `Cascade`                             |

Since the default referential action for `onUpdate` in the above relation would be `Cascade` and for `onDelete` it would be `SetNull`, it creates a cycle and the solution is to explicitly set the `onUpdate` and `onDelete` values to `NoAction`.

```prisma highlight=3;delete|4;add
model Employee {
  id        Int        @id @default(autoincrement())
  manager   Employee   @relation(name: "management", fields: [managerId], references: [id]) // [!code --]
  manager   Employee   @relation(name: "management", fields: [managerId], references: [id], onDelete: NoAction, onUpdate: NoAction) // [!code ++]
  managees  Employee[] @relation(name: "management")
  managerId Int
}
```

### Cyclic relation between three tables (SQL Server and MongoDB) [#cyclic-relation-between-three-tables-sql-server-and-mongodb]

The following models describe a cyclic relation between a `Chicken`, an `Egg` and a `Fox`, where each model references the other.

```prisma
model Chicken {
  id        Int   @id @default(autoincrement())
  egg       Egg   @relation(fields: [eggId], references: [id])
  eggId     Int
  predators Fox[]
}

model Egg {
  id         Int       @id @default(autoincrement())
  predator   Fox       @relation(fields: [predatorId], references: [id])
  predatorId Int
  parents    Chicken[]
}

model Fox {
  id        Int     @id @default(autoincrement())
  meal      Chicken @relation(fields: [mealId], references: [id])
  mealId    Int
  foodStore Egg[]
}
```

This will result in validation errors indicating a cycle exists:

```bash wrap
Error parsing attribute "@relation": Reference causes a cycle. One of the @relation attributes in this cycle must have `onDelete` and `onUpdate` referential actions set to `NoAction`. Cycle path: Chicken.egg → Egg.predator → Fox.meal. (Implicit default `onUpdate`: `Cascade`)
```

Since the default `onUpdate` action is `Cascade`, it creates a cycle. Set `onUpdate: NoAction` on any one of the relations to break the cycle:

```prisma highlight=3;delete|4;add
model Chicken {
  id        Int   @id @default(autoincrement())
  egg       Egg   @relation(fields: [eggId], references: [id]) // [!code --]
  egg       Egg   @relation(fields: [eggId], references: [id], onUpdate: NoAction) // [!code ++]
  eggId     Int
  predators Fox[]
}
```

### Multiple cascade paths between two models (SQL Server only) [#multiple-cascade-paths-between-two-models-sql-server-only]

The data model describes two different paths between same models, with both relations triggering cascading referential actions.

```prisma
model User {
  id       Int       @id @default(autoincrement())
  comments Comment[]
  posts    Post[]
}

model Post {
  id       Int       @id @default(autoincrement())
  authorId Int
  author   User      @relation(fields: [authorId], references: [id])
  comments Comment[]
}

model Comment {
  id          Int  @id @default(autoincrement())
  writtenById Int
  postId      Int
  writtenBy   User @relation(fields: [writtenById], references: [id])
  post        Post @relation(fields: [postId], references: [id])
}
```

There are two paths from `Comment` to `User`, and the default `onUpdate: Cascade` creates multiple cascade paths:

```bash wrap
Error parsing attribute "@relation": When any of the records in model `User` is updated or deleted, the referential actions on the relations cascade to model `Comment` through multiple paths. Please break one of these paths by setting the `onUpdate` and `onDelete` to `NoAction`. (Implicit default `onUpdate`: `Cascade`)
```

Set `onUpdate: NoAction` on any one of the relations to break the multiple cascade paths:

```prisma highlight=5;delete|6;add
model Comment {
  id          Int  @id @default(autoincrement())
  writtenById Int
  postId      Int
  writtenBy   User @relation(fields: [writtenById], references: [id]) // [!code --]
  writtenBy   User @relation(fields: [writtenById], references: [id], onUpdate: NoAction) // [!code ++]
  post        Post @relation(fields: [postId], references: [id])
}
```

## Related pages

- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations): How to define and work with many-to-many relations in Prisma.
- [`One-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-many-relations): How to define and work with one-to-many relations in Prisma.
- [`One-to-one relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-one-relations): How to define and work with one-to-one relations in Prisma.
- [`Relation mode`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode): Manage relations between records with relation modes in Prisma
- [`Self-relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/self-relations): How to define and work with self-relations in Prisma.

# Relation mode (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/relations/relation-mode)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Manage relations between records with relation modes in Prisma

Location: ORM > v7 > Prisma Schema > Data Model > Relations > Relation mode

**Questions answered in this page**

* What is `relationMode` in Prisma?
* When should I use `prisma` vs `foreignKeys`?
* How does relation emulation affect constraints?

In Prisma schema, relations between records are defined with the [`@relation`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#relation) attribute. For example, in the following schema there is a one-to-many relation between the `User` and `Post` models:

```prisma title="schema.prisma" highlight=4,5,10;normal showLineNumbers
model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade) // [!code highlight]
  authorId Int // [!code highlight]
}

model User {
  id    Int    @id @default(autoincrement())
  posts Post[] // [!code highlight]
}
```

Prisma ORM has two *relation modes*, `foreignKeys` and `prisma`, that specify how relations between records are enforced.

If you use Prisma ORM with a relational database, then by default Prisma ORM uses the [`foreignKeys` relation mode](#handle-relations-in-your-relational-database-with-the-foreignkeys-relation-mode), which enforces relations between records at the database level with foreign keys. A foreign key is a column or group of columns in one table that take values based on the primary key in another table. Foreign keys allow you to:

* set constraints that prevent you from making changes that break references
* set [referential actions](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions) that define how changes to records are handled

Together these constraints and referential actions guarantee the *referential integrity* of the data.

For the example schema above, Prisma Migrate will generate the following SQL by default if you use the PostgreSQL connector:

```sql highlight=19-22;normal

-- CreateTable
CREATE TABLE "Post" (
    "id" SERIAL NOT NULL,
    "title" TEXT NOT NULL,
    "authorId" INTEGER NOT NULL,

    CONSTRAINT "Post_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "User" (
    "id" SERIAL NOT NULL,

    CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "Post" -- [!code highlight]
  ADD CONSTRAINT "Post_authorId_fkey" -- [!code highlight]
  FOREIGN KEY ("authorId") -- [!code highlight]
  REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- [!code highlight]
```

In this case, the foreign key constraint on the `authorId` column of the `Post` table references the `id` column of the `User` table, and guarantees that a post must have an author that exists. If you update or delete a user then the `ON DELETE` and `ON UPDATE` referential actions specify the `CASCADE` option, which will also delete or update all posts belonging to the user.

Some databases, such as MongoDB or [PlanetScale](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale), do not support foreign keys. Additionally, in some cases developers may prefer not to use foreign keys in their relational database that usually does support foreign keys. For these situations, Prisma ORM offers [the `prisma` relation mode](#emulate-relations-in-prisma-orm-with-the-prisma-relation-mode), which emulates some properties of relations in relational databases. When you use Prisma Client with the `prisma` relation mode enabled, the behavior of queries is identical or similar, but referential actions and some constraints are handled by the Prisma engine rather than in the database.

> [!WARNING]
> There are performance implications to emulation of referential integrity and
> referential actions in Prisma Client. In cases where the underlying database
> supports foreign keys, it is usually the preferred choice.

## How to set the relation mode in your Prisma schema [#how-to-set-the-relation-mode-in-your-prisma-schema]

To set the relation mode, add the `relationMode` field in the `datasource` block:

```prisma title="schema.prisma" highlight=4,9;add showLineNumbers
datasource db {
  provider     = "mysql"
  relationMode = "prisma" // [!code ++]
}
```

For relational databases, the available options are:

* `foreignKeys`: this handles relations in the database with foreign keys. This is the default option for all relational database connectors and is active if no `relationMode` is explicitly set in the `datasource` block.
* `prisma`: this emulates relations in Prisma Client. You should also [enable this option](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale) when you use the MySQL connector with a PlanetScale database and don't have native foreign key constraints enabled in your PlanetScale database settings.

For MongoDB, the only available option is the `prisma` relation mode. This mode is also active if no `relationMode` is explicitly set in the `datasource` block.

> [!WARNING]
> If you switch between relation modes, Prisma ORM will add or remove foreign keys to your database next time you apply changes to your schema with Prisma Migrate or `db push`. See [Switch between relation modes](#switch-between-relation-modes) for more information.

## Handle relations in your relational database with the `foreignKeys` relation mode [#handle-relations-in-your-relational-database-with-the-foreignkeys-relation-mode]

The `foreignKeys` relation mode handles relations in your relational database with foreign keys. This is the default option when you use a relational database connector (PostgreSQL, MySQL, SQLite, SQL Server, CockroachDB).

The `foreignKeys` relation mode is not available when you use the MongoDB connector. Some relational databases, [such as PlanetScale](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale), also forbid the use of foreign keys. In these cases, you should instead [emulate relations in Prisma ORM with the `prisma` relation mode](#emulate-relations-in-prisma-orm-with-the-prisma-relation-mode).

### Referential integrity [#referential-integrity]

The `foreignKeys` relation mode maintains referential integrity at the database level with foreign key constraints and referential actions.

#### Foreign key constraints [#foreign-key-constraints]

When you *create* or *update* a record with a relation to another record, the related record needs to exist. Foreign key constraints enforce this behavior in the database. If the record does not exist, the database will return an error message.

#### Referential actions [#referential-actions]

When you *update* or *delete* a record with a relation to another record, referential actions are triggered in the database. To maintain referential integrity in related records, referential actions prevent changes that would break referential integrity, cascade changes through to related records, or set the value of fields that reference the updated or deleted records to a `null` or default value.

For more information, see the [referential actions](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions) page.

### Introspection [#introspection]

When you introspect a relational database with the `db pull` command with the `foreignKeys` relation mode enabled, a `@relation` attribute will be added to your Prisma schema for relations where foreign keys exist.

### Prisma Migrate and `db push` [#prisma-migrate-and-db-push]

When you apply changes to your Prisma schema with Prisma Migrate or `db push` with the `foreignKeys` relation mode enabled, foreign keys will be created in your database for all `@relation` attributes in your schema.

## Emulate relations in Prisma ORM with the `prisma` relation mode [#emulate-relations-in-prisma-orm-with-the-prisma-relation-mode]

The `prisma` relation mode emulates some foreign key constraints and referential actions for each Prisma Client query to maintain referential integrity, using some additional database queries and logic.

The `prisma` relation mode is the default option for the MongoDB connector. It should also be set if you use a relational database that does not support foreign keys. For example, [if you use PlanetScale](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale) without foreign key constraints, you should use the `prisma` relation mode.

> [!WARNING]
> There are performance implications to emulation of referential integrity in
> Prisma Client, because it uses additional database queries to maintain
> referential integrity. In cases where the underlying database can handle
> referential integrity with foreign keys, it is usually the preferred choice.

Emulation of relations is only available for Prisma Client queries and does not apply to raw queries.

### Which foreign key constraints are emulated? [#which-foreign-key-constraints-are-emulated]

When you *update* a record, Prisma ORM will emulate foreign key constraints. This means that when you update a record with a relation to another record, the related record needs to exist. If the record does not exist, Prisma Client will return an error message.

However, when you *create* a record, Prisma ORM does not emulate any foreign key constraints. You will be able to create invalid data.

### Which referential actions are emulated? [#which-referential-actions-are-emulated]

When you *update* or *delete* a record with related records, Prisma ORM will emulate referential actions.

The following table shows which emulated referential actions are available for each database connector:

| Database    | Cascade | Restrict | NoAction | SetNull | SetDefault |
| :---------- | :------ | :------- | :------- | :------ | :--------- |
| PostgreSQL  | **✔️**  | **✔️**   | **❌**‡   | **✔️**  | **❌**†     |
| MySQL       | **✔️**  | **✔️**   | **✔️**   | **✔️**  | **❌**†     |
| SQLite      | **✔️**  | **✔️**   | **❌**‡   | **✔️**  | **❌**†     |
| SQL Server  | **✔️**  | **✔️**   | **✔️**   | **✔️**  | **❌**†     |
| CockroachDB | **✔️**  | **✔️**   | **✔️**   | **✔️**  | **❌**†     |
| MongoDB     | **✔️**  | **✔️**   | **✔️**   | **✔️**  | **❌**†     |

* † The `SetDefault` referential action is not supported in the `prisma` relation mode.
* ‡ The `NoAction` referential action is not supported in the `prisma` relation mode for PostgreSQL and SQLite. Instead, use the `Restrict` action.

### Error messages [#error-messages]

Error messages returned by emulated constraints and referential actions in the `prisma` relation mode are generated by Prisma Client and differ slightly from the error messages in the `foreignKeys` relation mode:

```txt
Example:
// foreignKeys:
... Foreign key constraint failed on the field: `ProfileOneToOne_userId_fkey (index)`
// prisma:
... The change you are trying to make would violate the required relation 'ProfileOneToOneToUserOneToOne' between the `ProfileOneToOne` and `UserOneToOne` models.
```

### Introspection [#introspection-1]

When you introspect a database with the `db pull` command with the `prisma` relation mode enabled, relations will not be automatically added to your schema. You will instead need to add any relations manually with the `@relation` attribute. This only needs to be done once – next time you introspect your database, Prisma ORM will keep your added `@relation` attributes.

### Prisma Migrate and `db push` [#prisma-migrate-and-db-push-1]

When you apply changes to your Prisma schema with Prisma Migrate or `db push` with the `prisma` relation mode enabled, Prisma ORM will not use foreign keys in your database.

### Indexes [#indexes]

In relational databases that use foreign key constraints, the database usually also implicitly creates an index for the foreign key columns. For example, [MySQL will create an index on all foreign key columns](https://dev.mysql.com/doc/refman/8.0/en/constraint-foreign-key.html#:~\:text=MySQL%20requires%20that%20foreign%20key%20columns%20be%20indexed%3B%20if%20you%20create%20a%20table%20with%20a%20foreign%20key%20constraint%20but%20no%20index%20on%20a%20given%20column%2C%20an%20index%20is%20created.). This is to allow foreign key checks to run fast and not require a table scan.

The `prisma` relation mode does not use foreign keys, so no indexes are created when you use Prisma Migrate or `db push` to apply changes to your database. You instead need to manually add an index on your relation scalar fields with the [`@@index`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#index) attribute (or the [`@unique`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference#unique), [`@@unique`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) or [`@@id`](https://www.prisma.io/docs/orm/v7/reference/prisma-schema-reference) attributes, if applicable).

#### Index validation [#index-validation]

If you do not add the index manually, queries might require full table scans. This can be slow, and also expensive on database providers that bill per accessed row. To help avoid this, Prisma ORM warns you when your schema contains fields that are used in a `@relation` that does not have an index defined. For example, take the following schema with a relation between the `User` and `Post` models:

```prisma title="schema.prisma" showLineNumbers
datasource db {
  provider     = "mysql"
  relationMode = "prisma"
}

model User {
  id    Int    @id
  posts Post[]
}

model Post {
  id     Int  @id
  userId Int
  user   User @relation(fields: [userId], references: [id])
}
```

Prisma ORM displays the following warning when you run `prisma format` or `prisma validate`:

```bash wrap
With `relationMode = "prisma"`, no foreign keys are used, so relation fields will not benefit from the index usually created by the relational database under the hood. This can lead to poor performance when querying these fields. We recommend adding an index manually.
```

To fix this, add an index to your `Post` model:

```prisma title="schema.prisma" highlight=6;add showLineNumbers
model Post {
  id     Int  @id
  userId Int
  user   User @relation(fields: [userId], references: [id])

  @@index([userId]) // [!code ++]
}
```

If you use the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) (or our [language server in another editor](https://www.prisma.io/docs/orm/v7/more/dev-environment/editor-setup)), the warning is augmented with a Quick Fix that adds the required index for you:

![The Quick Fix pop-up for adding an index on a relation scalar field in VS Code](https://www.prisma.io/img/orm/prisma-schema/data-model/relations/quick-fix-index.png)

## Switch between relation modes [#switch-between-relation-modes]

It is only possible to switch between relation modes when you use a relational database connector (PostgreSQL, MySQL, SQLite, SQL Server, CockroachDB).

### Switch from `foreignKeys` to `prisma` [#switch-from-foreignkeys-to-prisma]

The default relation mode if you use a relational database and do not include the `relationMode` field in your `datasource` block is `foreignKeys`. To switch to the `prisma` relation mode, add the `relationMode` field with a value of `prisma`, or update the `relationMode` field value to `prisma` if it already exists.

When you switch the relation mode from `foreignKeys` to `prisma`, after you first apply changes to your schema with Prisma Migrate or `db push` Prisma ORM will remove all previously created foreign keys in the next migration.

If you keep the same database, you can then continue to work as normal. If you switch to a database that does not support foreign keys at all, your existing migration history contains SQL DDL that creates foreign keys, which might trigger errors if you ever have to rerun these migrations. In this case, we recommend that you delete the `migrations` directory. (If you use PlanetScale, which does not support foreign keys, we generally recommend that you [use `db push` rather than Prisma Migrate](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql#planetscale).)

### Switch from `prisma` to `foreignKeys` [#switch-from-prisma-to-foreignkeys]

To switch from the `prisma` relation mode to the `foreignKeys` relation mode, update the `relationMode` field value from `prisma` to `foreignKeys`. To do this, the database must support foreign keys. When you apply changes to your schema with Prisma Migrate or `db push` for the first time after you switch relation modes, Prisma ORM will create foreign keys for all relations in the next migration.

## Related pages

- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations): How to define and work with many-to-many relations in Prisma.
- [`One-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-many-relations): How to define and work with one-to-many relations in Prisma.
- [`One-to-one relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-one-relations): How to define and work with one-to-one relations in Prisma.
- [`Referential actions`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions): Referential actions let you define the update and delete behavior of related models on the database level
- [`Self-relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/self-relations): How to define and work with self-relations in Prisma.

# Self-relations (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/relations/self-relations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

How to define and work with self-relations in Prisma.

Location: ORM > v7 > Prisma Schema > Data Model > Relations > Self-relations

A relation field can reference its own model, called a *self-relation*. Self-relations can be 1-1, 1-n, or m-n.

> [!NOTE]
> Self-relations always require the `@relation` attribute.

## One-to-one self-relations [#one-to-one-self-relations]

```prisma
model User {
  id          Int     @id @default(autoincrement())
  name        String?
  successorId Int?    @unique
  successor   User?   @relation("BlogOwnerHistory", fields: [successorId], references: [id])
  predecessor User?   @relation("BlogOwnerHistory")
}
```

This expresses:

* A user can have zero or one predecessor
* A user can have zero or one successor

**Key rules:**

* Both sides must use the same `@relation` name
* One side must be fully annotated with `fields` and `references`
* The foreign key needs `@unique` for 1-1
* Cannot be required on both sides (impossible to create first record)

## One-to-many self relations [#one-to-many-self-relations]

```prisma
model User {
  id        Int     @id @default(autoincrement())
  name      String?
  teacherId Int?
  teacher   User?   @relation("TeacherStudents", fields: [teacherId], references: [id])
  students  User[]  @relation("TeacherStudents")
}
```

This expresses:

* A user has zero or one teacher
* A user can have zero or more students

No `@unique` constraint on `teacherId` - multiple students can share the same teacher.

## Many-to-many self relations [#many-to-many-self-relations]

```prisma
model User {
  id         Int     @id @default(autoincrement())
  name       String?
  followedBy User[]  @relation("UserFollows")
  following  User[]  @relation("UserFollows")
}
```

This expresses:

* A user can be followed by zero or more users
* A user can follow zero or more users

For relational databases, this is an implicit m-n (Prisma manages the relation table).

**Explicit version** (for storing additional fields):

```prisma
model User {
  id         Int       @id @default(autoincrement())
  name       String?
  followedBy Follows[] @relation("followedBy")
  following  Follows[] @relation("following")
}

model Follows {
  followedBy   User @relation("followedBy", fields: [followedById], references: [id])
  followedById Int
  following    User @relation("following", fields: [followingId], references: [id])
  followingId  Int
  @@id([followingId, followedById])
}
```

## Multiple self-relations on same model [#multiple-self-relations-on-same-model]

You can combine multiple self-relations:

```prisma
model User {
  id         Int     @id @default(autoincrement())
  name       String?
  teacherId  Int?
  teacher    User?   @relation("TeacherStudents", fields: [teacherId], references: [id])
  students   User[]  @relation("TeacherStudents")
  followedBy User[]  @relation("UserFollows")
  following  User[]  @relation("UserFollows")
}
```

## Related pages

- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations): How to define and work with many-to-many relations in Prisma.
- [`One-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-many-relations): How to define and work with one-to-many relations in Prisma.
- [`One-to-one relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-one-relations): How to define and work with one-to-one relations in Prisma.
- [`Referential actions`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions): Referential actions let you define the update and delete behavior of related models on the database level
- [`Relation mode`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode): Manage relations between records with relation modes in Prisma

# Troubleshooting relations (Prisma ORM v7) (/docs/orm/v7/prisma-schema/data-model/relations/troubleshooting-relations)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Location: ORM > v7 > Prisma Schema > Data Model > Relations > Troubleshooting relations

Modelling your schema can sometimes offer up some unexpected results. This section aims to cover the most prominent of those.

## Implicit many-to-many self-relations return incorrect data if order of relation fields change [#implicit-many-to-many-self-relations-return-incorrect-data-if-order-of-relation-fields-change]

### Problem [#problem]

In the following implicit many-to-many self-relation, the lexicographic order of relation fields in `a_eats` (1) and `b_eatenBy` (2):

```prisma highlight=4,5;normal
model Animal {
  id        Int      @id @default(autoincrement())
  name      String
  a_eats    Animal[] @relation(name: "FoodChain") // [!code highlight]
  b_eatenBy Animal[] @relation(name: "FoodChain") // [!code highlight]
}
```

The resulting relation table in SQL looks as follows, where `A` represents prey (`a_eats`) and `B` represents predators (`b_eatenBy`):

| A            | B          |
| :----------- | :--------- |
| 8 (Plankton) | 7 (Salmon) |
| 7 (Salmon)   | 9 (Bear)   |

The following query returns a salmon's prey and predators:

```ts
const getAnimals = await prisma.animal.findMany({
  where: {
    name: "Salmon",
  },
  include: {
    b_eats: true,
    a_eatenBy: true,
  },
});
```

```json
{
  "id": 7,
  "name": "Salmon",
  "b_eats": [
    {
      "id": 8,
      "name": "Plankton"
    }
  ],
  "a_eatenBy": [
    {
      "id": 9,
      "name": "Bear"
    }
  ]
}
```

Now change the order of the relation fields:

```prisma highlight=4,5;normal
model Animal {
  id        Int      @id @default(autoincrement())
  name      String
  b_eats    Animal[] @relation(name: "FoodChain") // [!code highlight]
  a_eatenBy Animal[] @relation(name: "FoodChain") // [!code highlight]
}
```

Migrate your changes and re-generate Prisma Client. When you run the same query with the updated field names, Prisma Client returns incorrect data (salmon now eats bears and gets eaten by plankton):

```ts
const getAnimals = await prisma.animal.findMany({
  where: {
    name: "Salmon",
  },
  include: {
    b_eats: true,
    a_eatenBy: true,
  },
});
```

```json
{
  "id": 1,
  "name": "Salmon",
  "b_eats": [
    {
      "id": 3,
      "name": "Bear"
    }
  ],
  "a_eatenBy": [
    {
      "id": 2,
      "name": "Plankton"
    }
  ]
}
```

Although the lexicographic order of the relation fields in the Prisma schema changed, columns `A` and `B` in the database **did not change** (they were not renamed and data was not moved). Therefore, `A` now represents predators (`a_eatenBy`) and `B` represents prey (`b_eats`):

| A            | B          |
| :----------- | :--------- |
| 8 (Plankton) | 7 (Salmon) |
| 7 (Salmon)   | 9 (Bear)   |

### Solution [#solution]

If you rename relation fields in an implicit many-to-many self-relations, make sure that you maintain the alphabetic order of the fields - for example, by prefixing with `a_` and `b_`.

## How to use a relation table with a many-to-many relationship [#how-to-use-a-relation-table-with-a-many-to-many-relationship]

There are a couple of ways to define an m-n relationship, implicitly or explicitly. Implicitly means letting Prisma ORM handle the relation table (JOIN table) under the hood, all you have to do is define an array/list for the non scalar types on each model, see [implicit many-to-many relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#implicit-many-to-many-relations).

Where you might run into trouble is when creating an [explicit m-n relationship](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#explicit-many-to-many-relations), that is, to create and handle the relation table yourself. **It can be overlooked that Prisma ORM requires both sides of the relation to be present**.

Take the following example, here a relation table is created to act as the JOIN between the `Post` and `Category` tables. This will not work however as the relation table (`PostCategories`) must form a 1-to-many relationship with the other two models respectively.

The back relation fields are missing from the `Post` to `PostCategories` and `Category` to `PostCategories` models.

```prisma
// This example schema shows how NOT to define an explicit m-n relation

model Post {
  id             Int              @id @default(autoincrement())
  title          String
  categories     Category[] // This should refer to PostCategories
}

model PostCategories {
  post       Post     @relation(fields: [postId], references: [id])
  postId     Int
  category   Category @relation(fields: [categoryId], references: [id])
  categoryId Int
  @@id([postId, categoryId])
}

model Category {
  id             Int              @id @default(autoincrement())
  name           String
  posts          Post[] // This should refer to PostCategories
}
```

To fix this the `Post` model needs to have a many relation field defined with the relation table `PostCategories`. The same applies to the `Category` model.

This is because the relation model forms a 1-to-many relationship with the other two models its joining.

```prisma highlight=5,21;add|4,20;delete
model Post {
  id             Int              @id @default(autoincrement())
  title          String
  categories     Category[] // [!code --]
  postCategories PostCategories[] // [!code ++]
}

model PostCategories {
  post       Post     @relation(fields: [postId], references: [id])
  postId     Int
  category   Category @relation(fields: [categoryId], references: [id])
  categoryId Int

  @@id([postId, categoryId])
}

model Category {
  id             Int              @id @default(autoincrement())
  name           String
  posts          Post[] // [!code --]
  postCategories PostCategories[] // [!code ++]
}
```

## Using the `@relation` attribute with a many-to-many relationship [#using-the-relation-attribute-with-a-many-to-many-relationship]

It might seem logical to add a `@relation("Post")` annotation to a relation field on your model when composing an implicit many-to-many relationship.

```prisma
model Post {
  id         Int        @id @default(autoincrement())
  title      String
  categories Category[] @relation("Category")
  Category   Category?  @relation("Post", fields: [categoryId], references: [id])
  categoryId Int?
}

model Category {
  id     Int    @id @default(autoincrement())
  name   String
  posts  Post[] @relation("Post")
  Post   Post?  @relation("Category", fields: [postId], references: [id])
  postId Int?
}
```

This however tells Prisma ORM to expect **two** separate one-to-many relationships. See [disambiguating relations](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations#disambiguating-relations) for more information on using the `@relation` attribute.

The following example is the correct way to define an implicit many-to-many relationship.

```prisma highlight=4,11;delete|5,12;add
model Post {
  id         Int        @id @default(autoincrement())
  title      String
  categories Category[] @relation("Category") // [!code --]
  categories Category[] // [!code ++]
}

model Category {
  id    Int    @id @default(autoincrement())
  name  String
  posts Post[] @relation("Post") // [!code --]
  posts Post[] // [!code ++]
}
```

The `@relation` annotation can also be used to [name the underlying relation table](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#configuring-relation-table-name) created on a implicit many-to-many relationship.

```prisma
model Post {
  id         Int        @id @default(autoincrement())
  title      String
  categories Category[] @relation("CategoryPostRelation")
}

model Category {
  id    Int    @id @default(autoincrement())
  name  String
  posts Post[] @relation("CategoryPostRelation")
}
```

## Using m-n relations in databases with enforced primary keys [#using-m-n-relations-in-databases-with-enforced-primary-keys]

### Problem [#problem-1]

Some cloud providers enforce the existence of primary keys in all tables. However, any relation tables (JOIN tables) created by Prisma ORM (expressed via `@relation`) for many-to-many relations using implicit syntax do not have primary keys.

### Solution [#solution-1]

You need to use [explicit relation syntax](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations#explicit-many-to-many-relations), manually create the join model, and verify that this join model has a primary key.

## Related pages

- [`Many-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations): How to define and work with many-to-many relations in Prisma.
- [`One-to-many relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-many-relations): How to define and work with one-to-many relations in Prisma.
- [`One-to-one relations`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/one-to-one-relations): How to define and work with one-to-one relations in Prisma.
- [`Referential actions`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions): Referential actions let you define the update and delete behavior of related models on the database level
- [`Relation mode`](https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode): Manage relations between records with relation modes in Prisma

