Vue 3 Pinia vs Vuex: Modernes State Management und Interviewfragen 2026
Pinia vs Vuex im direkten Vergleich: API-Design, TypeScript-Unterstützung, Performance, Migrationsstrategien und häufige Vue-Interviewfragen zum State Management 2026.

Pinia vs Vuex markiert den bedeutendsten Umbruch im Vue State Management seit der Veröffentlichung von Vue 3. Da Pinia 3 mittlerweile die offizielle Empfehlung darstellt und Vuex nur noch im Wartungsmodus gepflegt wird, ist das Verständnis der Unterschiede zwischen beiden Bibliotheken für Vue-Entwickler unverzichtbar — und ein häufiges Thema in technischen Vorstellungsgesprächen.
Pinia ist die offizielle State-Management-Lösung für Vue 3. Vuex 5 wurde eingestellt, und Evan You hat Pinia als das de facto Vuex 5 bezeichnet. Alle neuen Vue-3-Projekte sollten Pinia 3 verwenden.
Pinia vs Vuex: Grundlegende Architekturunterschiede
Der fundamentale Architekturunterschied zwischen Pinia und Vuex liegt in der Art und Weise, wie State-Mutationen ablaufen. Vuex erzwingt einen strikten unidirektionalen Datenfluss: Komponenten dispatchen Actions, Actions committen Mutations, und Mutations verändern den State. Pinia entfernt die Mutation-Schicht vollständig und ermöglicht direkte State-Änderungen aus Actions oder sogar aus Komponenten heraus.
Diese Vereinfachung reduziert den Boilerplate-Code in den meisten Codebasen um etwa 40 %. Während Vuex vier Konzepte erfordert (State, Getters, Mutations, Actions), kommt Pinia mit drei aus (State, Getters, Actions).
| Feature | Pinia 3 | Vuex 4 | |---------|---------|--------| | Mutations | Keine (direkte State-Änderungen) | Erforderlich für State-Änderungen | | TypeScript | Volle Inferenz, keine Augmentation | Manuelle Typ-Augmentation nötig | | Store-Architektur | Mehrere flache Stores | Einzelner Store mit verschachtelten Modulen | | Composition API | Native Unterstützung | Options-API-basiert | | Bundle-Größe | ~1 KB gzipped | ~6 KB gzipped | | Vue Devtools | Volle Unterstützung (v7) | Volle Unterstützung | | SSR | Integriert | Konfiguration erforderlich | | Hot Module Replacement | Integriert | Manuelle Einrichtung |
Stores definieren: Options API vs Setup-Syntax
Pinia bietet zwei Syntaxvarianten für die Store-Definition. Die Options-Syntax orientiert sich an der Vuex-Struktur und erleichtert die Migration. Die Setup-Syntax nutzt die Composition API von Vue 3 für maximale Flexibilität.
import { defineStore } from 'pinia'
// Options Store Syntax — vertraut für Vuex-Entwickler
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
lastUpdated: null as Date | null,
}),
getters: {
// Getters erhalten state als erstes Argument mit voller Typ-Inferenz
doubleCount: (state) => state.count * 2,
isPositive(): boolean {
// Zugriff auf andere Getters über `this`
return this.count > 0
},
},
actions: {
increment() {
// Direkte State-Mutation — kein commit() nötig
this.count++
this.lastUpdated = new Date()
},
async fetchCount(id: string) {
// Asynchrone Actions funktionieren ohne zusätzliche Konfiguration
const response = await fetch(`/api/counters/${id}`)
const data = await response.json()
this.count = data.count
},
},
})Die Options-Syntax bildet Vuex-Konzepte direkt ab. State ersetzt Vuex State, Getters bleiben Getters, und Actions übernehmen sowohl Vuex Actions als auch Mutations.
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
// Setup Store Syntax — identische Muster wie Composition API
export const useCounterStore = defineStore('counter', () => {
// ref() wird zu State
const count = ref(0)
const lastUpdated = ref<Date | null>(null)
// computed() wird zu Getters
const doubleCount = computed(() => count.value * 2)
const isPositive = computed(() => count.value > 0)
// Funktionen werden zu Actions
function increment() {
count.value++
lastUpdated.value = new Date()
}
async function fetchCount(id: string) {
const response = await fetch(`/api/counters/${id}`)
const data = await response.json()
count.value = data.count
}
// Alle State-Eigenschaften, Getters und Actions müssen zurückgegeben werden
return { count, lastUpdated, doubleCount, isPositive, increment, fetchCount }
})Die Setup-Syntax bietet volle Flexibilität: Watchers, Composable-Wiederverwendung und bedingte Logik funktionieren innerhalb der Store-Definition auf natürliche Weise. Der Nachteil: Jede reaktive Eigenschaft und Methode muss explizit zurückgegeben werden.
TypeScript-Integration: Wo Pinia Vuex übertrifft
Die TypeScript-Unterstützung ist der Bereich, in dem Pinia eindeutig gewinnt. Vuex 4 erfordert manuelle Typ-Augmentation über Modul-Deklarationen, und bei komplexen verschachtelten Modulen wird die Typ-Inferenz brüchig. Pinia leitet Typen automatisch aus der Store-Definition ab.
// Vuex 4 — manuelle Typ-Augmentation erforderlich
import { Store } from 'vuex'
declare module 'vuex' {
interface State {
counter: {
count: number
lastUpdated: Date | null
}
}
}
// Zugriff auf State erfordert Type Assertions oder eigene Helfer
const count = (store.state as { counter: { count: number } }).counter.count// Pinia — volle Typ-Inferenz, keine Konfiguration
const counter = useCounterStore()
// TypeScript erkennt counter.count als number
// TypeScript erkennt counter.doubleCount als number
// TypeScript erkennt counter.increment() als void
// TypeScript erkennt counter.fetchCount() als Promise<void>
counter.increment()
console.log(counter.doubleCount)Pinia unterstützt außerdem generische Stores für wiederverwendbare Muster — eine Fähigkeit, die in Vuex erheblichen Boilerplate-Code erfordert.
Composition API und Composable-Integration
Pinia Setup Stores akzeptieren beliebige Vue Composables und ermöglichen leistungsstarke Muster wie gemeinsam genutzte VueUse-Utilitys oder router-abhängigen State.
import { defineStore } from 'pinia'
import { ref, watch } from 'vue'
import { useDebounceFn } from '@vueuse/core'
import { useRoute } from 'vue-router'
export const useSearchStore = defineStore('search', () => {
const route = useRoute()
const query = ref('')
const results = ref<SearchResult[]>([])
const isLoading = ref(false)
// VueUse Composable direkt im Store verwendet
const debouncedSearch = useDebounceFn(async (term: string) => {
if (!term.trim()) {
results.value = []
return
}
isLoading.value = true
try {
const res = await fetch(`/api/search?q=${encodeURIComponent(term)}`)
results.value = await res.json()
} finally {
isLoading.value = false
}
}, 300)
// Watcher synchronisiert URL-Query-Parameter mit Store-State
watch(() => route.query.q, (q) => {
if (typeof q === 'string') {
query.value = q
debouncedSearch(q)
}
})
function setQuery(term: string) {
query.value = term
debouncedSearch(term)
}
return { query, results, isLoading, setQuery }
})Dieses Muster ist in Vuex ohne Umwege nicht möglich. Vuex-Module können in ihrer Definition keine Composables, Watchers oder Router-Hooks verwenden. Die Store-Logik muss zwischen dem Vuex-Modul und externen Hilfsfunktionen aufgeteilt werden.
Bereit für deine Vue.js / Nuxt.js-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Store-Kommunikation und Store-übergreifende Referenzen
Vuex verwendet einen einzelnen Root-Store mit namespaced Modulen. Der Zugriff auf State über Module hinweg erfordert umständliche rootState- und rootGetters-Parameter. Pinia Stores sind bewusst unabhängig gestaltet, und die store-übergreifende Kommunikation erfolgt über direkte Imports.
import { defineStore } from 'pinia'
import { useProductStore } from './products'
import { useAuthStore } from './auth'
import { ref, computed } from 'vue'
export const useCartStore = defineStore('cart', () => {
const items = ref<CartItem[]>([])
const total = computed(() => {
// Zugriff auf einen anderen Store durch Aufruf seines Composable
const productStore = useProductStore()
return items.value.reduce((sum, item) => {
const product = productStore.getById(item.productId)
return sum + (product?.price ?? 0) * item.quantity
}, 0)
})
async function checkout() {
const auth = useAuthStore()
if (!auth.isAuthenticated) {
throw new Error('Authentifizierung erforderlich')
}
// Checkout-Logik
}
return { items, total, checkout }
})Diese flache Store-Architektur vermeidet die tief verschachtelten Modulbäume, die große Vuex-Anwendungen schwer navigierbar und refaktorierbar machen.
Migration von Vuex 4 zu Pinia 3
Die Migration von Vuex zu Pinia kann Modul für Modul erfolgen. Beide Bibliotheken können während der Übergangsphase koexistieren. Die empfohlene Strategie: mit Blatt-Modulen beginnen (Stores, von denen keine anderen Module abhängen) und sich nach innen vorarbeiten.
Pinia und Vuex können in derselben Anwendung parallel betrieben werden. Pinia neben Vuex installieren, ein Modul nach dem anderen migrieren und Vuex erst entfernen, wenn alle Module konvertiert sind.
// Vorher: Vuex-Modul
// store/modules/user.ts
const userModule = {
namespaced: true,
state: () => ({
profile: null as UserProfile | null,
preferences: {} as UserPreferences,
}),
mutations: {
SET_PROFILE(state, profile: UserProfile) {
state.profile = profile
},
UPDATE_PREFERENCES(state, prefs: Partial<UserPreferences>) {
state.preferences = { ...state.preferences, ...prefs }
},
},
actions: {
async fetchProfile({ commit }) {
const profile = await api.getProfile()
commit('SET_PROFILE', profile)
},
async updatePreferences({ commit }, prefs: Partial<UserPreferences>) {
await api.updatePreferences(prefs)
commit('UPDATE_PREFERENCES', prefs)
},
},
getters: {
isLoggedIn: (state) => state.profile !== null,
displayName: (state) => state.profile?.name ?? 'Guest',
},
}// Nachher: Pinia Store
// stores/user.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { api } from '@/lib/api'
export const useUserStore = defineStore('user', () => {
const profile = ref<UserProfile | null>(null)
const preferences = ref<UserPreferences>({})
const isLoggedIn = computed(() => profile.value !== null)
const displayName = computed(() => profile.value?.name ?? 'Guest')
async function fetchProfile() {
profile.value = await api.getProfile()
}
async function updatePreferences(prefs: Partial<UserPreferences>) {
await api.updatePreferences(prefs)
Object.assign(preferences.value, prefs)
}
return { profile, preferences, isLoggedIn, displayName, fetchProfile, updatePreferences }
})Das Migrationsmuster ist konsistent: Mutations verschmelzen mit direkten Zuweisungen in Actions, commit()-Aufrufe entfallen, und mapState/mapGetters-Helfer werden durch Destrukturierung des Store-Composable ersetzt.
SSR State Hydration mit Pinia und Nuxt 4
Server-Side Rendering bringt Komplexität für das State Management mit sich. Pinia übernimmt die SSR-State-Serialisierung und Hydration in Nuxt 4 automatisch, während Vuex eine manuelle window.__INITIAL_STATE__-Behandlung erfordert.
Setup Stores, die Composables wie useRoute() oder useFetch() verwenden, müssen im SSR-Kontext sorgfältig behandelt werden. Diese Composables dürfen nur während der Setup-Phase aufgerufen werden, niemals innerhalb asynchroner Callbacks.
import { defineStore } from 'pinia'
export const useProductStore = defineStore('products', {
state: () => ({
items: [] as Product[],
selectedCategory: 'all',
}),
actions: {
async fetchProducts() {
// useFetch ist Nuxt-spezifisch — $fetch für Store Actions verwenden
this.items = await $fetch<Product[]>('/api/products', {
query: { category: this.selectedCategory },
})
},
},
getters: {
getById: (state) => (id: string) =>
state.items.find((item) => item.id === id),
filteredCount: (state) =>
state.items.filter((p) => p.inStock).length,
},
})Nuxt 4 serialisiert den Pinia-State automatisch auf dem Server und hydriert ihn auf dem Client. Keine manuelle replaceState()- oder Dehydrierungslogik erforderlich.
Performance-Vergleich und Bundle-Auswirkung
Pinias Footprint von ~1 KB gzipped ist etwa sechsmal kleiner als die ~6 KB von Vuex. In Anwendungen mit Code Splitting sind Pinia Stores tree-shakable: Nicht verwendete Stores und ihre Abhängigkeiten werden aus Produktions-Bundles ausgeschlossen.
Laufzeit-Performance-Unterschiede sind für die meisten Anwendungen vernachlässigbar. Beide Bibliotheken verwenden unter der Haube das Reaktivitätssystem von Vue. Der praktische Performance-Gewinn ergibt sich aus reduziertem Boilerplate, der zu weniger Re-Renders führt, die durch zu breite State-Subscriptions verursacht werden — Pinias flaches Store-Modell fördert granulare Stores, was bedeutet, dass Komponenten weniger State abonnieren.
Mit der Einführung des Vapor Mode in Vue 3.6 profitieren sowohl Pinia als auch Vuex von der schnelleren Rendering-Pipeline. Allerdings ist Pinia durch seine engere Integration mit der Composition API besser für Vapor-Mode-Optimierungen aufgestellt.
Häufige Vue State Management Interviewfragen
In technischen Vorstellungsgesprächen wird häufig Wissen zum State Management geprüft. Hier sind die Fragen, die 2026 am häufigsten in Vue-Entwickler-Interviews gestellt werden.
F: Warum wurde die Mutation-Schicht von Vuex in Pinia entfernt?
Mutations existierten in Vuex, um Time-Travel-Debugging in den DevTools zu ermöglichen. Jede State-Änderung musste über eine synchrone Mutation laufen, damit die DevTools Snapshots aufzeichnen konnten. Pinia erreicht dieselbe Debugging-Fähigkeit, indem State-Änderungen auf reaktiver Ebene verfolgt werden, wodurch die explizite Mutation-Schicht überflüssig wird. Das Ergebnis: weniger Boilerplate, gleiche Debugging-Möglichkeiten.
F: Wann sollte ein Setup Store einem Options Store vorgezogen werden?
Setup Stores sind die bessere Wahl, wenn der Store Composables (useRoute, useDebounceFn), komplexe Watchers oder gemeinsam genutzte Logik aus externen Composable-Funktionen benötigt. Options Stores eignen sich gut für unkomplizierten CRUD-State mit einfachen Getters. In der Praxis sind Setup Stores in Produktions-Codebasen häufiger, da sie die Muster der Composition API in Komponenten widerspiegeln.
F: Wie behandelt Pinia die Reaktivität bei verschachtelten Objekten?
Pinia verwendet reactive() von Vue für das gesamte State-Objekt und ref() für einzelne Eigenschaften in Setup Stores. Deep Reactivity gilt standardmäßig — Änderungen an verschachtelten Objekten werden automatisch verfolgt. Für performance-kritische Fälle mit großen Datensätzen kann shallowRef() die Deep Reactivity deaktivieren.
F: Store-zu-Store-Abhängigkeiten in Pinia vs Vuex erklären.
In Vuex erfolgt der modulübergreifende Zugriff über rootState- und rootGetters-Parameter in Actions, was zu impliziter Kopplung führt. In Pinia importieren Stores einander direkt über useOtherStore()-Aufrufe. Das macht Abhängigkeiten explizit und ermöglicht TypeScript, sie zur Compile-Zeit zu überprüfen. Zirkuläre Abhängigkeiten funktionieren in Pinia, solange sie nicht während der initialen Setup-Phase aufgerufen werden.
F: Was passiert mit dem Pinia-State während der SSR-Hydration?
Während des SSR serialisiert Pinia alle aktiven Store-States zu JSON und bettet das Ergebnis in den HTML-Payload ein. Auf dem Client hydriert Pinia jeden Store, bevor Komponenten gemountet werden. Jeder State, der während des serverseitigen Renderings gesetzt wurde, ist sofort auf dem Client verfügbar, ohne dass API-Aufrufe dupliziert werden müssen. In Nuxt 4 ist dieser Prozess vollständig automatisiert.
Für weitere Vue- und Nuxt-Interviewvorbereitung bieten sich das State Management Interview-Modul oder das Vue Composables Modul an.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Fazit
- Pinia 3 ist die offizielle Vue State Management Bibliothek — Vuex befindet sich im Wartungsmodus ohne geplante v5-Veröffentlichung
- Die Mutation-Schicht ist verschwunden: Pinia Actions ändern den State direkt und reduzieren Boilerplate um ~40 %
- TypeScript-Inferenz funktioniert in Pinia sofort ohne jegliche Augmentation, im Gegensatz zu Vuex's manuellen Typ-Deklarationen
- Setup Stores integrieren sich nahtlos mit der Vue 3 Composition API und ermöglichen Composable-Wiederverwendung sowie Watchers innerhalb von Stores
- Flache Store-Architektur ersetzt Vuex's verschachtelten Modulbaum und macht Store-übergreifende Kommunikation explizit und typsicher
- Migration kann inkrementell erfolgen: Pinia und Vuex koexistieren und ermöglichen eine Modul-für-Modul-Konvertierung
- SSR-Hydration ist in Nuxt 4 mit Pinia automatisch — keine manuelle Serialisierung nötig
- Für alle neuen Vue-3-Projekte in 2026 ist Pinia die klare Wahl mit besserer Developer Experience, kleineren Bundles und stärkerer Ökosystem-Unterstützung
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Tags
Teilen
Verwandte Artikel

Wichtige Vue.js-Interviewfragen: 25 Fragen für den Job
Vorbereitung auf Vue.js-Interviews mit diesen 25 wichtigen Fragen. Von Reaktivität bis zu Composables die Schlüsselkonzepte für das nächste Gespräch.

Nuxt 3: SSR und statische Generierung, der vollständige Leitfaden
SSR und statische Generierung mit Nuxt 3 meistern. Von useFetch bis Route Rules: So lässt sich die Performance von Vue.js-Anwendungen optimieren.

Vue 3 Composition API: Der vollständige Leitfaden zur Reaktivität
Die Vue 3 Composition API praxisnah erklärt: ref, reactive, computed, watch und Composables für leistungsstarke Vue-Anwendungen.