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/smart-placement/patterns.md
1# Smart Placement Patterns23## Backend Worker with Database Access45```typescript6export default {7async fetch(request: Request, env: Env): Promise<Response> {8const user = await env.DATABASE.prepare('SELECT * FROM users WHERE id = ?').bind(userId).first();9const orders = await env.DATABASE.prepare('SELECT * FROM orders WHERE user_id = ?').bind(userId).all();10return Response.json({ user, orders });11}12};13```1415```jsonc16{ "placement": { "mode": "smart" }, "d1_databases": [{ "binding": "DATABASE", "database_id": "xxx" }] }17```1819## Frontend + Backend Split (Service Bindings)2021**Frontend:** Runs at edge for fast user response22**Backend:** Smart Placement runs close to database2324```typescript25// Frontend Worker - routes requests to backend26interface Env {27BACKEND: Fetcher; // Service Binding to backend Worker28}2930export default {31async fetch(request: Request, env: Env): Promise<Response> {32if (new URL(request.url).pathname.startsWith('/api/')) {33return env.BACKEND.fetch(request); // Forward to backend34}35return new Response('Frontend content');36}37};3839// Backend Worker - database operations40interface BackendEnv {41DATABASE: D1Database;42}4344export default {45async fetch(request: Request, env: BackendEnv): Promise<Response> {46const data = await env.DATABASE.prepare('SELECT * FROM table').all();47return Response.json(data);48}49};50```5152**CRITICAL:** Use fetch-based Service Bindings (shown above). If using RPC with `WorkerEntrypoint`, Smart Placement will NOT optimize those method calls - only `fetch` handlers are affected.5354**RPC vs Fetch - CRITICAL:** Smart Placement ONLY works with fetch-based bindings, NOT RPC.5556```typescript57// ❌ RPC - Smart Placement has NO EFFECT on backend RPC methods58export class BackendRPC extends WorkerEntrypoint {59async getData() {60// ALWAYS runs at edge, Smart Placement ignored61return await this.env.DATABASE.prepare('SELECT * FROM table').all();62}63}6465// ✅ Fetch - Smart Placement WORKS66export default {67async fetch(request: Request, env: Env): Promise<Response> {68// Runs close to DATABASE when Smart Placement enabled69const data = await env.DATABASE.prepare('SELECT * FROM table').all();70return Response.json(data);71}72};73```7475## External API Integration7677```typescript78export default {79async fetch(request: Request, env: Env): Promise<Response> {80const apiUrl = 'https://api.partner.com';81const headers = { 'Authorization': `Bearer ${env.API_KEY}` };8283const [profile, transactions] = await Promise.all([84fetch(`${apiUrl}/profile`, { headers }),85fetch(`${apiUrl}/transactions`, { headers })86]);8788return Response.json({89profile: await profile.json(),90transactions: await transactions.json()91});92}93};94```9596## SSR / API Gateway Pattern9798```typescript99// Frontend (edge) - auth/routing close to user100export default {101async fetch(request: Request, env: Env) {102if (!request.headers.get('Authorization')) {103return new Response('Unauthorized', { status: 401 });104}105const data = await env.BACKEND.fetch(request);106return new Response(renderPage(await data.json()), {107headers: { 'Content-Type': 'text/html' }108});109}110};111112// Backend (Smart Placement) - DB operations close to data113export default {114async fetch(request: Request, env: Env) {115const data = await env.DATABASE.prepare('SELECT * FROM pages WHERE id = ?').bind(pageId).first();116return Response.json(data);117}118};119```120121## Durable Objects with Smart Placement122123**Key principle:** Smart Placement does NOT control WHERE Durable Objects run. DOs always run in their designated region (based on jurisdiction or smart location hints).124125**What Smart Placement DOES affect:** The location of the coordinator Worker's `fetch` handler that makes calls to multiple DOs.126127**Pattern:** Enable Smart Placement on coordinator Worker that aggregates data from multiple DOs:128129```typescript130// Worker with Smart Placement - aggregates data from multiple DOs131export default {132async fetch(request: Request, env: Env): Promise<Response> {133const userId = new URL(request.url).searchParams.get('user');134135// Get DO stubs136const userDO = env.USER_DO.get(env.USER_DO.idFromName(userId));137const analyticsID = env.ANALYTICS_DO.idFromName(`analytics-${userId}`);138const analyticsDO = env.ANALYTICS_DO.get(analyticsID);139140// Fetch from multiple DOs141const [userData, analyticsData] = await Promise.all([142userDO.fetch(new Request('https://do/profile')),143analyticsDO.fetch(new Request('https://do/stats'))144]);145146return Response.json({147user: await userData.json(),148analytics: await analyticsData.json()149});150}151};152```153154```jsonc155// wrangler.jsonc156{157"placement": { "mode": "smart" },158"durable_objects": {159"bindings": [160{ "name": "USER_DO", "class_name": "UserDO" },161{ "name": "ANALYTICS_DO", "class_name": "AnalyticsDO" }162]163}164}165```166167**When this helps:**168- Worker's `fetch` handler runs closer to DO regions, reducing network latency for multiple DO calls169- Most beneficial when DOs are geographically concentrated or in specific jurisdictions170- Helps when coordinator makes many sequential or parallel DO calls171172**When this DOESN'T help:**173- DOs are globally distributed (no single optimal Worker location)174- Worker only calls a single DO175- DO calls are infrequent or cached176177## Best Practices178179- Split full-stack apps: frontend at edge, backend with Smart Placement180- Use fetch-based Service Bindings (not RPC)181- Enable for backend logic: APIs, data aggregation, DB operations182- Don't enable for: static content, edge logic, RPC methods, Pages with `run_worker_first`183- Wait 15+ min for analysis, verify `placement_status = SUCCESS`184