pinia-v3
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.
What this skill does
# Pinia v3 - Vue State Management
**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
---
## Quick Start (5 Minutes)
### 1. Install Pinia
```bash
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:**
- Pinia is the official Vue state management library
- Provides better TypeScript support than Vuex
- Eliminates mutations and namespacing complexity
- Full DevTools support with time-travel debugging
### 2. Create and Register Pinia Instance
```typescript
// 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:**
- Install Pinia BEFORE using any store
- Call `app.use(pinia)` before mounting the app
- Only one Pinia instance per application (unless SSR)
### 3. Define Your First Store
```typescript
// 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++
}
}
})
```
### 4. Use Store in Components
```vue
<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>
```
---
## The Two Store Syntaxes
**Load `references/store-syntax-guide.md` for complete comparison of Option vs Setup stores.**
### Quick Overview
Pinia supports two store definition syntaxes:
**Option Stores:**
- Similar to Vue Options API
- Built-in `$reset()` method
- Best for: Simpler use cases, teams familiar with Vuex
**Setup Stores:**
- Uses Composition API pattern
- Full composables integration
- Best for: Advanced patterns, need watchers/VueUse integration
**→ Load `references/store-syntax-guide.md` for:** Complete syntax comparison, examples, choosing criteria
---
## State, Getters, and Actions
**Load `references/state-getters-actions.md` for complete API reference.**
### Quick Reference
**State:**
- Define in `state: () => ({...})` (option) or `ref()` (setup)
- Access directly: `store.count`
- Mutate directly: `store.count++` or `store.$patch({...})`
- Reset: `store.$reset()` (option stores only)
**Getters:**
- Computed properties: `getters: { double: (state) => state.count * 2 }`
- Access other getters with `this` (must type return value)
**Actions:**
- Business logic: `actions: { increment() { this.count++ } }`
- Can be async
- Access other stores directly
**Store Destructuring:**
```typescript
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
---
## Plugins and Composables
**Load `references/plugins-composables.md` for complete plugin and composables guide.**
### Plugin Basics
```typescript
pinia.use(({ store, options }) => {
// Add properties to every store
return { customProperty: 'value' }
})
```
### Composables Integration
**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)
---
## Using Stores Outside Components
### The Problem
Stores need the Pinia instance, which is auto-injected in components but not available in module scope.
### ❌ Wrong: Accessing Store at Module Level
```typescript
// router.ts
import { useUserStore } from '@/stores/user'
// ❌ Fails: Pinia not installed yet
const userStore = useUserStore()
router.beforeEach((to) => {
if (userStore.isLoggedIn) { /* ... */ }
})
```
### ✅ Right: Accessing Store Inside Callbacks
```typescript
// 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.
### SSR: Explicit Pinia Instance
```typescript
// server-side
export function setupRouter(pinia) {
router.beforeEach((to) => {
const userStore = useUserStore(pinia) // Pass explicitly
})
}
```
---
## Server-Side Rendering & Nuxt
**Load `references/ssr-and-nuxt.md` for complete SSR and Nuxt integration guide.**
### SSR Quick Reference
**State Hydration:**
- Server: Serialize with `devalue()` (not `JSON.stringify`)
- Client: Hydrate BEFORE calling `useStore()`
- Critical: Call all `useStore()` BEFORE `await` in actions
### Nuxt 3/4 Integration
```bash
bunx 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
---
## Testing
**Load `references/testing-guide.md` for complete testing guide.**
### Testing Quick Start
```typescript
import { setActivePinia, createPinia } from 'pinia'
beforeEach(() => {
setActivePinia(createPinia()) // Fresh Pinia for each test
})
```
### Component Testing
```bash
bun add -d @pinia/testing
```
```typescript
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
---
## Hot Module Replacement (HMR)
### Vite Setup
```typescript
// 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))
}
```
### Webpack Setup
```typescript
if (import.meta.webpackHot) {
import.meta.webpackHot.accept(acceptHMRUpdate(useCounterStore, import.meta.webpackHot))
}
```
**Benefits:**
- Edit stores without full page reload
- Preserve application state during development
- Faster development iteration
---
## Options API Usage
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`)
---
## Migrating from Vuex
**Load `references/vuex-migration.md` for complete migration guide.**
### Quick Conversion Overview
**Key Changes:**
1. Remove `namespaced` (automatic via store ID)
2. Eliminate `mutations` (direct state mutation)
3. Replace `commit()` with direct mutations
4. Replace `rootState`/`rootGetters` with store imports
5. Use `store.$reset()` instead of custom clear mutations
**Directory:** `store/modules/` → `stores/` (each module = separate store)
**→ Load `references/vuex-migration.md` for:** Complete conversion steps, component migration, checklist, gradual migration strategy
---
## Critical Rules
### Always Do
✅ 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 Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.