---
title: "Piniaとは？読み方・使い方とVuexとの違い【Pinia 4対応】"
url: "https://www.issoh.co.jp/tech/details/3513/"
published: 2024-09-06
updated: 2026-09-28
categories: ["Vue.js"]
publisher: "株式会社一創"
---

# Piniaとは？読み方・使い方とVuexとの違い【Pinia 4対応】

Pinia（読み方：ピーニャ）は、Vue.jsの公式の状態管理ライブラリです。複数のコンポーネントから読み書きするデータを「ストア」にまとめ、Vuexの後継としてVue公式ドキュメントで推奨されています。最新版は2026年8月12日公開の4.0.3で、4系からは `@vue/devtools-api` を一緒にインストールしないと読み込みエラーになります。本記事では、Vuexとの違い、4系の変更点、ストアの書き方と使い方の注意点を、2026年9月28日時点のnpmレジストリと公式ドキュメント（v4.0.3のソース）、ローカル環境（Pinia 4.0.3・Vue 3.5.43・Node.js 26.5.0・Vitest 5.0.2）で動かした結果をもとに解説します。

## まとめ：Piniaの要点

- **正体**：Vueのコアチームが保守する公式の状態管理ライブラリ。Vue公式ドキュメントはVuexを「maintenance mode」とし、新規開発にはPiniaを推奨している。
- **読み方**：「ピーニャ」。スペイン語でパイナップルを意味する _piña_ に由来する。
- **Vuexとの違い**：mutationsが無く、stateをactionsや直接代入で書き換える。モジュールの入れ子や名前空間の代わりに、小さなストアを複数並べる。
- **最新版**：4.0.3。4系はESMのみの配布になり、`npm install pinia @vue/devtools-api` の2パッケージ導入が公式手順。Vue 2で使えるのは2系まで。
- **使い方の注意**：ストアを分割代入するとリアクティブ性が切れるので `storeToRefs()` を使う。Setup Storeには `$reset()` が無いので自分で定義する。

## Piniaの位置づけ：Vue公式の状態管理ライブラリ

Piniaは、Vuexの次期版（Vuex 5）の構想を試す実験として始まりました。公式ドキュメントは「Piniaが既にVuex 5で実現したかったことの大半を実装していると分かり、代わりにPiniaを新しい推奨にした」と経緯を説明しています。現在はVueエコシステムの他のコアライブラリと同じRFCの手続きで仕様が決まり、APIは安定段階に入っています。

### 読み方「ピーニャ」と名前の由来

公式ドキュメントには「Pinia (pronounced `/piːnjʌ/`, like “peenya” in English)」とあり、日本語では「ピーニャ」が近い発音です。_piña_（スペイン語でパイナップル）に最も近く、npmで使えるパッケージ名として選ばれました。パイナップルは小さな花が集まって1つの実になることから、「個別に生まれたストアが最後にはつながる」というストアの設計を表しています。ロゴがパイナップルなのもこのためです。

### ストアに置くデータと置かないデータ

公式が挙げるストアの用途は、ナビゲーションバーに出すユーザー情報のようにアプリの複数箇所で使うデータと、複数ページにまたがる入力フォームのようにページ遷移後も保持したいデータです。反対に、ある画面の要素の表示・非表示のようにコンポーネント内で完結するデータは、ストアに入れず `ref` で持つよう勧めています。処理を共有したいだけなら、ストアではなくコンポーザブル（`use` で始まる関数）で足ります。

## PiniaとVuexの違い：mutations廃止と保守モード

