DEV Community

Cover image for How to use Prisma with Bun
Aidan McAlister
Aidan McAlister

Posted on

How to use Prisma with Bun

Bun is a fast JavaScript runtime that's been making waves in the developer community. It includes a bundler, test runner, and package manager all in one. In this tutorial, we'll explore how to integrate Prisma ORM with Prisma Postgres in Bun to build a simple HTTP server.

The workflow is straightforward: set up Prisma with a Prisma Postgres database, create a simple data model, and build an HTTP server that queries your database. We'll even compile it into a single executable file for deployment.

What We'll Build

In this tutorial, we'll create a simple user management system with:

  • Type-safe database queries using Prisma
  • A basic HTTP server with Bun
  • Seed data for development
  • A compiled executable for production deployment

Quick Setup

1. Create your project

mkdir bun-prisma
cd bun-prisma
bun init -y
Enter fullscreen mode Exit fullscreen mode

This creates a basic Bun project with a package.json and index.ts file.

2. Install dependencies

bun add -d prisma
bun add @prisma/client
Enter fullscreen mode Exit fullscreen mode

3. Initialize database

bun prisma init --db
Enter fullscreen mode Exit fullscreen mode

This command does several things:

  • -db: Automatically configures Prisma Postgres for you
  • Creates a prisma/ directory with your schema.prisma file
  • Generates a new Prisma Postgres database
  • Creates a prisma.config.ts file
  • Sets up a .env file with your DATABASE_URL

You'll need to answer a few questions while setting up your Prisma Postgres database. Select the region closest to your location and a memorable name like "My Bun Project".

4. Configure direct connection

We're going to use a direct connection string for connecting to Prisma Postgres. To get your direct connection string:

  1. Navigate to your recently created Prisma Postgres project dashboard
  2. Click the API Keys tab in the project's sidebar
  3. Click Create API key
  4. Provide a name and click Create
  5. Copy the connection string starting with postgres://

Update your .env file to replace the DATABASE_URL:

DATABASE_URL="your_direct_connection_string_here"
Enter fullscreen mode Exit fullscreen mode

5. Define your data model

Open prisma/schema.prisma and update it to include a simple User model:

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?
}
Enter fullscreen mode Exit fullscreen mode

You can learn more about the Prisma schema in the official documentation.

Setting Up Database Utilities

6. Create a database utility file

Create a db.ts file in your project root to configure PrismaClient:

import { PrismaClient } from "./generated/prisma/client";

export const prisma = new PrismaClient();
Enter fullscreen mode Exit fullscreen mode

This centralizes your Prisma Client instance so you can import it anywhere in your application.

7. Create a seed script

During development, it's helpful to have test data. Create prisma/seed.ts:

import { PrismaClient } from "../generated/prisma/client";

const prisma = new PrismaClient();

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" },
      { email: "diana@example.com", name: "Diana" },
      { email: "eve@example.com", name: "Eve" },
      { email: "frank@example.com", name: "Frank" },
      { email: "grace@example.com", name: "Grace" },
      { email: "henry@example.com", name: "Henry" },
      { email: "isabella@example.com", name: "Isabella" },
      { email: "jack@example.com", name: "Jack" },
    ],
    skipDuplicates: true,
  });

  console.log("Seed data inserted!");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
Enter fullscreen mode Exit fullscreen mode

8. Add the seed script to Prisma config

Update prisma.config.ts to include the seed command:

import { defineConfig, env } from 'prisma/config';

export default defineConfig({
  schema: 'prisma/schema.prisma',
  migrations: {
    path: 'prisma/migrations',
    seed: `bun run prisma/seed.ts`
  },
  engine: 'classic',
  datasource: {
    url: env('DATABASE_URL'),
  },
});
Enter fullscreen mode Exit fullscreen mode

Generate Client and Run Migrations

9. Push schema to database

Now we need to migrate the schema to the actual database and generate the Prisma Client:

bunx --bun prisma migrate dev --name init
Enter fullscreen mode Exit fullscreen mode

This command will:

  • Create the database tables based on your schema
  • Generate the Prisma Client in the generated/prisma directory

10. Seed the Database

Run the seed script to populate your database:

bunx --bun prisma db seed
Enter fullscreen mode Exit fullscreen mode

Building Your Bun Server

11. create the HTTP server

Replace the contents of index.ts with the following code:

import { prisma } from './db'

const server = Bun.serve({
  port: 3000,
  async fetch(req) {
    const { pathname } = new URL(req.url)

    // Skip favicon route
    if (pathname === '/favicon.ico') {
      return new Response(null, { status: 204 })
    }

    // Return all users
    const users = await prisma.user.findMany()

    // Count all users
    const count = await prisma.user.count()

    // Format the response with JSON
    return new Response(
      JSON.stringify({
        users: users,
        totalUsers: count,
      }),
      { headers: { 'Content-Type': 'application/json' } },
    )
  },
})

console.log(`Listening on http://localhost:${server.port}`)
Enter fullscreen mode Exit fullscreen mode

This creates a simple HTTP server that fetches all users from the database and returns them as JSON along with the total count.

Running your application

Start your Bun server:

bun run index.ts
Enter fullscreen mode Exit fullscreen mode

You should see Listening on http://localhost:3000 in the console. Visit http://localhost:3000 in your browser to see a JSON response with all the users in your database.

Building a Production Executable

One of Bun's coolest features is the ability to compile your TypeScript application into a single executable file. This is incredibly useful for deployment and distribution.

12. Build the Executable

bun build --compile index.ts
Enter fullscreen mode Exit fullscreen mode

This creates an executable file named index (or index.exe on Windows) in your project directory.

13. Run the executable

./index
Enter fullscreen mode Exit fullscreen mode

You should see the same Listening on http://localhost:3000 message, and your application will work exactly the same as before. The executable includes all dependencies and can be deployed to any compatible system without requiring Bun or Node.js to be installed.

Why use Bun executables?

  • Deployment: Ship a single file instead of managing dependencies
  • Distribution: Share your application without requiring users to install Bun
  • Performance: Faster startup times compared to running TypeScript files
  • Security: Your source code is compiled and not easily readable

Key advantages of this approach

Fast Runtime: Bun is significantly faster than Node.js for many operations, including server startup and package installation.

Type Safety: Prisma provides full type safety for your database queries, catching errors at compile time rather than runtime.

Simple Deployment: The compiled executable makes deployment straightforward - just copy one file to your server.

All-in-One Tooling: Bun includes everything you need (bundler, test runner, package manager) without additional dependencies.

Top comments (0)