On this page
Pinia State Management
Pinia is Vue’s official state management library. It replaces Vuex with a simpler API that works naturally with the Composition API.
Installation
npm install pinia
Register in 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');
Define a Store
stores/counter.js:
import { ref, computed } from 'vue';
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++;
}
function reset() {
count.value = 0;
}
return { count, doubleCount, increment, reset };
});
This is the Setup Store syntax — mirrors Composition API patterns.
Use a Store in Components
<script setup>
import { useCounterStore } from '../stores/counter';
import { storeToRefs } from 'pinia';
const store = useCounterStore();
// Destructure reactive state with storeToRefs
const { count, doubleCount } = storeToRefs(store);
// Actions can be destructured directly
const { increment, reset } = store;
</script>
<template>
<p>Count: {{ count }} (double: {{ doubleCount }})</p>
<button @click="increment">+1</button>
<button @click="reset">Reset</button>
</template>
User Store Example
stores/user.js:
import { ref } from 'vue';
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', () => {
const user = ref(null);
const isLoggedIn = ref(false);
async function login(email, password) {
const res = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
user.value = await res.json();
isLoggedIn.value = true;
}
function logout() {
user.value = null;
isLoggedIn.value = false;
}
return { user, isLoggedIn, login, logout };
});
When to Use Pinia
| Use Pinia | Use local state |
|---|---|
| Auth user across routes | Form input on one page |
| Shopping cart | Toggle visibility |
| Shared theme/settings | Component-specific UI state |
Next: extract reusable logic into composables.