All skills
hyf0 avatar

/vue-pinia-best-practices

@bc922e4 official
by hyf0hyf0/vue-skills2.9k stars
167

Pinia stores, state management patterns, store setup, and reactivity with stores.

Use this Skill: https://skilld.dev/gh/hyf0/vue-skills/vue-pinia-best-practices

This session only. Nothing lands on disk.

referencestate-use-pinia-for-large-apps.md

≈1.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Use Pinia for Large-Scale Vue Applications

Impact: MEDIUM - While Vue's Composition API allows creating simple reactive stores with reactive() and ref(), these hand-rolled solutions lack the tooling, conventions, and debugging capabilities needed for large-scale production applications. Pinia is the official Vue state management solution and should be used for any non-trivial application.

Task Checklist

  • Use Pinia for applications with shared state across multiple components
  • Use Pinia when team collaboration requires consistent patterns
  • Use Pinia when you need Vue DevTools state debugging
  • Hand-rolled reactive() is acceptable only for simple, single-developer apps
  • Migrate from Vuex to Pinia (Vuex is in maintenance mode)

When Hand-Rolled State is Acceptable

Simple reactive state is fine for:

  • Prototypes and proof-of-concepts
  • Very small applications with minimal shared state
  • Single-developer projects with limited scope
  • Learning purposes
// Simple hand-rolled store - OK for small apps
import { reactive, readonly } from 'vue'

export const store = reactive({
  count: 0,
  increment() {
    this.count++
  }
})

When to Use Pinia

Use Pinia when you have any of these requirements:

1. DevTools Integration

Pinia provides rich Vue DevTools support:

  • Timeline of state changes
  • State inspection and editing
  • Time-travel debugging
  • Action tracking
// Pinia store - fully visible in DevTools
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.count++  // Tracked in DevTools timeline
    }
  }
})

2. TypeScript Support

Pinia has excellent TypeScript inference:

// Full type inference without extra configuration
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    name: '',
    age: 0,
    preferences: {
      theme: 'light' as 'light' | 'dark'
    }
  }),

  getters: {
    // Return type is inferred
    displayName: (state) => state.name || 'Anonymous'
  },

  actions: {
    // Full parameter type checking
    setUser(name: string, age: number) {
      this.name = name
      this.age = age
    }
  }
})

// Usage is fully typed
const userStore = useUserStore()
userStore.name  // string
userStore.displayName  // string
userStore.setUser('John', 30)  // Type-checked

3. Team Collaboration

Pinia enforces conventions that help teams:

// Consistent structure across all stores
// stores/products.js
export const useProductsStore = defineStore('products', {
  state: () => ({ /* ... */ }),
  getters: { /* ... */ },
  actions: { /* ... */ }
})

// stores/cart.js - Same structure
export const useCartStore = defineStore('cart', {
  state: () => ({ /* ... */ }),
  getters: { /* ... */ },
  actions: { /* ... */ }
})

4. Hot Module Replacement (HMR)

Pinia supports HMR out of the box - state persists during development:

// State survives code changes during development
// No need to re-login or re-create state after every edit

5. Server-Side Rendering (SSR)

Pinia handles SSR state correctly:

// Automatic per-request state isolation
// State serialization for hydration
// No cross-request pollution

6. Plugin Ecosystem

Pinia supports plugins for common needs:

import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

// Now stores can persist to localStorage
export const useSettingsStore = defineStore('settings', {
  state: () => ({
    theme: 'light',
    language: 'en'
  }),
  persist: true  // Automatically saved/restored
})

Pinia vs Hand-Rolled Comparison

Feature Hand-Rolled reactive() Pinia
DevTools integration No Yes
TypeScript inference Manual Automatic
HMR support No Yes
SSR support Manual Built-in
Plugins No Yes
Time-travel debugging No Yes
Learning curve Lower Slightly higher
Bundle size Smaller ~1KB
Team conventions None Enforced

Migration from Vuex

Vuex is now in maintenance mode. Migrate to Pinia for new features:

// Vuex (legacy)
export default createStore({
  state: { count: 0 },
  mutations: {
    INCREMENT(state) { state.count++ }
  },
  actions: {
    increment({ commit }) { commit('INCREMENT') }
  }
})

// Pinia (recommended)
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() { this.count++ }  // No mutations needed!
  }
})

Pinia advantages over Vuex:

  • No mutations (simpler mental model)
  • Better TypeScript support
  • No nested modules complexity
  • Smaller bundle size
  • Composition API style available

Pinia Store Styles

Choose the style that fits your team:

Options Style (Similar to Options API)

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2
  },
  actions: {
    increment() { this.count++ }
  }
})

Setup Style (Composition API)

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const double = computed(() => count.value * 2)
  function increment() { count.value++ }

  return { count, double, increment }
})

Quick Start

npm install pinia
// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
app.use(createPinia())
app.mount('#app')

Reference

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides educational content and best practices for Pinia state management in Vue.js applications. It is a documentation-focused skill with no malicious patterns detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    7 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at bc922e4. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 8 months ago
version
1.0.0
author
github.com/vuejs-ai

README badge

README badge for hyf0/vue-skills/vue-pinia-best-practices

Teaches Pinia store setup, reactivity patterns, and state management conventions for Vue applications. Covers common mistakes like destructuring breaking reactivity, setup stores missing state in DevTools, and losing method context in templates.

Generated from the current SKILL.md.

What does this skill cover?
Pinia store setup, state management patterns, reactivity gotchas, and common errors like getActivePinia and broken destructuring in Vue components.
Does this skill address SSR with Pinia?
Yes. It includes guidance on setup stores missing state in DevTools or SSR environments.
How does this handle filter state across page refreshes?
The skill references patterns for persisting ephemeral filters using URL state rather than relying on store alone.
Does this cover store method binding issues?
Yes. It addresses the gotcha where store methods lose context when called directly in templates and explains the parentheses solution.

Generated from the current SKILL.md. These answers refresh after source changes.