Intuitive, type safe and flexible Store for Vue
Pinia is the official state management solution for Vue.js applications, specifically designed for Vue 3's Composition API. It replaces Vuex as the recommended approach for sharing reactive state across components, offering a dramatically simplified API that eliminates mutations, magic strings, and nested module structures. Instead of the traditional Flux pattern, Pinia provides a flat store architecture where actions directly mutate state, getters compute derived values, and everything is typed by default.
The library was created by Eduardo San Martin Morote (a Vue.js core team member) to address Vuex's complexity and provide better TypeScript integration. With over 2.8 million weekly downloads, Pinia has become the de facto standard for Vue 3 projects requiring centralized state management. It's particularly valuable in medium-to-large applications where prop drilling becomes unwieldy or when multiple components need synchronized access to shared data like user authentication, shopping carts, or application settings.
Pinia's core philosophy centers on developer experience: stores are defined with defineStore(), accessed directly as functions, and fully tree-shakable. The library weighs only ~1KB gzipped and includes first-class SSR support, hot module replacement, and Vue DevTools integration with time-travel debugging. Unlike Vuex, Pinia requires no manual store registration—stores are automatically available when imported, and they support circular dependencies out of the box.
While optional for small Vue apps (Composition API's ref() and provide/inject may suffice), Pinia shines when you need organized state patterns, computed state across components, plugin ecosystems (like persistence to localStorage), or predictable state changes during debugging. It works seamlessly with Nuxt 3 through dedicated modules and maintains backward compatibility with Vue 2 via a separate branch.
import { createApp } from 'vue';
import { createPinia, defineStore } from 'pinia';
import { storeToRefs } from 'pinia';
// Define a counter store with state, getters, and actions
const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
history: []
}),
getters: {
doubleCount: (state) => state.count * 2,
historyLength: (state) => state.history.length
},
actions: {
increment() {
this.count++;
this.history.push(`Incremented to ${this.count}`);
},
async fetchInitialCount() {
const response = await fetch('/api/count');
const data = await response.json();
this.count = data.count;
}
}
});
// Setup in main.js
const app = createApp(App);
app.use(createPinia());
app.mount('#app');
// Usage in a component
export default {
setup() {
const counterStore = useCounterStore();
// Destructure with reactivity preservation
const { count, doubleCount } = storeToRefs(counterStore);
// Actions destructure directly (not reactive)
const { increment } = counterStore;
// Or call directly
const handleClick = () => counterStore.increment();
return { count, doubleCount, increment, handleClick };
}
};Global authentication state: Store user login status, permissions, and tokens in a Pinia store accessible from navigation guards, header components, and protected routes without prop drilling through component hierarchies.
E-commerce shopping cart: Manage cart items, totals, and discounts with actions like addToCart() and getters like cartTotal, enabling synchronization between product lists, cart dropdowns, and checkout pages with automatic reactivity.
Multi-step form wizard: Share form data across wizard steps where each step is a separate component, using Pinia to persist partial data, validate across steps, and handle submission without passing props through intermediate wrapper components.
Real-time notifications system: Centralize WebSocket message handling in a Pinia store that receives server events, updates notification counts, and triggers UI updates across multiple components (navbar badge, notification panel, page-specific alerts) simultaneously.
Application settings and theme management: Store user preferences like dark mode, language selection, and layout density with Pinia plugins to persist to localStorage, making settings instantly available across all components and surviving page refreshes.
npm install piniapnpm add piniabun add pinia