Redux Persist Storage Options: From LocalStorage to IndexedDB and Beyond (2025)

9 min read

·

Oct 20, 2024

--

Picture this… You’re building an awesome web app — everything’s working perfectly, users are logging in, filling out forms, adding items to their shopping carts,… Your app is smooth, fast, and everyone’s loving it. Then, disaster strikes: Users refresh the page, or worse, they accidentally close the browser. Boooom! All their progress — gone in an instant. The shopping cart they spent an hour curating? Vanished. The long form they were meticulously filling out? Poof. Even their login session is nowhere to be found.

That’ when the Redux Persist enters the game. It stores your app’s data somewhere safe — like LocalStorage, SessionStorage or the mighty IndexedDB — and brings it back every time your app reloads. But which storage option should you choose? Do you go with the simple, reliable LocalStorage, the here-for-a-good-time-not-a-long-time SessionStorage, or the complex, bigger-than-your-data-structure IndexedDB?

In this article, we’ll take a dive into Redux Persist, its key features, and how to pick the right storage medium for your app’s needs.

Redux Persist Storage Options: From LocalStorage to IndexedDB and Beyond (2)

In most web apps, when a user refreshes the page or closes the browser, the application’s state resets, which can be pretty frustrating. Imagine filling out a long form, and after an accidental refresh, all your data vanishes. Not fun.

Redux Persist solves this problem by allowing your Redux store to persist its state across page reloads or browser sessions. It’s like giving your app a memory, so it doesn’t forget everything the moment the page refreshes.

Redux Persist Storage Options: From LocalStorage to IndexedDB and Beyond (3)

🤔 Use Cases of Redux Persist

  • Forms: Save form data so users can resume filling out a form after closing the browser or navigating away.
  • Authentication: Keep users logged in across sessions by persisting authentication tokens.
  • Shopping Cart: Retain shopping cart items across page reloads or session terminations.
  • Offline Support: Combine Redux Persist with a storage engine like IndexedDB to enable offline-first capabilities.
Redux Persist Storage Options: From LocalStorage to IndexedDB and Beyond (4)

🔑 Key features of Redux Persist

  • State Persistence: It stores your Redux state in a chosen storage (browser or mobile storage) and rehydrates it when the app is reloaded, ensuring state continuity across sessions.
  • Rehydration: When your application starts or reloads, Redux Persist will fetch the saved state from the storage and merge it back into your Redux store, providing the same state as before the reload.
  • Selective Persistence (Whitelisting and Blacklisting): You can choose which parts of the Redux state should be persisted. You can “whitelist” reducers that need to be saved or “blacklist” reducers that should not be persisted.
  • Transforms: You can apply custom transforms to the state before saving it to storage and after retrieving it. This can be useful for things like encrypting the state, trimming down large data objects, or handling date conversions.
  • Storage Engines: It supports multiple storage engines like LocalStorage, SessionStorage, IndexedDB, and AsyncStorage (for React Native), as well as custom storage implementations.
  • Auto Rehydrate: Once Redux Persist restores the state from storage, it automatically updates the Redux store with the persisted state.

🔨 Set up Redux Persist

  • Install redux-persist and redux if you don’t already have them installed:
npm install redux-persist redux
  • In your Redux setup, you’ll need to modify the store configuration to enable persistence.
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage'; // defaults to localStorage for web
import rootReducer from './reducers'; // your root reducer

// Redux Persist configuration
const persistConfig = {
key: 'root', // the key for the persist state in storage
storage, // the storage engine to use (localStorage in this case)
};

// Wrap the root reducer with persistReducer
const persistedReducer = persistReducer(persistConfig, rootReducer);

// Create the Redux store with the persisted reducer
const store = createStore(
persistedReducer
);

// Create a persistor, which will be used to persist and rehydrate the store
const persistor = persistStore(store);

export { store, persistor };

  • Use the Persistor in your app. To enable persistence in your app, you need to wrap your application with PersistGate provided by Redux Persist. This delays the rendering of your app’s UI until the persisted state has been retrieved and rehydrated.
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from './store'; // your store setup
import App from './App';

