Quickstart · API · Storage engines · npm
Persist and rehydrate a redux store. Your state is saved to storage as it changes and restored into the store when your app starts.
Hey all! redux-persist is maintained again, and v7 is in beta (
npm install redux-persist@next): Redux Toolkit 2 support with no extra setup, a fix for stored data getting wiped (#809), and lots more. Please try it and tell us how it goes in the v7 beta discussion.These docs are for v7, which needs Redux 5 or Redux Toolkit 2. Upgrading from 6? Read the migration guide; your stored data carries over as is. For 6.x, see the v6 docs.
persistReducer and call
persistStore. Nothing else in your app changes, and Redux Toolkit needs no
extra setup.npm install redux-persist
Wrap your root reducer and create a persistor alongside the store:
// app/store.ts
import { configureStore, combineReducers } from '@reduxjs/toolkit'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/storage' // localStorage on the web
import userReducer from './features/user/userSlice'
import configReducer from './features/config/configSlice'
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)
If you use React, wrap your root component in
PersistGate. It holds off rendering until the stored
state has been loaded back into redux. loading can be null or any React
element, e.g. loading={<Loading />}.
import { PersistGate } from 'redux-persist/react'
import { store, persistor } from './app/store'
// ... normal setup, import components etc.
const App = () => {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<RootComponent />
</PersistGate>
</Provider>
);
};
If you'd rather not gate rendering, useRehydrated(persistor) from
redux-persist/react returns whether stored state has loaded.
Every app has to decide how many levels of stored state to merge into its initial state. The default is one level; read state reconcilers before you ship.
Pass your storage engine explicitly:
import AsyncStorage from '@react-native-async-storage/async-storage'
const persistConfig = {
key: 'root',
storage: AsyncStorage,
}
redux-persist/storage works during server rendering (Next.js and others): on
the server it stores nothing, and stored state is loaded in the browser. With
the Next.js App Router, render PersistGate from a Client Component; see
PersistGate.
denylist and allowlist pick top-level keys:
persistReducer({ key: 'root', storage, denylist: ['navigation'] }, rootReducer) // navigation will not be persisted
persistReducer({ key: 'root', storage, allowlist: ['navigation'] }, rootReducer) // only navigation will be persisted
They're checked against your state's keys, so a typo is a type error. If you
declare the config separately, annotate it with PersistConfig<RootState> or
use as const on the array. The older names blacklist and whitelist still
work.
For keys you can't list ahead of time, pass a function that's called with each top-level key:
persistReducer({ key: 'root', storage, denylist: key => key.startsWith('temp') }, rootReducer) // keys starting with temp will not be persisted
To go deeper than one level, use nested persists.
Reset state inside the reducer you pass to persistReducer, so the reset
state is saved too:
const rootReducer = (state, action) =>
appReducer(action.type === 'user/logout' ? undefined : state, action)
const persistedReducer = persistReducer(persistConfig, rootReducer)
The reset state is saved like any other change. To write it right away (for
example before the app might close), await persistor.flush() after
dispatching the action.
Don't reset above persistReducer (by wrapping the persisted reducer, or with
a store enhancer that replaces the whole state): that removes the _persist
key, so the state stops being saved, and the previous user's state is loaded
again on the next launch. redux-persist logs an error in development when this
happens.
persistReducer, persistStore, the persistor, and config typesBug reports and pull requests are welcome; see CONTRIBUTING.md, especially before changing anything that touches stored data. Questions and feature ideas go in Discussions. Feedback on the v7 beta goes in the v7 beta discussion.
Overall
Maintained
Code review
Latest release
Releases this year
(top 24 of 37)
718 followers · starred Apr 2018
1,568 followers · starred May 2017
75 followers · starred May 2017
533 followers · starred Jun 2025
Quickstart · API · Storage engines · npm
Persist and rehydrate a redux store. Your state is saved to storage as it changes and restored into the store when your app starts.
Hey all! redux-persist is maintained again, and v7 is in beta (
npm install redux-persist@next): Redux Toolkit 2 support with no extra setup, a fix for stored data getting wiped (#809), and lots more. Please try it and tell us how it goes in the v7 beta discussion.These docs are for v7, which needs Redux 5 or Redux Toolkit 2. Upgrading from 6? Read the migration guide; your stored data carries over as is. For 6.x, see the v6 docs.
persistReducer and call
persistStore. Nothing else in your app changes, and Redux Toolkit needs no
extra setup.npm install redux-persist
Wrap your root reducer and create a persistor alongside the store:
// app/store.ts
import { configureStore, combineReducers } from '@reduxjs/toolkit'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/storage' // localStorage on the web
import userReducer from './features/user/userSlice'
import configReducer from './features/config/configSlice'
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)
If you use React, wrap your root component in
PersistGate. It holds off rendering until the stored
state has been loaded back into redux. loading can be null or any React
element, e.g. loading={<Loading />}.
import { PersistGate } from 'redux-persist/react'
import { store, persistor } from './app/store'
// ... normal setup, import components etc.
const App = () => {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<RootComponent />
</PersistGate>
</Provider>
);
};
If you'd rather not gate rendering, useRehydrated(persistor) from
redux-persist/react returns whether stored state has loaded.
Every app has to decide how many levels of stored state to merge into its initial state. The default is one level; read state reconcilers before you ship.
Pass your storage engine explicitly:
import AsyncStorage from '@react-native-async-storage/async-storage'
const persistConfig = {
key: 'root',
storage: AsyncStorage,
}
redux-persist/storage works during server rendering (Next.js and others): on
the server it stores nothing, and stored state is loaded in the browser. With
the Next.js App Router, render PersistGate from a Client Component; see
PersistGate.
denylist and allowlist pick top-level keys:
persistReducer({ key: 'root', storage, denylist: ['navigation'] }, rootReducer) // navigation will not be persisted
persistReducer({ key: 'root', storage, allowlist: ['navigation'] }, rootReducer) // only navigation will be persisted
They're checked against your state's keys, so a typo is a type error. If you
declare the config separately, annotate it with PersistConfig<RootState> or
use as const on the array. The older names blacklist and whitelist still
work.
For keys you can't list ahead of time, pass a function that's called with each top-level key:
persistReducer({ key: 'root', storage, denylist: key => key.startsWith('temp') }, rootReducer) // keys starting with temp will not be persisted
To go deeper than one level, use nested persists.
Reset state inside the reducer you pass to persistReducer, so the reset
state is saved too:
const rootReducer = (state, action) =>
appReducer(action.type === 'user/logout' ? undefined : state, action)
const persistedReducer = persistReducer(persistConfig, rootReducer)
The reset state is saved like any other change. To write it right away (for
example before the app might close), await persistor.flush() after
dispatching the action.
Don't reset above persistReducer (by wrapping the persisted reducer, or with
a store enhancer that replaces the whole state): that removes the _persist
key, so the state stops being saved, and the previous user's state is loaded
again on the next launch. redux-persist logs an error in development when this
happens.
persistReducer, persistStore, the persistor, and config typesBug reports and pull requests are welcome; see CONTRIBUTING.md, especially before changing anything that touches stored data. Questions and feature ideas go in Discussions. Feedback on the v7 beta goes in the v7 beta discussion.
Overall
Maintained
Code review
Latest release
Releases this year
(top 24 of 37)
718 followers · starred Apr 2018
1,568 followers · starred May 2017
75 followers · starred May 2017
533 followers · starred Jun 2025