Prisma ORM with Postgres
Contracts · Query API · Runnable example
Install the dependencies
Section titled “Install the dependencies”bun add alchemy effect @prisma/orm-postgres arktypebun add -d prismaCloudflare setup · Neon setup · Define a contract
Configure validation for Workers
Section titled “Configure validation for Workers”import { configure } from "arktype/config";
configure({ jitless: true });Import the bootstrap before the contract builder:
import "./validation.ts";import { defineContract } from "alchemy/Prisma/ORM";If your package uses "sideEffects": false, preserve this module:
{ "sideEffects": ["./src/prisma/validation.ts"] }PSL-first projects skip this step.
Provision the database and migrations
Section titled “Provision the database and migrations”import * as Neon from "alchemy/Neon";import * as Prisma from "alchemy/Prisma";import * as Effect from "effect/Effect";
export const Db = Effect.gen(function* () { const contract = yield* Prisma.Contract("contract"); const project = yield* Neon.Project("app-db"); const branch = yield* Neon.Branch("app-branch", { project });
yield* Prisma.Migrate("migrate", { url: branch.connectionUri, contract, });
return branch;});Add Hyperdrive
Section titled “Add Hyperdrive”import * as Cloudflare from "alchemy/Cloudflare";
export const Hyperdrive = Effect.gen(function* () { const branch = yield* Db; return yield* Cloudflare.Hyperdrive.Connection("app-hyperdrive", { origin: branch.origin, caching: { disabled: true }, });});Caching is disabled so reads immediately reflect writes. Hyperdrive guide.
Connect in a Worker
Section titled “Connect in a Worker”import * as Cloudflare from "alchemy/Cloudflare";import * as PrismaPostgres from "alchemy/Prisma/ORM/Postgres";import * as Effect from "effect/Effect";import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";import { contract } from "./prisma/contract.ts";import { Hyperdrive } from "./db.ts";
export default class Api extends Cloudflare.Worker<Api>()( "Api", { main: import.meta.url }, Effect.gen(function* () { const conn = yield* Cloudflare.Hyperdrive.Connect(Hyperdrive); const db = yield* PrismaPostgres.Postgres(conn.connectionString, { contract });
return { fetch: Effect.gen(function* () { const users = yield* db.orm.public.User.all(); return yield* HttpServerResponse.json({ users }); }), }; }).pipe(Effect.provide(Cloudflare.Hyperdrive.ConnectBinding)),) {}Use a PSL contract
Section titled “Use a PSL contract”import { makeDatabase } from "./prisma/generated/client.ts";
const conn = yield* Cloudflare.Hyperdrive.Connect(Hyperdrive);const db = yield* makeDatabase(conn.connectionString);Generate the PSL client before compiling. The handler and binding layer stay the same.
Wire the stack
Section titled “Wire the stack”import * as Alchemy from "alchemy";import * as Cloudflare from "alchemy/Cloudflare";import * as Neon from "alchemy/Neon";import * as Prisma from "alchemy/Prisma";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import Api from "./src/api.ts";
export default Alchemy.Stack( "PrismaWorker", { providers: Layer.mergeAll( Cloudflare.providers(), Neon.providers(), Prisma.providers(), ), state: Alchemy.localState(), }, Effect.gen(function* () { const api = yield* Api; return { url: api.url }; }),);Deploy and query
Section titled “Deploy and query”bun alchemy deploycurl https://<your-worker>.workers.devThis demo route is public. Add authentication before exposing private data.
Clean up
Section titled “Clean up”bun alchemy destroyDestroy removes the example’s Worker, Hyperdrive configuration, and Neon resources, including the database data.