Connect a Worker to existing Postgres via Hyperdrive
You already have a Postgres. Hyperdrive makes it fast and safe to query from Workers — no migration needed.
What are we wiring?
You have a regional Postgres already running — maybe on Neon, Supabase, AWS RDS, or your own server. It lives in one place. Your Workers, on the other hand, run in hundreds of cities. This guide wires a Worker to that database through Hyperdrive, so every request reuses warm connections and reads from cache instead of paying full latency each time.
Hyperdrive sits in the middle as a connection pooler plus query cache. Your code still uses a normal Postgres driver — the only change is that it connects to env.HYPERDRIVE.connectionString instead of your database's real URL.
Think of it like…
A taxi rank outside your database. Instead of every Worker calling a brand-new cab and waiting for it to arrive (a fresh connection), Hyperdrive keeps a few engines running at the curb and remembers popular destinations — so most riders leave immediately.
Who does what?
Your Worker
Runs globally and stays stateless. It opens a client against env.HYPERDRIVE.connectionString and runs SQL.
Hyperdrive
The pooling + caching layer in front of your DB. Reuses connections and serves cached reads.
Your Postgres
Still the single source of truth. Schema, data, and provider all stay exactly as they are.
Connection string
Stored inside the Hyperdrive config, not in your Worker code — your DB password never ships in the bundle.
Why not connect directly?
A direct connection from a far-away Worker pays a TCP + TLS + auth handshake every single time, and serverless invocations can quickly exhaust your database's connection limit. Pooling reuses warm links; caching skips the round-trip entirely for repeated reads.
Without vs with Hyperdrive
The diagram below shows the same workload twice. The top half connects directly and rebuilds a connection on every request. The bottom half goes through Hyperdrive and reuses a warm, pooled link — often answering straight from cache.
Where the time goes
On a cold direct connection, the handshake can cost several round-trips before a single byte of data moves. Hyperdrive pays that cost once and shares the result across many requests.
Wire it up
Five steps: create a Hyperdrive config pointing at your DB, add the binding to wrangler.toml, install a Postgres driver, query through env.HYPERDRIVE.connectionString, and deploy.
Create a Hyperdrive config
Hand Hyperdrive your existing connection string. Wrangler prints an id — copy it for the next step.
npx wrangler hyperdrive create my-postgres \ --connection-string="postgres://user:password@db.example.com:5432/appdb"Add the [[hyperdrive]] binding
Paste the id into wrangler.toml. The nodejs_compat flag is required, because Postgres drivers depend on Node APIs.
name = "my-worker" main = "src/index.js" compatibility_date = "2024-09-23" compatibility_flags = ["nodejs_compat"] [[hyperdrive]] binding = "HYPERDRIVE" id = "<paste-the-id-from-step-1>"Install a Postgres driver
We use postgres.js here; the node-postgres pg package works too.
npm i postgresQuery through Hyperdrive
Connect to env.HYPERDRIVE.connectionString — never the real DB URL. Keep a small per-isolate pool and close it in the background.
import postgres from "postgres"; export default { async fetch(request, env, ctx) { // Connect to Hyperdrive, not the database directly const sql = postgres(env.HYPERDRIVE.connectionString, { max: 5, // small pool per Worker isolate fetch_types: false // skip an extra round-trip }); try { const products = await sql`SELECT id, name, price FROM products LIMIT 10`; // Close in the background so it does not delay the response ctx.waitUntil(sql.end()); return Response.json(products); } catch (err) { console.error(err); return Response.json({ error: String(err) }, { status: 500 }); } } };Deploy
Publish the Worker. Queries now flow through the pooled, cached fast lane.
npx wrangler deploy
Reads and writes, safely
// Parameterized values are sent separately, never string-concatenated
const id = 42;
const rows = await sql`SELECT id, name FROM products WHERE id = ${id}`;
// Writes (INSERT/UPDATE/DELETE) are never cached — they always hit Postgres
await sql`INSERT INTO views (product_id) VALUES (${id})`;Keep the real URL out of your code
The database password lives only inside the Hyperdrive config you created in step 1. Always connect via env.HYPERDRIVE.connectionString so the secret never ends up in your source or bundle.
Key concepts
Connection string
The URL with host, port, user, password, and DB name. Hyperdrive hides yours behind env.HYPERDRIVE.connectionString.
Connection pool
A set of warm, ready connections shared across requests so nobody pays the setup cost twice.
Query cache
Cacheable SELECT results are remembered (default 60s) so identical repeats skip the database.
Setup latency
The TCP + TLS + auth handshake a fresh connection must finish before any query runs. Pooling pays it once.
Connection limits
Every Postgres has a max connection count. Bursty serverless traffic can exhaust it — pooling keeps usage flat.
DB stays the source
Hyperdrive only accelerates access. Your real rows always live in your own Postgres.
Tips & gotchas
Tune caching for freshness
Caching is on by default with a 60s max age (configurable up to 1 hour). For data that must always be live, disable it with: npx wrangler hyperdrive update <id> --caching-disabled true
- Without compatibility_flags = ["nodejs_compat"] and a recent compatibility_date, the Postgres driver fails to load.
- Only read-only SELECTs are cached; INSERT/UPDATE/DELETE always reach Postgres.
- Queries using NOW(), RANDOM(), or CURRENT_DATE are treated as uncacheable — even just naming one in a SQL comment disables caching for that query.
- Always close with ctx.waitUntil(sql.end()) so cleanup never delays the response.
- Keep the per-isolate pool small (e.g. max: 5); Hyperdrive multiplexes across them anyway.
- Works with Postgres and Postgres-compatibles (Neon, Supabase, RDS, CockroachDB, Timescale) — and MySQL too.
- Need a Cloudflare-native SQL database instead of bringing your own? See D1.
Related products
menu_bookOfficial docsopen_in_new