Vuexは3系がVue 2用、4系がVue 3用です。npmの最終リリースは2022年10月14日の4.1.0で、それ以降の公開はありません。VuexのREADMEは「Vuex 3 and 4 will still be maintained. However, it’s unlikely to add new functionalities to it.」と書き、[Vue公式ドキュメントの状態管理のページ](https://vuejs.org/guide/scaling-up/state-management)も「Vuex is now in maintenance mode」「It is recommended to use Pinia for new applications.」としています。

| 項目         | Vuex 4            | Pinia 4           |
| ---------- | ----------------- | ----------------- |
| 状態の変更      | mutationsをcommit  | actionsまたは直接代入    |
| ストアの構成     | 1ストア＋modules      | 複数ストアを並列          |
| 名前空間       | namespaced: true  | ストアIDがそのまま役割      |
| 呼び出し       | 文字列（’cart/add’）   | 関数を直接import       |
| TypeScript | 型の補助定義が必要         | 定義から型推論           |
| 最新リリース     | 4.1.0（2022-10-14） | 4.0.3（2026-08-12） |

mutationsはもともとVue Devtoolsで変更を追跡するための仕組みでしたが、Piniaでは直接代入もDevtoolsに記録されるため不要になりました。文字列でactionを呼ぶ代わりに関数をimportするので、エディタの補完と型チェックが効きます。ストア同士の相互利用は可能ですが、Setup Storeの初期化中に互いのstateを直接読み合う構成や、getters・actionsが無限に呼び合う構成は避ける必要があります。

## Piniaのバージョン：4系の変更点と2系・3系との違い

Piniaのメジャーバージョンは、新機能よりも対応環境の整理で上がってきました。3.0も4.0も、リリースノートは「新機能は無い」「技術的な破壊的変更のみ」と説明しています。各版の変更内容は[PiniaのCHANGELOG](https://github.com/vuejs/pinia/blob/v4/packages/pinia/CHANGELOG.md)で確認できます。

| 版     | 公開日        | 主な変更                     |
| ----- | ---------- | ------------------------ |
| 2.0.0 | 2021-10-27 | Vue 2とVue 3の両対応          |
| 3.0.0 | 2025-02-11 | Vue 2対応と非推奨APIを削除        |
| 4.0.0 | 2026-07-14 | ESMのみ、devtools-api v8が必須 |
| 4.0.3 | 2026-08-12 | SSRのSet・Map復元などを修正       |

3.0では、Vue 2対応に加えて `PiniaStorePlugin` 型と `defineStore({ id: 'id' })` の書き方が削除されました。4.0では配布がESMのみになり、エラーと開発時の警告がNosticsという診断ライブラリで作り直されています。4.0.3のpackage.jsonに記載されたpeer dependency（TypeScriptは任意依存で、使用する場合の最低バージョン）は、`vue ^3.5.11`・`typescript >=5.6.0`・`@vue/devtools-api ^8.1.5` です。

### Pinia 4へ上げるときの確認点

最も影響が大きいのは `@vue/devtools-api` です。公式のインストール手順は「Since v4, you must also install `@vue/devtools-api`」と明記しています。npm 7以降は通常peer dependencyを自動で入れますが、`--legacy-peer-deps` 付きでPinia 4.0.3とVue 3.5.43だけを入れて `import { createPinia } from 'pinia'` を実行すると、`Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@vue/devtools-api' imported from .../pinia/dist/pinia.js` で起動に失敗しました。peerを自動で入れない設定のプロジェクトでは、package.jsonに明示しておくのが安全です。

ESMのみになった点は、Node.js 26.5.0では `require('pinia')` でも読み込めました（Node.jsのrequire(esm)機能による）。CommonJS前提の古いテスト設定やビルドツールを使っているなら、上げる前にテストを一度通して確かめてください。なお、Vue公式ドキュメントの状態管理のページには「works with both Vue 2 and Vue 3」と書かれていますが、これはPinia 2系までの話です。Vue 2.7のプロジェクトで使えるのはPinia 2.3系までです。

## Piniaのインストールと初期設定

ViteやVue公式の `create-vue` で作ったVue 3プロジェクトなら、次のコマンドと初期設定で導入できます。`create-vue` の質問でPiniaを選ぶと、ここまでの設定が最初から入ったプロジェクトが生成されます。

```
npm install pinia @vue/devtools-api
```

次に、ルートのPiniaインスタンスを作ってアプリにプラグインとして登録します。

```
// src/main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
app.use(createPinia())
app.mount('#app')
```

yarn・pnpm・bun・denoでも、パッケージ名は同じ2つです。Nuxtを使う場合は、後述するモジュールで導入します。

## ストアの定義：Option StoreとSetup Storeの書き分け

ストアは `defineStore()` で定義し、第1引数のID（アプリ内で一意の文字列）がDevtoolsの表示名やSSRのシリアライズのキーになります。書き方は2種類あります。

### Option Store：Options APIに近い書き方

`state`・`getters`・`actions` の3つを持つオブジェクトで定義します。公式はこの3つを、コンポーネントの `data`・`computed`・`methods` に相当すると説明しています。

```
// src/stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0, items: [] }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})
```

### Setup Store：Composition APIと同じ書き方

関数の中で `ref`（state）・`computed`（getters）・関数（actions）を作り、返します。ストアの中で `watch` を使ったり、他のコンポーザブルを呼んだりできるのが利点です。

```
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCartStore = defineStore('cart', () => {
  const items = ref([])
  const total = computed(() => items.value.reduce((sum, i) => sum + i.price, 0))
  function add(item) {
    items.value.push(item)
  }
  return { items, total, add }
})
```

公式は「stateのプロパティはすべて返す必要がある」と強調しています。返さない、あるいは `readonly` で包んだstateは、SSR・Devtools・プラグインが扱えなくなります。

### Option StoreとSetup Storeの選択基準

公式の立場は「慣れている方を選べばよい」で、Option Storeは扱いやすく、Setup Storeは柔軟です。判断の目安は、コンポーネントをどちらのAPIで書いているかです。`<script setup>` で書いているチームならSetup Storeに揃えると、ストアとコンポーネントで書き方を切り替えずに済みます。一方、次章の `$reset()` のように、Option Storeにしか無い機能もあります。Composition APIそのものの書き方は[Composition APIとは？書き方とOptions APIとの違い・移行判断を解説](/tech/details/3589/)で解説しています。

## コンポーネントでの使い方：分割代入とstoreToRefs

ストアは定義した関数（`useCounterStore()`）を呼ぶと取得できます。同じPiniaインスタンス内では、同じIDのストアを何度呼んでも同じストアインスタンスが返り、実測でも `useCounterStore() === store` は `true` でした。

```
<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'

const store = useCounterStore()
const { count, double } = storeToRefs(store)  // stateとgettersはref化して取り出す
const { increment } = store                  // actionsはそのまま取り出せる
</script>

<template>
  <button @click="increment">{{ count }}（2倍: {{ double }}）</button>
</template>
```

ストアは `reactive` で包まれたオブジェクトなので、`const { count } = store` と分割代入すると、その時点の値がコピーされるだけです。実測では、分割代入した `count` は1のまま、ストア側は2に増えていました。`storeToRefs()` で取り出した値はrefになり、ストアの変更に追従します。actionsはストアに束縛されているので、そのまま分割代入して呼んでも動きます。

コンポーネント外（Vue Routerのナビゲーションガードなど）でストアを使うときは、`app.use(pinia)` の後で呼ぶ必要があります。SSRでは、どのリクエストのPiniaかを区別するため `useStore(pinia)` のようにインスタンスを渡します。

## stateの更新・リセット・監視：$patch・$reset・$subscribe

stateは `store.count++` のように直接書き換えられます。複数の値をまとめて変えるときは `$patch` を使います。配列への追加のように、オブジェクトでは表しにくい変更は関数形式で渡します。

```
store.$patch({ count: 10 })
store.$patch((state) => {
  state.items.push('a')
})
```

### Setup Storeに$resetが無い問題

Option Storeでは `store.$reset()` でstateを初期値に戻せます。Setup Storeで同じ呼び出しをすると、Pinia 4.0.3では「Store “cart” is built using the setup syntax and does not implement $reset().」というエラーになりました。公式ドキュメントは、Setup Storeでは自分で `$reset` を定義する方法を示しています。

```
import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  function $reset() {
    count.value = 0
  }
  return { count, $reset }
})
```

### $subscribeで変更を検知するときの注意

`$subscribe` はstateの変更ごとにコールバックを呼び、変更の種類を `'direct'`（直接代入）・`'patch object'`・`'patch function'` で渡します。既定の設定では、同じtick内の直接代入はまとめて1回として通知されます。`store.count++` を2回続けた後に `nextTick()` を待つと、通知は1回でした。第2引数に `{ flush: 'sync' }` を渡すと直接代入のたびに通知され、同じ操作で通知は2回になりました。関数形式の `$patch()` は中で何度値を変えても1回の通知なので、通知回数を変更回数として数えることはできません。公式ドキュメントの例は、変更のたびにstate全体をlocalStorageへ保存する使い方です。永続化が目的なら、`pinia-plugin-persistedstate`（4.7.1、peer dependencyは `pinia >=3.0.0`）でストアに `persist: true` を付ける方法もあります。

## NuxtでPiniaを使う設定

Nuxtでは公式モジュール `@pinia/nuxt`（最新1.0.2）を使います。公式ドキュメントはNuxt 3と4への対応を明記しており、1.0.2のリリースノートではNuxt 5への対応も宣言されました。導入は次のコマンドで、`nuxt.config` の `modules` に `'@pinia/nuxt'` が追加されます。

```
npx nuxi@latest module add pinia
```

モジュールは `defineStore()`・`storeToRefs()`・`usePinia()`・`acceptHMRUpdate()` を自動インポートし、`stores` ディレクトリ（Nuxt 4では `app/stores`）のストアも自動で読み込みます。入れ子のディレクトリは対象外なので、使う場合は `pinia.storesDirs` で指定します。SSRでは、stateのシリアライズとXSS対策をNuxtが受け持ちます。ページでデータを取得するactionは、`await callOnce('user', () => store.fetchUser())` のように `callOnce()` で包むと、サーバーで取得済みのデータをクライアントで再取得しません。Nuxt 4のディレクトリ構成は[Nuxt 4とは？インストール・最新バージョン確認・Nuxt 3との違いとPinia連携まで使い方を解説](/tech/details/9938/)で詳しく扱っています。

## VuexからPiniaへの移行手順

VuexとPiniaは同じプロジェクトに同時にインストールできるので、画面や機能の単位で段階的に移せます。公式の移行ガイドが示す対応関係は次の4点です。

- **モジュール**：Vuexのモジュール1つをPiniaのストア1つにする。入れ子のモジュールも、それぞれ独立したストアにする。
- **名前空間**：ストアIDに旧名前空間に対応する名前を付ける（公式の例では `nested/module2` を `'nestedModule2'` にしている）。フォルダ名も `store` ではなく複数形の `stores` にする。
- **mutations**：actionsに統合する。単純な代入だけのmutationは削除し、呼び出し側で直接代入するか `$patch` を使う。
- **rootState・rootGetters**：他のストアをimportして呼ぶ形に書き換える。

コンポーネント側で `mapState`・`mapActions` を使っていた箇所は、Piniaにも同名のヘルパー（`mapState()`・`mapActions()`・`mapStores()`）があるので、Options APIのままでも書き換えられます。移行の優先度を判断する材料として、Vuexには2022年10月以降リリースが無く、新機能が追加されないことを押さえておいてください。

## Piniaのテスト：createTestingPiniaの既定動作

コンポーネントのテストでは、`@pinia/testing`（最新2.0.1）の `createTestingPinia()` を使います。見落としやすいのは、**既定でactionsがすべてスタブ（呼び出しを記録するだけの空関数）に置き換わる**点です。Vitest 5.0.2で確かめると、`increment()` を呼んでも呼び出し回数だけが1になり、stateは0のままでした。

```
import { createTestingPinia } from '@pinia/testing'
import { setActivePinia } from 'pinia'
import { vi } from 'vitest'

setActivePinia(createTestingPinia({
  createSpy: vi.fn,                              // globals: true でなければ必須
  stubActions: false,                            // actionsを実際に実行する
  initialState: { counter: { count: 20 } },      // ストアIDごとに初期stateを指定
}))
```

もう1つの落とし穴は、Setup Storeの中でaction同士を呼ぶ場合です。`incTwice()` の中から `inc()` を2回呼ぶストアで `stubActions: false` にして `incTwice()` を実行すると、stateは2になりましたが、`inc` のスパイの呼び出し回数は0でした。ストア内部の呼び出しは閉じ込められた関数を直接呼ぶため、スパイを経由しません。公式ドキュメントにも同じ注意があります。内部呼び出しを検証したいなら、呼び出し回数ではなくstateの結果で確かめます。Vitestでのコンポーネントテストの組み方は[Vitestの使い方｜React Testing Libraryでコンポーネントテストを書く実践ガイド【2026年版】](/tech/details/2867/)も参考になります。

## Piniaを使わない方がよい場面

Piniaは導入が軽いぶん、何でもストアに入れてしまいがちです。次の場合は使わない判断をしてください。

- **親子2〜3階層で完結するデータ**：propsとemit、または `provide`/`inject` で足りる。ストアに入れると、どの画面が値を変えたかを追いにくくなる。
- **処理の共有だけが目的**：状態を持たない、あるいは呼び出し元ごとに別の状態を持つならコンポーザブルにする。同じPiniaインスタンス内ではストアIDごとに1つのインスタンスを共有する。SSRではリクエストごとにPiniaインスタンスを分ける。
- **サーバーから取ってきたデータのキャッシュ**：Pinia本体のstateとactionsだけで作ると、再取得・キャッシュの破棄・読み込み中の状態を手で管理することになる。避けたいのはこのキャッシュ管理の自作で、Piniaの導入そのものではない。Piniaの作者Eduardo San Martin Morote氏が開発する `@pinia/colada`（1.4.6、npmの説明は「The smart data fetching layer for Vue.js」）は、Piniaを土台にこの部分を受け持つデータ取得用のライブラリで、自作より短く書ける。
- **Vue 2.6以前のプロジェクト**：Vue 2.6で使う場合は、Vue 2.6対応のPinia 2.2系以前と `@vue/composition-api` が必要になる。Pinia 2.3以降はVue 2.7以上が必要で、3系以降はVue 2に対応しない。Vue 3への移行と合わせて検討する。

React向けの状態管理を比べる場合は[Zustandとは？Reactの状態管理を最小コードで実現する使い方を徹底解説【v5対応】](/tech/details/7615/)を参照してください。PiniaはVueのリアクティブシステムの上に作られているため、Reactでは使えません。

## よくある質問

### Piniaの読み方は？

「ピーニャ」です。公式ドキュメントが発音を `/piːnjʌ/`（英語の “peenya” に近い）と示しており、スペイン語でパイナップルを意味する _piña_ が由来です。

### VuexとPiniaはどちらを使うべきですか？

新規開発ならPiniaです。Vue公式ドキュメントはVuexを保守モードとし、新しいアプリにはPiniaを推奨しています。既存のVuexプロジェクトは動き続けますが、2022年10月の4.1.0以降リリースが無いため、段階的な移行を計画してください。

### Piniaの最新バージョンは？

2026年9月28日時点で4.0.3（2026年8月12日公開）です。4系は2026年7月14日に出ました。最新はnpmで `npm view pinia version` を実行すると確認できます。

### PiniaはReactでも使えますか？

使えません。PiniaはVueのリアクティブシステム（`ref`・`reactive`）に依存しており、peer dependencyにもVueが入っています。ReactならZustandやRedux Toolkitが相当します。

### Piniaのstateをリロード後も残せますか？

Pinia本体には永続化の機能はありません。`pinia-plugin-persistedstate` を `pinia.use()` で登録し、ストアに `persist: true` を付けると、既定でlocalStorageに保存・復元されます。

## 関連記事

- [Composition APIとは？書き方とOptions APIとの違い・移行判断を解説【2026年8月版】](/tech/details/3589/)
- [Nuxt 4とは？インストール・最新バージョン確認・Nuxt 3との違いとPinia連携まで使い方を解説](/tech/details/9938/)
- [Nuxtとは：Vue.jsとの違い・レンダリング方式・4系への移行手順と採用判断を実装視点で解説](/tech/details/15790/)
- [ReactとVue3の違いを比較｜どっちを選ぶべきか初心者向けに解説](/tech/details/2348/)
- [Redux Toolkitとは？createSliceとRTK Queryの実装と採用判断【2026年8月版】](/tech/details/16013/)

---

出典: [Piniaとは？読み方・使い方とVuexとの違い【Pinia 4対応】](<https://www.issoh.co.jp/tech/details/3513/>)（株式会社一創）
