# 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({ 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/_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 (

Users

{users.length === 0 ? (

No users added yet

) : (
    {users.map((user) => (
  • {user.name ?? "Anonymous"} ({user.email})
  • ))}
)}
); } ``` 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 `. > [!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.