Connect Neon from Workers: Hyperdrive first, serverless driver as fallback
Neon officially recommends pooled connections through Hyperdrive; lightweight cases can use @neondatabase/serverless over HTTP or WebSocket.
Edited and verified by Orange Book Editorial Team ·
Bottom line first
The officially recommended path is Hyperdrive: edge-side pooling amortizes Neon compute cold starts and TLS handshakes. For low query volume with no appetite for maintaining a Hyperdrive configuration, use @neondatabase/serverless over HTTP or WebSocket.
Choosing between the two paths
| Path | Best for | Key limits |
|---|---|---|
| Hyperdrive + Postgres driver | High-frequency queries, latency-sensitive workloads, existing Postgres tooling | Needs a dedicated role and a non-pooled connection string; no LISTEN/NOTIFY-style features |
@neondatabase/serverless | Infrequent reads and writes, prototypes, minimal configuration | Every request pays its own handshake; the first query after scale-to-zero takes hundreds of milliseconds |
On the Neon free plan, compute scales to zero after about 5 minutes idle, and waking it takes a few hundred milliseconds. Hyperdrive's pool hides most of that; the HTTP driver path pays it on every cold start.
Path one: Hyperdrive (recommended)
Create a dedicated role for the Worker in the Neon dashboard (do not reuse the owner account), then in the connection details uncheck connection pooling — Hyperdrive does its own pooling, and pointing it at Neon's pooled endpoint stacks two pools. The connection string looks like postgres://<role>:<password>@<host>/<db>?sslmode=require.
npx wrangler hyperdrive create neon-pg --connection-string="postgres://<role>:<password>@<host>/<db>?sslmode=require"{
"name": "notes-api",
"compatibility_date": "2026-08-25",
"compatibility_flags": ["nodejs_compat"],
"hyperdrive": [
{ "binding": "HYPERDRIVE", "id": "<id returned by the create command>" }
]
}import { Client } from 'pg';
interface Env {
HYPERDRIVE: Hyperdrive;
}
export default {
async fetch(request, env: Env): Promise<Response> {
const client = new Client({ connectionString: env.HYPERDRIVE.connectionString });
try {
await client.connect();
const result = await client.query('SELECT id, title FROM notes LIMIT 10');
return Response.json({ notes: result.rows });
} catch (error) {
return Response.json({ error: String(error) }, { status: 502 });
} finally {
await client.end().catch(() => {});
}
},
};Path two: @neondatabase/serverless
npm i @neondatabase/serverless
npx wrangler secret put DATABASE_URLDATABASE_URL is the full connection string from the Neon dashboard. The package runs single queries over HTTP by default and can also hold a session over WebSocket.
import { neon } from '@neondatabase/serverless';
interface Env {
DATABASE_URL: string;
}
export default {
async fetch(request, env: Env): Promise<Response> {
const sql = neon(env.DATABASE_URL);
try {
const rows = await sql`SELECT id, title FROM notes LIMIT 10`;
return Response.json({ notes: rows });
} catch (error) {
return Response.json({ error: String(error) }, { status: 502 });
}
},
};Verification and troubleshooting
curl -s https://<worker>.workers.dev/notes| Symptom | Check first | Recovery |
|---|---|---|
| First query takes hundreds of milliseconds, then normal | Whether compute just woke from scale-to-zero | Accept the latency, or migrate to the Hyperdrive path |
| Authentication failure on the Hyperdrive path | Whether you used the owner account or a pooled connection string | Rebuild Hyperdrive with the dedicated role and non-pooled string |
password authentication failed | Whether the password in the string contains characters needing escapes | Recopy the connection string; URL-encode if needed |
| SQL errors about unsupported features | Whether the code uses LISTEN/NOTIFY or advisory locks | Rewrite as polling or a queue-based design |
Remote boundary and rollback
Creating a Hyperdrive configuration, writing the DATABASE_URL secret, and creating a Neon role all change remote state; this tutorial does not run those actions. Rollback: remove the hyperdrive binding from wrangler.jsonc and redeploy, delete the configuration with wrangler hyperdrive delete <id>, then rotate the role password or drop the dedicated role on the Neon side, and finally delete any unused secrets in Cloudflare. The database data itself is unaffected by a code rollback.
Next: connect Turso from Workers. For monitoring after launch, see Observability.
Primary sources
Did this page help you complete your goal?
Beta feedback is generated in this browser and is never uploaded automatically.
Connect Supabase from Workers: supabase-js or Hyperdrive
Use @supabase/supabase-js over PostgREST, or Hyperdrive pooled direct Postgres; choose by query frequency and cold-start requirements.
Connect Turso from Workers: @libsql/client/web is the only path
Turso is libSQL (a SQLite fork) and cannot use Hyperdrive; in Workers you must import from @libsql/client/web.