Guide · Open source
How to use redux-persist: save and restore Redux state
Updated · written with AI from the project's own documentation and checked against our catalogue data
redux-persist is an open-source TypeScript library that saves your Redux store's state to storage as it changes and loads it back when the app starts. This guide shows you how to install it, wrap your root reducer, gate rendering until state is restored, and choose which keys are saved. By the end you will know the setup steps and the decisions you need to make before shipping.
Quick start
- 1Install the package. Run npm install redux-persist in your project.
- 2Combine your reducers. Create a root reducer with combineReducers from your slices.
- 3Configure persistence. Create a persistConfig object with key, version and storage (redux-persist/storage on the web).
- 4Wrap the root reducer. Pass the root reducer and config to persistReducer, then use the result in configureStore.
- 5Create the persistor. Call persistStore(store) and export the persistor.
- 6Gate rendering. Wrap your root component in PersistGate from redux-persist/react, passing the persistor.
- 7Choose saved keys. Add allowlist or denylist to limit which top-level keys are stored.
What redux-persist does and who it is for
redux-persist keeps Redux state across page reloads and app launches. It saves state to storage such as localStorage on the web or AsyncStorage in React Native, then restores it into the store on startup.
It suits web developers who want Redux state to survive a reload, React Native developers who need AsyncStorage, and teams already using Redux or Redux Toolkit who do not want a new state system. It is not meant for projects that do not use Redux.
Install redux-persist and check prerequisites
You need Node.js and either Redux or Redux Toolkit. The current docs are for v7, which requires Redux 5 or Redux Toolkit 2. Install the package from npm with your package manager.
- Prerequisites: Node.js, Redux or Redux Toolkit (v7 requires Redux 5 or Redux Toolkit 2)
- Upgrading from v6? The migration guide says your stored data carries over as is.
npm install redux-persistWrap your root reducer with persistReducer and create a persistor
Combine your slice reducers as usual. Pass a config object with a key, a version and a storage engine to persistReducer, then pass the result to configureStore. Finally, call persistStore on the store to create the persistor.
The storage import from redux-persist/storage uses localStorage on the web. On the server it stores nothing, so it is safe to use during server rendering.
- key: the name under which state is saved, e.g. 'root'
- version: used by migrations when stored state's shape changes
- storage: the engine to save to, e.g. localStorage via redux-persist/storage
import { configureStore, combineReducers } from '@reduxjs/toolkit'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/storage'
const rootReducer = combineReducers({ user: userReducer, config: configReducer })
const persistConfig = { key: 'root', version: 1, storage }
const persistedReducer = persistReducer(persistConfig, rootReducer)
export const store = configureStore({ reducer: persistedReducer })
export const persistor = persistStore(store)Delay rendering until state is restored with PersistGate
In a React app, wrap your root component in PersistGate. It holds off rendering until stored state has been loaded back into Redux. The loading prop can be null or any React element.
If you would rather not gate rendering, the useRehydrated hook from redux-persist/react returns whether stored state has loaded.
- loading={null} renders nothing while restoring
- loading={<Loading />} shows your own placeholder
import { PersistGate } from 'redux-persist/react'
import { store, persistor } from './app/store'
const App = () => (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<RootComponent />
</PersistGate>
</Provider>
)Choose which top-level keys are saved
Use allowlist to save only the listed keys, or denylist to skip them. If you declare the config separately, annotate it with PersistConfig<RootState> or use as const on the array so a typo is caught as a type error. The older names blacklist and whitelist still work.
For keys you cannot list in advance, pass a function to denylist. It is called with each top-level key.
- allowlist: only the named keys are persisted
- denylist: the named keys are not persisted
- function form: decide per top-level key, e.g. skip keys starting with 'temp'
persistReducer({ key: 'root', storage, denylist: ['navigation'] }, rootReducer)
persistReducer({ key: 'root', storage, allowlist: ['navigation'] }, rootReducer)Reset state on logout without losing the saved state
Reset state inside the reducer you pass to persistReducer so the reset state is saved too. Do not reset above persistReducer, for example by wrapping the persisted reducer or using a store enhancer that replaces the whole state. That removes the _persist key, so state stops being saved and the previous user's state can load again on the next launch. In development, redux-persist logs an error when this happens.
To write the reset right away, for example before the app might close, await persistor.flush() after dispatching the action.
const rootReducer = (state, action) =>
appReducer(action.type === 'user/logout' ? undefined : state, action)
const persistedReducer = persistReducer(persistConfig, rootReducer)Decide how stored state merges with initial state
Every app has to decide how many levels of stored state merge into its initial state. The default is one level. Read the state reconcilers documentation before you ship, because the README says this choice must be made explicitly.
Store large or sensitive data with care. The README points to recipes such as encryption rather than providing it by default.
What people use it for
- Keeping a user's Redux settings and preferences after a browser page reload
- Saving app state with AsyncStorage in a React Native app
- Persisting the config slice of a Redux Toolkit store while leaving temporary UI state out
- Clearing user-specific state on logout without leaving stale data for the next user
Frequently asked questions
Is redux-persist free to use?
redux-persist is released under the MIT licence, as stated in the project's license information. Check the LICENSE file in the repository for the full terms.
How do I install redux-persist?
Run npm install redux-persist with your package manager. The current v7 docs require Redux 5 or Redux Toolkit 2, and a beta is available via npm install redux-persist@next.
Does redux-persist work with React Native?
Yes. Pass AsyncStorage from @react-native-async-storage/async-storage as the storage option in your persist config.
Why is my state not loading after a reload?
Check that PersistGate or useRehydrated is used so rendering waits for rehydration, and that the store is created with the persisted reducer. If you reset state above persistReducer, the _persist key is removed and state stops being saved.
Is my stored data encrypted?
Not by default. The README points to recipes such as encryption rather than providing it out of the box, so sensitive data needs extra work.
What are alternatives to redux-persist?
The README lists redux-persist-transform-encrypt for encryption, localForage as a storage option, and the zustand persist middleware for projects using Zustand instead of Redux.
New agent skills, repos and AI tools — every week
The best new skills and open-source projects, the fastest-growing repos, and one free prompt. Five minutes to read. Unsubscribe anytime.
Our verdict
redux-persist suits teams already using Redux or Redux Toolkit who want Redux state to survive reloads or app restarts with a small setup. Pick something else if your project does not use Redux, or if you need encryption and large-data handling out of the box and do not want to add extra work.
Install options & downloads