Turborepo
This guide shows you how to set up Prisma ORM as a standalone package in a Turborepo monorepo, so that multiple apps share one Prisma Client, one set of generated types, and one migration workflow.
- 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.
To set up a Turborepo monorepo named turborepo-prisma, run the following command:
bunx create-turbo@latest turborepo-prismapnpm dlx create-turbo@latest turborepo-prismayarn dlx create-turbo@latest turborepo-prismanpx create-turbo@latest turborepo-prismaYou'll be prompted to select your package manager, this guide will use npm:
After the setup, navigate to the project root directory:
cd turborepo-prisma2. Add a new database package to the monorepo
Section titled “2. Add a new database package to the monorepo”Create a database directory inside packages and navigate into it:
mkdir -p packages/database
cd packages/databaseThen initialize it with a package.json:
{
"name": "@repo/db",
"version": "0.0.0"
}Then install the required Prisma ORM dependencies:
bun add prisma@prev --dev
bun add @prisma/client@7 @prisma/adapter-pg pg dotenvpnpm add prisma@prev --save-dev
pnpm add @prisma/client@7 @prisma/adapter-pg pg dotenvyarn add prisma@prev --dev
yarn add @prisma/client@7 @prisma/adapter-pg pg dotenvnpm 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.
Inside the database directory, initialize Prisma by running:
bunx --bun prisma initpnpm prisma inityarn prisma initnpx prisma initThis will create several files inside packages/database:
- A
prismadirectory with aschema.prismafile. - A
prisma.config.tsfile for configuring Prisma. - A
.envfile containing a localDATABASE_URLin thepackages/databasedirectory.
Create a Prisma Postgres database and replace the generated DATABASE_URL in your .env file with the postgres://... connection string from the CLI output:
npx create-dbIn the packages/database/prisma/schema.prisma file, add the following models:
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)
authorId Int
author User @relation(fields: [authorId], references: [id])
} The prisma.config.ts file created in the packages/database directory should look like this:
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"),
},
});The importance of generating Prisma types in a custom directory
Section titled “The importance of generating Prisma types in a custom directory”In the schema.prisma file, we specify a custom output path where Prisma will generate its types. This ensures Prisma's types are resolved correctly across different package managers.
Add the following scripts to the package.json inside packages/database:
{
"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"
}
}Also add these scripts to turbo.json in the root and ensure that DATABASE_URL is added to the environment:
{
"$schema": "https://turborepo.dev/schema.json",
"ui": "tui",
"globalEnv": ["DATABASE_URL"],
"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": {
"cache": false
},
"db:migrate": {
"cache": false
},
"db:deploy": {
"cache": false
}
}
}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:
bunx turbo run db:migrate -- --name initpnpm dlx turbo run db:migrate -- --name inityarn dlx turbo run db:migrate -- --name initnpx turbo run db:migrate -- --name initIn Prisma 7, migrate dev no longer runs prisma generate automatically, so run generate explicitly:
bunx turbo run db:generatepnpm dlx turbo run db:generateyarn dlx turbo run db:generatenpx turbo run db:generateUse the same npx turbo run db:generate command after future schema changes.
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:
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:
export { prisma } from "./client"; // exports instance of prisma
export * from "../generated/prisma/client"; // exports generated types from prismaFollow the Just-in-Time packaging pattern and create an entrypoint to the package inside 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": {
".": "./src/index.ts"
}
}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
Section titled “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:
{
// ...
"dependencies": {
"@repo/db": "*"
// ...
}
// ...
}{ // ... "dependencies": { "@repo/db": "workspace:*" // ... } // ...}bunx create-turbo@latest turborepo-prismaRun your package manager's install command from the project root to link the workspace dependency:
bun installpnpm installyarn install{ // ... "dependencies": { "@repo/db": "*" // ... } // ...}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:
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:
DATABASE_URL="Same database URL as used in the database directory"4. Configure task dependencies in Turborepo
Section titled “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:
{
"$schema": "https://turborepo.dev/schema.json",
"ui": "tui",
"globalEnv": ["DATABASE_URL"],
"tasks": {
"build": {
"dependsOn": ["^build", "^db:generate"],
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": [".next/**", "!.next/cache/**"]
},
"lint": {
"dependsOn": ["^lint"]
},
"check-types": {
"dependsOn": ["^check-types"]
},
"dev": {
"dependsOn": ["^db:generate"],
"cache": false,
"persistent": true
},
"db:generate": {
"cache": false
},
"db:migrate": {
"cache": false
},
"db:deploy": {
"cache": false
}
}
}Then from the project root run the project:
bunx turbo run dev --filter=webpnpm dlx turbo run dev --filter=webyarn dlx turbo run dev --filter=webnpm installImport 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:
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:
DATABASE_URL="Same database URL as used in the database directory"[!NOTE] If you want to use a single
.envfile in the root directory across your apps and packages in a Turborepo setup, consider using a package likedotenvx.To implement this, update the
package.jsonfiles for each package or app to ensure they load the required environment variables from the shared.envfile. For detailed instructions, refer to thedotenvxguide for Turborepo.Turborepo recommends using separate
.envfiles for each package to promote modularity and avoid potential conflicts.
Navigate to the http://localhost:3000 and you should see the message:
No user added yetPrisma ORM is now set up as a shared package in your Turborepo.
- Expand your Prisma models to handle more complex data relationships.
- Implement additional CRUD operations.
- Check out Prisma Postgres to see how you can scale your application.