Skip to main content
Prisma Documentation Docs

Search documentation

Type to search this documentation.

On this pageOverview

Bun (/docs/guides/runtimes/bun)

For the complete Prisma documentation index, see llms.txt. A markdown version of any docs page is available by appending .md to its URL.

Scaffold a Prisma ORM app with Bun, run your first typed query, serve users over HTTP, and deploy to Prisma Compute.

Location: Guides > Runtimes > Bun

In this guide, you scaffold a Prisma ORM project with Bun, initialize a PostgreSQL database from your schema, run your first typed query, serve query results over HTTP with Bun.serve, and deploy the server to Prisma Compute. Bun runs TypeScript directly, so nothing has to be compiled to work locally; the deploy bundles the server with tsdown.

Every command and code sample below was run end to end against a live Prisma Postgres database.

  • Bun 1.1 or later (bun --version)
  • A PostgreSQL connection string, or nothing at all: bunx create-db can create a Prisma Postgres database for you

To delegate this guide to your coding agent, copy the prompt below and hand it over:

text
Create a new Bun app with Prisma ORM, run a first typed query, and deploy it to Prisma Compute.

1. Scaffold: `bun create prisma@latest my-bun-app --template minimal --provider postgres --package-manager bun --yes`. Then run `bunx prisma@latest init` in `my-bun-app` so the Prisma agent skills are installed and stay current, and use them. Get a database connection string: use the one I give you, or create a Prisma Postgres database with `bunx create-db` and show me the claim URL it prints. Export it as `DATABASE_URL` in the shell; the generated scripts read the environment variable, not `.env`.
2. In `my-bun-app`, run `bun run contract:emit`, then `bun run db:init`, with `DATABASE_URL` exported.
3. Replace `src/index.ts` with a script that creates a user and reads all users back via `db.orm.public.User`, following https://www.prisma.io/docs/guides/runtimes/bun.md, and verify `bun src/index.ts` prints the created user (`bun run dev` is `tsx watch`, which does not exit).
4. Add `src/server.ts` with a `Bun.serve` server exposing GET /users, and verify `curl http://localhost:3000/users` returns the users.
5. Deploy: check `bunx prisma@latest auth whoami`; if I am not signed in, stop and ask me to run `bunx prisma@latest auth login`. Then point the build at the server by setting `entry` in `tsdown.config.ts` to `{ server: "src/server.ts" }`, run `bun run build`, then `bunx prisma@latest deploy module.ts`, and verify the live URL's /users endpoint returns `[]`. The deployed app provisions its own fresh Prisma Postgres database, so the local users are not there; do not pass the local DATABASE_URL. If the deploy fails with `HostedStateBootstrapError`, a project with the module's name exists in my workspace but its hosted state cannot be verified; re-run the deploy with `--name <a unique name>`.

Use the installed Prisma ORM skills.

Create the project with create-prisma. Pick Bun as the package manager when prompted, or pass everything up front:

Bash
bun create prisma@latest my-bun-app --template minimal --provider postgres --package-manager bun --no-deploy

Answer the prompts for contract authoring style and agent skills. The scaffold sets up src/prisma/ with a starter schema and installs dependencies with Bun.

Bash
cd my-bun-app

Next, set the database connection for the local steps. Use your own PostgreSQL connection string, or create a Prisma Postgres database with bunx create-db; it prints a connection string and a claim URL you can open to keep the database. Export the variable in the shell you work in; the generated scripts read the environment variable, not .env:

Bash
export DATABASE_URL="<your connection string>"

2. Emit the contract and initialize the database

Section titled “2. Emit the contract and initialize the database”

Prisma ORM compiles your schema (src/prisma/contract.prisma) into a contract that your queries are type-checked against. If you chose TypeScript authoring (--authoring typescript), the source is src/prisma/contract.ts and the emitted files land in src/prisma/generated/ instead. Emit it, then apply the schema to the database:

Bash
bun run contract:emit
bun run db:init

db:init creates the tables and signs the database:

no-copy
"summary": "Applied 5 operation(s) across 1 space(s), database signed"

