---
name: vuex-module-to-pinia-store
description: >-
  Use when migrating any Vuex pattern to Pinia. Covers module-by-module conversion of namespaced modules to defineStore, commit/dispatch migration to direct state updates, and replacing mapState/mapGetters/mapActions/mapMutations with Pinia access patterns. Triggers: "Vuex to Pinia", "commit/dispatch migration", "mapState", "mapGetters", "mapActions", "mapMutations", "direct store updates", "storeToRefs", "namespaced modules", "$store".
enabled: false
source: github:JuanJoseGonGi/skills
imported-from: github:JuanJoseGonGi/skills
---

# Vuex Module to Pinia Store

## Overview

Use this skill to migrate an entire Vuex codebase to Pinia: module conversion, commit/dispatch removal, and map helper replacement.

Supports incremental rollout with Vuex and Pinia coexisting temporarily.

## Migration Mapping

| Vuex | Pinia |
|---|---|
| `namespaced: true` module | `defineStore('id', ...)` (stores namespaced by id) |
| `state` object | `state: () => ({ ... })` |
| `getters` | `getters` |
| `mutations` | direct assignment or `actions` |
| `actions` | `actions` |
| `rootState/rootGetters` | import and use another store |
| `commit("x/y")` | direct assignment or `store.action()` |
| `dispatch("x/y")` | `store.action()` |
| `mapState` | `storeToRefs(store)` or local computed |
| `mapGetters` | direct getter access or `storeToRefs` |
| `mapActions` | call action methods on store |
| `mapMutations` | direct assignment or store action |
| `this.$store` | explicit `useXStore()` instance |

## Workflow

### 1. Snapshot Module Contract

- List public actions/getters used by components.
- Keep names stable initially to reduce call-site churn.

### 2. Create Pinia Store Next to Module

- Name id from namespace (camelCase recommended).
- Start with option stores for easier Vuex parity.

### 3. Move State and Getters

- Keep behavior identical before changing business logic.
- Remove trivial getters that only mirror state.

### 4. Convert Mutations → See [commit-dispatch-patterns](references/commit-dispatch-patterns.md)

Classify each mutation:
- **Trivial setter** → direct assignment at call site
- **Domain invariant** → named store action preserving the invariant
- **Side-effect hook** → action with explicit side-effect boundary

### 5. Convert Actions

- Replace `{ commit, dispatch, state }` context with `this`.
- Replace cross-module dispatches with direct store imports.
- Use typed args and return values.

### 6. Replace Map Helpers → See [map-helpers-patterns](references/map-helpers-patterns.md)

#### Composition API (`<script setup>`)

```ts
import { storeToRefs } from "pinia"
import { useUsersStore } from "@/stores/users"

const usersStore = useUsersStore()
const { users, loading } = storeToRefs(usersStore)
await usersStore.fetchUsers()
```

#### Options API (incremental migration)

```ts
import { useUsersStore } from "@/stores/users"

export default {
  computed: {
    users() { return useUsersStore().users },
  },
  methods: {
    fetchUsers() { return useUsersStore().fetchUsers() },
  },
}
```

### 7. Remove Vuex Module

- Delete module registration only after all call sites and tests pass.
- Remove `$store` access for migrated domains.

## Recommended Template

```ts
import { defineStore } from "pinia"

interface AuthState {
  token: string | null
}

export const useAuthStore = defineStore("auth", {
  state: (): AuthState => ({ token: null }),
  getters: {
    isLoggedIn: (state) => !!state.token,
  },
  actions: {
    setToken(token: string | null) {
      this.token = token
    },
  },
})
```

## Done Criteria

- No component references the old module namespace.
- No `commit`/`dispatch` string paths remain for migrated domain.
- No Vuex map helpers remain in migrated files.
- No `this.$store` access remains for migrated domains.
- Store behavior matches previous tests.
- Pinia store has typed state/getters/actions.

## Common Pitfalls

- Keeping Vuex-like mutation ceremony in Pinia when direct assignment is enough.
- Migrating module internals before inventorying external dependencies.
- Accessing stores outside runtime contexts in router guards or boot files.
- Converting every mutation to action blindly, preserving unnecessary indirection.
- Spreading domain rules across components after removing mutations.
- Forgetting to unwrap refs in script logic when using `storeToRefs`.
- Recreating store instances inside tight loops.
- Replacing a mutation with direct assignment when it encoded domain invariants.
