Cloudflare Worker (workers.cloudflare.com). Use this skill for ANY Cloudflare Worker request — reading, creating, updating, and deleting data. Whenever a task involves Cloudflare Worker, use this skill instead of calling the API directly.
设计与多媒体
scaffold-nuxt-cloudflare-app
试用An agent skill that scaffolds a new, production-oriented full-stack app on the latest version of Nuxt, deployed to Cloudflare Workers via Wrangler — from natural language descriptions like "build me a blog on Cloudflare".
它能做什么
Scaffold a new full-stack app on the latest version of Nuxt, deployable to Cloudflare Workers via Wrangler, with NuxtHub for D1/KV/Blob bindings. UI kit is a choice — Nuxt UI (Tailwind-based, default) or Antdv Next (Ant Design system), each with an official Nuxt module. Nuxt Content and i18n are opt-in only (blog/CMS content, or explicit multi-lingual requirement, respectively) — plus SEO, Drizzle, Vitest, pnpm. Use when creating a brand-new Nuxt app, or when asked to set up a Nuxt-on-Cloudflare project.
技能文档
Nuxt + Cloudflare App Scaffold
This skill scaffolds an SEO-optimized app on the latest version of Nuxt, deployed to Cloudflare Workers via Wrangler — content-driven and/or i18n-ready only when the request actually calls for that (see §1). NuxtHub (@nuxthub/core) is part of the stack too, but only as the binding/runtime layer for D1, KV, Blob, etc. and local dev emulation — it is not the deploy mechanism (see §7). This is not a minimal nuxi init — it's an opinionated, production-oriented stack. Only include the pieces the new app actually needs (see the decision step below); don't cargo-cult every module into a project that doesn't want them.
This skill owns the scaffolding decisions (which modules, how they're wired into nuxt.config.ts/directory structure/deployment) — enough on its own to produce a working app end to end. It doesn't cover deep per-module usage (which Nuxt UI/Antdv Next component to reach for, advanced content.config.ts/query patterns, theming, forms) — that's what the separate nuxt-ui, antdv-next, and nuxt-content skills are for, if they happen to be installed in this environment. They are not bundled with this skill and most environments running this skill won't have them — check your actual available-skills listing before ever telling a user "load skill X"; never assume one of these three exists. When one isn't present, don't stall or guess — this skill's own inline guidance (§4, §8) plus each project's official docs (ui.nuxt.com, antdv-next.com, content.nuxt.com) are sufficient to complete the scaffold and get a working starting point.
Always scaffold with the latest Nuxt release (nuxi init pulls it automatically) — don't assume the major version is still 4. Check npm view nuxt version or the scaffolded package.json if you need to confirm which major landed, since structural conventions (like the app/ srcDir default introduced in Nuxt 4) can change between majors.
1. Clarify scope before scaffolding
Don't ask the user about things you can infer from their request. Only ask (via AskUserQuestion, once, batched) what genuinely isn't decidable from context:
- App name + domain — needed for
site.name/site.urlin nuxt.config and thewrangler.jsoncproject name. - Which UI kit? → Nuxt UI (Tailwind-based, official
@nuxt/uimodule, this skill's default) or Antdv Next (Ant Design's Vue 3 component system, official@antdv-next/nuxtmodule). See §4 for scaffold-time wiring. Default to Nuxt UI unless the user names Ant Design/Antdv or an existing design system that maps to it. The two are mutually exclusive — never install both. - Does it need a database? → Drizzle + D1, accessed at runtime via NuxtHub's
hub:dbbinding (see §9), or skipserver/db/entirely for a static/content-only app. - Nuxt Content is opt-in, not default. Only include
@nuxt/content+content.config.ts+content/dir if the user's request mentions a blog, a CMS, or markdown/text content authoring. Absent that, skip it — most apps (tools, dashboards, internal apps) have no need for a file-based content layer. - i18n is opt-in, not default. Only include
@nuxtjs/i18n+i18n/locales/*.jsonif the user explicitly says the app needs to be multi-lingual/multi-language/localized. Absent that, build single-locale and skip i18n entirely — don't add it speculatively "in case" translation comes up later. - Monetization/analytics (AdSense, GA, cookie consent) — only wire these up if the user mentions ads/analytics; don't add tracking to an app that doesn't want it.
Skip modules that don't apply rather than stubbing them out disabled — an app without a DB should have no server/db/ folder, no wrangler.jsonc d1_databases block, no drizzle-kit/better-sqlite3/@libsql/client deps.
2. Scaffold the base project
pnpm dlx nuxi@latest init
cd
nuxi@latest always pulls the current latest Nuxt release — don't pin an older major. As of Nuxt 4, the default srcDir is app/; confirm app/app.vue exists after scaffolding. If a newer major changed this default, or the scaffold produced a flatter layout (top-level pages/, components/), move everything app-facing under app/ to match this skill's layout (see directory-structure reference) unless the new Nuxt version's own convention has moved on.
Set the package manager explicitly and pin native-build allowlists (Cloudflare's build environment needs this to build better-sqlite3/sharp from source rather than silently skipping the postinstall):
// pnpm-workspace.yaml
onlyBuiltDependencies:
- better-sqlite3 // only if using a local sqlite DB for dev
- sharp // only if using @nuxt/image
ignoredBuiltDependencies:
- '@parcel/watcher'
- '@tailwindcss/oxide'
- esbuild
- unrs-resolver
- vue-demi
Add "packageManager": "pnpm@" to package.json (match whatever pnpm version is installed locally — check with pnpm -v).
3. Install modules — pick from this table, don't install blindly
| Concern | Module(s) | Include when |
|---|---|---|
| UI kit (pick exactly one) | @nuxt/ui or @antdv-next/nuxt (+ antdv-next, @antdv-next/icons) | always — see §4 for setup |
| Images | @nuxt/image | any app with user-facing images; needs sharp |
| Markdown content | @nuxt/content (v3) | opt-in — only if the user mentions a blog, a CMS, or text-content authoring |
| i18n | @nuxtjs/i18n | opt-in — only if the user explicitly says multi-lingual/multi-language/localization |
| SEO bundle | @nuxtjs/seo | almost always — pulls in sitemap, robots, OG image, schema.org as one meta-module |
| Cloudflare bindings (D1/KV/Blob) + local dev emulation | @nuxthub/core | always, for any app targeting Cloudflare — provides hub:db/hub:kv/hub:blob imports and Miniflare-backed local dev; deployment itself is Wrangler, not this module — see §7 |
| Reactive utils | @vueuse/nuxt | almost always |
| Motion/animation | motion-v/nuxt | if the UI needs transitions/animation primitives |
| Analytics | nuxt-gtag, @nuxt/scripts | only if the user wants GA/AdSense |
| Cookie consent | nuxt-simple-cookie-consent | only if analytics/ads are present and consent is needed |
| AI-agent discoverability | nuxt-llms, nuxt-ai-ready | only if the app should expose /llms.txt and be crawlable by AI agents |
| Social share buttons | @stefanobartoletti/nuxt-social-share | only for content/blog sites |
| Linting | @nuxt/eslint | always |
| DB layer | drizzle-orm, drizzle-kit, better-sqlite3 (dev), @libsql/client | only if the app has a DB |
| Testing | @nuxt/test-utils, vitest, @vue/test-utils, @vitejs/plugin-vue, happy-dom | always |
# swap @nuxt/ui for @antdv-next/nuxt antdv-next @antdv-next/icons if that's the chosen UI kit
pnpm add @nuxt/ui @nuxt/image @nuxtjs/seo @nuxthub/core @vueuse/nuxt
pnpm add -D @nuxt/eslint @nuxt/test-utils @vitejs/plugin-vue @vue/test-utils vitest happy-dom
# then add only the optional modules selected in step 1
4. Wire up the UI kit
Both options are official Nuxt modules with auto-registered components — the wiring is more similar than different. This section covers the scaffold-time wiring only; if a nuxt-ui or antdv-next skill happens to be installed (check the available-skills listing — don't assume), it's the better source for anything component-level afterward: which component fits a given UI need, theming/design-system work, forms, layouts. If not installed, the official docs linked in each option below cover the same ground.
Option A: Nuxt UI (default)
- Add
'@nuxt/ui'tomodulesinnuxt.config.ts(seenuxt.config.example.ts). - Import its CSS in
app/assets/css/main.css:@import "tailwindcss"; @import "@nuxt/ui"; - Wrap the root component in
UApp— required for toasts, tooltips, and programmatic overlays to work at all, easy to forget since nothing errors loudly if it's missing:<!-- app/app.vue -->
Components auto-import with a U prefix (UButton, UCard, ...); theming goes through app/app.config.ts. For anything beyond this — component selection, design-system/forms/layout/recipe guidance — use the nuxt-ui skill if it's installed; otherwise ui.nuxt.com covers the same ground, and Nuxt UI also ships an MCP server worth setting up for live component API lookup regardless of which skill situation applies.
Option B: Antdv Next
antdv-next is Ant Design's Vue 3 component library, with an official Nuxt module, @antdv-next/nuxt (requires Nuxt ≥ 4.0.0, Vue ≥ 3.5.0):
- Install:
npx nuxi module add @antdv-next/nuxt(or manually:pnpm add -D @antdv-next/nuxt antdv-next @antdv-next/icons— the upstream docs list all three as devDependencies even though components render at runtime; Nuxt modules commonly work this way). Drop@nuxt/uiand its Tailwind CSS import instead — don't run both design systems at once. - Configure via the
antdkey (nothub, notui):// nuxt.config.ts export default defineNuxtConfig({ modules: ['@antdv-next/nuxt'], antd: { icon: true } // enables auto-registration of @antdv-next/icons }) - Add reset styles (and the zero-runtime theme CSS, recommended over runtime CSS-in-JS for SSR):
export default defineNuxtConfig({ css: ['antdv-next/dist/reset.css', 'antdv-next/dist/antd.css'] })
Components auto-register with an A prefix (AButton, ATable, ...) — same auto-import ergonomics as Nuxt UI's U prefix, just a different design system. antd.prefix/antd.include/antd.exclude (and the icon equivalents) narrow what gets registered if bundle size matters. For component API/props/slots/demos/theme-token lookups, use the antdv-next skill if it's installed; otherwise www.antdv-next.com has the same per-component docs.
5. Lay out the directory structure
Use this exact layout — see the directory-structure reference for the annotated full tree. Summary:
app/—app.vue,app.config.ts,error.vue,assets/css/main.css,components/,composables/,layouts/,pages/,plugins/,utils/server/—api/(file-based,*.get.ts/*.post.tssuffix = HTTP method),db/schema.ts+db/migrations/sqlite/(Drizzle, only if DB is in scope),middleware/,plugins/,repositories/,utils/shared/types/— types used by bothapp/andserver/(Nuxt'sshared/auto-import layer, introduced in Nuxt 4)content//...+content.config.ts— only if@nuxt/contentis in scope; one subdirectory per locale if i18n is also in scopei18n/locales/*.json— only if@nuxtjs/i18nis in scopetests/app/,tests/server/,tests/setup.ts+vitest.config.tspublic/— static assets,favicon.ico,.well-known/- Root config:
nuxt.config.ts,wrangler.jsonc,eslint.config.mjs,tsconfig.json(references-only, pointing at.nuxt/tsconfig.*.json),.nuxtrc,.env.example
6. Wire up nuxt.config.ts
Use nuxt.config.example.ts as the template — copy it, then strip out any module blocks for things not selected in step 1. Key points that are easy to miss:
modulesorder doesn't matter functionally but keep it grouped (UI/content → i18n → SEO/analytics → hub) for readability.site.url/site.name(from@nuxtjs/seo) must be set to the real domain — sitemap, OG image, and schema.org all derive from this.hub: { db: { dialect: 'sqlite', applyMigrationsDuringBuild: false } }— only when a DB is in scope. This is NuxtHub's binding config (it's what makes thehub:dbimport resolve to the right D1 instance locally vs. in production) — it has nothing to do with how the app gets deployed.applyMigrationsDuringBuild: falseis deliberate: migrations run as an explicit step (npx nuxt db migrate, §9), not silently during every build. This minimal shape assumes bindings come from a hand-maintainedwrangler.jsonc(§7); NuxtHub also accepts a fullerdb: { dialect, driver: 'd1', connection: { databaseId } }shape that lets it auto-generatewrangler.jsoninstead — seenuxthub-deployment.md.compatibilityDate— set to the current date at scaffold time; Nitro/Cloudflare use this to pin runtime behavior.routeRulesfor any public API surface that needs CORS opened up (see the commented/api/tools/**example innuxt.config.example.ts) — CORS is closed by default, open it explicitly per-route, not globally.nitro.prerender.routes+crawlLinks: trueif the site should be statically prerendered where possible.- If i18n is in scope, use the pattern in
nuxt.config.example.ts: aLOCALESconst at the top of the file,prefix_except_defaultstrategy, anddetectBrowserLanguagewithredirectOn: 'root'.
7. Wire up Cloudflare bindings (NuxtHub) and deployment (Wrangler)
These are two separate concerns — don't conflate them:
- NuxtHub (
@nuxthub/core) gives the app its Cloudflare bindings and local dev emulation: D1/KV/R2, accessed via thehub:db/hub:kv/hub:blobvirtual-module imports (or the equivalent@nuxthub/dbpackage import — see §9), plus Miniflare-backed local dev. This is a runtime/dev-experience layer, configured via thehubblock innuxt.config.ts(§6). - Wrangler is what actually builds and deploys the app to Cloudflare Workers, configured via
wrangler.jsonc.npx nuxthub deployand NuxtHub Admin are deprecated as of NuxtHub v0.10 (Admin sunsets 2025-12-31) —wrangler deployis the only supported deploy path now, not a preference of this skill's.
NuxtHub can actually auto-generate wrangler.json from the hub block at build time, so a manual wrangler.jsonc isn't strictly required for a minimal single-environment app — see nuxthub-deployment.md for that shape. This skill still defaults to a hand-maintained wrangler.jsonc because observability config and the multi-environment/preview setup below aren't covered by auto-generation.
Copy wrangler.example.jsonc, then:
- Set
nameto the Cloudflare Workers project name (must be globally unique on the account). - Set
compatibility_dateto today; keepcompatibility_flags: ["nodejs_compat", "nodejs_als"]— both are required by NuxtHub's runtime bindings. - If a DB is in scope, keep the
d1_databasesblock but leavedatabase_idblank/placeholder until the DB is actually provisioned (wrangler d1 createwill produce the real ID — never fabricate one). Same pattern forkv_namespaces/r2_bucketsif KV/Blob are in scope — seenuxthub-deployment.mdfor the required binding names (DB,KV,CACHE,BLOB). migrations_dir: "server/db/migrations/sqlite"must match wherever migrations are emitted (see §9 — vianpx nuxt db generate, not rawdrizzle-kit).
Set nitro.preset: 'cloudflare_module' in nuxt.config.ts so nuxt build emits Nitro's Cloudflare Workers output shape. Deploy with Wrangler directly:
pnpm build
npx wrangler deploy
Alternatively, connect the repo to Cloudflare Workers Builds (git-integrated CI/CD, configured in the Cloudflare dashboard rather than the codebase) so pushes to the deploy branch build and deploy automatically — check the target Cloudflare account/dashboard for whether this is already set up before assuming a manual wrangler deploy workflow is needed. For anything beyond this basic flow (Pages instead of Workers, secrets, custom domains, etc.), use a cloudflare/wrangler skill if one is installed in this environment; otherwise developers.cloudflare.com/workers is the authoritative source — don't assume such a skill exists.
Preview environment
Set this up alongside production rather than bolting it on later — there are two independent pieces:
1. A named Wrangler environment, isolated from production data. Add an env.preview block to wrangler.jsonc (see wrangler.example.jsonc) with its own Worker name and, if a DB is in scope, its own D1 binding pointing at a separate database. Bindings are not inherited between environments — this cuts both ways: skipping it doesn't mean preview falls back to the production database, it means the DB binding is simply undefined in that environment and hub:db calls fail. Give preview its own database rather than leaving the binding out.
{
"name": "",
// ...production-level config...
"env": {
"preview": {
"name": "-preview",
"vars": { "NUXT_PUBLIC_SITE_URL": "https://-preview..workers.dev" },
"d1_databases": [
{
"binding": "DB",
"database_name": "-preview",
"database_id": "",
"migrations_dir": "server/db/migrations/sqlite"
}
]
}
}
}
Build and deploy against it using both the CLOUDFLARE_ENV build-time variable and Wrangler's --env deploy-time flag (NuxtHub's Cloudflare integration reads the former at build time; Wrangler reads the latter at deploy time — pass both rather than relying on just one):
CLOUDFLARE_ENV=preview npx nuxi build
npx wrangler deploy --env preview # or: wrangler dev --env preview, for local preview-env testing
NuxtHub's hub:db/hub:kv/hub:blob need no separate config for this — they just resolve to whatever binding is active for the environment that was built/deployed against.
2. Cloudflare Workers Builds' native per-branch/PR preview URLs. Since this is git-integrated CI/CD configured in the Cloudflare dashboard (not the codebase), it's something to point out to the user rather than something this skill can wire up directly — but the shape to set up is two build triggers:
- Production trigger: branch = the production branch (e.g.
main), deploy commandnpx wrangler deploy. - Preview trigger: all other branches (
branch_includes: ["*"],branch_excludes: ["main"]), withCLOUDFLARE_ENV=previewset as a build environment variable and deploy commandnpx wrangler versions upload --env preview—versions upload(notdeploy) uploads a version and gets a preview URL without promoting it to the live/production deployment.
Each PR then gets its own stable branch-based preview URL (-..workers.dev) posted as a PR comment, plus a per-commit versioned preview URL — both automatic once the triggers exist, no extra per-PR config. Preview URLs are opt-in (a security default changed in Sept 2025): the Worker needs its workers.dev subdomain and Preview URLs toggle enabled in Settings → Domains & Routes, or the URLs simply won't appear even though builds succeed.
Note this is distinct from preview_database_id on a d1_databases binding — that field only affects local wrangler dev --remote, not git-triggered preview deployments; the env.preview block above is what actually isolates preview deployments.
For anything else — Vercel/Netlify/Deno providers, D1-over-HTTP for non-Cloudflare hosts, KV/Blob provider tables — see nuxthub-deployment.md and its upstream source.
8. Content + i18n (if in scope)
content.config.ts: onedefineCollectionper content type (e.g.article,about),type: 'page',sourceas an array of{ include: '/' }per locale, and a Zodschemathat always includes the@nuxtjs/seocontent schemas (defineRobotsSchema,defineSitemapSchema,defineOgImageSchema,defineSchemaOrgSchema) alongside the collection's own fields. Seecontent.config.example.ts. This SEO-schema layering is scaffold-specific (this skill's own pattern) — for everything else about collections,queryCollection, Markdown/MDC rendering, or content databases, use thenuxt-contentskill if it's installed, otherwise content.nuxt.com covers the same ground.- Locale files live in
i18n/locales/.json; content lives incontent//...mirroring the same locale codes. - Don't scaffold a long list of locales speculatively — start with what the user actually needs (often just
en) and note that more can be added later by extending theLOCALESarray + adding a locale dir.
9. Database (if in scope)
server/db/schema.ts— Drizzle schema usingsqliteTable(D1 is SQLite-compatible).server/repositories/— one file per aggregate/entity, wrapping raw Drizzle queries, e.g.import { db, schema } from '@nuxthub/db', soserver/api/*handlers stay thin.- Access the DB via the
hub:dbvirtual-module import —import { db, schema } from 'hub:db'— or the equivalent@nuxthub/dbpackage import; both resolve to the same D1 binding wiring for local dev (via Miniflare) and production.db/schemaare also auto-imported server-side, so an explicit import often isn't even needed. Don't reach for the olderhubDatabase()composable in new code — it predates the current virtual-module API. - Generate/apply migrations with the
nuxt dbCLI (from@nuxthub/db, wraps Drizzle Kit), not rawdrizzle-kitcommands:npx nuxt db generate,npx nuxt db migrate,npx nuxt db sql "". Output lands in the sameserver/db/migrations/sqlite/+meta/_journal.jsonshape either way — seenuxthub-deployment.md. - Local dev DB state lives under
.data/(gitignored) — don't commit it.
10. Testing + linting
vitest.config.ts:environment: 'node',setupFiles: ['./tests/setup.ts'],@vitejs/plugin-vueplugin — even for a Nuxt app, most unit tests run fine under plain Vitest; reach for@nuxt/test-utils'ssetup()only for tests that need the full Nuxt runtime context.eslint.config.mjs— thin wrapper around the generated.nuxt/eslint.config.mjs(@nuxt/eslintmodule generates this atnuxt prepare/devtime). Add project-specific rule overrides here, don't hand-roll a flat config from scratch.package.jsonscripts:dev,build,preview,postinstall: nuxt prepare,lint,lint:fix,typecheck: nuxt typecheck,test: vitest run.
11. Final checklist before handing back to the user
-
.env.exampledocuments every required runtime env var (at minimumNUXT_PUBLIC_SITE_URLif OG image generation needs it at build time). -
site.urlinnuxt.config.tsandnameinwrangler.jsoncreflect the real app, not the scaffold's placeholder values. - No leftover placeholder/example IDs (AdSense client ID, GA measurement ID, D1 database UUID, domain) — these must come from the new project's own accounts.
- Every module added in step 3 is actually used — no dead config blocks for skipped features.
- Only one UI kit is installed (
@nuxt/uior@antdv-next/nuxt, never both), and its integration matches §4 (module + Tailwind CSS import +UAppwrapper for Nuxt UI; module +antdconfig key + reset/theme CSS for Antdv Next). -
wrangler.jsonchas anenv.previewblock with its own Worker name (and its own D1/KV bindings if a DB is in scope) — not just a bare production config (§7 "Preview environment"). -
pnpm install && pnpm devruns clean before considering the scaffold done.
相关技能
Cloudflare Docs (developers.cloudflare.com). Use this skill for ANY Cloudflare Docs request — searching and reading data. Whenever a task involves Cloudflare Docs, use this skill instead of calling the API directly.
Deploy applications and infrastructure to Cloudflare using Workers, Pages, and related platform services. Use when the user asks to deploy, host, publish, or...
Deploy small, non-sensitive static sites to temporary Cloudflare Workers previews. Use when an intended user explicitly accepts Cloudflare terms and needs a short-lived workers.dev URL with a privately delivered Claim URL.
用 Wrangler CLI 在 Cloudflare 全球边缘网络上开发并部署 JavaScript、TypeScript、Python 或 Rust 代码。
Cloudflare Email Routing (cloudflare.com). Use this skill for ANY Cloudflare Email Routing request — reading, creating, updating, and deleting data. Whenever a task involves Cloudflare Email Routing, use this skill instead of calling the API directly.