$npx -y skills add jezweb/claude-skills --skill cloudflare-worker-builderScaffold and deploy Cloudflare Workers with Hono routing, Vite plugin, and Static Assets. Describe project, scaffold structure, configure bindings, deploy. Use whenever the user wants to create a Worker project, set up Hono on Cloudflare, configure D1 / R2 / KV / Queues bindings,
| 1 | # Cloudflare Worker Builder |
| 2 | |
| 3 | Scaffold a working Cloudflare Worker project from a brief description. Produces a deployable project with Hono routing, Vite dev server, and Static Assets. |
| 4 | |
| 5 | ## Workflow |
| 6 | |
| 7 | ### Step 1: Understand the Project |
| 8 | |
| 9 | Ask about the project to choose the right bindings and structure: |
| 10 | |
| 11 | - What does the app do? (API only, SPA + API, landing page) |
| 12 | - What data storage? (D1 database, R2 files, KV cache, none) |
| 13 | - Auth needed? (Clerk, better-auth, none) |
| 14 | - Custom domain or workers.dev subdomain? |
| 15 | |
| 16 | A brief like "todo app with database" is enough to proceed. |
| 17 | |
| 18 | ### Step 2: Scaffold the Project |
| 19 | |
| 20 | ```bash |
| 21 | npm create cloudflare@latest my-worker -- --type hello-world --ts --git --deploy false --framework none |
| 22 | cd my-worker |
| 23 | npm install hono |
| 24 | npm install -D @cloudflare/vite-plugin vite |
| 25 | ``` |
| 26 | |
| 27 | Copy and customise the asset files from this skill's `assets/` directory: |
| 28 | - `wrangler.jsonc` — Worker configuration |
| 29 | - `vite.config.ts` — Vite + Cloudflare plugin |
| 30 | - `src/index.ts` — Hono app with Static Assets fallback |
| 31 | - `package.json` — Scripts and dependencies |
| 32 | - `tsconfig.json` — TypeScript config |
| 33 | - `public/index.html` — SPA entry point |
| 34 | |
| 35 | ### Step 3: Configure Bindings |
| 36 | |
| 37 | Add bindings to `wrangler.jsonc` based on project needs. Wrangler 4.45+ auto-provisions resources on first deploy — always specify explicit names: |
| 38 | |
| 39 | ```jsonc |
| 40 | { |
| 41 | "name": "my-worker", |
| 42 | "main": "src/index.ts", |
| 43 | "compatibility_date": "2025-11-11", |
| 44 | "assets": { |
| 45 | "directory": "./public/", |
| 46 | "binding": "ASSETS", |
| 47 | "not_found_handling": "single-page-application", |
| 48 | "run_worker_first": ["/api/*"] |
| 49 | }, |
| 50 | // Add as needed: |
| 51 | "d1_databases": [{ "binding": "DB", "database_name": "my-app-db" }], |
| 52 | "r2_buckets": [{ "binding": "STORAGE", "bucket_name": "my-app-files" }], |
| 53 | "kv_namespaces": [{ "binding": "CACHE", "title": "my-app-cache" }] |
| 54 | } |
| 55 | ``` |
| 56 | |
| 57 | ### Step 4: Deploy |
| 58 | |
| 59 | ```bash |
| 60 | npm run dev # Local dev at http://localhost:8787 |
| 61 | wrangler deploy # Production deploy |
| 62 | ``` |
| 63 | |
| 64 | --- |
| 65 | |
| 66 | ## Critical Patterns |
| 67 | |
| 68 | ### Export Syntax |
| 69 | |
| 70 | ```typescript |
| 71 | // CORRECT — use this pattern |
| 72 | export default app |
| 73 | |
| 74 | // WRONG — causes "Cannot read properties of undefined" |
| 75 | export default { fetch: app.fetch } |
| 76 | ``` |
| 77 | |
| 78 | Source: [honojs/hono #3955](https://github.com/honojs/hono/issues/3955) |
| 79 | |
| 80 | ### Static Assets + API Routes |
| 81 | |
| 82 | Without `run_worker_first`, SPA fallback intercepts API routes and returns `index.html` instead of JSON: |
| 83 | |
| 84 | ```jsonc |
| 85 | "assets": { |
| 86 | "not_found_handling": "single-page-application", |
| 87 | "run_worker_first": ["/api/*"] // CRITICAL |
| 88 | } |
| 89 | ``` |
| 90 | |
| 91 | Source: [workers-sdk #8879](https://github.com/cloudflare/workers-sdk/issues/8879) |
| 92 | |
| 93 | ### Vite Config |
| 94 | |
| 95 | ```typescript |
| 96 | import { defineConfig } from 'vite' |
| 97 | import { cloudflare } from '@cloudflare/vite-plugin' |
| 98 | |
| 99 | export default defineConfig({ plugins: [cloudflare()] }) |
| 100 | ``` |
| 101 | |
| 102 | Always set the `main` field in wrangler.jsonc — the Vite plugin needs it. |
| 103 | |
| 104 | ### Scheduled/Cron Handlers |
| 105 | |
| 106 | When adding cron triggers, switch to explicit export: |
| 107 | |
| 108 | ```typescript |
| 109 | export default { |
| 110 | fetch: app.fetch, |
| 111 | scheduled: async (event, env, ctx) => { /* ... */ } |
| 112 | } |
| 113 | ``` |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ## Reference Files |
| 118 | |
| 119 | Read these for detailed troubleshooting: |
| 120 | |
| 121 | - `references/common-issues.md` — 10 documented issues with sources and fixes |
| 122 | - `references/architecture.md` — Route priority, caching, Workers RPC |
| 123 | - `references/deployment.md` — CI/CD, auto-provisioning, gradual rollouts |