TL;DR: Cloudflare Workers run serverless functions in 330+ cities with zero cold starts, sub-millisecond startup, and no egress fees. More importantly, Workers sit at the centre of a complete serverless ecosystem: D1 for SQL, KV for fast global reads, R2 for object storage, Durable Objects for stateful coordination, Queues for async processing, and Workflows for long-running operations.
Understanding when to use each, and how to wire them together, is what separates a Worker that does one clever thing from a production application that scales without servers.
Why Cloudflare Workers over traditional serverless
Lambda, Cloud Functions, and Azure Functions all share a fundamental limitation: they run in specific regions. A user in Singapore hitting a function deployed in us-east-1 experiences 200–400ms of avoidable latency before your code runs a single line. Cloudflare Workers run in the location closest to the user — automatically, with no configuration required.
The other structural difference is cold starts. Traditional serverless functions spin up a container on first invocation, adding 100–3,000ms of latency. Workers use the V8 isolate model — the same JavaScript engine in your browser — which starts in under a millisecond. Always.
| Traditional Serverless | Cloudflare Workers | |
|---|---|---|
| Execution location | Specific region | 330+ cities, closest to user |
| Cold starts | 100ms–3,000ms | Sub-millisecond, always |
| Egress fees | Yes (often significant) | No egress fees on R2 |
| Runtime | Container-based | V8 isolate |
| Idle cost | Varies | Pay only for CPU time |
The storage ecosystem: choosing the right layer
The most important architectural decision when building on Workers is choosing the right storage for each type of data. Using the wrong one adds latency, complexity, or cost.
| Storage | Best for | Consistency |
|---|---|---|
| Workers KV | Sessions, feature flags, config | Eventual |
| D1 | Relational application data, user records | ACID transactions |
| R2 | Files, media, uploads, backups | Strong per-object |
| Durable Objects | Real-time coordination, per-user state | Strongly consistent |
| Queues | Async task offloading, event processing | At-least-once |
| Hyperdrive | Existing Postgres/MySQL databases | External |
| Vectorize | Semantic search, RAG workflows | — |
The storage choice in one sentence: Use KV for configuration and session data read constantly but rarely written. Use D1 for relational application data with a global user base. Use R2 for files where you refuse to pay egress fees. Use Durable Objects when you need a single, globally-consistent coordinator — one instance per room, per user, per session.
Your first Worker: anatomy of a production function
A Cloudflare Worker is a TypeScript module that exports a fetch handler — a function that receives a Request and returns a Response. Everything else — routing, middleware, storage bindings, environment variables — is configured in wrangler.jsonc and injected via the env parameter.
typescript
// src/index.ts — minimal production Worker export interface Env { DB: D1Database; // D1 binding KV: KVNamespace; // KV binding BUCKET: R2Bucket; // R2 binding API_SECRET: string; // Secret — set via wrangler secret put } export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> { const url = new URL(request.url); if (url.pathname === '/api/health') { return Response.json({ status: 'ok', region: request.cf?.colo }); } if (url.pathname.startsWith('/api/')) { return handleApi(request, env, ctx); } return new Response('Not found', { status: 404 }); } };
Connecting Claude Code to Cloudflare
Cloudflare publishes a dedicated MCP server that gives Claude Code accurate, up-to-date knowledge of the Workers platform. Add https://docs.mcp.cloudflare.com/mcp as a custom MCP connector in Claude Code. Once connected, Claude Code will use correct binding patterns, enforce prepared statements for D1, use the WebSocket Hibernation API, set observability in wrangler.jsonc, and deploy via Wrangler — without additional instruction.
Claude Code prompt:
Create a new Cloudflare Workers API project with: - TypeScript throughout - Hono as the routing framework (lightweight, Workers-optimised) - D1 database binding for user records - KV binding for session storage - R2 binding for file uploads - Environment variable: API_SECRET - Routes: POST /auth/login, GET /users/:id, POST /upload - Wrangler.jsonc with all bindings and observability enabled (head_sampling_rate: 1) - D1 migration for the users table Do not hardcode secrets — use wrangler secret put.
Pattern 1: REST API with Hono and D1
Hono is a lightweight, fast web framework built specifically for edge runtimes including Cloudflare Workers. It weighs under 14kb, has zero dependencies, and its routing and middleware model matches Workers' execution model far better than Express.
Claude Code prompt:
Build a REST API Worker using Hono with: Routes: - POST /api/auth/register — create user, hash password, store in D1, return JWT - POST /api/auth/login — verify credentials, issue JWT, store session in KV - GET /api/users/me — auth-protected, return current user from D1 - POST /api/upload — auth-protected, accept file, store in R2, return URL Auth: JWT (jose library), 15min expiry Sessions: store in KV as { userId, issuedAt } with 7-day TTL Input validation: Zod schemas for all request bodies Error responses: consistent shape { error: { code, message } } Never log passwords, tokens, or PII to console.
Pattern 2: KV for sessions and configuration
Workers KV is globally distributed with Cloudflare's internal caching — frequently read keys can be served in under 1ms. It is ideal for session tokens, feature flags, and configuration.
Important: KV is eventually consistent — a write may take up to 60 seconds to propagate globally. For data that must be immediately consistent after a write, use D1 or Durable Objects instead.
typescript
// KV session management pattern export async function createSession(env: Env, userId: string): Promise<string> { const sessionId = crypto.randomUUID(); await env.KV.put( `session:${sessionId}`, JSON.stringify({ userId, createdAt: Date.now() }), { expirationTtl: 60 * 60 * 24 * 7 } // 7-day TTL ); return sessionId; }
Pattern 3: D1 serverless SQL
D1 is built on SQLite and sits natively in the Workers runtime — queries run in the same location as your Worker, with no network round-trip. For read-heavy global applications, D1's automatic read replication means reads are served from the closest data centre.
⚠️ Always use prepared statements. Never concatenate user input into SQL strings. Use
db.prepare(sql).bind(...args).first()for every query that accepts user-supplied values.
Claude Code prompt:
Write D1 migrations and query helpers for a SaaS application with: Tables: - users: id, email, password_hash, name, plan, created_at - api_keys: id, user_id, key_hash, name, last_used_at, created_at - audit_logs: id, user_id, action, resource_type, resource_id, ip, created_at Use prepared statements throughout — never string interpolation in queries. Add indexes on email (users) and user_id (api_keys, audit_logs). Write the migration SQL files for wrangler d1 migrations apply.
Pattern 4: R2 for zero-egress file uploads
R2 is S3-compatible object storage without egress fees. For user-facing uploads, the recommended pattern is a two-step process: the client requests a presigned upload URL from your Worker, uploads directly to R2, then notifies your Worker to record the upload. This keeps large file bytes out of Worker CPU time and memory limits.
Pattern 5: Durable Objects for stateful coordination
Durable Objects solve a specific problem: you need a single, globally-unique coordinator with persistent state. A chat room where every message must be ordered correctly. A collaborative document where simultaneous edits must be reconciled. The Durable Object model gives you exactly one instance of a class per named ID — globally.
Always use the WebSocket Hibernation API for any Durable Object handling WebSocket connections. It suspends the object when connections are idle, dramatically reducing billing for idle periods.
Pattern 6: Queues and Workflows for async operations
Workers have a 30-second CPU limit per request. Any operation that might take longer — sending emails, processing uploaded files, calling slow third-party APIs — should be moved off the request path. Cloudflare Queues provide guaranteed delivery between Workers with no egress charges. Cloudflare Workflows (now GA) provide durable, resumable multi-step execution with automatic retries.
Claude Code prompt:
Build an async email notification system using Cloudflare Queues: Producer Worker (runs on API request): - User registers → push { type: 'welcome', to: email, name, userId } - Password reset → push { type: 'password_reset', to, token, expiresAt } Consumer Worker (queue binding): - Read message type, select email template - Call Resend API to send the email - On failure: log to D1 audit_logs with error details Never block the API response waiting for email delivery.
Deploying with Wrangler
Wrangler is Cloudflare's official CLI. Run wrangler dev for local development. Run wrangler deploy to push to production. Manage secrets with wrangler secret put SECRET_NAME — never committed to your repository.
json
// wrangler.jsonc — production-ready configuration { "name": "my-api-worker", "main": "src/index.ts", "compatibility_date": "2025-01-01", "observability": { "enabled": true, "head_sampling_rate": 1 }, "d1_databases": [ { "binding": "DB", "database_name": "my-app-db", "database_id": "YOUR_DB_ID" } ], "kv_namespaces": [ { "binding": "KV", "id": "YOUR_KV_ID" } ], "r2_buckets": [ { "binding": "BUCKET", "bucket_name": "my-app-uploads" } ] }
Security hardening for production Workers
Claude Code prompt:
Security audit and hardening for this Cloudflare Workers project. Phase 1 — Audit (read-only): - SQL injection: check all D1 queries use prepared statements - Authentication: verify JWT validation on every protected route - CORS: check Origin header validation, no wildcard on authenticated endpoints - Rate limiting: check all public endpoints have KV-backed rate limiting - Secret handling: confirm no API keys in code or wrangler.jsonc - Error responses: confirm no stack traces leak to clients Phase 2 — Hardening (one fix at a time, with my approval): Apply each fix, run wrangler dev to test locally, confirm before next fix. Output a report to docs/security/workers-hardening.md.
Frequently asked questions
What are Cloudflare Workers and how do they differ from AWS Lambda?
Cloudflare Workers run on Cloudflare's edge network in 330+ cities, automatically routed to the user's nearest location. AWS Lambda runs in specific regions, adding latency for distant users. Workers use the V8 isolate model with sub-millisecond cold starts — Lambda cold starts range from 100ms to several seconds.
When should I use D1 versus Durable Objects?
Use D1 for centralised relational application data — user records, content, transactions — with SQL queries and global read replication. Use Durable Objects when you need strongly consistent per-entity state with compute attached — one chat room, one document session, one rate limiter that must be accurate globally.
Does Workers KV have eventual consistency and does that matter?
Yes, KV is eventually consistent — a write may take up to 60 seconds to propagate globally. This is fine for session tokens, feature flags, and configuration. For counters or inventory where writes must be immediately visible, use Durable Objects or D1 instead.
What is the CPU time limit for Cloudflare Workers?
On the paid plan, each invocation has a 30-second CPU time limit and 128MB memory. On the free plan, the limit is 10ms CPU time. Note that time spent waiting for network requests (D1 queries, R2 reads, external API calls) does not count against the CPU limit.
What is Wrangler and how do I use it to deploy Workers?
Wrangler is Cloudflare's official CLI. Run wrangler dev for local development simulating the full Workers runtime. Run wrangler deploy to push globally. Manage secrets with wrangler secret put SECRET_NAME — stored encrypted in Cloudflare, never in your code. All bindings and configuration live in wrangler.jsonc.
How do I connect Claude Code to Cloudflare for building Workers?
Add https://docs.mcp.cloudflare.com/mcp as a custom MCP connector in Claude Code, and add Cloudflare's published Workers prompt to your CLAUDE.md. Once connected, Claude Code will use correct binding patterns, enforce prepared statements for D1, use the WebSocket Hibernation API, and deploy via Wrangler without needing additional instruction.
Next steps
- See the full Claude stack: The Complete Claude AI Stack
- Learn Claude Code fundamentals: 10 Things to Know About Claude Code
- Build your React apps to deploy on Workers: One Codebase, Multiple React Apps
- Work with ARISE GTM: arisegtm.com/agency-services
- Talk to Paul: arisegtm.com/contact-us
About the author
Paul Sullivan is the Founder of ARISE GTM and creator of the ARISE GTM Methodology®. He is the author of Go To Market Uncovered (Wiley, 2025) and host of the GTM Uncovered podcast.
- Based: Here East, Queen Elizabeth Olympic Park, London E15 2GW
- Work with ARISE GTM: arisegtm.com/agency-services
- Speak to Paul: arisegtm.com/contact-us
- Podcast: GTM Uncovered on Spotify
- YouTube: @gtmuncovered
Based on ARISE GTM's Claude Code and Cloudflare deployment engagements (2024–2026). Current as of April 2026.