Volt v0.1 · TypeScript APIs on Bun · Get started
Docs/Plugins Ecosystem/Prisma ORM

Prisma ORM

Create a schema, generate a client, and persist users.

Install and configure

This example uses Prisma 6's prisma-client-js generator. Use matching versions of prisma and @prisma/client. A running PostgreSQL database is required for migration and requests.

bash
bun add @prisma/client@6
bun add --dev prisma@6
mkdir -p prisma
export DATABASE_URL='postgresql://postgres:postgres@localhost:5432/volt'

Create prisma/schema.prisma

prisma/schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
generator client {
  provider = "prisma-client-js"
}
model User {
  id    String @id @default(uuid())
  name  String
  email String @unique
}

Generate and migrate

bash
bunx prisma generate --schema=prisma/schema.prisma
bunx prisma migrate dev --schema=prisma/schema.prisma --name init

Generate before typechecking code that imports model types. Client generation needs the schema; migration and queries need database connectivity.

Complete API

index.ts
import { Volt, prismaPlugin, t } from 'voltts';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();
await prisma.$connect();
const app = new Volt();
app.plugin(prismaPlugin({ client: prisma, handleErrors: true }));
app.post('/users', async (c) => {
  const user = await prisma.user.create({ data: { name: c.body.name, email: c.body.email } });
  return c.json(user, 201);
}, { body: t.Object({ name: t.String({ minLength: 2 }), email: t.String({ format: 'email' }) }) });
app.get('/users', async () => ({ users: await prisma.user.findMany() }));
process.once('SIGTERM', async () => { await app.stop(); process.exit(0); });
app.listen(3000);

Test persistence and conflicts

bash
bun run index.ts
curl -i -X POST http://localhost:3000/users -H 'Content-Type: application/json' -d '{"name":"Chansy","email":"[email protected]"}'
curl http://localhost:3000/users

Repeat the POST with the same email to receive a 409 from P2002 translation. P2025 becomes 404; P2003/P2000 become 400. Without client the plugin creates a memory mock with no model methods. Pass an initialized real client directly, not an async client factory. Cleanup calls $disconnect() during app.stop(). This database recipe requires integration testing against your database.