Configurable persistence and rehydration of Pinia stores with SSR-friendly Nuxt integration.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Configuration options for individual store persistence behavior, including storage selection, state filtering, and lifecycle hooks. Each store can configure its own persistence settings independently of global plugin options.
Configure how individual stores persist their state with fine-grained control over storage, serialization, and state selection.
/**
* Persistence options for individual stores
*/
interface PersistenceOptions<State = any> {
/** Storage key to use (defaults to store.$id) */
key?: string;
/** Enable debug logging for this store */
debug?: boolean;
/** Storage backend for this store */
storage?: StorageLike;
/** Serializer for state conversion */
serializer?: Serializer;
/** Hook called before hydrating store */
beforeHydrate?: (context: PiniaPluginContext) => void;
/** Hook called after hydrating store */
afterHydrate?: (context: PiniaPluginContext) => void;
/** Dot-notation paths to include in persistence */
pick?: Path<State>[] | string[];
/** Dot-notation paths to exclude from persistence */
omit?: Path<State>[] | string[];
}
/**
* Dot-notation path type for deep object property access
*/
type Path<T> = string;
/**
* Persist option types for store configuration
*/
type Persist<State = any> = boolean | PersistenceOptions<State> | PersistenceOptions<State>[];Usage Examples:
import { defineStore } from 'pinia';
// Simple boolean persistence
export const useSimpleStore = defineStore('simple', {
state: () => ({ count: 0 }),
persist: true,
});
// Configured persistence
export const useConfiguredStore = defineStore('configured', {
state: () => ({
user: { name: 'John', email: 'john@example.com' },
settings: { theme: 'dark', notifications: true },
tempData: 'not persisted',
}),
persist: {
key: 'user-store',
storage: sessionStorage,
pick: ['user', 'settings'], // Only persist these fields
},
});
// Multiple persistence configurations
export const useMultiStore = defineStore('multi', {
state: () => ({
localData: 'saved locally',
sessionData: 'saved in session',
tempData: 'not saved',
}),
persist: [
{
key: 'local-data',
storage: localStorage,
pick: ['localData'],
},
{
key: 'session-data',
storage: sessionStorage,
pick: ['sessionData'],
},
],
});Stores with persistence enabled automatically receive additional methods for manual hydration and persistence control.
/**
* Additional methods added to persisted stores
*/
interface PiniaCustomProperties {
/** Manually hydrate store from configured storage */
$hydrate: (opts?: { runHooks?: boolean }) => void;
/** Manually persist store to configured storage */
$persist: () => void;
}Usage Examples:
const store = useMyStore();
// Manual hydration (useful for conditional loading)
store.$hydrate();
// Manual hydration without hooks
store.$hydrate({ runHooks: false });
// Manual persistence (useful for explicit save points)
store.$persist();Custom storage key for the store, overriding the default store ID.
interface PersistenceOptions {
key?: string;
}Usage Example:
export const useStore = defineStore('internal-store-id', {
state: () => ({ data: [] }),
persist: {
key: 'user-friendly-key', // Stored as 'user-friendly-key' instead of 'internal-store-id'
},
});Choose storage backend for this specific store.
interface PersistenceOptions {
storage?: StorageLike;
}Usage Examples:
// Use sessionStorage
persist: {
storage: sessionStorage,
}
// Custom storage
persist: {
storage: {
getItem: (key) => indexedDB.getItem(key),
setItem: (key, value) => indexedDB.setItem(key, value),
},
}Control which parts of the state are persisted using pick/omit patterns.
interface PersistenceOptions<State> {
/** Include only these paths */
pick?: Path<State>[] | string[];
/** Exclude these paths */
omit?: Path<State>[] | string[];
}Usage Examples:
export const useUserStore = defineStore('user', {
state: () => ({
profile: {
name: 'John',
email: 'john@example.com',
preferences: {
theme: 'dark',
notifications: true,
},
},
session: {
token: 'secret',
expires: Date.now(),
},
tempData: {},
}),
persist: {
// Only persist user profile and preferences
pick: ['profile.name', 'profile.email', 'profile.preferences'],
// Alternative: exclude sensitive data
// omit: ['session.token', 'tempData'],
},
});Custom hooks that run before and after state hydration from storage.
interface PersistenceOptions {
beforeHydrate?: (context: PiniaPluginContext) => void;
afterHydrate?: (context: PiniaPluginContext) => void;
}Usage Examples:
export const useStore = defineStore('store', {
state: () => ({ version: '1.0', data: [] }),
persist: {
beforeHydrate: (context) => {
console.log('About to hydrate store:', context.store.$id);
},
afterHydrate: (context) => {
// Migrate data if needed
const store = context.store;
if (store.version !== '1.0') {
// Perform migration logic
store.version = '1.0';
}
},
},
});Custom serialization for this store, overriding global serializer.
interface PersistenceOptions {
serializer?: Serializer;
}
interface Serializer {
serialize: (data: any) => string;
deserialize: (data: string) => any;
}Usage Example:
export const useStore = defineStore('store', {
state: () => ({ sensitiveData: 'secret' }),
persist: {
serializer: {
serialize: (data) => btoa(JSON.stringify(data)), // Base64 encode
deserialize: (data) => JSON.parse(atob(data)), // Base64 decode
},
},
});Install with Tessl CLI
npx tessl i tessl/npm-pinia-plugin-persistedstate