pinia@4.0.3
Source citations use package-relative paths from the prepared pinia 4.0.3 source: package.json, README.md, dist/pinia.js (runtime), dist/pinia.d.ts (types). Other citations are official documentation URLs.
Requirements
- Vue
^3.5.11peer [package.json:62]. Vue 2 is unsupported since v3. @vue/devtools-api^8.1.5is a required, non-optional peer [package.json:60-68]. Install it alongside pinia:npm install pinia @vue/devtools-api[README.md:108-111], v4.0.0 release notes.- TypeScript
>=5.6.0optional peer [package.json:69-71]. - ESM-only package:
"type": "module", single export.todist/pinia.js[package.json:42,47-50]. v4 removed CJS resolution; a require() fallback breaks. @pinia/nuxt1.x and@pinia/testing2.x are the companion versions for pinia 4 (https://github.com/vuejs/pinia/releases).
Install and setup
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')
From [README.md:119-130]. In dev on the client, createPinia() registers the devtools plugin itself [dist/pinia.js:832,847].
Define a store
Two syntaxes. The id is a unique string, first argument in both [dist/pinia.d.ts:645,653].
import { defineStore } from 'pinia'
// Option store: state/getters/actions
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})
// Setup store: refs are state, computed are getters, functions are actions
export const useTodos = defineStore('todos', () => {
const todos = ref<Todo[]>([])
const done = computed(() => todos.value.filter((t) => t.done))
function add(todo: Todo) {
todos.value.push(todo)
}
return { todos, done, add }
})
Rules for setup stores [dist/pinia.js:1178-1202]:
ref()andreactive()become state.computed()becomes a getter.- Functions become actions, wrapped automatically for
$onAction. - Return every state property. Pinia only picks up returned state, so private state breaks SSR hydration and devtools.
The setup function receives helpers: defineStore('id', ({ action }) => { ... }) [dist/pinia.js:1177, dist/pinia.d.ts:628-638]. action(fn, name?) makes a helper function trackable by $onAction when called within the store. Rarely needed; intended for advanced cases like Pinia Colada.
Use a store
Call useStore() inside setup() (or any composable). Every call returns the same store instance.
const counter = useCounterStore()
counter.count++ // direct state mutation
counter.doubleCount // getter
counter.increment() // action
const { count, doubleCount } = storeToRefs(counter) // refs for destructuring
storeToRefs() converts state and getters to refs. It ignores actions and non-reactive properties [dist/pinia.js:1475-1489]. Destructure with it, never plain toRefs() or ...store, when you need reactivity.
Common operations:
- Group changes into one devtools entry with
store.$patch(obj)or$patch(fn). The function form must be synchronous [dist/pinia.d.ts:219-225] and suits array, Map, and Set edits [dist/pinia.js:964-975]. $reset()exists only on option stores. On a setup store it throws in dev [dist/pinia.js:1085-1087]; implement your own$resetin the returned object.- Assigning
store.$state = {...}does not replace state; it calls$patchinternally [dist/pinia.js:1207-1216]. - Declare every state key in
state()(or return it from setup), even when the initial value isundefined. New keys added later are not reactive. - Outside a component, pass the pinia instance:
useStore(pinia). On the server this is mandatory; skipping it risks cross-request state pollution [dist/pinia.js:37-39].
Details: stores, subscriptions.
Version notes and migration
v4.0.0, technically breaking only (https://github.com/vuejs/pinia/releases/tag/v4.0.0):
- ESM-only distribution.
@vue/devtools-apiupgraded to v8 and now a required install.- Errors and dev warnings refactored onto Nostics diagnostics, codes
PINIA_R1001toPINIA_R1007[dist/pinia.js:18-56]. See diagnostics. piniaSymbolis now part of the public exports [dist/pinia.js:1491].storeToRefs()skips nullish values gracefully;$subscribe()ignores a duplicate callback instead of stacking a second watcher.
Still relevant from v3.0.0 (https://pinia.vuejs.org/cookbook/migration-v2-v3.html):
defineStore({ id: 'x', ... })object-only signature removed. UsedefineStore('x', { ... }).PiniaStorePlugintype removed. UsePiniaPlugin.- Vue 2 support dropped. Vue 2 users stay on pinia v2.
Reference files
- API surface: every public export with signatures and type helpers.
- Stores: state, getters, actions, typing, composing stores, HMR.
- Subscriptions:
$subscribe,$onAction,MutationType, detached and flush options. - Plugins:
pinia.use(), context, typing extensions, new state and options. - SSR: hydration,
skipHydrate, per-request pinia, Nuxt. - Testing:
setActivePinia,@pinia/testing2.x usage. - Options API: map helpers without
setup(). - Diagnostics: dev-only
PINIA_R100xcatalog with fixes.
Official docs: https://pinia.vuejs.org