createPersister()
Creates a persister instance for saving and restoring flow state. Adds features like TTL, versioning, and validation on top of storage stores.
Import
Section titled “Import”import { createPersister } from "@useflow/react";Signature
Section titled “Signature”function createPersister(options: PersisterOptions): FlowPersisterParameters
Section titled “Parameters”options
Section titled “options”Configuration object for the persister:
type PersisterOptions = { store: FlowStore; // Required: Storage backend ttl?: number; // Optional: Time to live in ms validate?: (state: PersistedFlowState) => boolean; // Optional: State validation onSave?: (flowId: string, state: PersistedFlowState) => void; // Optional: Save callback onRestore?: (flowId: string, state: PersistedFlowState) => void; // Optional: Restore callback onError?: (error: Error) => void; // Optional: Error handler}Storage stores
Section titled “Storage stores”Built-in stores
Section titled “Built-in stores”import { createLocalStorageStore, createSessionStorageStore, createMemoryStore} from "@useflow/react";
// Browser localStorageconst localStore = createLocalStorageStore();
// Browser sessionStorageconst sessionStore = createSessionStorageStore();
// In-memory (for testing)const memoryStore = createMemoryStore();Custom store interface
Section titled “Custom store interface”type FlowStore = { get: (flowId: string, options?: FlowStoreOptions) => Promise<PersistedFlowState | null> | PersistedFlowState | null; set: (flowId: string, state: PersistedFlowState, options?: FlowStoreOptions) => Promise<void> | void; remove: (flowId: string, options?: FlowStoreOptions) => Promise<void> | void; removeFlow?: (flowId: string) => Promise<void> | void; removeAll?: () => Promise<void> | void;}
type FlowStoreOptions = { instanceId?: string; variantId?: string;}Examples
Section titled “Examples”Basic persistence
Section titled “Basic persistence”import { createPersister, createLocalStorageStore } from "@useflow/react";
const persister = createPersister({ store: createLocalStorageStore()});
// Use with Flow component<Flow flow={myFlow} persister={persister} initialContext={{}}> {({ renderStep }) => renderStep({ /* ... */ })}</Flow>With ttl (time to live)
Section titled “With ttl (time to live)”const persister = createPersister({ store: createLocalStorageStore(), ttl: 7 * 24 * 60 * 60 * 1000 // 7 days});
// State older than 7 days will be ignoredWith custom validation
Section titled “With custom validation”const persister = createPersister({ store: createLocalStorageStore(), validate: (state) => { // Ensure required fields exist return state?.stepId && state?.context?.userId; }});
// Invalid states will be ignored on restoreWith callbacks
Section titled “With callbacks”const persister = createPersister({ store: createLocalStorageStore(), onSave: (flowId, state) => { console.log(`Saved ${flowId} at step ${state.stepId}`); }, onRestore: (flowId, state) => { console.log(`Restored ${flowId} from step ${state.stepId}`); }, onError: (error) => { console.error('Persistence error:', error); }});Custom storage backend
Section titled “Custom storage backend”Create a custom store for any backend:
API backend
Section titled “API backend”const apiStore: FlowStore = { get: async (flowId, options) => { const params = new URLSearchParams({ flowId, ...(options?.instanceId && { instanceId: options.instanceId }), ...(options?.variantId && { variantId: options.variantId }) }); const response = await fetch(`/api/flow-state?${params}`); if (!response.ok) return null; return response.json(); },
set: async (flowId, state, options) => { await fetch('/api/flow-state', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ flowId, state, ...options }) }); },
remove: async (flowId, options) => { const params = new URLSearchParams({ flowId, ...(options?.instanceId && { instanceId: options.instanceId }), ...(options?.variantId && { variantId: options.variantId }) }); await fetch(`/api/flow-state?${params}`, { method: 'DELETE' }); }};
const persister = createPersister({ store: apiStore });IndexedDB
Section titled “IndexedDB”const indexedDBStore: FlowStore = { get: async (flowId, options) => { const db = await openDB(); const key = formatKey(flowId, options); return db.get('flows', key); },
set: async (flowId, state, options) => { const db = await openDB(); const key = formatKey(flowId, options); await db.put('flows', state, key); },
remove: async (flowId, options) => { const db = await openDB(); const key = formatKey(flowId, options); await db.delete('flows', key); }};
// Helper to format keys consistentlyfunction formatKey(flowId: string, options?: FlowStoreOptions) { const parts = [flowId]; if (options?.variantId) parts.push(options.variantId); if (options?.instanceId) parts.push(options.instanceId); return parts.join(':');}
const persister = createPersister({ store: indexedDBStore });Persister methods
Section titled “Persister methods”The returned persister object has these methods:
save()
Section titled “save()”await persister.save( flowId: string, state: FlowState, options?: { version?: string; instanceId?: string; variantId?: string; }): Promise<PersistedFlowState | null>restore()
Section titled “restore()”await persister.restore( flowId: string, options?: { version?: string; migrate?: MigrateFunction; instanceId?: string; variantId?: string; }): Promise<PersistedFlowState | null>remove()
Section titled “remove()”await persister.remove( flowId: string, options?: { instanceId?: string; variantId?: string; }): Promise<void>removeFlow()
Section titled “removeFlow()”await persister.removeFlow( flowId: string): Promise<void>Removes all instances of a specific flow (base + all instances).
removeAll()
Section titled “removeAll()”await persister.removeAll(): Promise<void>Removes all flows managed by this persister.
Storage keys
Section titled “Storage keys”The store implementation determines the key format. For key-value stores (localStorage, sessionStorage), keys typically follow this pattern:
[flowId]:[variantId]:[instanceId]Examples:
onboarding::- Default (no variant or instance)onboarding:v2:- With variantonboarding::user123- With instancecheckout:v2:session456- All options
Different stores may use different formats. Check your store’s documentation for specifics.
Best practices
Section titled “Best practices”Handle storage errors
Section titled “Handle storage errors”<Flow flow={myFlow} persister={persister} onPersistenceError={(error) => { console.error('Storage failed:', error); // Fallback or notify user }}> {/* ... */}</Flow>Clean up old data
Section titled “Clean up old data”// Remove specific flow stateawait persister.remove('onboarding', { instanceId: 'user123' });
// Remove all instances of a flowawait persister.removeFlow?.('onboarding');
// Clear all persisted dataawait persister.removeAll?.();Instance IDs for multiple flows
Section titled “Instance IDs for multiple flows”// Different persistence for each user<Flow flow={checkoutFlow} persister={persister} instanceId={userId} // Separate storage per user> {/* ... */}</Flow>Migration support
Section titled “Migration support”Handle breaking changes in your flow:
const migration: MigrateFunction = (oldState, fromVersion) => { if (fromVersion === "v1") { // Migrate v1 → v2 return { ...oldState, context: { ...oldState.context, newField: 'default' } }; } return oldState;};
// Flow will use migration function on restore<Flow flow={myFlow} persister={persister}> {/* ... */}</Flow>Related
Section titled “Related”- Persistence Guide - Complete persistence patterns
- Storage Stores - Built-in store details
- Custom Stores - Building custom backends