If db:init stops with Connection terminated unexpectedly, a database you just created is still starting; wait a few seconds and run it again. The command is safe to repeat and reports Applied 0 operation(s) when there is nothing left to do.

If db:init reports that the contract file is missing, run bun run contract:emit first; the emit step generates src/prisma/contract.json.

Replace src/index.ts with a script that creates a user and reads every user back. Model access is namespace-qualified on PostgreSQL: db.orm.public.User, where public is the default schema.

src/index.ts
import { db } from "./prisma/db";

// Create a user, then read every user back
const user = await db.orm.public.User.create({
  email: `ada+${Date.now()}@prisma.io`,
  name: "Ada Lovelace",
});
console.log(`created user ${user.email}`);

const users = await db.orm.public.User.select("id", "email", "name").all();
console.log(`there are now ${users.length} users`);

await db.close();

await db.close() at the end lets the script exit cleanly; without it, the connection pool keeps the process alive.

The generated dev script is tsx watch src/index.ts, which re-runs the file on every save. For a single run, call Bun directly:

Bash
bun src/index.ts
no-copy
created user ada+1784893846026@prisma.io
there are now 1 users

The pg driver may print an SSL mode deprecation warning above the output; it comes from the sslmode=require setting in the generated connection string and does not affect the query.

That is the whole loop: schema to contract, contract to database, typed queries against both.

The script pattern works for one-off jobs. To keep the app running and serve query results, add a small HTTP server with Bun.serve. Create src/server.ts:

src/server.ts
import { db } from "./prisma/db";

const server = Bun.serve({
  port: Number(process.env.PORT ?? 3000),
  async fetch(req) {
    const { pathname } = new URL(req.url);
    if (pathname === "/users") {
      const users = await db.orm.public.User.select("id", "email", "name").all();
      return Response.json(users);
    }
    return new Response("Not found", { status: 404 });
  },
});

console.log(`Listening on http://localhost:${server.port}`);

Start it and check the endpoint:

Bash
bun src/server.ts
Bash
curl http://localhost:3000/users
no-copy
[{ "id": 1, "email": "ada+1784893846026@prisma.io", "name": "Ada Lovelace" }]

The server listens on port 3000; set PORT to change it. Unlike the script, the server never calls db.close(): the connection pool is shared across requests and closes when the process exits.

Plain Bun servers are supported on Prisma Compute. The scaffold declares the app for Prisma Composer in module.ts and service.ts, which deploy whatever the build script bundles into dist/server.mjs. That script runs tsdown, and the generated tsdown.config.ts sets its entry to src/index.ts, so point the entry at your server instead:

tsdown.config.ts
export default defineConfig({
  entry: { server: "src/server.ts" },
  // the rest of the generated config is unchanged
});

Sign in once (it opens a browser):

Bash
bunx prisma@latest auth login

Then build and deploy from the project directory:

Bash
bun run build
bunx prisma@latest deploy module.ts
no-copy
my-bun-app
├─ database   postgres-database db_abc123
└─ app        compute-service cps_abc123
              https://xyz.ewr.prisma.build

The deploy creates a project named after your module in your workspace, and re-running the deploy reuses it: the CLI finds the hosted state it stored on the first run and converges the project to your module. If a project with that name exists but the CLI cannot identify or verify its stored state (one left behind by a different checkout, for example), the deploy stops with HostedStateBootstrapError; deploy under another name with --name <unique-name>, or rename the module in module.ts. The deploy also provisions its own Prisma Postgres database on the platform, declared in module.ts; the users you created locally are not in it. Verify the live endpoint responds with an empty list from the fresh database:

Bash
curl https://xyz.ewr.prisma.build/users
no-copy
[]

For previews per Git branch and deploy on push, see Deploy on push.

Run bunx prisma@latest init once to install the Prisma ORM skills for your coding agent and keep them matching your installed packages. Prompts that map to this guide:

  • "Using the prisma-8 skill, add a script that lists the 10 newest users."
  • "Add a published flag to the Post model in the starter contract, emit the contract, and update the database."
  • Deno: Run a minimal Prisma ORM and PostgreSQL app on Deno.
Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu