Deployment

Bun workspaces

Learn step-by-step how to integrate Prisma ORM in a Bun workspaces monorepo to build scalable and modular applications efficiently

Introduction

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.

Prerequisites

1. Set up project

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:

package.json
{
  "name": "my-monorepo", 
  "workspaces": ["apps/*", "packages/*"] 
}

Finally, create directories for your applications and shared packages:

mkdir apps
mkdir -p packages/database

2. Set up database package

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.

2.1. Install dependencies

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

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.

2.2. Set up Prisma ORM and schema

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.

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:

  • Connects your CLI to your Prisma Data Platform account. If you're not logged in or don't have an account, your browser will open to guide you through creating a new account or signing into your existing one.
  • Creates a prisma directory containing a schema.prisma file for your database models.
  • Creates a prisma.config.ts file (which uses process.env["DATABASE_URL"] and expects dotenv).
  • Creates a .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":

prisma/schema.prisma
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { 
  id    Int     @id @default(autoincrement()) 
  email String  @unique
  name  String?
} 

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

database/package.json
{
  "scripts": { 
    "db:generate": "prisma generate", 
    "db:migrate": "prisma migrate dev", 
    "db:deploy": "prisma migrate deploy", 
    "db:seed": "prisma db seed", 
    "db:studio": "prisma studio"
  } 
}

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:

database/client.ts
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:

database/index.ts
export { prisma } from "./client";
export * from "./generated/prisma/client";

2.3. Seed the database

Add a seed script to populate the database with sample users. Create prisma/seed.ts in the database package:

database/prisma/seed.ts
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: "alice@example.com", name: "Alice" },
      { email: "bob@example.com", name: "Bob" },
      { email: "charlie@example.com", 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):

database/prisma.config.ts
  migrations: {
    path: "prisma/migrations",
    seed: "bun prisma/seed.ts", 
  },

At this point, your shared database package is fully configured and ready for use across your monorepo.

2.4. Add root scripts

Add the following scripts to the root package.json of your monorepo. They let you run database and app commands from the root:

package.json
"scripts": { 
  "build": "bun run --filter database db:deploy && bun run --filter database db:generate && bun run --filter web build", 
  "start": "bun run --filter web start", 
  "dev": "bun run --filter database db:generate && bun run --filter web dev", 
  "seed": "bun run --filter database db:seed", 
  "studio": "bun run --filter database db:studio"
} 

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.

3. Set up Next.js app

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.

3.1. Create Next.js app

Navigate to the apps directory:

cd ../../apps

Create a new Next.js app named web:

bun create next-app@latest web --yes

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:

web/package.json
"dependencies": {
  "database": "workspace:*"
}

Run the following command to install the database package:

bun install

3.2. Add database to app

Modify your Next.js application code to use the Prisma ORM client from the database package. Update app/page.tsx as follows:

app/page.tsx
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.

3.3. Run the app

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.

Next steps

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.

On this page