Keep the Postgres.js API by Rasmus Porsager and get critical fixes and new features:
- Correctness fixes. Queries get the right results, transactions stay isolated, and rollbacks are reported as failures.
- Fewer hangs and crashes. Fixes for stuck queries, shutdown hangs and crashes after disconnects.
- Pool monitoring. See busy connections, idle connections and waiting queries with
sql.stats(). - Faster queries behind poolers. Removes an extra network round trip for supported values (opt-in).
- Vercel Fluid Compute support. Reuse connections between requests and close idle ones before suspension to avoid connection leaks.
- Cloudflare Workers on the cheapest path. Connects through Cloudflare's own
cloudflare:socketsAPI, which costs less CPU per connection than workerd'snode:net, tested locally and on Cloudflare's network with Neon, Supabase and Hyperdrive.
50+ reported upstream bugs fixed, with regression tests.
Start a new project · Switch from Postgres.js · Why this fork · API reference · Roadmap
npm install @steadybrew/postgresjsOr, for Drizzle or Kysely, use the alias:
npm install postgres@npm:@steadybrew/postgresjs@^4import postgres from '@steadybrew/postgresjs' // or 'postgres' with the alias
const sql = postgres(process.env.DATABASE_URL)
const minAge = 18
const users = await sql`select name, age from users where age >= ${ minAge }`Check first. The migration codemod reports required changes, behaviour differences to review and useful fixes, with file and line. It changes nothing:
npx @steadybrew/postgresjs-migrate .Then migrate with Codemod:
npx codemod @steadybrew/postgresjs-migrateRun it from your project root. It checks again, switches dependencies and overrides to the fork, and removes patches already covered by the fork. Your source code and imports stay unchanged. Run your package manager's install afterwards to update the lockfile.
See the migration guide for behaviour changes, manual installation and the direct npm CLI.
The alias above works with drizzle-orm/postgres-js, drizzle-kit, kysely-postgres-js and dd-trace. Drizzle's and Kysely's own tests pass on the fork as they do on 3.4.9 (results). The codemod sets it up for existing projects, preserving import postgres from 'postgres'.
Sentry needs an extra step: add the tracing preload to retain automatic database spans. The codemod flags Sentry but does not apply this adjustment.
Maintained by Oleg Komarov. Since 4.5.0, every version is published from GitHub Actions through npm trusted publishing, with provenance and maintainer approval using two-factor authentication. No stored npm token, runtime dependencies or registry install scripts. Verify with npm audit signatures, or under Provenance at the bottom of the npm page.
Driver changes since Postgres.js 3.4.9 · Report a vulnerability · Unlicense
Releases pass the test matrix before publishing:
| Runtime | PostgreSQL tested |
|---|---|
| Node.js 22, 24 and 26, ESM and CommonJS | 15–18 |
| Deno 1.46.3 | 18 |
| Cloudflare Workers, compatibility dates 2025-01-01 to 2026-10-12, in local workerd and on Cloudflare's network | 18; Neon directly, pooled and through Hyperdrive; Supabase through Hyperdrive |
TypeScript declarations are included; use @types/node 22+ or skipLibCheck.
Older Node.js versions may work but aren't tested. The package declares engines.node: >=22, so package managers may warn or reject installation on older versions.
Hosted Supabase Edge Functions are deployed in production with this fork, outside the CI matrix. Standalone Deno 2 is unverified. Bun is best effort, without CI coverage. On Cloudflare Workers the driver connects through Cloudflare's cloudflare:sockets API, which costs less CPU per connection than workerd's node:net; the Worker needs Node.js compatibility, which is on by default from compatibility date 2026-08-04 and is otherwise the nodejs_compat flag. On compatibility dates before 2026-03-03, each closed connection logs one unhandled rejection that the driver has in fact handled, unless the Worker sets the unhandled_rejection_after_microtask_checkpoint flag (#1196, #1202). See Cloudflare Workers support.
As many of my deployments are on serverless, I ran into some Postgres.js limitations that made it harder to use it reliably. I moved a couple of projects off it and patched others to compare the pros and cons.
But I also realised that even for a small team of one, there is a clear path to updating and fixing Postgres.js, and I decided to bring those changes, whether from local patches, parked issues or PRs, to the benefit of the wider community.
The aim of this fork is to move faster while keeping rigorous review, automate broader, tedious testing, welcome community contributions, and make a library I enjoy using work better for everyone.
- Transactions keep their own connection. Fixes connection reuse that could commit another transaction's unfinished writes or let a disconnected handle read another user's rows through RLS. #1204, #1216
- Each query gets its own result. Fixes pipelined queries receiving another query's rows or error, and results with empty slots after a failed query. #1082, #1252, #1253
- Rollbacks aren't reported as successful commits.
sql.begin()rejects when the server rolls back the commit. #1217 - Fewer hangs and crashes. Fixes reservations and shutdown hanging after disconnects, queries stuck after a slow
COPYreader, and closed transaction handles crashing the process. #1195, #1097, #1016, #1208 - Recover after outages. Failed connections wait before retrying, avoiding a burst of simultaneous retries. With multiple hosts, the client tries another server and can wait for a writable primary.
50+ bug fixes and test coverage →
With prepare: false, parameterized queries can pay for an extra network round trip. The opt-in parameter_types: 'client' removes it for supported values. In one production app behind the Supabase pooler, median query time fell from 5.3 ms to 3.1 ms over a day on each mode. Results depend on your workload; p99 was unchanged. Use 'warn' first to check for serialization differences.
- See pool pressure.
sql.stats()reports busy and idle connections and waiting queries. - Handle serverless suspension. Expired idle connections are replaced on resume; the Vercel Fluid Compute adapter keeps instances alive until idle connections close.
- Automatic cleanup.
await usingcloses a pool andusingreleases a reserved connection when its scope ends. Requires Node.js 24+ or TypeScript 5.2+. - Cloudflare Workers fixes. On Workers,
COPY TOstreams andsubscribe()pause and resume the socket (#975),ssl: 'prefer'falls back to plaintext when the server declines TLS, and a certificate from a private CA fails at once withTLS_CLOSEDinstead of a timeout (#1213). - Cheaper new connections. SCRAM-SHA-256 logins reuse the keys derived from the password for five minutes (SCRAM key cache), so opening a connection costs about a quarter less CPU on Cloudflare Workers and 40% less at the median on Node.js.
- Arrays without startup discovery. With
fetch_types: false, common built-in arrays still parse and serialize without a catalog query.
- API reference — queries, transactions, types, options and errors. Also shipped in the npm package at
docs/api.mdfor editors and code assistants. - Migration guide — switching, behaviour changes and tracing.
- Changelog · Roadmap · Contributing
Based on Postgres.js by Rasmus Porsager. Thank you to its creator and everyone contributing fixes and reproductions.