Store state is ephemeral by default — it resets every time the page reloads or the app restarts. Adding persistence lets a store rehydrate from storage on startup, so users return to the same state they left behind.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/christianbaroni/stores/llms.txt
Use this file to discover all available pages before exploring further.
@storesjs/stores makes this a single option: pass a storageKey to createBaseStore or createQueryStore and the framework handles serialization, hydration, and write-through automatically.
Enabling Persistence
PassstorageKey as part of the options object to any base or query store. The key is scoped with the global prefix (default 'stores:'), so the full storage key for the example below is stores:settings.
partialize are written to storage. Everything else — including action methods — stays in memory.
PersistConfig Fields
Every persistence option is part of thePersistConfig type. All fields except storageKey are optional.
| Field | Type | Description |
|---|---|---|
storageKey | string | Required. Unique key for this store. Scoped by storageKeyPrefix. |
partialize | (state: S) => PersistedState | Selects which state to persist. Defaults to the full state object. |
version | number | Schema version number. Defaults to 0. Bump when your persisted shape changes. |
migrate | (persistedState, version) => PersistedState | Promise<PersistedState> | Transforms persisted state from an older version to the current schema. |
merge | (persistedState, currentState) => S | Custom merge strategy applied during hydration. Defaults to a shallow merge. |
onRehydrateStorage | (state: S) => ((state?, error?) => void) | void | Lifecycle hook called before hydration begins. The returned function is called after hydration completes or when an error occurs. |
serializer | (storageValue) => string | Overrides the default JSON serializer for writing to storage. |
deserializer | (serializedState) => StorageValue<PersistedState> | Overrides the default JSON deserializer for reading from storage. |
storage | SyncStorageInterface | AsyncStorageInterface | Custom storage adapter. Defaults to localStorage on web and MMKV on React Native. |
persistThrottleMs | number | Throttle interval (ms) for sync storage writes. Not available for async storage. |
Migration Example
Bumpversion when you change the persisted shape, and provide migrate to transform stale data:
The persist Object
When persistence is configured, the store exposes a persist property with methods for inspecting and controlling the hydration lifecycle:
persist.hydrationPromise() returns a Promise<void> that resolves once hydration finishes:
Global Default Storage
Set a storage adapter once for all stores usingconfigureStores. By default the framework uses localStorage in browsers and MMKV in React Native environments.
Storage Key Prefix
All storage keys are automatically prefixed. The default prefix is'stores:'. Change it globally with configureStores:
storageKey: 'settings' will then write to myapp:settings.
Custom Storage Interface
Provide your own adapter by implementingSyncStorageInterface or AsyncStorageInterface.
Synchronous (SyncStorageInterface)
Asynchronous (AsyncStorageInterface)
When async: true is set on the adapter, the framework treats the store as async. store.setState() returns Promise<void>, and persist.hydrationPromise() becomes available.
storage in the options, or globally via configureStores({ storage: asyncAdapter }).
Internally,
@storesjs/stores uses createHydrationGate middleware to queue setState calls that arrive before rehydration completes. You do not need to gate renders manually; the store flushes all queued updates atomically as soon as storage is read. Gate your UI explicitly only if you need to delay rendering until the store is hydrated — for example by checking persist.hasHydrated() or awaiting persist.hydrationPromise().