| name | workers |
| description | Write Cloudflare Workers code for stateless HTTP handlers, APIs, SSR, streaming responses, service orchestration, bindings, async I/O, global-scope initialization, and ctx.waitUntil. Use for Worker fetch handlers and edge runtime TypeScript patterns.
|
| compatibility | Cloudflare Workers TypeScript projects using Wrangler; verify current Cloudflare APIs, limits, and pricing before production use. |
| metadata | {"source":"Architecting on Cloudflare plus official Cloudflare Developer Platform docs","generated":"2026-04-28"} |
Workers
Use this skill when writing Cloudflare Worker code. Workers are the default stateless compute layer; other primitives are accessed through bindings.
Runtime assumptions
- Code runs in V8 isolates, not a traditional Node server process.
- Do not use mutable global state for per-user data, sessions, counters, locks, or caches that must be correct.
- Global scope is appropriate for immutable configuration, compiled regexes, lazy-loaded clients, and small best-effort caches.
- I/O waits are normal. Use
Promise.all for independent binding calls and external fetches.
- Use
ctx.waitUntil() for non-critical background work that should not delay the response.
- Use Web APIs:
Request, Response, URL, ReadableStream, crypto.subtle, fetch.
Handler skeleton
export interface Env {
API_HOST: string;
DB?: D1Database;
BUCKET?: R2Bucket;
CACHE?: KVNamespace;
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/health") {
return Response.json({ ok: true, env: env.API_HOST });
}
if (url.pathname.startsWith("/api/")) {
return handleApi(request, env, ctx);
}
return new Response("Not found", { status: 404 });
}
} satisfies ExportedHandler<Env>;
async function handleApi(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
if (request.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
return Response.json({ message: "hello" });
}
Parallel I/O pattern
const [user, featureFlags] = await Promise.all([
env.DB.prepare("SELECT id, email FROM users WHERE id = ?").bind(userId).first<User>(),
env.CACHE.get(`flags:${tenantId}`, "json") as Promise<FeatureFlags | null>
]);
Streaming pattern
return new Response(readableStream, {
headers: {
"Content-Type": "text/plain; charset=utf-8"
}
});
Background side effect pattern
ctx.waitUntil(writeAuditLog(env, {
route: new URL(request.url).pathname,
at: new Date().toISOString()
}));
Use waitUntil for logs, cache refresh, non-critical notifications, and analytics. Do not use it for required business state unless the user-facing response can tolerate the task failing later.
Error handling
- Return structured JSON errors for APIs.
- Include a correlation ID in logs and responses.
- Avoid leaking secrets, tokens, raw stack traces, or internal object keys.
function jsonError(message: string, status = 400, requestId = crypto.randomUUID()) {
console.error(JSON.stringify({ requestId, status, message }));
return Response.json({ error: message, requestId }, { status });
}
Anti-patterns
- Starting an HTTP server with Express/Koa/Fastify inside a Worker.
- Long CPU-bound loops or in-memory processing of large files.
- Assuming the same isolate will handle future requests.
- Using Node-only APIs without verifying compatibility.
- Fetching Cloudflare resources through public APIs instead of using bindings.