Storage Stores
Built-in storage implementations for persisting flow state across different environments.
Available stores
Section titled “Available stores”Browser stores
Section titled “Browser stores”import { createLocalStorageStore } from "@useflow/react";
const store = createLocalStorageStore(localStorage, { prefix: "flow" // Optional: custom key prefix});Characteristics:
- Persists across browser sessions
- ~5-10MB storage limit
- Synchronous API
- Same-origin only
import { createSessionStorageStore } from "@useflow/react";
const store = createSessionStorageStore(sessionStorage, { prefix: "flow" // Optional: custom key prefix});Characteristics:
- Cleared when tab closes
- ~5-10MB storage limit
- Synchronous API
- Per-tab isolation
Memory store
Section titled “Memory store”import { createMemoryStore } from "@useflow/react";
const store = createMemoryStore();Characteristics:
- In-memory only (no persistence)
- Perfect for testing
- No storage limits
- Synchronous API
React Native store
Section titled “React Native store”import AsyncStorage from "@react-native-async-storage/async-storage";import { createAsyncStorageStore } from "@useflow/react-native";
const store = createAsyncStorageStore(AsyncStorage, { prefix: "flow" // Optional: custom key prefix});Characteristics:
- Persists on device
- ~6MB limit on Android, larger on iOS
- Asynchronous API
- App-specific storage
Store interface
Section titled “Store interface”All stores implement this interface:
interface StorageStore { get(key: string): Promise<string | null> | string | null; set(key: string, value: string): Promise<void> | void; delete(key: string): Promise<void> | void; clear?(): Promise<void> | void;}Usage examples
Section titled “Usage examples”Basic usage
Section titled “Basic usage”import { createLocalStorageStore, createPersister} from "@useflow/react";
// Create storeconst store = createLocalStorageStore();
// Create persister with storeconst persister = createPersister({ store });
// Use with Flow<Flow flow={myFlow} persister={persister}> {({ renderStep }) => renderStep({ /* ... */ })}</Flow>With custom prefix
Section titled “With custom prefix”const store = createLocalStorageStore(localStorage, { prefix: "myapp"});
// Keys will be: "myapp:flowId:variantId:instanceId"Testing with memory store
Section titled “Testing with memory store”import { createMemoryStore, createPersister } from "@useflow/react";
describe('MyFlow', () => { it('should persist state', () => { const store = createMemoryStore(); const persister = createPersister({ store });
render( <Flow flow={myFlow} persister={persister}> {/* ... */} </Flow> );
// State is saved in memory during test });});Switching stores by environment
Section titled “Switching stores by environment”const store = process.env.NODE_ENV === 'test' ? createMemoryStore() : createLocalStorageStore();
const persister = createPersister({ store });Storage limits
Section titled “Storage limits”Handling storage errors
Section titled “Handling storage errors”<Flow flow={myFlow} persister={persister} onPersistenceError={(error) => { if (error.name === 'QuotaExceededError') { // Storage full - clear old data localStorage.clear(); } }}> {/* ... */}</Flow>Monitoring storage usage
Section titled “Monitoring storage usage”// Check localStorage usageconst getStorageSize = () => { let size = 0; for (const key in localStorage) { if (key.startsWith('flow:')) { size += localStorage[key].length; } } return size;};
console.log(`Using ${getStorageSize()} bytes`);Custom store implementation
Section titled “Custom store implementation”Create your own store by implementing the interface:
Redis store example
Section titled “Redis store example”import Redis from 'ioredis';
function createRedisStore(redis: Redis): StorageStore { return { async get(key: string) { return await redis.get(key); },
async set(key: string, value: string) { await redis.set(key, value); },
async delete(key: string) { await redis.del(key); },
async clear() { const keys = await redis.keys('flow:*'); if (keys.length > 0) { await redis.del(...keys); } } };}
const redis = new Redis();const store = createRedisStore(redis);const persister = createPersister({ store });Database store example
Section titled “Database store example”function createDatabaseStore(db: Database): StorageStore { return { async get(key: string) { const row = await db.query( 'SELECT value FROM flow_states WHERE key = ?', [key] ); return row?.[0]?.value || null; },
async set(key: string, value: string) { await db.query( 'INSERT OR REPLACE INTO flow_states (key, value) VALUES (?, ?)', [key, value] ); },
async delete(key: string) { await db.query( 'DELETE FROM flow_states WHERE key = ?', [key] ); } };}Store selection guide
Section titled “Store selection guide”| Store | Use When | Avoid When |
|---|---|---|
| localStorage | Long-term persistence needed | Large data, private data |
| sessionStorage | Tab-specific state | Need cross-tab state |
| Memory | Testing, temporary state | Production persistence |
| AsyncStorage | React Native apps | Web applications |
| Custom | Special requirements | Simple use cases |
Security considerations
Section titled “Security considerations”Encrypting sensitive data
Section titled “Encrypting sensitive data”import { encrypt, decrypt } from 'your-crypto-lib';
const encryptedStore: StorageStore = { async get(key) { const encrypted = localStorage.getItem(key); if (!encrypted) return null; return decrypt(encrypted); },
async set(key, value) { const encrypted = encrypt(value); localStorage.setItem(key, encrypted); },
async delete(key) { localStorage.removeItem(key); }};
const persister = createPersister({ store: encryptedStore});Performance tips
Section titled “Performance tips”1. Use appropriate save modes
Section titled “1. Use appropriate save modes”<Flow flow={myFlow} persister={persister} saveMode="navigation" // Only save on navigation, not every change saveDebounce={500} // Debounce saves by 500ms>2. Clean up old data
Section titled “2. Clean up old data”// Remove old flow states periodicallyconst cleanupOldStates = () => { const oneWeekAgo = Date.now() - (7 * 24 * 60 * 60 * 1000);
for (const key in localStorage) { if (key.startsWith('flow:')) { try { const data = JSON.parse(localStorage.getItem(key)); if (data.savedAt < oneWeekAgo) { localStorage.removeItem(key); } } catch {} } }};3. Compress large states
Section titled “3. Compress large states”import { compress, decompress } from 'lz-string';
const compressedStore: StorageStore = { get(key) { const compressed = localStorage.getItem(key); return compressed ? decompress(compressed) : null; },
set(key, value) { localStorage.setItem(key, compress(value)); },
delete(key) { localStorage.removeItem(key); }};Related
Section titled “Related”- createPersister() - Create persisters
- Persistence Guide - Persistence patterns
- Custom Stores - Advanced implementations