Cloudflare workers
Skill Goodsmileduck/claude-registry/plugins/cloud-platform-skills/skills/cloudflare-workers
Authors and reviews Cloudflare Workers projects — wrangler config (toml/jsonc), bindings (KV, R2, D1, Queues, Durable Objects, service bindings, Vectorize, Workers AI), env-scoped vs root config and the non-inheritable bindings trap, Durable Object migrations (renames, SQLite backend), compatibility_date semantics, static assets and Pages migration, secrets vs vars, cron triggers, observability, and deploy/CI patterns with `cloudflare/wrangler-action`. Use when working with Cloudflare Workers, wrangler.toml/wrangler.jsonc, Workers bindings, Durable Objects, Workers KV/R2/D1/Queues, Workers Static Assets, migrating from Pages to Workers, service bindings or WorkerEntrypoint RPC, or deploying Workers from CI.From its SKILL.md
npx -y skills add Goodsmileduck/claude-registry --skill cloudflare-workersAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 7 commands, including `wrangler deploy --dry-run --outdir=./dist-deploy` and 6 more.
SKILL.md
9.4 KB, ~2.2k tokens by cl100k_base, as published. Nobody here has run it
Cloudflare Workers
When to invoke
Symptoms:
- A binding works in
wrangler devbut isundefinedin production. wrangler deployfails withCannot apply new-class migration to class 'X' that is already depended on by existing Durable ObjectsorClass 'X' cannot be used as a Durable Objectafter a code rename.- A secret value is visible in the Cloudflare dashboard under "Variables" — or worse, committed in
wrangler.toml. - Same hostname has both a Custom Domain and a route pattern, and routing is non-deterministic.
- New Pages project — should it actually be a Worker?
- Two Workers in the same account need to talk; engineer is about to wire it through a public URL.
compatibility_datewas bumped and something started 500-ing.wrangler tailshows the deploy succeeded but the new code isn't running.
The trap this prevents: treating wrangler.toml/wrangler.jsonc as docstring-like config. Several keys are non-inheritable across envs, several have implicit ordering, and the Durable Object migrations array is append-only with strict semantics. Most "it broke in prod" Workers incidents trace to one of these.
Inputs to collect first
| Input | Why | Example |
|---|---|---|
| Account ID | All Workers are account-scoped | dashboard sidebar |
| Worker name | Becomes <name>.<subdomain>.workers.dev and route target | checkout-api |
| Routes vs Custom Domain | Decide before deploying — they conflict on the same hostname | api.example.com/* (route) or api.example.com (custom domain) |
| Bindings list | KV / R2 / D1 / Queues / DOs / services / AI / Vectorize | [{type: kv, id: ...}, {type: do, class: Counter}] |
| Environments | staging, production, ephemeral PR envs | dictates env block structure |
compatibility_date | Behavior pin; not metadata | 2025-05-01, recent but not future |
| Static assets | Yes/no; SPA vs MPA; needs Worker handler? | ./dist, SPA, no |
API token scopes for deploy: see references/recipes/ci-deploy.md for the full per-resource list.
Config format
Use wrangler.jsonc for new projects. wrangler init defaults to it, it supports $schema for IDE autocomplete, and Cloudflare's docs lead with it. wrangler.toml is fully supported — no urgency to migrate.
Add "$schema": "node_modules/wrangler/config-schema.json" at the top of any jsonc file; the IDE will underline unknown keys.
Deep dive: references/recipes/wrangler-config.md.
Hard rules
scripts/validate_wrangler.py flags rules 1–5 statically.
-
Bindings are non-inheritable across envs. (Every binding type.) A populated
env.productionblock fully overrides the root config for non-inheritable keys (vars,kv_namespaces,r2_buckets,d1_databases,queues,durable_objects.bindings,services,routes/route). It does NOT merge. If you set KV at root and only routes underenv.production, production deploys with zero KV bindings — silently. Either repeat per env, or move everything into envs and leave root empty. -
migrationsis append-only and class-name driven. (Durable Objects.) Every class referenced by a DO binding must appear in the cumulativemigrationshistory asnew_classes/new_sqlite_classes/ thetoside ofrenamed_classes. Renames need a new entry with a newtag— never edit a past entry. Switching backends (KV → SQLite) is one-way;new_sqlite_classescannot be downgraded. -
Secrets are not
vars. (All projects.)varsships in plaintext with the deploy bundle and is visible in the dashboard. Anything ending in_KEY/_TOKEN/_SECRET/_PASSWORD/_PASSPHRASEbelongs inwrangler secret put NAME(per env if envs are used). Secrets persist acrosswrangler deploy; vars are overwritten. -
compatibility_dateis behavior, not metadata. Bumping it can changefetchredirect handling,nodejs_compatsemantics, error formatting, and more. Read the changelog before bumping; pin to a date in the past, not the future (deploys reject future dates). -
Custom Domain and route patterns can collide. A Custom Domain attached to
api.example.comAND a[[routes]]pattern matchingapi.example.com/*produce undefined precedence. Pick one per hostname. -
Module syntax only. Service Worker syntax (
addEventListener('fetch', ...)) is deprecated. Newcompatibility_datevalues can refuse it. Useexport default { fetch(req, env, ctx) { ... } }. -
Local
wrangler devuses local bindings. Local KV / R2 / D1 / DO state lives in.wrangler/state/. It diverges silently from production. For real-binding behavior usewrangler dev --remote, or set"remote": trueper-binding in newer Wrangler versions.
Bindings
Each binding type has its own block in the config and its own dev-mode behavior. Per-binding shape, gotchas, and the remote flag for local dev: references/recipes/bindings.md.
Durable Objects
Migrations array gotchas and the SQLite-vs-KV backend choice get a dedicated page: references/recipes/durable-objects.md. The five migration verbs (new_classes, new_sqlite_classes, renamed_classes, deleted_classes, transferred_classes) and tag semantics are easy to get subtly wrong.
Static assets and Pages migration
[assets] block in a Worker now covers what Pages used to. references/recipes/static-assets.md covers the conversion, not_found_handling modes (SPA vs 404 page vs none), run_worker_first for auth interceptors, and DNS coordination during the cutover.
Don't migrate a working Pages project just to migrate — wait for a meaningful change. New projects should pick Workers + Static Assets directly.
CI deploy
references/recipes/ci-deploy.md covers the Workers-specific deploy: cloudflare/wrangler-action, API token scopes, multi-env deploys, environment-scoped secrets, and the --env flag. For OIDC, GITHUB_TOKEN permissions, concurrency, and reusable-workflow posture see the github-actions-pipelines skill — that surface is shared with AWS/GCP deploys and not Workers-specific.
Validator
# Validates wrangler.toml or wrangler.jsonc against the hard rules.
python3 scripts/validate_wrangler.py --config wrangler.jsonc
# --format json for CI; non-zero exit on findings.
Checks: env-override (rule 1), DO migrations coverage (rule 2), secret-shape vars (rule 3), future or missing compatibility_date (rule 4), route/custom_domain hostname overlap (rule 5), and an INFO for missing $schema in jsonc.
Proactive triggers
- User pastes a
wrangler.jsoncwith bindings at root AND a populatedenv.production/env.stagingblock → check whether bindings are repeated per env; flag if not. - User renames a Durable Object class in code without touching
migrations→ flag rule 2 before they try to deploy. - User adds
STRIPE_*/_TOKEN/_SECRETetc. tovars→ suggestwrangler secret put. - User attaches both a Custom Domain and a
[[routes]]pattern to the same hostname → pick one. - User has Worker A about to
fetch('https://worker-b...')for an internal call → suggest service binding + RPC. - User starts a new project with
wrangler.tomland thepages_build_output_dirkey → suggest Workers Static Assets ([assets]block) instead. - User uses
wrangler publishin CI → it's deprecated in favor ofwrangler deploy. - User bumps
compatibility_dateto today and 500s appear → ask which flags they changed.
Verification
-
wrangler deploy --dry-run --outdir=./dist-deploysucceeds and theworker.jslooks right. -
python3 scripts/validate_wrangler.py --config wrangler.jsoncreturns 0 findings. - For each env:
wrangler deploy --env <env> --dry-runsucceeds. -
curl -i https://<worker-route>/<health-path>returns the expected response after deploy. -
wrangler tail --env <env>shows request logs for the production hostname. - If DOs are used:
wrangler deployreports the migration tag applied, not a no-op. - Secrets set per env:
wrangler secret list --env productionlists what you expect.
Old patterns
- Service Worker syntax (
addEventListener('fetch', ...)) — use modules (export default { fetch }). wrangler publish— renamed towrangler deploy. Old command still works but is being removed.- One Pages project per app for new projects — prefer Workers +
[assets]. - Worker → Worker via
fetch('https://other-worker.workers.dev')— use service bindings. - DO classes without
migrations— required since launch; if you see a Worker that "just works" without it, you're looking at one of the legacy bindings. workers_dev = truefor production — fine for staging; in production prefer a Custom Domain or zone route.
What ships with it: 12 files
54.4 KB alongside SKILL.md, 1 of them executable
evals/
- do-class-rename.json1.7 KB
- env-override-trap.json1.6 KB
- pages-to-static-assets.json2.1 KB
- secret-in-vars.json1.6 KB
- service-binding-vs-fetch.json2.1 KB
- toml-vs-jsonc.json992 B
references/
- recipes/bindings.md6.3 KB
- recipes/ci-deploy.md6.0 KB
- recipes/durable-objects.md6.5 KB
- recipes/static-assets.md6.1 KB
- recipes/wrangler-config.md5.9 KB
scripts/
- validate_wrangler.pyruns13.6 KB