discover · compare · collections · requirements · contribute · feed · watching · stats · help with your tokens
endograph/redux-persist · source
Snapshot 0 · 2026-11-04T12:47:23Z · TypeScript · MIT
Content fingerprint
f96e7d755c08e4d94423c4921ce041538c2dc1d934a8cb335f159173e9f592ccGitHub description at capture
persist and rehydrate a redux store
README at capture
<p align="center">
<img src="https://raw.githubusercontent.com/endograph/redux-persist/master/favicon.svg" alt="redux-persist" width="120" />
</p>
<p align="center">
<a href="#quickstart">Quickstart</a> ·
<a href="docs/api.md">API</a> ·
<a href="docs/storage-engines.md">Storage engines</a> ·
<a href="https://www.npmjs.com/package/redux-persist">npm</a>
</p>
# redux-persist
[](https://github.com/endograph/redux-persist/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/redux-persist)
[](https://www.npmjs.com/package/redux-persist?activeTab=versions)
[](https://www.npmjs.com/package/redux-persist)
[](LICENSE)
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](https://github.com/endograph/redux-persist/issues/809)), and lots
> more. Please try it and tell us how it goes in
> [the v7 beta discussion](https://github.com/endograph/redux-persist/discussions/1527).
>
> These docs are for v7, which needs Redux 5 or Redux Toolkit 2. Upgrading
> from 6? Read the [migration guide](docs/MigrationGuide-v7.md); your stored
> data carries over as is. For 6.x, see the
> [v6 docs](https://github.com/endograph/redux-persist/tree/v6#readme).
- **Drop-in.** Wrap your root reducer with `persistReducer` and call
`persistStore`. Nothing else in your app changes, and Redux Toolkit needs no
extra setup.
- **Any storage.** localStorage and sessionStorage ship in the box;
AsyncStorage, IndexedDB, the filesystem and more plug in —
[storage engines](docs/storage-engines.md).
- **You choose what's saved.** Allow or block keys, nest persisted reducers
for finer control, and transform state on the way in and out.
- **Versioned.** Migrations upgrade stored state when its shape changes —
[how migrations work](docs/migrations.md).
## Quickstart
```sh
npm install redux-persist
```
Wrap your root reducer and create a persistor alongside the store:
```ts
// 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`](docs/PersistGate.md). 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 />}`.
```js
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](docs/state-reconciler.md) before you ship.
### React Native
Pass your storage engine explicitly:
```js
import AsyncStorage from '@react-native-async-storage/async-storage'
const persistConfig = {
key: 'root',
storage: AsyncStorage,
}
```
### Server rendering
`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](docs/PersistGate.md#nextjs-app-router-react-server-components).
### Choosing what's saved
`denylist` and `allowlist` pick top-level keys:
```ts
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:
```ts
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](docs/nested-persists.md).
### Resetting state on logout
Reset state inside the reducer you pass to `persistReducer`, so the reset
state is saved too:
```ts
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.
## Learn more
- [API](docs/api.md) — `persistReducer`, `persistStore`, the persistor, and config types
- [PersistGate](docs/PersistGate.md) — delaying render until rehydration finishes
- [State reconcilers](docs/state-reconciler.md) — how stored state merges with initial state
- [Nested persists](docs/nested-persists.md) — per-branch storage, code splitting, deep filtering
- [Migrations](docs/migrations.md) — upgrading stored state between versions
- [Transforms](docs/transforms.md) — customizing what's serialized, and community transforms
- [Storage engines](docs/storage-engines.md) — built-in and community storage backends
- [Recipes](docs/recipes.md) — loading state later, state per user, syncing tabs, knowing when state was saved, encryption
- [Hot module replacement](docs/hot-module-replacement.md)
- [Migrating from v6 to v7](docs/MigrationGuide-v7.md)
- [Storage format](docs/storage-format.md) — what's stored, and the compatibility promise
- [Migrating from v4 to v5](docs/MigrationGuide-v5.md)
## Contributing
Bug reports and pull requests are welcome; see [CONTRIBUTING.md](CONTRIBUTING.md),
especially before changing anything that touches stored data. Questions and
feature ideas go in [Discussions](https://github.com/endograph/redux-persist/discussions).
Feedback on the v7 beta goes in [the v7 beta discussion](https://github.com/endograph/redux-persist/discussions/1527).