What should a CLAUDE.md for Vue include?
A CLAUDE.md for Vue should list the npm scripts Claude Code can run, show where components, views, stores and composables live, and state your rules for <script setup>, props, list keys, state and tests. Keep it under 200 lines, as Anthropic's memory docs recommend, and add the gotchas that only exist in your app.
Vue projects vary more than most. The official scaffolding tool asks whether you want TypeScript, Vue Router, Pinia, Vitest, an end-to-end tool, ESLint and a formatter, so two Vue apps rarely have the same scripts. Claude cannot know which you picked until it reads package.json, and it may still mix in Options API code or Vuex patterns it has seen in older projects. A short CLAUDE.md settles those choices once.
The main template targets a Vue 3 app created with npm create vue@latest, as shown in the Vue quick start, with TypeScript, Router, Pinia, Vitest, Playwright and ESLint selected. A separate block below covers Nuxt 4. Folder names such as composables/ and rules such as "no Options API" are common choices, not requirements, so swap them for yours. For the file format itself, see what a CLAUDE.md file is.
The Vue CLAUDE.md template
Save this as CLAUDE.md at the root of your project, replace the angle-bracket placeholders, and remove any script your project does not have.
# <App name>
<One sentence: what this app does and who uses it.>
Stack: Vue 3.5, Vite, TypeScript, Vue Router, Pinia, Vitest, Playwright, ESLint.
Node ^22.18.0 or >=24.12.0. Package manager: npm.
## Commands
- Install: `npm install`
- Dev server: `npm run dev`
- Build: `npm run build` (runs type-check and the Vite build in parallel)
- Preview the production build: `npm run preview`
- Type check: `npm run type-check` (vue-tsc)
- Unit tests, single run: `npm run test:unit -- --run`
- One test file: `npm run test:unit -- --run src/components/__tests__/OrderCard.spec.ts`
- E2E: `npm run test:e2e` (Playwright)
- Lint: `npm run lint` (this runs eslint with --fix, so it edits files)
- Format: `npm run format`
- Done means: type-check, lint and the unit tests for touched files all pass
## Project structure
- `src/main.ts`: creates the app, installs router and Pinia
- `src/App.vue`: root component. `src/views/`: one component per route
- `src/router/index.ts`: all routes. Lazy-load views with `() => import(...)`
- `src/components/`: shared components. Tests in `__tests__/` next to them
- `src/stores/`: Pinia stores, one per domain, named `useXxxStore`
- `src/composables/`: reusable `useXxx()` functions
- `src/assets/`: processed by Vite. `public/`: copied as is
## Component rules
- Composition API with `<script setup lang="ts">`. No Options API in new code
- Typed props and events: `defineProps<{...}>()` and `defineEmits<{...}>()`
- Multi-word component names, PascalCase file names: `OrderCard.vue`
- Every `v-for` has a stable `:key`. Never put `v-if` on the same element as `v-for`
- Styles are `<style scoped>` unless the component is App.vue or a layout
- Keep template expressions simple; move logic into `computed`
## State and data
- Shared state lives in Pinia stores. No Vuex, no global reactive objects
- Components do not call `fetch` directly; use a store action or composable
- API base URL comes from `import.meta.env.VITE_API_URL`
## Security
- Never use `v-html` with user content
- Never build a template string from user input
- `VITE_` variables are bundled into the browser. No secrets in them
## Testing
- Vitest and @vue/test-utils for components and composables
- Test what the user sees: rendered text, emitted events, not internal refs
- Every bug fix comes with a test that failed before the fix
## Do not
- Do not add a dependency without asking
- Do not edit `vite.config.ts` or `tsconfig*.json` unless the task is about config
## Gotchas
- Vite does not type check. A page can render while types are broken
- `vitest` without `--run` can start in watch mode and never exit. Always pass `--run`
- <Your app's own surprises: auth flow, mocked API, feature flags>
What does each part of the template do?
Header and stack line. Naming Vue 3.5 and each library stops Claude from writing Vue 2 or Vuex code. The Node range is the one the quick start lists, and create-vue writes it into engines in package.json.
Commands. The script names come from the create-vue templates on the main branch of its GitHub repo, checked in October 2026, so confirm them against your own package.json: dev, build and preview in the base template, type-check running vue-tsc --build and a build that runs type-check in parallel with the Vite build when TypeScript is selected, test:unit running Vitest, test:e2e running Playwright, and a lint script that calls eslint . --fix --cache. That last detail is worth writing down, because Claude might run lint expecting a report and instead get edited files. The --run flag matters too: the Vitest CLI docs say plain vitest enters watch mode in a development environment and run mode only in CI or a non-interactive terminal.
Project structure. src/router/, src/views/ and src/stores/ match what create-vue generates when you add Router and Pinia. A composables/ folder is a common convention rather than a generated one. Lazy-loading route views is a project choice.
Component rules. The Vue introduction recommends going "with Composition API + Single-File Components" for full applications. The rules on multi-word names, detailed props, keyed v-for, avoiding v-if with v-for and scoped styles are the Priority A rules of the Vue style guide, and consistent file name casing (PascalCase or kebab-case) and simple template expressions come from its strongly recommended rules.
State and data. The state management guide says Pinia is maintained by the Vue core team, Vuex is in maintenance mode, and "It is recommended to use Pinia for new applications." Routing all fetching through stores or composables is a team choice that keeps components easy to test.
Security. The Vue security guide states the core rule: "never use non-trusted content as your component template", and warns that user-provided HTML is never fully safe outside a sandboxed iframe.
Testing and gotchas. The Vue testing guide recommends Vitest for Vite projects and @vue/test-utils for mounting components. The TypeScript guide explains that the Vite dev server and bundler "do not perform any type-checking", which is why type-check is part of done.
How do you write a CLAUDE.md for Nuxt instead?
Nuxt changes enough that the Vue template above does the wrong thing in a Nuxt app: it has its own CLI, auto-imports, server routes and runtime config. Use this block instead. The commands come from the Nuxt package.json docs and the typecheck command page.
# <App name>
Stack: Nuxt 4, Vue 3, TypeScript, Pinia, Vitest with @nuxt/test-utils. Node 22 or newer.
## Commands
- Dev: `npm run dev` (nuxt dev). Build: `npm run build`. Static: `npm run generate`
- Preview a build locally: `npm run preview` (loads .env)
- Type check: `npx nuxt typecheck`
- Tests: `npx vitest run`
- Done means: typecheck and tests pass
## Structure
- `app/pages/`: file-based routes. `app/layouts/`, `app/middleware/`, `app/plugins/`
- `app/components/`, `app/composables/`, `app/utils/`: auto-imported. Do not add imports for them
- `server/api/`: server endpoints. `shared/`: code used by app and server
## Rules
- Fetch data in components with `useFetch` or `useAsyncData`, not bare `$fetch` in setup
- Config goes in `runtimeConfig` in nuxt.config.ts. Secrets stay outside `public`
- Override runtimeConfig in production with `NUXT_...` env vars; the built server does not read `.env`
The data fetching rule comes from the Nuxt data fetching guide, which warns that $fetch in a component's setup "may cause data to be fetched twice, once on the server" and once on the client. The runtime config docs say only uppercase variables starting with NUXT_ can override runtime config, and the .env docs note that .env files are not used in production. Nuxt also runs an MCP server for its documentation; the Nuxt MCP page gives claude mcp add --transport http nuxt https://nuxt.com/mcp for Claude Code.
Which agent mistakes does the template prevent?
| Without the rule | Line in the template that prevents it |
|---|---|
| A new component written with the Options API in a Composition API codebase | "Composition API with <script setup lang="ts">" |
| A list renders without keys and reorders wrongly | "Every v-for has a stable :key" |
| Claude declares done because the page loads, with type errors left behind | "Vite does not type check" and the done line |
| A test command hangs in watch mode | "npm run test:unit -- --run" |
An API key put in a VITE_ variable and shipped to the browser |
"VITE_ variables are bundled into the browser" |
$fetch in a Nuxt page causing a double request |
"Fetch data in components with useFetch" |
How do you adapt it to your project?
- pnpm, Yarn or Bun: replace
npm runeverywhere. Wrong commands cost more than missing ones. - JavaScript instead of TypeScript: drop the type-check line and use
definePropswith runtime declarations. - Oxlint or oxfmt: create-vue can set these up too; copy the exact script names from your
package.json. - Vue inside Laravel or another backend: put this file in the frontend folder, or merge the component rules into the backend's CLAUDE.md. The Laravel template covers the PHP side.
- Rules for one area: create
.claude/rules/stores.mdwithpaths: ["src/stores/**/*.ts"]in the frontmatter, so Pinia rules load only when Claude edits a store.
After saving, run /context in a Claude Code session and check that CLAUDE.md appears under Memory files. If you have no file yet, /init drafts one from your code that you can merge with these sections.
Should you write an AGENTS.md version too?
If your team also uses Codex, Cursor or Copilot, keep the shared rules in AGENTS.md and make CLAUDE.md a short file that imports it. Claude Code reads AGENTS.md on its own only when there is no CLAUDE.md or CLAUDE.local.md, and only from v2.1.277:
@AGENTS.md
## Claude Code only
- Use plan mode before changing the router or auth store
- Run `/doctor prompt-audit` after editing AGENTS.md or this file
Claude reads the imported file first, then the lines below it. The AGENTS.md guide covers which tools read the file, and CLAUDE.md vs AGENTS.md compares the two.
How do you keep a Vue CLAUDE.md useful?
Add a line when Claude repeats a mistake, and remove lines it follows without prompting. When you change a script in package.json, change it in CLAUDE.md in the same commit. /doctor prompt-audit (Claude Code v2.1.283 or later) reports outdated or conflicting instructions with proposed edits, and changes nothing until you approve. CLAUDE.md guides Claude but cannot block anything, so for hard limits use a hook.
If you build Vue apps often, keep the template somewhere you can reuse it. Kipt stores prompts and Agent Skills as Markdown in a private GitHub repo you own, so you could save the template as a prompt with blanks like {{package_manager:npm}} and fill them per project. The Vue prompts collection has task prompts to use alongside it, and the Next.js template covers the React side.