Loading...
Loading...
Connect Workers to PostgreSQL/MySQL with Hyperdrive's global pooling and caching. Use when: connecting to existing databases, setting up connection pools, using node-postgres/mysql2, integrating Drizzle/Prisma, or troubleshooting pool acquisition failures, TLS errors, nodejs_compat missing, or eval() disallowed.
npx skill4agent add ovachiever/droid-tings cloudflare-hyperdrive# For PostgreSQL
npx wrangler hyperdrive create my-postgres-db \
--connection-string="postgres://user:password@db-host.cloud:5432/database"
# For MySQL
npx wrangler hyperdrive create my-mysql-db \
--connection-string="mysql://user:password@db-host.cloud:3306/database"
# Output:
# ✅ Successfully created Hyperdrive configuration
#
# [[hyperdrive]]
# binding = "HYPERDRIVE"
# id = "a76a99bc-7901-48c9-9c15-c4b11b559606"idwrangler.jsonc{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2024-09-23",
"compatibility_flags": ["nodejs_compat"], // REQUIRED for database drivers
"hyperdrive": [
{
"binding": "HYPERDRIVE", // Available as env.HYPERDRIVE
"id": "a76a99bc-7901-48c9-9c15-c4b11b559606" // From wrangler hyperdrive create
}
]
}nodejs_compatbindingenv.HYPERDRIVEid# For PostgreSQL (choose one)
npm install pg # node-postgres (most common)
npm install postgres # postgres.js (modern, minimum v3.4.5)
# For MySQL
npm install mysql2 # mysql2 (minimum v3.13.0)import { Client } from "pg";
type Bindings = {
HYPERDRIVE: Hyperdrive;
};
export default {
async fetch(request: Request, env: Bindings, ctx: ExecutionContext) {
const client = new Client({
connectionString: env.HYPERDRIVE.connectionString
});
await client.connect();
try {
const result = await client.query('SELECT * FROM users LIMIT 10');
return Response.json({ users: result.rows });
} finally {
// Clean up connection AFTER response is sent
ctx.waitUntil(client.end());
}
}
};import { createConnection } from "mysql2/promise";
export default {
async fetch(request: Request, env: Bindings, ctx: ExecutionContext) {
const connection = await createConnection({
host: env.HYPERDRIVE.host,
user: env.HYPERDRIVE.user,
password: env.HYPERDRIVE.password,
database: env.HYPERDRIVE.database,
port: env.HYPERDRIVE.port,
disableEval: true // REQUIRED for Workers (eval() not supported)
});
try {
const [rows] = await connection.query('SELECT * FROM users LIMIT 10');
return Response.json({ users: rows });
} finally {
ctx.waitUntil(connection.end());
}
}
};npx wrangler deploy# PostgreSQL
postgres://user:password@host:5432/database
postgres://user:password@host:5432/database?sslmode=require
# MySQL
mysql://user:password@host:3306/database
# URL-encode special chars: p@ssw$rd → p%40ssw%24rdconst client = new Client({ connectionString: env.HYPERDRIVE.connectionString });
await client.connect();
const result = await client.query('SELECT ...');
ctx.waitUntil(client.end()); // CRITICAL: Non-blocking cleanupconst pool = new Pool({
connectionString: env.HYPERDRIVE.connectionString,
max: 5 // CRITICAL: Workers limit is 6 connections (July 2025: configurable ~20 Free, ~100 Paid)
});
const [result1, result2] = await Promise.all([
pool.query('SELECT ...'),
pool.query('SELECT ...')
]);
ctx.waitUntil(pool.end());ctx.waitUntil(client.end())await client.end()import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
const sql = postgres(env.HYPERDRIVE.connectionString, { max: 5 });
const db = drizzle(sql);
const allUsers = await db.select().from(users);
ctx.waitUntil(sql.end());import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "@prisma/client";
import { Pool } from "pg";
const pool = new Pool({ connectionString: env.HYPERDRIVE.connectionString, max: 5 });
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({ adapter });
const users = await prisma.user.findMany();
ctx.waitUntil(pool.end());@prisma/adapter-pgexport CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgres://user:password@localhost:5432/local_db"
npx wrangler dev{ "hyperdrive": [{ "binding": "HYPERDRIVE", "id": "prod-id", "localConnectionString": "postgres://..." }] }npx wrangler dev --remote # ⚠️ Uses PRODUCTION databaseconst sql = postgres(env.HYPERDRIVE.connectionString, {
prepare: true // REQUIRED for caching
});response.headers.get('cf-cache-status'); // HIT, MISS, BYPASS, EXPIREDrequireverify-caverify-fullnpx wrangler cert upload certificate-authority --ca-cert root-ca.pem --name my-ca-cert
npx wrangler hyperdrive create my-db --connection-string="postgres://..." --ca-certificate-id <ID> --sslmode verify-fullnpx wrangler cert upload mtls-certificate --cert client-cert.pem --key client-key.pem --name my-cert
npx wrangler hyperdrive create my-db --connection-string="postgres://..." --mtls-certificate-id <ID># 1. Install cloudflared (macOS: brew install cloudflare/cloudflare/cloudflared)
# 2. Create tunnel
cloudflared tunnel create my-db-tunnel
# 3. Configure config.yml
# tunnel: <TUNNEL_ID>
# ingress:
# - hostname: db.example.com
# service: tcp://localhost:5432
# 4. Run tunnel
cloudflared tunnel run my-db-tunnel
# 5. Create Hyperdrive
npx wrangler hyperdrive create my-private-db --connection-string="postgres://user:password@db.example.com:5432/database"nodejs_compatcompatibility_flagsctx.waitUntil(client.end())max: 5prepare: truedisableEval: truewrangler devnodejs_compatawait client.end()ctx.waitUntil()# Create Hyperdrive configuration
wrangler hyperdrive create <name> --connection-string="postgres://..."
# List all Hyperdrive configurations
wrangler hyperdrive list
# Get details of a configuration
wrangler hyperdrive get <hyperdrive-id>
# Update connection string
wrangler hyperdrive update <hyperdrive-id> --connection-string="postgres://..."
# Delete configuration
wrangler hyperdrive delete <hyperdrive-id>
# Upload CA certificate
wrangler cert upload certificate-authority --ca-cert <file>.pem --name <name>
# Upload client certificate pair
wrangler cert upload mtls-certificate --cert <cert>.pem --key <key>.pem --name <name>PREPAREEXECUTEDEALLOCATELISTENNOTIFYUSECOM_STMT_PREPARECOM_INIT_DBcaching_sha2_passwordmysql_native_passwordprepare: truereferences/troubleshooting.md| Error | Solution |
|---|---|
| "No such module 'node:*'" | Add |
| "TLS not supported by database" | Enable SSL/TLS on your database |
| "Connection refused" | Check firewall rules, allow public internet or use Tunnel |
| "Failed to acquire connection" | Use |
| "Code generation from strings disallowed" | Set |
| "Bad hostname" | Verify DNS resolves, check for typos |
| "Invalid database credentials" | Check username/password (case-sensitive) |
# Option 1: Create new config (zero downtime)
wrangler hyperdrive create my-db-v2 --connection-string="postgres://new-creds..."
# Update wrangler.jsonc, deploy, delete old config
# Option 2: Update existing
wrangler hyperdrive update <id> --connection-string="postgres://new-creds..."