Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/hyperdrive/patterns.md
1# Patterns23See [README.md](./README.md), [configuration.md](./configuration.md), [api.md](./api.md).45## High-Traffic Read-Heavy67```typescript8const sql = postgres(env.HYPERDRIVE.connectionString, {max: 5, prepare: true});910// Cacheable: popular content11const posts = await sql`SELECT * FROM posts WHERE published = true ORDER BY views DESC LIMIT 20`;1213// Cacheable: user profiles14const [user] = await sql`SELECT id, username, bio FROM users WHERE id = ${userId}`;15```1617**Benefits:** Trending/profiles cached (60s), connection pooling handles spikes.1819## Mixed Read/Write2021```typescript22interface Env {23HYPERDRIVE_CACHED: Hyperdrive; // max_age=12024HYPERDRIVE_REALTIME: Hyperdrive; // caching disabled25}2627// Reads: cached28if (req.method === "GET") {29const sql = postgres(env.HYPERDRIVE_CACHED.connectionString, {prepare: true});30const products = await sql`SELECT * FROM products WHERE category = ${cat}`;31}3233// Writes: no cache (immediate consistency)34if (req.method === "POST") {35const sql = postgres(env.HYPERDRIVE_REALTIME.connectionString, {prepare: true});36await sql`INSERT INTO orders ${sql(data)}`;37}38```3940## Analytics Dashboard4142```typescript43const client = new Client({connectionString: env.HYPERDRIVE.connectionString});44await client.connect();4546// Aggregate queries cached (use fixed timestamps for caching)47const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();48const dailyStats = await client.query(`49SELECT DATE(created_at) as date, COUNT(*) as orders, SUM(amount) as revenue50FROM orders WHERE created_at >= $151GROUP BY DATE(created_at) ORDER BY date DESC52`, [thirtyDaysAgo]);5354const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();55const topProducts = await client.query(`56SELECT p.name, COUNT(oi.id) as count, SUM(oi.quantity * oi.price) as revenue57FROM order_items oi JOIN products p ON oi.product_id = p.id58WHERE oi.created_at >= $159GROUP BY p.id, p.name ORDER BY revenue DESC LIMIT 1060`, [sevenDaysAgo]);61```6263**Benefits:** Expensive aggregations cached (avoid NOW() for cacheability), dashboard instant, reduced DB load.6465## Multi-Tenant6667```typescript68const tenantId = req.headers.get("X-Tenant-ID");69const sql = postgres(env.HYPERDRIVE.connectionString, {prepare: true});7071// Tenant-scoped queries cached separately72const docs = await sql`73SELECT * FROM documents74WHERE tenant_id = ${tenantId} AND deleted_at IS NULL75ORDER BY updated_at DESC LIMIT 5076`;77```7879**Benefits:** Per-tenant caching, shared connection pool, protects DB from multi-tenant load.8081## Geographically Distributed8283```typescript84// Worker runs at edge nearest user85// Connection setup at edge (fast), pooling near DB (efficient)86const sql = postgres(env.HYPERDRIVE.connectionString, {prepare: true});87const [user] = await sql`SELECT * FROM users WHERE id = ${userId}`;8889return Response.json({90user,91serverRegion: req.cf?.colo, // Edge location92});93```9495**Benefits:** Edge setup + DB pooling = global → single-region DB without replication.9697## Multi-Query + Smart Placement9899For Workers making **multiple queries** per request, enable Smart Placement to execute near DB:100101```jsonc102// wrangler.jsonc103{104"placement": {"mode": "smart"},105"hyperdrive": [{"binding": "HYPERDRIVE", "id": "<ID>"}]106}107```108109```typescript110const sql = postgres(env.HYPERDRIVE.connectionString, {prepare: true});111112// Multiple queries benefit from Smart Placement113const [user] = await sql`SELECT * FROM users WHERE id = ${userId}`;114const orders = await sql`SELECT * FROM orders WHERE user_id = ${userId} ORDER BY created_at DESC LIMIT 10`;115const stats = await sql`SELECT COUNT(*) as total, SUM(amount) as spent FROM orders WHERE user_id = ${userId}`;116117return Response.json({user, orders, stats});118```119120**Benefits:** Worker executes near DB → reduces latency for each query. Without Smart Placement, each query round-trips from edge.121122## Connection Pooling123124Operates in **transaction mode**: connection acquired per transaction, `RESET` on return.125126**SET statements:**127```typescript128// ✅ Within transaction129await client.query("BEGIN");130await client.query("SET work_mem = '256MB'");131await client.query("SELECT * FROM large_table"); // Uses SET132await client.query("COMMIT"); // RESET after133134// ✅ Single statement135await client.query("SET work_mem = '256MB'; SELECT * FROM large_table");136137// ❌ Across queries (may get different connection)138await client.query("SET work_mem = '256MB'");139await client.query("SELECT * FROM large_table"); // SET not applied140```141142**Best practices:**143```typescript144// ❌ Long transactions block pooling145await client.query("BEGIN");146await processThousands(); // Connection held entire time147await client.query("COMMIT");148149// ✅ Short transactions150await client.query("BEGIN");151await client.query("UPDATE users SET status = $1 WHERE id = $2", [status, id]);152await client.query("COMMIT");153154// ✅ SET LOCAL within transaction155await client.query("BEGIN");156await client.query("SET LOCAL work_mem = '256MB'");157await client.query("SELECT * FROM large_table");158await client.query("COMMIT");159```160161## Performance Tips162163**Enable prepared statements (required for caching):**164```typescript165const sql = postgres(connectionString, {prepare: true}); // Default, enables caching166```167168**Optimize connection settings:**169```typescript170const sql = postgres(connectionString, {171max: 5, // Stay under Workers' 6 connection limit172fetch_types: false, // Reduce latency if not using arrays173idle_timeout: 60, // Match Worker lifetime174});175```176177**Write cache-friendly queries:**178```typescript179// ✅ Cacheable (deterministic)180await sql`SELECT * FROM products WHERE category = 'electronics' LIMIT 10`;181182// ❌ Not cacheable (volatile NOW())183await sql`SELECT * FROM logs WHERE created_at > NOW()`;184185// ✅ Cacheable (parameterized timestamp)186const ts = Date.now();187await sql`SELECT * FROM logs WHERE created_at > ${ts}`;188```189190See [gotchas.md](./gotchas.md) for limits, troubleshooting.191