apps/docs/content/docs/guides/deployment/bun-workspaces.mdx
This guide shows you how to use Prisma ORM in a Bun Workspaces monorepo. You'll set up a shared database package with Prisma ORM, then integrate it into a Next.js app in the same workspace.
Before integrating Prisma ORM, you need to set up your project structure. Start by creating a new directory for your project (for example, my-monorepo) and initialize a Node.js project:
mkdir my-monorepo
cd my-monorepo
bun init -y
Next, add the workspaces array to your root package.json to define your workspace structure:
{
"name": "my-monorepo", // [!code ++]
"workspaces": ["apps/*", "packages/*"] // [!code ++]
}
Finally, create directories for your applications and shared packages:
mkdir apps
mkdir -p packages/database
This section covers creating a standalone database package that uses Prisma ORM. The package will house all database models and the generated Prisma ORM client, making it reusable across your monorepo.
Navigate to the packages/database directory and initialize a new package:
cd packages/database
bun init
Install the required Prisma ORM packages and other dependencies:
bun add -d prisma typescript tsx @types/node @types/pg
bun add @prisma/client @prisma/adapter-pg pg
:::info
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.
:::
Initialize Prisma ORM with an instance of Prisma Postgres in the database package by running the following command:
bunx prisma init --db
Enter a name for your project and choose a database region.
:::info
We're going to be using Prisma Postgres in this guide. If you're not using a Prisma Postgres database, you won't need to add the --db flag.
:::
This command:
prisma directory containing a schema.prisma file for your database models.prisma.config.ts file (which uses process.env["DATABASE_URL"] and expects dotenv)..env file with your DATABASE_URL (e.g., for Prisma Postgres it should have something similar to DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/?api_key=eyJhbGciOiJIUzI...").Edit the schema.prisma file to add a User model. The default generator already sets output = "../generated/prisma":
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
datasource db {
provider = "postgresql"
}
model User { // [!code ++]
id Int @id @default(autoincrement()) // [!code ++]
email String @unique // [!code ++]
name String? // [!code ++]
} // [!code ++]
If the generated prisma.config.ts comments mention installing dotenv, install it so environment variables load:
bun add dotenv
Add a scripts section to your database package.json (Bun init may not add one by default):
{
"scripts": { // [!code ++]
"db:generate": "prisma generate", // [!code ++]
"db:migrate": "prisma migrate dev", // [!code ++]
"db:deploy": "prisma migrate deploy", // [!code ++]
"db:seed": "prisma db seed", // [!code ++]
"db:studio": "prisma studio" // [!code ++]
} // [!code ++]
}
Use Prisma Migrate to migrate your database changes:
bun run db:migrate
When prompted by the CLI, enter a descriptive name for your migration. After the migration completes, run generate so the Prisma ORM client is created:
bun run db:generate
Create a client.ts file to initialize the Prisma ORM client with a driver adapter:
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
});
// Use globalThis for broader environment compatibility
const globalForPrisma = globalThis as typeof globalThis & {
prisma?: PrismaClient;
};
export const prisma: PrismaClient =
globalForPrisma.prisma ??
new PrismaClient({
adapter,
});
if (process.env.NODE_ENV !== "production") {
globalForPrisma.prisma = prisma;
}
Then, create an index.ts file to re-export the instance of the Prisma ORM client and all generated types:
export { prisma } from "./client";
export * from "./generated/prisma/client";
Add a seed script to populate the database with sample users. Create prisma/seed.ts in the database package:
import "dotenv/config";
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL!,
});
const prisma = new PrismaClient({ adapter });
async function main() {
await prisma.user.createMany({
data: [
{ email: "[email protected]", name: "Alice" },
{ email: "[email protected]", name: "Bob" },
{ email: "[email protected]", name: "Charlie" },
],
skipDuplicates: true,
});
console.log("Seed complete.");
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
Add the seed option to the existing migrations config in your database package's prisma.config.ts (add the seed line inside migrations):
migrations: {
path: "prisma/migrations",
seed: "bun prisma/seed.ts", // [!code ++]
},
At this point, your shared database package is fully configured and ready for use across your monorepo.
Add the following scripts to the root package.json of your monorepo. They let you run database and app commands from the root:
"scripts": { // [!code ++]
"build": "bun run --filter database db:deploy && bun run --filter database db:generate && bun run --filter web build", // [!code ++]
"start": "bun run --filter web start", // [!code ++]
"dev": "bun run --filter database db:generate && bun run --filter web dev", // [!code ++]
"seed": "bun run --filter database db:seed", // [!code ++]
"studio": "bun run --filter database db:studio" // [!code ++]
} // [!code ++]
From the monorepo root, run bun run seed to add sample users. Run bun run studio to open Prisma Studio at http://localhost:5555 to view and edit your data.
Now that the database package is set up, create a frontend application (using Next.js) that uses the shared Prisma ORM client to interact with your database.
Navigate to the apps directory:
cd ../../apps
Create a new Next.js app named web:
bun create next-app@latest web --yes
:::note[important]
The --yes flag uses default configurations to bootstrap the Next.js app (which in this guide uses the app router without a src/ directory). When prompted for a package manager, choose Bun so the app uses Bun within the workspace.
Additionally, the flag may automatically initialize a Git repository in the web folder. If that happens, please remove the .git directory by running rm -r .git.
:::
Then, navigate into the web directory:
cd web/
Copy the .env file from the database package to ensure the same environment variables are available:
cp ../../packages/database/.env .
Open the package.json file of your Next.js app and add the shared database package as a dependency:
"dependencies": {
"database": "workspace:*" // [!code ++]
}
Run the following command to install the database package:
bun install
Modify your Next.js application code to use the Prisma ORM client from the database package. Update app/page.tsx as follows:
import { prisma } from "database";
export default async function Home() {
const user = await prisma.user.findFirst({
select: {
name: true,
},
});
return (
<div>
{user?.name && <p>Hello from {user.name}</p>}
{!user?.name && <p>No user has been added to the database yet.</p>}
</div>
);
}
This code demonstrates importing and using the shared Prisma ORM client to query your User model.
Then head back to the root of the monorepo:
cd ../../
Start your development server by executing:
bun run dev
Open your browser at http://localhost:3000 to see your app in action. You can run bun run studio to open Prisma Studio at http://localhost:5555 to view and edit your data.
You have now created a monorepo that uses Prisma ORM, with a shared database package integrated into a Next.js application.
For further exploration and to enhance your setup, consider reading the How to use Prisma ORM with Turborepo guide.