dev-basic-cloudflare-webapp
The house tech stack for a new web project on Cloudflare — framework, lint, test, CI, docs, and repo conventions, with copy-ready config templates. Cloudflare is the default infra and backend (Workers
SKILL.mdskills/dev-basic-cloudflare-webapp/SKILL.md
GitHubCloudflare Web App — House Stack
The reference for what to pick when starting a new web project. Every choice here is already running in production across the other repos, so matching it means CI, hooks, deploy, and agent workflows all behave the way they do elsewhere.
Cloudflare is the infra and the backend. Workers, D1, KV, R2, Durable Objects, Workers AI, Queues. Not AWS, not Vercel, not Netlify, not Supabase. Reach outside Cloudflare only for something Cloudflare genuinely lacks (Stripe, Resend, npm registry) and say so explicitly.
Two modes
Reference mode (default) — the user described a project and wants the stack. Read the tables below, pick the project shape, read the reference files that matter for that shape, and report the recommended stack with concrete versions and file names. Do not write files.
Scaffold mode — the user passed --scaffold or asked to actually create the
project. Do reference mode first, confirm the shape, then copy from
assets/templates/ and adapt. See "Scaffolding" below.
Step 1 — Pick the project shape
| Shape | When | Frontend | Deploy target |
|---|---|---|---|
| Content site | Marketing, blog, portfolio, landing | zfb + Preact + Tailwind v4 | Workers Static Assets |
| Docs site | Reference docs, manuals, changelog | zudo-doc (a zfb preset) | Workers Static Assets |
| SSR app | Auth, forms, DB-backed pages | zfb SSR routes (prerender = false) + CF adapter |
Workers Static Assets + bindings |
| API / worker | JSON API, webhook, proxy, cron, agent | Hono on Workers, no frontend | Workers |
| Interactive app | Editor, dashboard, canvas, heavy client state | Vite + React + Tailwind v4 | Workers Static Assets (+ separate API worker) |
| Library / CLI | Publishable npm package | none | npm — use /dev-npm-package instead |
Mixed projects are normal: a pnpm workspace with a zfb site at the root and
worker packages under workers/*. Split when the deploy units differ.
Step 2 — The non-negotiable base
Every repo gets these regardless of shape. Details and rationale in references/tooling.md.
| Concern | Choice |
|---|---|
| Package manager | pnpm, packageManager pinned in package.json, engines.node >= 22 |
| Language | TypeScript, strict: true |
| Unit tests | vitest |
| Worker tests | @cloudflare/vitest-pool-workers |
| E2E | Playwright |
| Format | Prettier for code, @takazudo/mdx-formatter for .md/.mdx |
| Lint | ESLint flat config (eslint.config.js) |
| Git hooks | lefthook (lefthook.yml) + prepare script |
| Pre-push gate | pnpm b4push — mirrors CI locally |
| CI | GitHub Actions, SHA-pinned actions |
| Deploy | wrangler deploy from GitHub Actions |
| Dep updates | Renovate (preferred) or Dependabot |
Step 3 — Read the reference for what you're deciding
Load only what the current decision needs.
references/stack.md — every library choice with its
rationale, plus the explicit do-not-use list (Pages, Next.js, AWS SDK, Prisma, Jest, styled-components, …). Read this for any "what should we use for X" question.
references/cloudflare.md —
wrangler.tomlanatomy, Workers Static Assets, bindings (D1/KV/R2/DO/AI/Queues/services), named environments, preview aliases, secrets vs vars, and the TOML/config gotchas that cost real debugging time.
references/ci.md — the standard workflow set, SHA pinning,
concurrency, self-skipping deploy jobs, PR preview comments, actionlint, security audit.
references/tooling.md — pnpm settings, workspace
layout, lefthook, prettier, eslint, mdx-formatter, design-token-lint, tsconfig, the b4push script.
references/testing.md — test levels and tiers, what
runs in b4push vs CI vs nightly, Playwright conventions.
references/conventions.md — directory layout,
CLAUDE.md, docs site, README, worktrees,.gitignore, scratch dirs.
For Cloudflare platform API detail (exact binding APIs, runtime limits,
current wrangler flags), defer to the Cloudflare plugin skills — /cloudflare:cloudflare,
/cloudflare:wrangler, /cloudflare:workers-best-practices,
/cloudflare:durable-objects, and /cloudflare:agents-sdk — they
retrieve live docs. This skill owns the opinion; those own the facts.
Step 4 — Report
Report as a short stack table (shape, framework, styling, data, tests, CI, deploy target) plus the list of files the project needs. Name the Cloudflare resources that must be provisioned (D1 database, KV namespace, R2 bucket, custom domain) and the secrets that must be set — these are manual, one-time, and easy to forget.
Scaffolding
Only in scaffold mode. Copy from assets/templates/ and adapt — every file
carries comments explaining the traps, so keep them.
| Template | Copy to | Notes |
|---|---|---|
package.json |
package.json |
Replace latest with resolved versions after the first install |
pnpm-workspace.yaml |
same | Delete if single-package |
npmrc |
.npmrc |
|
gitignore |
.gitignore |
|
prettierignore |
.prettierignore |
|
.prettierrc.json |
same | |
tsconfig.json |
same | |
lefthook.yml |
same | |
wrangler.toml |
same | Strip unused binding blocks |
.github/workflows/*.yml |
same | ci.yml, deploy.yml, actionlint.yml |
scripts/run-b4push.sh |
same | chmod +x; keep steps identical to ci.yml |
scripts/smoke.mjs |
same | Fill in EXPECTED with real page markers |
scripts/install-git-hooks.sh, scripts/hooks/pre-push |
same | chmod +x both |
cloudflare-setup.md |
docs/cloudflare-setup.md |
Three templates ship without their leading dot (npmrc, gitignore,
prettierignore) so they stay inert inside this skill's own repo — rename on
copy.
Then:
Replace every
__PROJECT_NAME__and__DOMAIN__placeholderWrite
README.mdandCLAUDE.md(outline inpnpm install, then confirmpnpm b4pushpasses before the first push
Do not invent Cloudflare resource ids. Leave REPLACE_ME plus the
wrangler ... create command that produces it — the deploy job self-skips until
the real id is committed.