← Back to Design Systems and Frontend Team
See how it helps
Pinia shared state
Places Vue state at the right scope and uses Pinia only for information genuinely shared across views.
pinia-state
Team members using this skill
When is it useful?
Use when stores grow unnecessarily or shared values stop updating correctly.
What does it help you do?
- Distinguishes component, URL, subtree and application-level state.
- Defines store state, computed getters and actions with predictable reset behavior.
- Preserves reactivity when consuming stores and respects serialization needs.
Try asking this
Refactor our workspace store so shared selection persists across routes while form drafts remain local and reset on dismissal. Switch routes with a selected workspace, then close and reopen an edited form. Shared selection should persist while the discarded draft does not reappear.
Detailed documentation
Read the skill’s original instructions, examples and checks in their authored language.
Show less
Pinia & Shared State
Introduce a global store only when state genuinely outlives a single view or is shared across independent branches of the component tree.
1. Choosing the right state scope
- Component-local
ref/computed: state used by one component or a parent and its direct children (open modals, form drafts, local toggles). - URL query / route params: filters, search terms, sorting, pagination and active tabs that should survive page reloads and be shareable by link.
- Scoped
provide/inject: state shared within a subtree or compound component family that should reset when that subtree unmounts. - Pinia store: authenticated user/session context, cross-route workspaces, shopping carts, notification queues, or client caches shared across unrelated routes. Never move every form field or modal toggle into Pinia just for convenience.
2. Defining Setup Stores cleanly
- Prefer Setup Stores (
defineStore('id', () => { ... })) for TypeScript inference and composable integration, unless the codebase standardizes on Option Stores:ref()/shallowRef()become state properties.computed()becomes getters.function(sync or async) becomes actions.
- Return every state
reffrom the setup store function! Private unreturned refs break SSR serialization, Vue DevTools inspection andstore.$stateplugins. - In Setup Stores,
store.$reset()is not built in by default — implement an explicitfunction $reset()action that restores initial values when reset behavior is needed.
3. Consuming and composing stores safely
- Never destructure state or getters directly from a store instance (
const { count } = useCounterStore()breaks reactivity). Always wrap state and getters instoreToRefs(store), and destructure actions directly fromstore:const store = useCartStore() const { items, total } = storeToRefs(store) const { addItem, clear } = store - Call
useXStore()inside<script setup>,setup(), actions or routerbeforeEachguards — never at module top level beforeapp.use(pinia)has run (especially in SSR or unit tests). - When composing stores, call the other store inside the setup store body or inside an action, and never create circular store dependencies where Store A and Store B read each other's state synchronously during initialization.
- Use
store.$patch({ ... })orstore.$patch((state) => { ... })when applying multiple related state mutations together.
Before you finish
- Confirmed the state belongs in Pinia rather than local refs, URL params or scoped
provide/inject. - Setup store returns all state refs, computed getters and actions, with an explicit
resetaction if needed. - Consumers use
storeToRefs(store)for state/getters and never instantiate stores at module import time. - No circular synchronous dependencies between stores; unit tests initialize a fresh Pinia instance per test.
Included files 2
LICENSE.txtSKILL.md
