Learn-skills.dev web-state-pinia
Pinia stores, Vue 3 state patterns. Use when managing client state in Vue applications, choosing between Options/Setup stores, composing stores, or implementing persistence.
git clone https://github.com/NeverSight/learn-skills.dev
T=$(mktemp -d) && git clone --depth=1 https://github.com/NeverSight/learn-skills.dev "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/skills-md/agents-inc/skills/web-state-pinia" ~/.claude/skills/neversight-learn-skills-dev-web-state-pinia && rm -rf "$T"
data/skills-md/agents-inc/skills/web-state-pinia/SKILL.mdPinia State Management Patterns
Quick Guide: Use Pinia for all shared client state in Vue 3. Options stores for simplicity, Setup stores for flexibility. Server data? Use your data fetching solution. Use
when destructuring state.storeToRefs()
<critical_requirements>
CRITICAL: Before Managing State with Pinia
(You MUST use a data fetching solution for ALL server/API data - NEVER put API responses in Pinia stores)
(You MUST use
when destructuring state from stores - direct destructuring loses reactivity)storeToRefs()
(You MUST return ALL state properties in Setup stores - private state breaks SSR and DevTools)
(You MUST use named exports ONLY - NO default exports in any store files)
(You MUST use named constants for ALL numbers - NO magic numbers in state code)
</critical_requirements>
Auto-detection: Pinia, defineStore, Vue 3 state, storeToRefs, Vue state management, Options store, Setup store
When to use:
- Managing shared client state in Vue 3 applications
- Choosing between Options stores and Setup stores
- Composing stores that depend on each other
- Implementing state persistence across sessions
- Adding DevTools integration for debugging
- Setting up stores for SSR applications
When NOT to use:
- Server/API data (use a dedicated data fetching solution)
- Simple component-local state (use
orref()
)reactive() - URL-appropriate state like filters (use route query params)
<philosophy>
Philosophy
Pinia is the official state management solution for Vue 3, designed to be intuitive, type-safe, and flexible. It eliminates the boilerplate of Vuex while maintaining powerful features like DevTools integration, plugin support, and SSR compatibility.
Core Principles:
- Modular by Default - Each store is independent, no nested modules
- No Mutations - Actions handle all state changes directly
- Full TypeScript Support - Type inference works out of the box
- Composition API Friendly - Works seamlessly with
<script setup>
State Ownership:
| State Type | Solution | Reason |
|---|---|---|
| Server/API data | Data fetching solution | Caching, synchronization, loading states |
| Shared client state | Pinia | Reactivity, DevTools, persistence |
| Component-local state | / | Simpler, no overhead |
| URL state (filters) | Route query params | Shareable, bookmarkable |
<patterns>
Core Patterns
Pattern 1: Options Store vs Setup Store Decision
Pinia offers two store definition syntaxes. Choose based on your needs.
Decision Tree
Which store syntax should I use? Need composables (useRoute, useI18n)? ├─ YES → Setup Store └─ NO → Need watchers inside store? ├─ YES → Setup Store └─ NO → Prefer Vue Options API style? ├─ YES → Options Store └─ NO → Setup Store (more flexible)
Options Store: Simpler, familiar to Vuex users, built-in
$reset() method
Setup Store: More flexible, supports composables, requires manual reset
For implementation examples, see examples/core.md.
Pattern 2: Options Store Definition
Use Options stores for straightforward state management with familiar syntax.
When to Use
- Teams familiar with Vuex or Vue Options API
- Simple stores without composable dependencies
- When built-in
method is needed$reset() - Standard CRUD operations on client state
For implementation examples and good/bad comparisons, see examples/core.md.
Pattern 3: Setup Store Definition
Use Setup stores when you need maximum flexibility and composable integration.
When to Use
- Using Vue Router composables (
,useRoute
)useRouter - Using i18n composables (
)useI18n - Need watchers inside the store
- Complex computed dependencies
- Integrating with external composables
Critical Requirements for Setup Stores
- Return ALL state properties (no private state)
- Use
for state,ref()
for getterscomputed() - Functions become actions automatically
- Must implement custom
if needed$reset()
For implementation examples, see examples/core.md.
Pattern 4: Accessing Store State in Components
Proper store access patterns prevent reactivity issues.
Key Rules
- Never destructure state directly - loses reactivity
- Use
for state/getters - preserves reactivitystoreToRefs() - Destructure actions directly - they don't need reactivity
For implementation examples with storeToRefs, see examples/core.md.
Pattern 5: Composing Stores
Stores can use other stores, but follow rules to avoid circular dependencies.
Guidelines
- Import and use stores at the top of your store function
- Avoid circular dependencies through getters/actions
- If stores reference each other, ensure no infinite loops
- Use setup stores for complex composition patterns
For implementation examples, see examples/core.md.
Pattern 6: State Persistence
Use plugins for persisting state across sessions.
Persistence Guidelines
- Use
for most casespinia-plugin-persistedstate - Only persist user preferences and non-sensitive data
- Use
option to persist specific properties onlypick - Never persist server data (refetch on load instead)
- Consider storage type: localStorage vs sessionStorage
For implementation examples, see examples/persistence.md.
Pattern 7: Pinia Plugins
Extend all stores with shared functionality.
Common Plugin Use Cases
- Adding shared properties (router, analytics)
- Wrapping actions with logging/timing
- Adding custom options (debounce, throttle)
- Implementing side effects (localStorage)
For implementation examples, see examples/plugins.md.
Pattern 8: Testing Stores
Test stores in isolation and within components.
Testing Approaches
- Unit tests: Test store actions/getters directly with
setActivePinia() - Component tests: Use
for component mountingcreateTestingPinia() - Mocking: Actions are stubbed by default with
@pinia/testing
For implementation examples, see examples/testing.md.
Pattern 9: SSR Considerations
Handle server-side rendering and hydration properly.
SSR Guidelines
- Use SSR-safe defaults (no browser APIs in initial state)
- Guard client-only logic with
checkstypeof window !== "undefined" - Be careful with Setup stores - ensure all refs are returned
- Sanitize serialized state to prevent XSS
For implementation examples, see examples/ssr.md.
</patterns><red_flags>
RED FLAGS
High Priority Issues:
- Storing server/API data in Pinia instead of using a data fetching solution - causes stale data, no caching, manual sync
- Destructuring state without
- silently breaks reactivity, UI shows stale datastoreToRefs() - Private state in Setup stores (not returning all refs) - breaks SSR hydration, DevTools, and plugins
- Browser APIs in state initialization (
,localStorage
) - crashes SSRwindow
Gotchas & Edge Cases:
works for state and getters only, not actions - destructure actions directlystoreToRefs()- Options stores have built-in
, Setup stores do not - implement manually or use a plugin$reset() - Store instances are singletons per Pinia instance - in SSR, each request needs its own Pinia
with a function allows accessing current state:$patchstore.$patch(state => { state.items.push(item) })- Arrow functions in Options store getters have no
- usethis
keyword or state parameterfunction
For complete anti-pattern examples, see reference.md.
</red_flags>
Detailed Resources:
- examples/core.md - Options store, Setup store, storeToRefs, composing stores
- examples/persistence.md - Selective persistence with pinia-plugin-persistedstate
- examples/testing.md - Unit testing stores, component testing with createTestingPinia
- examples/plugins.md - Logger plugin, reset plugin for Setup stores
- examples/ssr.md - SSR-safe stores, hydration, client-only guards
- reference.md - Decision frameworks, anti-patterns, TypeScript patterns, performance tips
<critical_reminders>
CRITICAL REMINDERS
(You MUST use a data fetching solution for ALL server/API data - NEVER put API responses in Pinia stores)
(You MUST use
when destructuring state from stores - direct destructuring loses reactivity)storeToRefs()
(You MUST return ALL state properties in Setup stores - private state breaks SSR and DevTools)
(You MUST use named exports ONLY - NO default exports in any store files)
(You MUST use named constants for ALL numbers - NO magic numbers in state code)
Failure to follow these rules will cause reactivity bugs, SSR hydration errors, and DevTools failures.
</critical_reminders>