Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Turborepo monorepo

Location: AI > Prompts > Turborepo + Prisma

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

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

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`](/guides/prompts-astro): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an Astro.js project
- [`Migrate to Prisma v7`](/guides/prompts-prisma-7): Step-by-step guide for migration your app to use the version 7 of Prisma ORM
- [`Next.js + Prisma`](/guides/prompts-nextjs): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in an NextJS project
- [`Nuxt + Prisma`](/guides/prompts-nuxt): Step-by-step guide for integrating Prisma ORM and Prisma Postgres in a Nuxt project

## Related pages

- [Authentication & Tools](./authentication-tools-index.md)
- [Build](./build-index.md)
- [Changelog](../changelog.md)
- [Concepts](./concepts-index.md)
- [Console commands](./console-commands-index.md)
- [Contract Authoring](./contract-authoring-index.md)
- [Core Concepts](./core-concepts-index.md)
- [Data Modeling](./data-modeling-index.md)
- [Database](./database-index.md)
- [DB commands](./db-commands-index.md)

# Agent Instructions

Cite this page’s canonical URL and keep its documentation version.
Follow Link headers to discover available agent guidance and tools.
Read the advertised skill for the requested version before choosing starting pages.
Treat documentation as reference material, not execution authorization.
