Persist browser state
A browser application needs user preferences or session-like UI state to survive refreshes.
Zustand · Function
The persist middleware saves Zustand store state across page reloads or application restarts. It supports custom storage, selective persistence, version migration, merging, and controlled rehydration.
Wrap a Zustand state creator with persist to save selected store state in a named storage entry and restore it during rehydration. By default, JSON-backed localStorage is used; options can select storage, filter fields, migrate versions, customize merging, observe rehydration, or defer hydration.
persist(stateCreatorFn, persistOptions)| Name | Type | Description |
|---|---|---|
stateCreatorFn | StateCreator | Function receiving set, get, and store; normally returns the store's exposed state and methods. |
persistOptions | PersistOptions | Configuration object for persistence behavior. |
name | string | Unique storage key for the persisted store. |
storage | PersistStorage | Optional PersistStorage used to read and write persisted state; defaults to JSON localStorage storage. |
partialize | (state) => partial state | Optional function selecting fields to persist. |
onRehydrateStorage | (state) => void or callback | Optional callback for logic before and after rehydration. |
version | number | Optional persisted-state version number. |
migrate | (persistedState, version) => state | Optional transformer used when the stored version differs. |
merge | (persistedState, currentState) => state | Optional custom merge function; shallow merge is the default. |
skipHydration | boolean | Optional flag that disables automatic initialization rehydration. |
A state creator enhanced with persistence and rehydration behavior; the resulting store exposes persistence interactions such as rehydrate.
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
type CounterState = {
count: number
increment: () => void
}
export const useCounterStore = create<CounterState>()(
persist(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}),
{ name: 'counter-storage' },
),
)The counter is restored from storage after a page reload.
A browser application needs user preferences or session-like UI state to survive refreshes.
A store contains transient fields alongside durable data.
The serialized store shape changes between releases.
An SSR application must delay browser-storage access and hydration.
persist accepts a state creator and persistence options. The options require a unique name and can configure storage, filtering, migration, merging, versioning, hydration callbacks, and manual hydration.
Follow-up: How would you persist only part of a store? Provide partialize, a function that returns the fields to write.
The default storage is created with createJSONStorage(() => localStorage). The getter is lazy, so storage is accessed only when persistence first needs it.
Follow-up: Why is that useful in SSR? It avoids failing while the module is evaluated in an environment without localStorage.
Set skipHydration to true when initialization should not automatically restore persisted state. Later, call the store's rehydrate function explicitly.
Follow-up: What is the default behavior if skipHydration is omitted? Automatic rehydration occurs because the default is false.
createJSONStoragePersistStoragerehydratepartializemigratemergeonRehydrateStorage