How to use Prisma ORM with Turborepo
Prisma is a powerful ORM for managing databases, and Turborepo 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.
What you'll 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
1. Set up your project
To set up a Turborepo monorepo named turborepo-prisma, run the following command:
npx create-turbo@latest turborepo-prisma
You'll be prompted to select your package manager, this guide will use npm:
- Which package manager do you want to 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:
- npm
- yarn
- pnpm
cd turborepo-prisma
npm install turbo --save-dev
cd turborepo-prisma
yarn add turbo --dev --ignore-workspace-root-check
cd turborepo-prisma
pnpm add turbo --save-dev --ignore-workspace-root-check
For more information about installing Turborepo, refer to the official Turborepo guide.
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:
cd packages/
mkdir database
cd database
touch package.json
Define the package.json file as follows:
{
"name": "@repo/db",
"version": "0.0.0"
}
Next, install the required dependencies to use Prisma ORM. Use your preferred package manager:
- npm
- yarn
- pnpm
npm install prisma --save-dev
npm install @prisma/client
yarn add prisma --dev
yarn add @prisma/client
pnpm add prisma --save-dev
pnpm add @prisma/client
If using Prisma Postgres, install the @prisma/extension-accelerate package:
- npm
- yarn
- pnpm
npm install @prisma/extension-accelerate
yarn add @prisma/extension-accelerate
pnpm add @prisma/extension-accelerate
2.2. Initialize Prisma and define models
Inside the database directory, initialize prisma by running:
- npm
- yarn
- pnpm
npx prisma init --db --output ../generated/prisma
yarn prisma init --db --output ../generated/prisma
pnpm prisma init --db --output ../generated/prisma
This will create several files inside packages/database:
- A
prismadirectory with aschema.prismafile. - A
prisma.config.tsfile for configuring Prisma - A Prisma Postgres database.
- A
.envfile containing theDATABASE_URLat the project root. - An
outputdirectory for the generated Prisma Client asgenerated/prisma.
In the packages/database/prisma/schema.prisma file, add the following models:
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
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])
}
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.
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.
In this guide, the types will be generated in the database/generated/prisma directory.
2.3. Add scripts and run migrations
Let's add some scripts to the package.json inside packages/database:
{
"name": "@repo/db",
"version": "0.0.0",
"scripts": {
"db:generate": "prisma generate",
"db:migrate": "prisma migrate dev --skip-generate",
"db:deploy": "prisma migrate deploy"
},
"devDependencies": {
"prisma": "^6.6.0"
},
"dependencies": {
"@prisma/client": "^6.6.0"
}
}
Let's also add these scripts to turbo.json in the root and ensure that DATABASE_URL is added to the environment:
{
"$schema": "https://turbo.build/schema.json",
"ui": "tui",
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": [".next/**", "!.next/cache/**"],
"env": ["DATABASE_URL"]
},
"lint": {
"dependsOn": ["^lint"]
},
"check-types": {
"dependsOn": ["^check-types"]
},
"dev": {
"cache": false,
"persistent": true
},
"db:generate": {
"cache": false
},
"db:migrate": {
"cache": false,
"persistent": true // This is necessary to interact with the CLI and assign names to your database migrations.
},
"db:deploy": {
"cache": false
}
}
Migrate your prisma.schema and generate types
Navigate to the project root and run the following command to automatically migrate our database:
- npm
- yarn
- pnpm
npx turbo db:migrate
yarn turbo db:migrate
pnpm turbo db:migrate
Generate your prisma.schema
To generate the types from Prisma schema, from the project root run:
- npm
- yarn
- pnpm
npx turbo db:generate
yarn turbo db:generate
pnpm turbo db:generate
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.
In the packages/database directory, create a src folder and add a client.ts file. This file will define an instance of PrismaClient:
- Prisma Postgres (recommended)
- Other databases
import { PrismaClient } from "../generated/prisma";
import { withAccelerate } from "@prisma/extension-accelerate";
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma =
globalForPrisma.prisma || new PrismaClient().$extends(withAccelerate());
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
import { PrismaClient } from "../generated/prisma";
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma =
globalForPrisma.prisma || new PrismaClient();
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" // exports generated types from prisma
Follow the Just-in-Time packaging pattern and create an entrypoint to the package inside packages/database/package.json:
If you're not using a bundler, use the Compiled Packages strategy instead.
{
"name": "@repo/db",
"version": "0.0.0",
"scripts": {
"db:generate": "npx prisma generate",
"db:migrate": "npx prisma migrate dev --skip-generate",
"db:deploy": "npx prisma migrate deploy"
},
"devDependencies": {
"prisma": "^6.6.0"
},
"dependencies": {
"@prisma/client": "^6.6.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
The turborepo-prisma project should have an app called web at apps/web. Add the database dependency to apps/web/package.json:
- npm
- yarn
- pnpm
{
// ...
"dependencies": {
"@repo/db": "*"
// ...
}
// ...
}
{
// ...
"dependencies": {
"@repo/db": "*"
// ...
}
// ...
}
{
// ...
"dependencies": {
"@repo/db": "workspace:*"
// ...
}
// ...
}
Run your package manager's install command inside the apps/web directory:
- npm
- yarn
- pnpm
cd apps/web
npm install
cd apps/web
yarn install
cd apps/web
pnpm install
Let's import the intantiated 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"
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.
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.
Keep in mind that Turborepo recommends using separate .env files for each package 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.
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:
{
"$schema": "https://turbo.build/schema.json",
"ui": "tui",
"tasks": {
"build": {
"dependsOn": ["^build", "^db:generate"],
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": [".next/**", "!.next/cache/**"],
"env": ["DATABASE_URL"]
},
"lint": {
"dependsOn": ["^lint"]
},
"check-types": {
"dependsOn": ["^check-types"]
},
"dev": {
"dependsOn": ["^db:generate"],
"cache": false,
"persistent": true
},
"db:generate": {
"cache": false
},
"db:migrate": {
"cache": false,
"persistent": true
},
"db:deploy": {
"cache": false
}
}
}
5. Run the project in development
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. Remove Turbopack from your dev script by updating your apps/web/package.json
"script":{
"dev": "next dev --port 3000",
}
Then from the project root run the project:
- npm
- yarn
- pnpm
npx turbo run dev --filter=web
yarn turbo run dev --filter=web
pnpm turbo run dev --filter=web
Navigate to the http://localhost:3000 and you should see the message:
No user added yet
You can add users to your database by creating a seed script or manually by using Prisma 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:
- npm
- yarn
- pnpm
npx prisma studio
yarn prisma studio
pnpm prisma studio
This command starts a server with a GUI at http://localhost:5555, allowing you to view and modify your data.
Congratulations, you're done setting up Prisma for Turborepo!
Next Steps
- Expand your Prisma models to handle more complex data relationships.
- Implement additional CRUD operations to enhance your application's functionality.
- Check out Prisma Postgres to see how you can scale your application.
More Info
Stay connected with Prisma
Continue your Prisma journey by connecting with our active community. Stay informed, get involved, and collaborate with other developers:
- Follow us on X for announcements, live events and useful tips.
- Join our Discord to ask questions, talk to the community, and get active support through conversations.
- Subscribe on YouTube for tutorials, demos, and streams.
- Engage on GitHub by starring the repository, reporting issues, or contributing to an issue.