Vue cookbook · Beginner
Persist a Pinia store to localStorage
The cart or preferences disappear when users reload the page.
Approach
Load the initial state from storage in the setup store, save changes with a deep watcher, and guard against
invalid stored data and server-side rendering (no localStorage on the server).
Solution
// stores/preferences.ts
import { defineStore } from "pinia";
import { ref, watch } from "vue";
type Preferences = { theme: "light" | "dark" | "system"; currency: string; recentSearches: string[] };
const KEY = "preferences:v1";
const defaults: Preferences = { theme: "system", currency: "USD", recentSearches: [] };
function load(): Preferences {
if (typeof window === "undefined") return { ...defaults };
try {
return { ...defaults, ...JSON.parse(localStorage.getItem(KEY) ?? "{}") };
} catch {
return { ...defaults }; // corrupted or old data
}
}
export const usePreferences = defineStore("preferences", () => {
const prefs = ref<Preferences>(load());
watch(prefs, (value) => {
if (typeof window !== "undefined") localStorage.setItem(KEY, JSON.stringify(value));
}, { deep: true });
function addSearch(term: string) {
prefs.value.recentSearches = [term, ...prefs.value.recentSearches.filter((t) => t !== term)].slice(0, 5);
}
return { prefs, addSearch };
});
Pitfalls
- Storing sensitive data (tokens, personal data) in localStorage, readable by any script on the page.
- No version in the key, so changed shapes break old stored data.
- Reading
localStorageduring SSR.
Variations
pinia-plugin-persistedstateadds apersist: trueoption to stores.- Sync between tabs with the
storageevent.
Further reading: Pinia
Reference: https://pinia.vuejs.org/core-concepts/
More Vue recipes
- Access child component methods with template refs and defineExpose
- Add SEO metadata and structured data in Nuxt
- Build an accessible modal with Teleport
- Build custom inputs with defineModel and modifiers
- Catch component errors with an error boundary
- Debounce user input with a custom ref
- Fetch data in a composable and cancel stale requests
- Fetch, refresh and share data with Nuxt useFetch