// Wrap the app with both Provider and PersistGate
ReactDOM.render(
<Provider store={store}>
{/* PersistGate delays the rendering of the app until Redux state is rehydrated */}
<PersistGate loading={<div>Loading...</div>} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById('root')
);

  • Use Whitelisting or Blacklisting Reducers. As mentioned above, you can use whitelist or blacklist in the persistConfig to control which parts of your Redux state should persist.

Whitelist: Only the reducers in the whitelist will be persisted.


const persistConfig = {
key: 'root',
storage,
whitelist: ['auth', 'user'], // only the auth and user reducers will be persisted
};

Blacklist: All reducers will be persisted except the ones in the blacklist.

const persistConfig = {
key: 'root',
storage,
blackList: ['temporaryData'], // temporaryData won't be persisted
};
  • You can also add transforms to the persisted state, such as encrypting sensitive data or trimming large objects before they are saved.
import { createTransform } from 'redux-persist';
import storage from 'redux-persist/lib/storage';

// Example transform to encrypt/decrypt sensitive state
const encryptTransform = createTransform(
// Transform the state on its way to being serialized and persisted
(inboundState, key) => {
// Apply encryption or data manipulation here
return encrypt(inboundState); // hypothetical encryption function
},
// Transform the state after it is rehydrated
(outboundState, key) => {
return decrypt(outboundState); // hypothetical decryption function
},
{ whitelist: ['auth'] }
);

const persistConfig = {
key: 'root',
storage,
transforms: [encryptTransform], // use the transform here
};

LocalStorage

LocalStorage is ideal for small to moderate data sets that need to persist across sessions. A synchronous storage mechanism available in browsers stores data in key-value pairs. Data persists even after the browser is closed and reopened.

Usage: redux-persist/lib/storage

import storage from 'redux-persist/lib/storage/session'; // Import sessionStorage instead of localStorage

const persistConfig = {
key: 'root',
storage, // the storage engine (localStorage by default)
};

👍 Pros:

  • Simple and easy to use.
  • Persistent across sessions (until explicitly deleted).
  • Compatible with most modern browsers.

👎 Cons:

  • Size limit (around 5–10 MB depending on the browser).
  • Synchronous, which can block the main thread on larger data sets.

SessionStorage

SessionStorage is uitable for storing temporary state that doesn’t need to persist across sessions (e.g., form inputs, temporary UI states). Similar to LocalStorage, but data is only stored for the duration of the browser session. Once the user closes the browser, the data is cleared.

Usage: redux-persist/lib/storage/session

import storage from 'redux-persist/lib/storage/session'; // Import sessionStorage

const persistConfig = {
key: 'root',
storage, // defaults to sessionStorage
};

👍 Pros:

  • Simple and easy to use.
  • Data is cleared when the session ends, preventing long-term data persistence.

👎 Cons:

  • Same limitations as LocalStorage regarding size (~5–10 MB).
  • Synchronous and can block the main thread for large state data.

IndexedDB

IndexedDB is best for applications with large, complex, or structured state data (e.g., offline-first apps, apps handling large media files). A low-level API for storing large amounts of structured data in the browser. Asynchronous and designed for high performance.

