dist/plugins/shared-ci-cd-cloudflare-workers/skills/shared-ci-cd-cloudflare-workers/SKILL.md
Cloudflare Workers edge compute platform — Wrangler CLI, KV, D1, R2, Durable Objects, Queues, Workers AI
npx skillsauth add agents-inc/skills shared-ci-cd-cloudflare-workersInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Quick Guide: Cloudflare Workers run TypeScript/JavaScript on Cloudflare's global edge network with V8 isolates (not containers). Use
wrangler.jsoncfor configuration,wrangler devfor local development, andwrangler deployfor production. Access KV, D1, R2, Queues, Durable Objects, and Workers AI through type-safe bindings on theenvparameter. Runwrangler typesto auto-generate yourEnvinterface. Stream large payloads — Workers have a 128 MB memory limit. Never store request-scoped state in module-level variables.
<critical_requirements>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST run wrangler types to generate your Env interface — NEVER hand-write binding types)
(You MUST use wrangler.jsonc for new projects — Cloudflare recommends JSON config and some features are JSON-only)
(You MUST stream large request/response bodies — NEVER buffer entire payloads in memory (128 MB limit))
(You MUST avoid module-level mutable state — Workers reuse V8 isolates across requests, causing cross-request data leaks)
(You MUST use bindings for Cloudflare services (KV, D1, R2, Queues) — NEVER use REST APIs from within Workers)
</critical_requirements>
Auto-detection: Cloudflare Workers, wrangler, wrangler.toml, wrangler.jsonc, Workers KV, Cloudflare KV, D1 database, R2 bucket, Durable Objects, Cloudflare Queues, Workers AI, service binding, miniflare, compatibility_date, compatibility_flags, nodejs_compat, cloudflare:workers, ExportedHandler, DurableObject, wrangler dev, wrangler deploy, wrangler types, Cloudflare Pages Functions, edge worker, CF Worker
When to use:
When NOT to use:
Key patterns covered:
wrangler.jsonc) and project setupCloudflare Workers run on V8 isolates (not containers) across 300+ data centers worldwide. They start in under 5ms with zero cold starts. The programming model is fundamentally different from traditional servers:
env parameter, not REST API calls. Bindings have zero network hop and zero auth overhead.TransformStream and pipeTo.When to use Workers:
When NOT to use Workers:
Every Workers project starts with wrangler.jsonc. Cloudflare recommends JSON format — some newer features are JSON-only. Run wrangler types after changing bindings to regenerate the Env interface.
// wrangler.jsonc
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "my-api",
"main": "src/index.ts",
"compatibility_date": "2025-09-15",
"compatibility_flags": ["nodejs_compat"],
"observability": { "enabled": true },
"placement": { "mode": "smart" },
"upload_source_maps": true,
}
See examples/core.md for full project initialization, multi-environment config, secrets management, CI/CD, and testing setup.
The fetch handler is the entry point for HTTP requests. Use satisfies ExportedHandler<Env> for type safety.
import type { ExportedHandler } from "cloudflare:workers";
export default {
async fetch(request, env, ctx): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/health") {
return Response.json({ status: "healthy" });
}
return new Response("Not Found", { status: 404 });
},
} satisfies ExportedHandler<Env>;
Never store mutable state in module-level variables — V8 isolate reuse causes cross-request data leaks. See examples/core.md for complete handler with CORS and routing.
KV is an eventually-consistent key-value store for read-heavy workloads. Use typed get<T>(key, "json"), always set expirationTtl, and use ctx.waitUntil() for non-blocking writes.
const CACHE_TTL_SECONDS = 3_600;
const profile = await env.CACHE.get<UserProfile>(`user:${id}`, "json");
ctx.waitUntil(
env.CACHE.put(`user:${id}`, JSON.stringify(data), {
expirationTtl: CACHE_TTL_SECONDS,
}),
);
When to use: Read-heavy workloads (config, cache, feature flags) where eventual consistency is acceptable (~60s propagation).
When not to use: Relational data (use D1), frequent writes to same key, strong consistency (use Durable Objects).
See examples/kv.md for stale-while-revalidate pattern and full caching examples.
D1 is serverless SQLite at the edge. Always use parameterized queries via prepare().bind() to prevent SQL injection. Use batch() for atomic multi-statement operations. Use withSession() for read replica consistency when read replication is enabled.
const user = await db
.prepare("SELECT * FROM users WHERE email = ?")
.bind(email)
.first<User>();
const { results } = await db
.prepare("SELECT * FROM users LIMIT ? OFFSET ?")
.bind(DEFAULT_PAGE_SIZE, offset)
.all<User>();
See examples/d1.md for migrations, batch operations, and full CRUD API.
R2 is S3-compatible storage with zero egress fees. Always stream R2 bodies directly to responses — never call .arrayBuffer() or .text() on large objects.
const object = await env.BUCKET.get(key);
if (!object) return new Response("Not Found", { status: 404 });
const headers = new Headers();
object.writeHttpMetadata(headers);
return new Response(object.body, { headers }); // Stream directly
See examples/r2.md for file service with content-type validation and list operations.
Durable Objects provide single-threaded, strongly consistent compute. Each instance has SQLite storage. Use RPC methods (not fetch) and blockConcurrencyWhile for schema migrations.
import { DurableObject } from "cloudflare:workers";
export class Counter extends DurableObject<Env> {
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
ctx.blockConcurrencyWhile(async () => {
this.ctx.storage.sql.exec("CREATE TABLE IF NOT EXISTS ...");
});
}
async increment(name: string): Promise<number> {
/* RPC method */
}
}
When to use: Coordination (chat, collaboration), per-entity state (sessions, game instances), WebSocket connections, rate limiting.
When not to use: Stateless requests, high fan-out, global rate limiting (bottleneck).
See examples/durable-objects.md for rate limiter and WebSocket chat with hibernation.
Queues decouple producers from consumers with at-least-once delivery and configurable retries. Cron triggers invoke Workers on a schedule. Service bindings enable zero-cost worker-to-worker calls. Workers AI runs inference on Cloudflare's GPU network.
See examples/routing.md for all these patterns with full configuration and code examples.
For structured APIs, use a framework with typed bindings (Hono is the Workers ecosystem standard). Export the framework's fetch handler alongside scheduled/queue handlers.
import { Hono } from "hono";
const app = new Hono<{ Bindings: Env }>();
app.get("/users/:id", async (c) => {
const user = await c.env.DB.prepare("SELECT * FROM users WHERE id = ?")
.bind(c.req.param("id"))
.first();
return user ? c.json(user) : c.json({ error: "Not found" }, 404);
});
export default app;
See examples/routing.md for production API with middleware, error handling, and multi-handler setup.
</patterns>| Technique | Impact |
| ------------------------------------- | -------------------------------------------------------- |
| Smart Placement ("mode": "smart") | Routes to optimal data center based on binding locations |
| Streaming responses | Avoids 128 MB memory limit, improves TTFB |
| ctx.waitUntil() for background work | Returns response immediately, processes async work after |
| nodejs_compat flag | Access Node.js built-in modules (crypto, buffer, stream) |
| Storage | Reads | Writes | Consistency | Best For | | --------------- | ------------------ | ----------------------- | ------------------------ | ------------------------ | | KV | Fast (edge cached) | Slow (~60s propagation) | Eventually consistent | Cache, config, flags | | D1 | Medium | Medium | Strong (per-region) | Relational data, queries | | R2 | Medium | Medium | Strong | Files, blobs, uploads | | Durable Objects | Fast (in-memory) | Fast (SQLite) | Strong (single-threaded) | Coordination, real-time |
When connecting to PostgreSQL/MySQL outside Cloudflare, always use Hyperdrive. It maintains a connection pool close to your database, eliminating per-request TCP/TLS overhead.
| Plan | CPU Time per Request | | ------------- | --------------------------------------------------- | | Free | 10 ms | | Paid | 30 seconds (default), configurable up to 15 minutes | | Cron Triggers | 15 minutes |
</performance><decision_framework>
What kind of data?
|
+-- Key-value pairs (cache, config, sessions)
| +-- Read-heavy, eventual consistency OK --> KV
| +-- Strong consistency needed --> Durable Objects
|
+-- Relational data with queries
| +-- Edge-native SQLite --> D1
| +-- External PostgreSQL/MySQL --> Hyperdrive
|
+-- Files and blobs (images, documents)
| +-- S3-compatible storage --> R2
|
+-- Coordination state (chat, multiplayer, collaboration)
| +-- Single-threaded consistency --> Durable Objects
|
+-- Message passing / background work
+-- Simple fan-out, buffering --> Queues
+-- Multi-step durable execution --> Workflows
What are you building?
|
+-- API only (no frontend) --> Workers
|
+-- Static site + API --> Pages with Functions
|
+-- Full-stack with SSR --> Pages (framework) or Workers + Static Assets
|
+-- Background processing / cron --> Workers (Pages lacks cron support)
|
+-- Real-time / WebSockets --> Workers + Durable Objects
Do you need coordination between concurrent requests?
|
+-- YES (chat, game, collaboration) --> Durable Objects
| +-- Single-threaded, no race conditions
| +-- WebSocket support with hibernation
| +-- Per-entity sharding (one DO per room/session)
|
+-- NO (CRUD, reporting, querying) --> D1
+-- Full SQL support
+-- Cross-entity queries
+-- Traditional database patterns
</decision_framework>
Cloudflare Platform Services:
cloudflare/wrangler-action@v3 for CI/CD deploymentFramework & ORM Compatibility:
Workers are compatible with edge-optimized frameworks and ORMs that support the V8 runtime. Use Hono<{ Bindings: Env }> for type-safe binding access in the recommended framework. D1 works with any ORM that supports SQLite (check your ORM's Workers compatibility docs).
Testing:
Use @cloudflare/vitest-pool-workers to run tests inside the actual Workers runtime with real bindings (KV, D1, R2). See examples/core.md for test configuration.
Comparable Platforms:
<red_flags>
High Priority Issues:
.text() / .arrayBuffer() (128 MB memory limit)Env interface instead of running wrangler types (mismatches between config and code)wrangler.jsonc, source code, or environment variables (use wrangler secret put)Medium Priority Issues:
wrangler.toml for new projects (JSON format recommended, some features JSON-only)compatibility_date (misses runtime improvements and bug fixes)observability config (production Workers are a black box without logs/traces)ctx in fetch handler (loses this binding, ctx.waitUntil throws "Illegal invocation")exec() for D1 queries instead of prepare().bind() (no parameterization, SQL injection risk)Common Mistakes:
Math.random() for security-sensitive tokens (use crypto.randomUUID() or crypto.getRandomValues())ctx.waitUntil() for post-response background work (work may be cancelled when response is sent)=== instead of crypto.subtle.timingSafeEqual() (timing side-channel attack)passThroughOnException() as error handling (hides bugs, use explicit try/catch)waitUntil()) causing silent failures — enable @typescript-eslint/no-floating-promises to catch at dev timeGotchas and Edge Cases:
wrangler dev uses local simulation by default; use --remote to test against real Cloudflare servicesawait between DO storage writes breaks write coalescing — batch writes happen atomically when you don't await between themblockConcurrencyWhile() on every request limits throughput to ~200 req/sec — use it only for initialization.dev.vars file is for local secrets only and must be gitignoredenv parameter from cloudflare:workers import creates a fresh reference; avoid caching binding derivatives at module scope</red_flags>
<critical_reminders>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST run wrangler types to generate your Env interface — NEVER hand-write binding types)
(You MUST use wrangler.jsonc for new projects — Cloudflare recommends JSON config and some features are JSON-only)
(You MUST stream large request/response bodies — NEVER buffer entire payloads in memory (128 MB limit))
(You MUST avoid module-level mutable state — Workers reuse V8 isolates across requests, causing cross-request data leaks)
(You MUST use bindings for Cloudflare services (KV, D1, R2, Queues) — NEVER use REST APIs from within Workers)
Failure to follow these rules will result in memory crashes (buffering), data leaks (module state), type mismatches (hand-written Env), unnecessary latency (REST over bindings), and secret exposure (secrets in config).
</critical_reminders>
development
Material Design component library for Vue 3
development
VitePress 1.x — Vue-powered static site generator for documentation sites, built on Vite
tools
Docusaurus 3.x documentation framework — site configuration, docs/blog plugins, sidebars, versioning, MDX, swizzling, and deployment
development
TanStack Form patterns - useForm, form.Field, validators, arrays, linked fields, createFormHook, type safety