Developing Pinia Stores
When to use this skill
Use this skill when you need to:
- Create new Pinia stores for state management
- Define store state, getters, and actions
- Compose multiple stores together
- Integrate stores with Vue components
- Handle async operations in stores
- Refactor stores for better type safety or structure
Store File Structure
storeName.ts: Store definition with state, getters, and actions- Place stores in
stores/directory (e.g.,stores/user.ts,stores/cart.ts) - Use
use<Name>Storenaming convention (e.g.,useUserStore,useCartStore)
Instructions
Creating a New Store
Follow these steps to create a new Pinia store:
-
Create store file:
stores/storeName.ts -
Define the store using Setup Store pattern:
- Import
defineStorefrom Pinia - Import
ref,computedfrom Vue - Define state as
ref()values - Define getters as
computed()properties - Define actions as plain functions
- Return all public state, getters, and actions
- See setup-stores.md for patterns
- Import
-
Add TypeScript types:
- Type all state refs explicitly
- Let TypeScript infer computed types when possible
- Type action parameters and return values
- See typescript.md for patterns
-
Handle async operations (if needed):
- Add loading/error state refs
- Use try/catch/finally in async actions
- Clean up state appropriately
Modifying an Existing Store
-
Understand current state:
- Review existing state, getters, and actions
- Identify dependencies on other stores
-
Make changes:
- Add/modify state refs as needed
- Update getters if derived state changes
- Update actions for new behavior
- Ensure all new exports are returned
-
Update consumers:
- Check components using the store
- Update destructuring if new state/actions added
- Verify reactivity is preserved
Using Stores in Components
<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
const store = useCounterStore()
// Destructure reactive state/getters with storeToRefs
const { count, doubleCount } = storeToRefs(store)
// Actions can be destructured directly
const { increment, reset } = store
</script>
Quality Checklist
Before completing work on any store, verify:
- [ ] Store uses Setup Store pattern (not Options API)
- [ ] All state is typed explicitly
- [ ] Getters use
computed()for reactivity - [ ] Async actions have loading/error handling
- [ ] No circular dependencies between stores
- [ ] Store is properly exported and named (
use<Name>Store) - [ ] Components use
storeToRefs()for destructuring state
Best Practices
Naming:
- Store IDs: lowercase with hyphens (
'user-settings') - Store functions:
use<Name>Storepattern (useUserSettingsStore) - State: descriptive nouns (
items,currentUser,isLoading) - Getters: descriptive, often prefixed with
is/has/get(isLoggedIn,totalItems) - Actions: verbs describing the action (
fetchUser,addItem,reset)
State Management:
- Keep stores focused on a single domain
- Prefer multiple small stores over one large store
- Use
shallowRef()for large objects that don't need deep reactivity - Initialize state with sensible defaults
Composition:
- Access other stores inside actions/getters, not at setup level
- Avoid circular dependencies between stores
- Use composables for shared logic
- See composables.md for patterns
Type Safety:
- Always type state refs explicitly
- Export store return type for consumers
- Avoid
anyandunknowntypes - See typescript.md for patterns
Note:
- For detailed patterns and examples, consult the reference documentation in the
references/directory. - Starter template is available in the
assets/directory.