vuejs/pinia
pinia
Intuitive, type safe and flexible Store for Vue
Version:
3.0.4 (Nov 2025)
Deps:
@vue/devtools-api@^7.7.7
Tags:
next: 2.0.0-rc.10 (Sep 2021), beta: 2.1.8-beta.0 (Apr 2024), latest: 3.0.4 (Nov 2025)
References:
Docs
— API reference, guides
API Changes
This section documents version-specific API changes — prioritize recent major/minor releases.
BREAKING:
defineStore({ id: 'storeName', ... })
— object signature with
id
property removed in v3.0.0; use
defineStore('storeName', { ... })
instead. Old object syntax silently compiled but is now a runtime error
source
BREAKING:
PiniaStorePlugin
type — removed in v3.0.0; use
PiniaPlugin
instead. Code using
PiniaStorePlugin
will fail to compile
source
BREAKING: Vue 2 support dropped in v3.0.0 — Pinia v3 requires Vue 3 only. Users on Vue 2 must stay on Pinia v2
source
BREAKING: TypeScript 5 or newer required in v3.0.0 — uses native
Awaited
type introduced in TS 4.5; TS 5+ recommended
source
BREAKING: IIFE bundle no longer bundles Vue Devtools in v3.0.0 — devtools API was too large; must be included manually depending on your workflow
source
BREAKING: Package is now published as
type: module
in v3.0.0 — CJS dist files still provided but the package root is ESM. May break setups relying on implicit CJS resolution
source
NEW:
action(fn, name?)
helper in setup stores — added in v2.2.0, available via
SetupStoreHelpers
parameter. Wraps a function so it is tracked by
$onAction
when called within the store; intended for advanced use cases like Pinia Colada
source
NEW:
disposePinia(pinia)
— added in v2.1.7, stops the pinia effect scope and removes state, plugins, and stores. Useful in tests or multi-pinia apps; disposed instance cannot be reused
source
NEW:
SetupStoreDefinition
type — added in v2.1.7 for the return type of
defineStore()
when using a setup function. Extends
StoreDefinition
and enables better IDE support for setup stores
source
NEW:
mapWritableState
now picks up writable
computed
s in setup stores — added in v2.3.0. Previously only
ref
state was mapped;
WritableComputedRef
returns from setup stores are now included
source
Also changed:
mapGetters
DEPRECATED (alias for
mapState
, still exported) ·
getActivePinia()
returns
Pinia | undefined
(typed more strictly since v2.0.35) ·
skipHydrate(obj)
stable — skips SSR hydration for non-state objects returned from setup stores ·
shouldHydrate(obj)
exported utility for plugin authors
Best Practices
Use
$patch()
with a function callback rather than an object when mutating arrays or performing multiple related changes — the function form groups all mutations into a single devtools entry and avoids creating intermediate collections
source
Use
$subscribe()
instead of
watch()
on store state — subscriptions fire only once per
$patch
call regardless of how many individual properties changed, avoiding redundant callbacks when using the function form of
$patch
source
Pass
{ detached: true }
to
$subscribe()
and
true
as the second arg to
$onAction()
when you need listeners to outlive the component — by default both are automatically removed on component unmount
source
In setup stores, use
skipHydrate()
to wrap state properties that must not be picked up from SSR initial state (e.g., composables backed by
localStorage
, client-only refs) — without it, the server's serialized value will override the intended client-side source
source
return
{
lastColor
:
skipHydrate
(
lastColor
)
,
// won't be overwritten by SSR state
open
,
}
When a plugin adds new state properties, set the value on both
store.$state
(for SSR serialization and devtools) and
store
via
toRef(store.$state, 'key')
— setting only one breaks devtools display or reactivity sharing
source
Wrap non-reactive external objects (router, class instances, third-party lib instances) with
markRaw()
before assigning them in plugins — prevents Vue from trying to deeply observe objects that aren't meant to be reactive
source
When composing stores that reference each other, place
useOtherStore()
calls before any
await
in async actions — after an
await
the active pinia context may have changed, causing the wrong instance to be returned in SSR
source
Use
createTestingPinia()
from
@pinia/testing
for component tests rather than
createPinia()
— it stubs all actions by default and makes them inspectable as spies; pass plugins via the
plugins
option, not via
testingPinia.use()
source
In options store getters, prefer arrow functions that receive
state
as the first parameter over regular functions using
this
— arrow function return types are inferred automatically, while
this
-based getters require an explicit return type annotation
source