Workers best practices, Wrangler CLI quick reference, and wrangler.jsonc config. Load when writing/reviewing Workers code, configuring wrangler.jsonc, or running wrangler commands. Biases towards retrieval from Cloudflare docs over pre-trained knowledge.
Prefer retrieval over pre-training for Workers APIs, types, config fields, and CLI flags.
| Source | How to retrieve |
|---|---|
| Workers best practices | Fetch https://developers.cloudflare.com/workers/best-practices/workers-best-practices/ |
| Workers types | bunx wrangler types generates typed Env (see references/review.md) |
| Wrangler config schema | node_modules/wrangler/config-schema.json |
| Cloudflare docs | https://developers.cloudflare.com/workers/ |
Env from config; never hand-write binding interfaceswrangler secret put; never hardcode in config or sourceawait response.text() on unbounded datactx.waitUntil() for post-response work; never destructure ctxobservability in config with head_sampling_rate; structured JSON loggingawaited, returned, voided, or passed to ctx.waitUntil()crypto.randomUUID() / crypto.getRandomValues(); never Math.random() for security| Anti-pattern | Fix |
|---|---|
await response.text() on unbounded data | Stream it (128 MB limit) |
| Hardcoded secrets | wrangler secret put |
Math.random() for tokens | crypto.randomUUID() |
Bare fetch() without await/waitUntil | Floating promise — await or ctx.waitUntil() |
| Module-level mutable variables | Pass state through handler args |
| REST API from inside Worker | Use bindings |
ctx.passThroughOnException() | Explicit try/catch |
Hand-written Env interface | wrangler types |
| Direct string comparison for secrets | crypto.subtle.timingSafeEqual |
Destructuring ctx | Loses this binding — "Illegal invocation" |
any on Env or handler params | Type properly |
implements on platform base classes | Use extends (DurableObject, WorkerEntrypoint, Workflow) |
env.X in platform base class | Use this.env.X |
wrangler --version # Requires v4.x+
| Task | Command |
|---|---|
| Local dev server | wrangler dev |
| Deploy | wrangler deploy |
| Deploy dry run | wrangler deploy --dry-run |
| Generate types | wrangler types |
| Profile startup | wrangler check startup |
| Live logs | wrangler tail |
| Set secret | wrangler secret put KEY |
| List secrets | wrangler secret list |
| Auth status | wrangler whoami |
| Delete Worker | wrangler delete |
| Resource | Create | List |
|---|---|---|
| KV namespace | wrangler kv namespace create NAME | wrangler kv namespace list |
| R2 bucket | wrangler r2 bucket create NAME | wrangler r2 bucket list |
| D1 database | wrangler d1 create NAME | wrangler d1 list |
| D1 migration | wrangler d1 migrations create DB NAME | wrangler d1 migrations list DB |
| D1 execute | wrangler d1 execute DB --remote --command "SQL" | — |
| Vectorize | wrangler vectorize create NAME --dimensions N --metric cosine | wrangler vectorize list |
| Hyperdrive | wrangler hyperdrive create NAME --connection-string "..." | wrangler hyperdrive list |
| Queue | wrangler queues create NAME | wrangler queues list |
wrangler dev # Local mode (default)
wrangler dev --env staging # Specific environment
wrangler dev --port 8787 # Custom port
wrangler dev --test-scheduled # Test cron handlers (visit /__scheduled)
Local secrets go in .dev.vars:
API_KEY=local-dev-key
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2026-01-01",
"compatibility_flags": ["nodejs_compat"],
"observability": { "enabled": true, "head_sampling_rate": 1 }
}
{
"kv_namespaces": [{ "binding": "KV", "id": "<ID>" }],
"r2_buckets": [{ "binding": "BUCKET", "bucket_name": "my-bucket" }],
"d1_databases": [{ "binding": "DB", "database_name": "my-db", "database_id": "<ID>" }],
"ai": { "binding": "AI" },
"vectorize": [{ "binding": "INDEX", "index_name": "my-index" }],
"hyperdrive": [{ "binding": "HYPERDRIVE", "id": "<ID>" }],
"durable_objects": { "bindings": [{ "name": "COUNTER", "class_name": "Counter" }] },
"queues": {
"producers": [{ "binding": "MY_QUEUE", "queue": "my-queue" }],
"consumers": [{ "queue": "my-queue", "max_batch_size": 10, "max_batch_timeout": 30 }]
},
"workflows": [{ "binding": "WF", "name": "my-workflow", "class_name": "MyWorkflow" }],
"triggers": { "crons": ["0 * * * *"] },
"env": { "staging": { "name": "my-worker-staging", "vars": { "ENVIRONMENT": "staging" } } }
}
Use remote: true on bindings that require it during local dev (AI, Vectorize, Browser Rendering).
any, no unsafe castsbunx tsc --noEmit, lint for no-floating-promisesreferences/rules.md — all best practice rules with code examples and anti-patternsreferences/review.md — type validation, config validation, binding access patternsreferences/wrangler-cli.md — full Wrangler CLI reference (all commands, flags, examples)