Hook — 05 : 57 a.m., Medellín ↔ Tulum refactor sprint
A power‑flicker rattled my Colombian apartment just as Sofía, coding from a beachfront hostel in Tulum, DM’d: “Our Vuex boilerplate doubled since we moved to Vue 3, and TypeScript is screaming.” Minutes later we spiked the same feature in Pinia. Setup shrank from 120 lines to 35, hot‑module reload worked again, and the surf forecast widget stayed buttery smooth. Sofía merged the branch, packed her board, and paddled out before the sun got cruel. That save‑the‑swell moment frames today’s deep dive: choosing between Vuex and Pinia for modern Vue.js apps.


Why This Comparison Matters in 2025

Vue 3 ships with the Composition API, script‑setup sugar, and Vite’s lightning builds—but many tutorials still default to Vuex 4, a pattern born in 2015. Meanwhile, Pinia has matured into Vue’s official state‑management library, offering smaller bundles, simpler dev‑tools, and first‑class TypeScript. Picking the right store affects:


Bird’s‑Eye View at a Glance

FeaturePiniaVuex 4
API styleComposition & OptionsOptions
BoilerplateLow (no mutations)Higher (state + getters + actions + mutations)
TypeScript DXExcellent (auto‑infer)Manual typing or plugins
DevToolsTimeline, hot‑reload by defaultSupported but mutation noise
Persist PluginsPiniaPersist, localForage, etc.vuex‑persistedstate
SSR SupportBuilt‑in (ssr:true)Yes, manual hydration
Vue 2 supportVia pluginNative
Bundle size (brotli)~1.5 kB~6 kB

Step‑by‑Step Walkthroughs

1 – Declaring State

Pinia

tsCopyEdit// stores/useCart.ts
import { defineStore } from 'pinia';

export const useCart = defineStore('cart', {
  state: () => ({ items: [] as { id:number; qty:number }[] }),
  getters: {
    total: (s) => s.items.reduce((t, i) => t + i.qty, 0),
  },
  actions: {
    add(id:number) { this.items.push({ id, qty:1 }); },
  },
});

Vuex 4

// store/index.ts
import { createStore } from 'vuex';

export default createStore({
state: () => ({ items: [] }),
getters: {
total: (state) => state.items.reduce((t,i) => t+i.qty,0),
},
mutations: {
ADD(state, id:number) { state.items.push({ id, qty:1 }); },
},
actions: {
add({ commit }, id:number) { commit('ADD', id); },
},
});

Pinia skips mutations; actions mutate state directly—no switch‑case ceremony.


2 – Consuming in Components

<script setup lang="ts">
import { useCart } from '@/stores/useCart';
const cart = useCart();
</script>

<template>
<button @click="cart.add(7)">Add to cart</button>
<span>{{ cart.total }} items</span>
</template>

Reactive store properties work like component refs—no mapGetters helpers needed.


3 – Persisting State

Pinia plugin

import { createPinia } from 'pinia';
import piniaPersist from 'pinia-plugin-persistedstate';
const pinia = createPinia().use(piniaPersist);
app.use(pinia);

Add persist: true to any store definition—done.

Vuex requires configuring vuex‑persistedstate and manually whitelisting modules.


4 – Lazy Loading for Code Splitting

With Pinia you can import a store only inside routes that need it, letting Vite tree‑shake unused code. Vuex modules live in a global registry; dynamic modules are possible but verbose.


Remote‑Work Insight Box

My team in Brazil hot‑reloads features via Vite’s dev server, but huge Vuex mutation logs slowed DevTools timeline to a crawl. Migrating one module to Pinia restored instant HMR—saving at least two coffee refills per day.


Performance & Accessibility Checkpoints


Common Pitfalls & How to Dodge Them

IssuePinia FixVuex Fix
“Store is undefined”Call useX() inside setup() after pinia plugin mountedRegister module before accessing
Object loses reactivityUse set() or Vue’s reactive?Same, but mutation must commit deep copy
DevTools floodPinia shows only actionsFilter mutation logs
SSR hydration mismatchdefineStore({ ssr: true })Manual store.replaceState()

CLI Commands Worth Remembering

CommandPurpose
npm i piniaAdd Pinia
vue add piniaVue‑CLI plugin (Vue 2/3)
npx vite build --reportInspect bundle sizes
npx pinia-inspectStand‑alone dev tools if Vue DevTools blocked

Diagram (text)

Component → calls useCart() → Pinia store proxy → state, getters, actions → Vue DevTools timeline (actions only). Parallel path shows Vuex dispatch → commit → mutation logs.


Wrap‑Up

Have migration war stories or doubts? Drop them below; I’ll respond between flights and late‑night arepa sessions.


Meta: Compare Pinia and Vuex for Vue.js—features, DX, and performance insights to help teams pick the right store library for modern apps.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x