$npx -y skills add skilld-dev/vue-ecosystem-skills --skill pinia-skilldIntuitive, type safe and flexible Store for Vue. ALWAYS use when writing code importing \"pinia\". Consult for debugging, best practices, or modifying pinia.
| 1 | # vuejs/pinia `pinia@3.0.4` |
| 2 | **Tags:** next: 2.0.0-rc.10, beta: 2.1.8-beta.0, latest: 3.0.4 |
| 3 | |
| 4 | **References:** [Docs](./references/docs/_INDEX.md) |
| 5 | ## API Changes |
| 6 | |
| 7 | This section documents version-specific API changes — prioritize recent major/minor releases. |
| 8 | |
| 9 | - 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](./references/releases/CHANGELOG.md#300-2025-02-11) |
| 10 | |
| 11 | - BREAKING: `PiniaStorePlugin` type — removed in v3.0.0; use `PiniaPlugin` instead. Code using `PiniaStorePlugin` will fail to compile [source](./references/releases/CHANGELOG.md#300-2025-02-11) |
| 12 | |
| 13 | - 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](./references/docs/cookbook/migration-v2-v3.md#new-versions) |
| 14 | |
| 15 | - BREAKING: TypeScript 5 or newer required in v3.0.0 — uses native `Awaited` type introduced in TS 4.5; TS 5+ recommended [source](./references/releases/CHANGELOG.md#300-2025-02-11) |
| 16 | |
| 17 | - 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](./references/releases/CHANGELOG.md#300-2025-02-11) |
| 18 | |
| 19 | - 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](./references/releases/CHANGELOG.md#300-2025-02-11) |
| 20 | |
| 21 | - 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](./references/releases/CHANGELOG.md#220-2024-07-26) |
| 22 | |
| 23 | - 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](./references/releases/CHANGELOG.md#218-beta0-2024-04-17) |
| 24 | |
| 25 | - NEW: `SetupStoreDefinition<Id, SS>` 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](./references/releases/CHANGELOG.md#217-2023-10-13) |
| 26 | |
| 27 | - 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](./references/releases/CHANGELOG.md#230-2024-12-04) |
| 28 | |
| 29 | **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 |
| 30 | |
| 31 | ## Best Practices |
| 32 | |
| 33 | - 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](./references/docs/core-concepts/state.md#mutating-the-state) |
| 34 | |
| 35 | - 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](./references/docs/core-concepts/state.md#subscribing-to-the-state) |
| 36 | |
| 37 | - 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](./references/docs/core-concepts/state.md#detaching-subscriptions) |
| 38 | |
| 39 | - 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](./references/docs/cookbook/composables.md#ssr) |
| 40 | |
| 41 | ```ts |
| 42 | return { |
| 43 | lastColor: skipHydrate(lastColor), // won't be overwritten by SSR state |
| 44 | open, |
| 45 | } |
| 46 | ``` |
| 47 | |
| 48 | - 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](./references/docs/core-concepts/plugins.md#adding-new-state) |
| 49 | |
| 50 | - Wrap non-reactive external objects (router, class instances, third-party lib instances) with `markRaw()` be |