Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 105 additions & 86 deletions apps/docs/content/docs/guides/deployment/turborepo.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ metaTitle: How to use Prisma ORM and Prisma Postgres with Turborepo
metaDescription: 'Learn step-by-step how to integrate Prisma ORM with Turborepo to build modular, scalable monorepo architectures efficiently.'
---

Prisma is a powerful ORM for managing databases, and [Turborepo](https://turbo.build/) simplifies monorepo workflows. By combining these tools, you can create a scalable, modular architecture for your projects.
Prisma is a powerful ORM for managing databases, and [Turborepo](https://turborepo.dev/docs) simplifies monorepo workflows. By combining these tools, you can create a scalable, modular architecture for your projects.

This guide will show you how to set up Prisma as a standalone package in a Turborepo monorepo, enabling efficient configuration, type sharing, and database management across multiple apps.

Expand All @@ -19,7 +19,8 @@ This guide will show you how to set up Prisma as a standalone package in a Turbo

### Prerequisites

- [Node.js 20+](https://nodejs.org/)
- [Node.js 20.19.0+](https://nodejs.org/)
- [TypeScript 5.4.0+](https://www.typescriptlang.org/)

## 1. Set up your project

Expand All @@ -37,29 +38,24 @@ You'll be prompted to select your package manager, this guide will use `npm`:

:::

After the setup, choose a package manager for the project. Navigate to the project root directory and install Turborepo as a development dependency:
After the setup, navigate to the project root directory:

```npm
```bash
cd turborepo-prisma
npm install turbo --save-dev
```

For more information about installing Turborepo, refer to the [official Turborepo guide](https://turbo.build/repo/docs/getting-started/installation).

## 2. Add a new `database` package to the monorepo

### 2.1 Create the package and install Prisma

Create a `database` package within the `packages` directory. Then, create a `package.json` file for the package by running:
Create a `database` directory inside `packages` and navigate into it:

```bash
cd packages/
mkdir database
cd database
touch package.json
mkdir -p packages/database
cd packages/database
```

Define the `package.json` file as follows:
Then initialize it with a `package.json`:

```json title="packages/database/package.json"
{
Expand All @@ -68,11 +64,11 @@ Define the `package.json` file as follows:
}
```

Next, install the required dependencies to use Prisma ORM. Use your preferred package manager:
Then install the required Prisma ORM dependencies:

```npm
npm install prisma @types/pg --save-dev
npm install @prisma/client @prisma/adapter-pg dotenv pg
npm install prisma --save-dev
npm install @prisma/client @prisma/adapter-pg pg dotenv
```

:::info
Expand All @@ -83,19 +79,20 @@ If you are using a different database provider (MySQL, SQL Server, SQLite), inst

### 2.2. Initialize Prisma and define models

Inside the `database` directory, initialize prisma by running:
Inside the `database` directory, initialize Prisma by running:

```npm
npx prisma init --db --output ../generated/prisma
npx prisma init --db
```

You'll be prompted to authenticate in Prisma Console, choose a project name, and pick a region for your Prisma Postgres database.

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 `prisma.config.ts` file for configuring Prisma.
- A Prisma Postgres database.
- A `.env` file containing the `DATABASE_URL` at the project root.
- An `output` directory for the generated Prisma Client as `generated/prisma`.
- A `.env` file containing the `DATABASE_URL` in the `packages/database` directory.

In the `packages/database/prisma/schema.prisma` file, add the following models:

Expand Down Expand Up @@ -145,7 +142,7 @@ export default defineConfig({

:::warning

It is recommended to add `../generated/prisma` to the `.gitignore` file because it contains platform-specific binaries that can cause compatibility issues across different environments.
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`.

:::

Expand All @@ -167,17 +164,21 @@ Let's add some scripts to the `package.json` inside `packages/database`:
{
"name": "@repo/db",
"version": "0.0.0",
"type": "module", // [!code ++]
"scripts": {
// [!code ++]
"db:generate": "prisma generate", // [!code ++]
"db:migrate": "prisma migrate dev --skip-generate", // [!code ++]
"db:migrate": "prisma migrate dev", // [!code ++]
"db:deploy": "prisma migrate deploy" // [!code ++]
}, // [!code ++]
"devDependencies": {
"prisma": "^6.6.0"
"prisma": "^7.0.0"
},
"dependencies": {
"@prisma/client": "^6.6.0"
"@prisma/client": "^7.0.0",
"@prisma/adapter-pg": "^7.0.0",
"pg": "^8.0.0",
"dotenv": "^16.0.0"
}
}
```
Expand All @@ -186,57 +187,57 @@ Let's also add these scripts to `turbo.json` in the root and ensure that `DATABA

```json title="turbo.json"
{
"$schema": "https://turbo.build/schema.json",
"ui": "tui",
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": [".next/**", "!.next/cache/**"],
"env": ["DATABASE_URL"] // [!code ++]
},
"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 ++]
"persistent": true // This is necessary to interact with the CLI and assign names to your database migrations. // [!code ++]
}, // [!code ++]
"db:deploy": { // [!code ++]
"cache": false // [!code ++]
} // [!code ++]
"$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 ++]
}
}
```

Migrate your `prisma.schema` and generate types
Run your first migration and generate Prisma Client

Navigate to the project root and run the following command to automatically migrate our database:
Navigate to the project root and run the following command to create and apply your first migration:

```npm
npx turbo db:migrate
npx turbo run db:migrate -- --name init
```

Generate your `schema.prisma`

To generate the types from Prisma schema, from the project root run:
In Prisma 7, `migrate dev` no longer runs `prisma generate` automatically, so run generate explicitly:

```npm
npx turbo db:generate
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

Next, export the generated types and an instance of `PrismaClient` so it can used in your applications.
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`:

Expand All @@ -248,7 +249,7 @@ const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
});

const globalForPrisma = global as unknown as { prisma: PrismaClient };
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };

export const prisma =
globalForPrisma.prisma ||
Expand All @@ -266,28 +267,32 @@ 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://turbo.build/repo/docs/core-concepts/internal-packages#just-in-time-packages) and create an entrypoint to the package inside `packages/database/package.json`:
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.com/docs/core-concepts/internal-packages#compiled-packages) strategy instead.
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": "npx prisma generate",
"db:migrate": "npx prisma migrate dev --skip-generate",
"db:deploy": "npx prisma migrate deploy"
"db:generate": "prisma generate",
"db:migrate": "prisma migrate dev",
"db:deploy": "prisma migrate deploy"
},
"devDependencies": {
"prisma": "^6.6.0"
"prisma": "^7.0.0"
},
"dependencies": {
"@prisma/client": "^6.6.0"
"@prisma/client": "^7.0.0",
"@prisma/adapter-pg": "^7.0.0",
"pg": "^8.0.0",
"dotenv": "^16.0.0"
},
"exports": {
// [!code ++]
Expand All @@ -302,7 +307,7 @@ By completing these steps, you'll make the Prisma types and `PrismaClient` insta

The `turborepo-prisma` project should have an app called `web` at `apps/web`. Add the `database` dependency to `apps/web/package.json`:

```json
```json tab="npm"
{
// ...
"dependencies": {
Expand All @@ -313,16 +318,31 @@ The `turborepo-prisma` project should have an app called `web` at `apps/web`. Ad
}
```

:::note

If you're using pnpm, use `"@repo/db": "workspace:*"` instead.
```json tab="pnpm"
{
// ...
"dependencies": {
"@repo/db": "workspace:*" // [!code ++]
// ...
}
// ...
}
```

:::
```json tab="bun"
{
// ...
"dependencies": {
"@repo/db": "workspace:*" // [!code ++]
// ...
}
// ...
}
```

Run your package manager's install command inside the `apps/web` directory:
Run your package manager's install command from the project root to link the workspace dependency:

```npm
cd apps/web
npm install
```

Expand Down Expand Up @@ -352,28 +372,28 @@ If you want to use a single `.env` file in the root directory across your apps a

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

Keep in mind that Turborepo [recommends using separate `.env` files for each package](https://turbo.build/repo/docs/crafting-your-repository/using-environment-variables#use-env-files-in-packages) to promote modularity and avoid potential conflicts.
Keep in mind that 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

The `db:generate` and `db:deploy` scripts are not yet optimized for the monorepo setup but are essential for the `dev` and `build` tasks.
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`. Additionally, make sure both `db:deploy` and `db:generate` are executed before `db:build`. Here's how to configure this in your `turbo.json` file:
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://turbo.build/schema.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/**"],
"env": ["DATABASE_URL"] // [!code ++]
"outputs": [".next/**", "!.next/cache/**"]
},
"lint": {
"dependsOn": ["^lint"]
Expand All @@ -390,8 +410,7 @@ To prevent this, ensure that `db:generate` is always executed before running `de
"cache": false
},
"db:migrate": {
"cache": false,
"persistent": true
"cache": false
},
"db:deploy": {
"cache": false
Expand Down Expand Up @@ -438,6 +457,6 @@ Congratulations, you're done setting up Prisma for Turborepo!

### More Info

- [Turborepo Docs](https://turbo.build/repo/docs)
- [Turborepo Docs](https://turborepo.dev/docs)
- [Next.js Docs](https://nextjs.org/docs)
- [Prisma ORM Docs](/orm)
Loading