Cloudflare workers deploy skeleton
Skill okayus/okayus-skills/skills/cloudflare-workers-deploy-skeleton
Agent Skills for Claude Code / agentskills.io-compatible agents. Cloudflare Workers + Discord integration patterns.
npx -y skills add okayus/okayus-skills --skill cloudflare-workers-deploy-skeletonAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 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.
What its author says it does
Copied from the file, not written here
Set up a Cloudflare Workers "Walking Skeleton" that serves SPA + API + Cron from a single Worker, with D1 migrations and GitHub Actions auto-deploy. Use when starting a new Cloudflare Workers project and you need the full deployment pipeline (wrangler.jsonc, the 3-layer SPA routing dance, deploy.yml, empty D1 migration) wired up with business logic deferred. Covers the setup pitfalls that are easy to lose hours on — D1 token scope, `pnpm deploy` npm-script collision, database_id placeholder, and the RP_ID locking rule for any future WebAuthn use.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
8.1 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
Cloudflare Workers Deploy Skeleton
Get a new Cloudflare Workers project to the state where main push → production URL returns /health 200 and serves SPA HTML, with business logic = zero.
Why do this first: Deployment boundaries (wrangler.jsonc, GH Actions, D1, Cron registration, SPA routing, secure-headers-ready asset serving) are the most expensive things to debug if they break after a codebase is full. Wire them end-to-end on an empty app, then grow logic on top of proven infrastructure.
When to use this skill
- Starting a new Cloudflare Workers project where you intend to serve SPA + API + Cron from one Worker
- Re-scaffolding an existing project that grew organically and now has SPA routing / deploy drift issues
- Onboarding a teammate and you need a known-good baseline to reproduce
Do not use for multi-Worker microservices, Pages-only sites, or projects that don't need D1.
Deliverables (completion criteria)
Run through the steps in references/setup-order.md. You're done when:
curl https://<project>.<cf-subdomain>.workers.dev/healthreturns{"status":"ok"}with HTTP 200curl https://<project>.<cf-subdomain>.workers.dev/returns 200 with SPA HTML containing<h1>...</h1>mainpush → GH Actionsdeploy.ymlruns D1 migrations → deploys Worker, all greenwrangler d1 migrations list <db> --remoteshows0000_initappliedwrangler.jsonchas bothassets.run_worker_first: trueandtriggers.crons.dev.varsis gitignored,.dev.vars.exampleis committeddatabase_idinwrangler.jsoncis a real UUID (not a<placeholder>)
The 3-layer SPA routing dance
This is the thing that breaks silently. Serving a React SPA + a Hono Worker + preparing for secureHeaders to cover the SPA HTML requires three pieces to agree. Miss any one → / returns 404.
| Layer | Location | Setting | Purpose |
|---|---|---|---|
| L1 | wrangler.jsonc | assets.not_found_handling: "single-page-application" | Fallback assets to index.html |
| L2 | wrangler.jsonc | assets.run_worker_first: true | Worker sees every request before Assets (lets secureHeaders wrap SPA HTML later) |
| L3 | worker/index.ts | app.notFound(async (c) => new Response((await c.env.ASSETS.fetch(c.req.raw)).body, res)) | Worker explicitly delegates unmatched routes to the Assets binding |
If any layer is missing and / returns 404, consult references/spa-routing-diagnosis.md.
Core files (copy from references)
These references contain fully-formed, copy-ready templates. Use them verbatim and change only what's marked <...>:
references/wrangler-template.md—wrangler.jsoncwith 3-layer SPA + D1 + Cronreferences/worker-template.md—worker/index.ts+worker/cron.ts+worker/types.ts(single-sourceBindings)references/gh-actions-template.md—.github/workflows/deploy.ymlwith migrations → deploy ordering + concurrencyreferences/tsconfig-and-vite.md— TypeScript strict config + Vite +@cloudflare/vite-pluginreferences/d1-scaffold.md— emptydrizzle/0000_init.sqlto validate the migration pipelinereferences/dev-vars.md—.dev.vars.examplepattern (keys only, no values)
Setup flow
High-level — step-by-step with exact commands in references/setup-order.md:
- User (interactive):
wrangler loginin a browser - User:
wrangler d1 create <db-name>→ copydatabase_idUUID - User: Create CF API token with
Workers Scripts:Edit + D1:Edit + Account Settings:Read + User Details:Read→ GitHub repo secretCLOUDFLARE_API_TOKEN+CLOUDFLARE_ACCOUNT_ID - Agent: Generate files from references above. Substitute the real
database_idUUID immediately; never leave a<placeholder>inwrangler.jsonc - Agent:
pnpm install→pnpm check→pnpm db:migrate(local) → verify with a dev run - Agent: Commit → push → draft PR → user merges → GH Actions runs → observe deploy success
- User: Look up the assigned production URL in CF Dashboard → Triggers → Route
- Agent: Update
wrangler.jsoncRP_ID/ORIGINto the real production hostname → push → re-deploy
The pitfalls that eat hours
Brief summary; full write-ups in references/pitfalls.md:
pnpm deploycollides with a pnpm built-in subcommand. In the workspace root'spackage.json, use"deploy": "pnpm --filter <pkg> run deploy"with explicitrun- "Edit Cloudflare Workers" API token template lacks
D1:Edit→wrangler d1 migrations apply --remotefails with error 7403 in CI. Add the D1 permission manually when creating the token database_idplaceholder left as<...>inwrangler.jsonc→ deploy fails. Substitute immediately afterwrangler d1 create, don't deferRP_IDlocking rule: If you'll ever use WebAuthn / passkeys, the RP_ID (hostname) must be locked on first deploy. Changing it later invalidates every registered credential. Pin to the productionworkers.devsubdomain or your custom domain from day 1, treat as permanent- vite-plugin
/__scheduleddev caveat:@cloudflare/[email protected]doesn't route/__scheduledin dev (falls back to SPA).1.xfixes it but requireswrangler@^4. For dev Cron testing, see thecloudflare-cron-to-discordskill's fallback
Scope boundary — what this skill does NOT cover
- Authentication (passkeys / sessions / JWT) — deferred to a later phase
- Security hardening (
secureHeaders, CSP,app.onError,sessionMiddleware) — build on top of this skeleton in a later phase - Domain schema (tasks, users, etc.) — defer to when you know what the domain actually looks like
drizzle-orm/drizzle-kit— don't install until you have a real schema to generate migrations for. The empty0000_init.sqlvalidates the pipeline without forcing a Chekhov's-gun dependency. When you do adopt drizzle for real schema work, read thecloudflare-d1-drizzle-migrationskill first — D1 has a silent incompatibility with drizzle-kit's generated PRAGMAs that can cascade-delete child data on table-rebuild migrations
Build logic on top after deploy is provably working, not before.
References
All references below are concrete, copy-ready templates and diagnostic playbooks:
- setup-order.md — end-to-end setup sequence with exact commands
- wrangler-template.md —
wrangler.jsonctemplate - worker-template.md —
worker/index.ts/cron.ts/types.tstemplates - gh-actions-template.md —
deploy.ymltemplate - tsconfig-and-vite.md — TypeScript + Vite setup
- d1-scaffold.md — empty migration for pipeline validation
- dev-vars.md —
.dev.vars.examplepattern - spa-routing-diagnosis.md — 3-layer SPA 404 troubleshooting
- pitfalls.md — known setup traps with full write-ups