Vue.js Patterns and Best Practices
Comprehensive guide for Vue.js 3 development using Composition API (<script setup>), covering component design, reactivity, state management, routing, testing, and SSR patterns. Nuxt-specific guidance is included where it differs from vanilla Vue.
When to Activate
Activate this skill when:
- The project uses Vue.js (any version), Nuxt, Vite + Vue, or Pinia.
- The user asks about Vue component architecture, composables, reactivity, or state management.
- Reviewing Vue Single-File Components (
.vuefiles). - Setting up Vue Router, Pinia stores, or Vite/Vitest configuration.
- Discussing Vue-specific performance, security, or SSR patterns.
1. Project Structure
Recommended Layout (Feature-First)
File Naming
2. Component Architecture
Single-File Component Order
Presentational vs Container
- Container components: Own data fetching, state, and side effects. Render presentational components.
- Presentational components: Receive props, emit events. No API calls, no store access. Pure rendering.
Props Best Practices
- Always provide
type, andrequired/defaultwhere appropriate. - Boolean props:
isXxx,hasXxx,canXxx. - Never mutate props — emit events instead.
- For v-model binding, use
defineModel()(Vue 3.4+) ormodelValue+update:modelValue.
Events
- Use kebab-case in templates (
@update:model-value). - Use camelCase in script (
emit("update:modelValue", val)).
3. Composables (Reusable Logic)
Structure
Rules
- Must start with
useprefix. - Return reactive values (
ref,computed,reactive), never plain primitives. - Accept reactive inputs via
MaybeRef/toRef()/toValue(). - Clean up side effects in
onUnmountedor watcheronCleanup. - No module-scope side effects.
vs Mixins
Composables replace Vue 2 mixins entirely:
- Mixins: Opaque data flow, source-of-truth collisions, name conflicts.
- Composables: Explicit imports, clear return values, composable and tree-shakable.
4. State Management
When to Use What
Pinia Setup Store (Preferred)
- Use Setup Store syntax (not Options Store).
- Prefer actions for business-level mutations and
$patch()for grouped updates. - Every async action: handle loading + success + error.
5. Vue Router
Route Definitions
Navigation Guards
Reactive Route Params
When a component stays mounted but route params change:
6. Template Patterns
Template Syntax
7. Performance
8. Testing
Stack
- Vitest for unit and component tests
- Vue Test Utils for mounting and interaction
- @pinia/testing for store mocking
- Playwright for E2E
Component Test Pattern
9. Nuxt-Specific Patterns
Auto-Imports
Nuxt auto-imports ref, computed, watch, useFetch, useAsyncData, etc. Use them directly without importing. For non-Nuxt projects, always import explicitly.
useAsyncData / useFetch
Server Routes
Runtime Config
10. Vue 3.5+ New APIs
Reactive Props Destructure
Vue 3.5 stabilized reactive props destructure — destructured variables from defineProps() are automatically reactive:
useTemplateRef()
Replace name-matched plain refs with useTemplateRef() for template references:
Supports dynamic ref IDs: useTemplateRef(dynamicRefId).
onWatcherCleanup()
Globally importable watcher cleanup API (Vue 3.5+). It must be called synchronously inside the watcher callback:
useId()
SSR-stable unique ID generation for form elements and accessibility:
defer Teleport
<Teleport defer> allows teleporting to targets rendered in the same cycle:
Lazy Hydration (SSR)
defineAsyncComponent() now supports hydrate strategy:
Anti-Patterns
Related Skills
accessibility— ARIA, semantic HTML, focus managementfrontend-patterns— Cross-framework frontend architecturetypescript— TypeScript best practices applied to Vue projectscoding-standards— General code quality standards