Using Redux Persist with IndexedDB is a powerful combination for persisting the state of your application, especially for web apps with large, complex state or offline capabilities. Here are some key reasons why this setup is so beneficial:

  1. Redux Persist allows you to automatically save your Redux state to a storage medium such as IndexedDB which is providing persistent storage across the sessions.
  2. IndexedDB handles large data efficiently unlike LocalStorage or SessionStorage (which have a size limit of around 5MB), IndexedDB is a low-level API that allows storage of much larger amounts of data. It’s designed for handling large datasets, making it ideal for applications that manage heavy state data such as files, media, or complex app states.
  3. IndexedDB is an asynchronous, non-blocking API, which makes it much faster than synchronous storage options like LocalStorage. This means saving and restoring large chunks of state will not block the main thread, improving the app’s performance and user experience.
  4. By using Redux Persist with IndexedDB, you can store state even when the user is offline. When the user reconnects, the state can be synced back, enabling seamless offline-first functionality.
  5. IndexedDB stores data in a structured way (using object stores), allowing you to manage more complex state data. This structured approach is beneficial for larger applications where data integrity is critical, and objects need to be stored and retrieved in a structured manner.
  6. LocalStorage has relatively strict size limitations and isn’t suited for storing large datasets or binary data. IndexedDB, on the other hand, allows for virtually unlimited storage (depending on the browser), making it ideal for web apps with large amounts of data.
  7. IndexedDB allows for more custom control over how data is stored and queried, enabling you to handle specific use cases like versioning, updating only parts of the state, or dealing with more complex app structures.
  8. Modern browsers have extensive support for IndexedDB, making it a reliable choice for persisting app state across multiple platforms, including mobile and desktop.

Usage: Via a third-party library like redux-persist-indexeddb-storage or custom implementation.

🔨 Set up Redux Persist with IndexedDB

  • Install redux-persist, redux, and redux-persist-indexeddb-storage .
npm install redux-persist redux redux-persist-indexeddb-storage
  • Configure your Redux store to use IndexedDB as the storage engine
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import createIndexedDBStorage from 'redux-persist-indexeddb-storage';
import rootReducer from './reducers'; // your root reducer

// Create an IndexedDB storage engine
const indexedDBStorage = createIndexedDBStorage('myIndexedDB', 'myDataStore');

// Redux Persist configuration
const persistConfig = {
key: 'root',
storage: indexedDBStorage, // use IndexedDB as storage
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

const store = createStore(
persistedReducer,
);

const persistor = persistStore(store);

export { store, persistor };

  • Just like with LocalStorage and SessionStorage, you will use PersistGate to delay rendering your application until the persisted state from IndexedDB is rehydrated.
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from './store'; // your store setup
import App from './App';

// Wrap the app with both Provider and PersistGate
ReactDOM.render(
<Provider store={store}>
{/* PersistGate delays rendering until the persisted state is rehydrated */}
<PersistGate loading={<div>Loading...</div>} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById('root')
);

👍 Pros:

  • Can store large amounts of data (much more than LocalStorage or SessionStorage).
  • Asynchronous and non-blocking.
  • Supports complex data types (blobs, files, arrays, etc.).

👎 Cons:

  • More complex to work with compared to LocalStorage.
  • Asynchronous operations can add some complexity to the codebase.

Custom storage

When you need to store state in a non-standard storage medium (e.g., a remote server, database). You can create your own storage mechanism by implementing a custom adapter for specific needs (e.g., saving to a remote server, custom database, etc.).

Usage: Implement your own storage engine by creating a custom object with setItem, getItem, and removeItemmethods.

👍 Pros:

  • Flexible — can adapt to specific needs (cloud storage, remote databases, etc.).

👎 Cons:

  • You are responsible for handling the intricacies of the storage system.

The modern web landscape demands that we prioritize user experience and data integrity. Choosing the right storage option — whether it’s the straightforward LocalStorage, the transient SessionStorage, or the robust IndexedDB — depends on your specific use case and the nature of your application. Each option has its strengths and weaknesses, and understanding them will help you tailor a solution that enhances user satisfaction and engagement.

Redux Persist Storage Options: From LocalStorage to IndexedDB and Beyond (2025)
Top Articles
Latest Posts
Recommended Articles
Article information

Author: Virgilio Hermann JD

Last Updated:

Views: 6372

Rating: 4 / 5 (61 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Virgilio Hermann JD

Birthday: 1997-12-21

Address: 6946 Schoen Cove, Sipesshire, MO 55944

Phone: +3763365785260

Job: Accounting Engineer

Hobby: Web surfing, Rafting, Dowsing, Stand-up comedy, Ghost hunting, Swimming, Amateur radio

Introduction: My name is Virgilio Hermann JD, I am a fine, gifted, beautiful, encouraging, kind, talented, zealous person who loves writing and wants to share my knowledge and understanding with you.