Prisma
Full-featured ORM with a schema-first workflow, auto-generated client, and powerful query API. Define your models in a Prisma schema file and get a fully typed client.
Install
bun add prisma @prisma/client
bunx prisma init --datasource-provider sqliteThis creates a prisma/schema.prisma file and a .env file with the database URL.
Define Your Schema
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = "file:./app.db"
}
model Task {
id Int @id @default(autoincrement())
title String
done Boolean @default(false)
createdAt DateTime @default(now())
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String
}Generate and Push
Generate the Prisma Client and push the schema to the database. Run these after every schema change.
# Generate the typed client
bunx prisma generate
# Push schema to database (creates tables)
bunx prisma db push
# Open Prisma Studio to browse data
bunx prisma studioSetup in server.ts
Create a single PrismaClient instance and share it via context.
// server.ts
import { createRouter } from '@cmj/juice/runtime';
import { createContextKey, setContext } from '@cmj/juice/runtime';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export const prismaKey = createContextKey<PrismaClient>('prisma');
const router = createRouter({
onBeforeRequest: async (req) => {
setContext(req, prismaKey, prisma);
},
// ... routes
});
export default {
fetch: router.fetch,
};Query in Routes
Use the full Prisma Client API in your server components and actions. Every query is type-safe based on your schema.
// app/routes/home.tsx
import React from 'react';
import { getContext } from '@cmj/juice/runtime';
import { prismaKey } from '../../server.js';
export default async function Home({ request }: { request: Request }) {
const prisma = getContext(request, prismaKey);
const tasks = await prisma.task.findMany({
orderBy: { createdAt: 'desc' },
});
return (
<div>
<h2>Tasks</h2>
<ul>
{tasks.map(task => (
<li key={task.id}>
{task.done ? '\u2713' : '\u25CB'} {task.title}
</li>
))}
</ul>
</div>
);
}
export const response = {
head: { title: 'Tasks' },
};Create, Update, Delete
// Create
async function addTask(formData: FormData) {
'use server';
const title = formData.get('title') as string;
const prisma = getContext(this.request, prismaKey);
await prisma.task.create({
data: { title: title.trim() },
});
redirect('/', 303);
}
// Update
await prisma.task.update({
where: { id: taskId },
data: { done: true },
});
// Delete
await prisma.task.delete({
where: { id: taskId },
});
// Find with conditions
const pending = await prisma.task.findMany({
where: { done: false },
orderBy: { createdAt: 'desc' },
take: 10,
});
// Count
const total = await prisma.task.count();
const incomplete = await prisma.task.count({
where: { done: false },
});Relations
Prisma handles relational queries with include and nested writes.
// Schema with relations:
// model User {
// id Int @id @default(autoincrement())
// tasks Task[]
// }
// model Task {
// id Int @id @default(autoincrement())
// user User @relation(fields: [userId], references: [id])
// userId Int
// }
// Query with relations
const usersWithTasks = await prisma.user.findMany({
include: { tasks: true },
});
// Nested create
await prisma.user.create({
data: {
email: 'alice@example.com',
name: 'Alice',
tasks: {
create: [
{ title: 'First task' },
{ title: 'Second task' },
],
},
},
});Runtime caveat. Prisma uses Node.js APIs internally (file system, child processes). It works on Bun and Node.js but does NOT work on Cloudflare Workers or edge runtimes. For Workers, use Prisma Accelerate (a proxy that runs Prisma in a Node.js environment) or switch to Drizzle with D1.
Other Runtimes
Works out of the box. Prisma Client supports Bun natively.
Standard PrismaClient does NOT work on Workers. Use Prisma Accelerate for edge deployment. Requires a Prisma Accelerate connection string. See prisma.io/accelerate.
import { PrismaClient } from '@prisma/client/edge';
import { withAccelerate } from '@prisma/extension-accelerate';
const prisma = new PrismaClient().$extends(withAccelerate());Works with npm:@prisma/client. Run prisma generate with Deno-compatible output.
Works out of the box. This is Prisma's primary target.