# Workers

> 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.

- Skill: `zllovesuki/workers` (Agent Skill)
- Install (CLI): `npx skillmds@latest add zllovesuki/workers`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zllovesuki/workers/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: zllovesuki (https://skillmd.com/u/zllovesuki)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/zllovesuki/workers

---

# 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

```ts
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

```ts
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

```ts
return new Response(readableStream, {
  headers: {
    "Content-Type": "text/plain; charset=utf-8"
  }
});
```

## Background side effect pattern

```ts
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.

```ts
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.

