Pinia v3 Vue state management with defineStore, getters, actions. Use for Vue 3 stores, Nuxt SSR, Vuex migration, or encountering store composition, hydration, testing errors.
npx skills add https://github.com/secondsky/claude-skills --skill pinia-v3
Status: Production Ready ✅
Last Updated: 2025-11-11
Dependencies: Vue 3 (or Vue 2.7 with @vue/composition-api)
Latest Versions: pinia@^3.0.4, @pinia/nuxt@^0.11.2, @pinia/testing@^1.0.2
bun add pinia
# or
bun add pinia
# or
bun add pinia
For Vue <2.7 users: Also install @vue/composition-api with bun add @vue/composition-api
Why this matters:
// main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
CRITICAL:
app.use(pinia) before mounting the app// stores/counter.ts
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
name: 'Eduardo'
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>
<template>
<div>
<p>Count: {{ counter.count }}</p>
<p>Double: {{ counter.doubleCount }}</p>
<button @click="counter.increment">Increment</button>
</div>
</template>
Load references/store-syntax-guide.md for complete comparison of Option vs Setup stores.
Pinia supports two store definition syntaxes:
Option Stores:
$reset() methodSetup Stores:
→ Load references/store-syntax-guide.md for: Complete syntax comparison, examples, choosing criteria
Load references/state-getters-actions.md for complete API reference.
State:
state: () => ({...}) (option) or ref() (setup)store.countstore.count++ or store.$patch({...})store.$reset() (option stores only)Getters:
getters: { double: (state) => state.count * 2 }this (must type return value)Actions:
actions: { increment() { this.count++ } }Store Destructuring:
import { storeToRefs } from 'pinia'
// ✅ For reactivity
const { name, count } = storeToRefs(store)
// ✅ Actions can destructure directly
const { increment } = store
→ Load references/state-getters-actions.md for: Complete API, subscriptions, store composition patterns, Options API usage
Load references/plugins-composables.md for complete plugin and composables guide.
pinia.use(({ store, options }) => {
// Add properties to every store
return { customProperty: 'value' }
})
Option Stores: Limited to useLocalStorage style in state()
Setup Stores: Full VueUse/composables support
→ Load references/plugins-composables.md for: Complete plugin patterns, VueUse integration, TypeScript typing, common patterns (persistence, router, logger)
Stores need the Pinia instance, which is auto-injected in components but not available in module scope.
// router.ts
import { useUserStore } from '@/stores/user'
// ❌ Fails: Pinia not installed yet
const userStore = useUserStore()
router.beforeEach((to) => {
if (userStore.isLoggedIn) { /* ... */ }
})
// router.ts
import { useUserStore } from '@/stores/user'
router.beforeEach((to) => {
// ✅ Works: Called after Pinia is installed
const userStore = useUserStore()
if (userStore.isLoggedIn) { /* ... */ }
})
Why it works: Router guards execute AFTER app.use(pinia) completes.
// server-side
export function setupRouter(pinia) {
router.beforeEach((to) => {
const userStore = useUserStore(pinia) // Pass explicitly
})
}
Load references/ssr-and-nuxt.md for complete SSR and Nuxt integration guide.
State Hydration:
devalue() (not JSON.stringify)useStore()useStore() BEFORE await in actionsbunx nuxi@latest module add pinia
Auto-imports: defineStore, storeToRefs, usePinia, acceptHMRUpdate, all stores
→ Load references/ssr-and-nuxt.md for: Complete SSR patterns, Nuxt configuration, server-side data fetching, SSR pitfalls, debugging
Load references/testing-guide.md for complete testing guide.
import { setActivePinia, createPinia } from 'pinia'
beforeEach(() => {
setActivePinia(createPinia()) // Fresh Pinia for each test
})
bun add -d @pinia/testing
import { createTestingPinia } from '@pinia/testing'
mount(Component, {
global: { plugins: [createTestingPinia()] }
})
→ Load references/testing-guide.md for: Complete test patterns, stubbing actions, mocking getters, async testing, SSR testing
// stores/counter.ts
import { defineStore, acceptHMRUpdate } from 'pinia'
export const useCounterStore = defineStore('counter', {
// store definition
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useCounterStore, import.meta.hot))
}
if (import.meta.webpackHot) {
import.meta.webpackHot.accept(acceptHMRUpdate(useCounterStore, import.meta.webpackHot))
}
Benefits:
For projects still using Options API, load complete mapper documentation.
→ Load references/state-getters-actions.md for: Complete Options API integration, all mappers (mapStores, mapState, mapWritableState, mapActions)
Load references/vuex-migration.md for complete migration guide.
Key Changes:
namespaced (automatic via store ID)mutations (direct state mutation)commit() with direct mutationsrootState/rootGetters with store importsstore.$reset() instead of custom clear mutationsDirectory: store/modules/ → stores/ (each module = separate store)
→ Load references/vuex-migration.md for: Complete conversion steps, component migration, checklist, gradual migration strategy
✅ Define all state properties in state() or return them from setup stores
✅ Use storeToRefs() when destructuring state/getters in components
✅ Call app.use(pinia) BEFORE mounting the app
✅ Return all state from setup stores (private state breaks SSR/DevTools)
✅ Call useStore() inside functions/callbacks when used outside components
✅ Use acceptHMRUpdate() for development HMR support
✅ Type return values when getters use this to access other getters
✅ Use devalue for SSR state serialization (prevents XSS)
✅ Hydrate state BEFORE calling any useStore() on the client (SSR)
✅ Call all useStore() BEFORE any await in async actions (SSR)
❌ Add state properties dynamically after store creation
❌ Destructure store directly without storeToRefs() (loses reactivity)
❌ Use arrow functions for actions (need this context)
❌ Return private state in setup stores (breaks SSR/DevTools/plugins)
❌ Call useStore() at module top-level (before Pinia installed)
❌ Create circular dependencies between stores (both reading each other's state)
❌ Use JSON.stringify() for SSR serialization (vulnerable to XSS)
❌ Call useStore() after await in actions (breaks SSR)
❌ Forget to type getter return values when using this
❌ Skip beforeEach(() => setActivePinia(createPinia())) in unit tests
This skill prevents 12 documented issues:
Error: State changes don't update in template after destructuring
Why It Happens: JavaScript destructuring breaks Vue reactivity
Prevention: Always use storeToRefs() for state/getters
Error: New properties added after store creation aren't reactive
Why It Happens: Pinia needs all properties defined upfront for reactivity
Prevention: Declare all properties in state(), even if initially undefined
Error: getActivePinia() returns undefined
Why It Happens: Calling useStore() before app.use(pinia)
Prevention: Call app.use(pinia) before mounting or accessing stores
Error: State not serialized/hydrated correctly in SSR
Why It Happens: Properties not returned from setup aren't tracked
Prevention: Return ALL state properties from setup stores
this Don't Infer TypesError: TypeScript can't infer return type when getter uses this
Source: Known TypeScript limitation with Pinia
Prevention: Explicitly type return value: getterName(): ReturnType { ... }
Error: Can't find this.counterStore in component
Why It Happens: mapStores() automatically adds 'Store' suffix
Prevention: Use store name + 'Store' or call setMapStoreSuffix()
await Break SSRError: Wrong Pinia instance used in SSR, causing state pollution
Why It Happens: await changes execution context in async functions
Prevention: Call all useStore() before any await statements
Error: Maximum call stack exceeded
Why It Happens: Both stores read each other's state during initialization
Prevention: Use getters/actions for cross-store access, not setup-time reads
Error: User input in state can execute malicious scripts
Why It Happens: JSON.stringify() doesn't escape executable code
Prevention: Use devalue library for safe serialization
Error: Changes to store require full page reload
Why It Happens: Vite/webpack HMR not configured for store
Prevention: Add acceptHMRUpdate() block to each store file
Error: Store state contains non-serializable functions
Why It Happens: Option stores state() can only return writable refs
Prevention: Use setup stores for complex composables, or extract only writable state
Error: Tests affect each other, sporadic failures
Why It Happens: Single Pinia instance shared across tests
Prevention: beforeEach(() => setActivePinia(createPinia())) in test suites
Core: pinia@^3.0.4, vue@^3.5.24
Nuxt: @pinia/nuxt@^0.11.2, nuxt@^3.13.0
Testing: @pinia/testing@^1.0.2, vitest@^1.0.0
SSR: devalue@^5.3.2 (for safe serialization)
See reference files for complete pattern examples:
references/state-getters-actions.mdreferences/plugins-composables.mdreferences/store-syntax-guide.md (setup store examples)references/state-getters-actions.md (accessing stores outside components)Solution:
app.use(pinia) is called before mountinguseStore() inside callback/functionuseStore(pinia)Solution: Use storeToRefs() instead of direct destructuring
this has TypeScript errorsSolution: Explicitly type the return value: myGetter(): ReturnType { return this.otherGetter }
Solution: Implement custom reset manually:
function $reset() {
count.value = 0
name.value = ''
}
return { count, name, $reset }
Solution: Add HMR acceptance block:
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useMyStore, import.meta.hot))
}
Solution: Create fresh Pinia in beforeEach():
beforeEach(() => {
setActivePinia(createPinia())
})
Load references/store-syntax-guide.md when:
Load references/state-getters-actions.md when:
$patch, $subscribe, or $onActionmapStores, mapState, mapActions)Load references/plugins-composables.md when:
Load references/ssr-and-nuxt.md when:
Load references/testing-guide.md when:
createTestingPiniaLoad references/vuex-migration.md when:
pinia packagecreatePinia()app.use(pinia) before mountingsrc/stores/)defineStore()storeToRefs() when destructuring in componentsthisacceptHMRUpdate() (development)@pinia/nuxt (if using Nuxt)createTestingPinia() (if testing)use[Name]StoreQuestions? Issues?
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
Use when implementing any feature or bugfix, before writing implementation code
Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always
Expert guidance for systematic backtesting of trading strategies. Use when developing, testing, stress-testing, or validating quantitative trading strategies. Covers "beating ideas to death" methodology, parameter robustness testing, slippage modeling, bias prevention, and interpreting backtest results. Applicable when user asks about backtesting, strategy validation, robustness testing, avoiding overfitting, or systematic trading development.
Cloud laboratory platform for automated protein testing and validation. Use when designing proteins and needing experimental validation including binding assays, expression testing, thermostability measurements, enzyme activity assays, or protein sequence optimization. Also use for submitting experiments via API, tracking experiment status, downloading results, optimizing protein sequences for better expression using computational tools (NetSolP, SoluProt, SolubleMPNN, ESM), or managing protein design workflows with wet-lab validation.
This skill should be used for time series machine learning tasks including classification, regression, clustering, forecasting, anomaly detection, segmentation, and similarity search. Use when working with temporal data, sequential patterns, or time-indexed observations requiring specialized algorithms beyond standard ML approaches. Particularly suited for univariate and multivariate time series analysis with scikit-learn compatible APIs.
Take secondsky/pinia-v3 from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.