Skip to main content
Prisma Next ships two Postgres facades with different lifecycle models. The right choice depends on whether your runtime keeps a process alive across requests or spins up a fresh isolate per invocation. This guide covers the per-request facade (@prisma-next/postgres/serverless) and walks through a complete Cloudflare Workers + Hyperdrive deployment.

Two facades, one driver

@prisma-next/postgres exports two facades that compose the same execution stack and differ only in lifecycle ergonomics: The static authoring surface (sql, context, stack, contract) is identical on both facades — it is a pure function of the contract and is safe to cache at module scope. The runtime-bound surface differs because closure-caching a Runtime (and the pg.Client wired into it) across fetch invocations causes stale-connection failures after isolate idle and concurrent-fetch races on a shared client.

Cloudflare Workers + Hyperdrive

Cloudflare Workers + Hyperdrive is the primary tested deployment path. Hyperdrive is Cloudflare’s managed Postgres connection pooler at the edge: the Worker connects to it using the standard Postgres wire protocol via the pg library, and Hyperdrive pools connections to your origin Postgres. The Worker reads the connection string off env.HYPERDRIVE.connectionString.

Architecture

Step 1: Provision Hyperdrive

Wire the binding ID printed by Wrangler into wrangler.jsonc:
nodejs_compat is required. The Postgres driver (pg) uses Node built-ins that workerd polyfills under that flag.

Step 2: Configure local dev

For wrangler dev, set the local connection string in .env (not .dev.vars):

Step 3: Module-scope setup

Construct the db client once per isolate at module scope. Only the static authoring surface is closure-cached here — the runtime-bound surface is acquired per request:
Cursor mode hangs on Cloudflare Hyperdrive. The default cursor path uses pg-cursor’s extended-query named-portal protocol. Against a real deployed Hyperdrive config, after rows are returned, Hyperdrive emits Protocol Error: Unexpected protocol code: C (SQLSTATE 58000) and never sends ReadyForQuery. The connection wedges and Cloudflare kills the request after 30 s with error 1101. This affects every read path (SQL DSL, ORM .all() / .first(), for await). Workaround: pass cursor: { disabled: true } to postgresServerless({...}) to force the simple-protocol path. This bug is tracked upstream as a Cloudflare Hyperdrive issue.

Step 4: Per-request handler

Wiring the ORM client

createOrmClient(runtime) is a factory that passes the per-request runtime to orm({...}):

Migrations from Node

Migrations stay on Node, against the origin database connection string — not Hyperdrive or any edge pooler. Migration commands (prisma-next migration apply, prisma-next db init, etc.) are control-plane operations that run in long-lived Node processes (CI runners, deploy pipelines, dev workstations). Routing DDL through Hyperdrive is explicitly not recommended: Hyperdrive caches query results at the edge, which is desirable for runtime reads but unsafe for migration ledger reads (a stale read could cause duplicate-apply or skipped-apply).
There is no per-request migration story. See Managing database migrations for the full workflow.