Skip to main content
Make your Zustand store persistent across page refreshes and browser sessions using the built-in persist middleware.

What You’ll Build

You’ll create a persistent shopping cart store that demonstrates:
  • Using the persist middleware
  • Saving state to localStorage
  • Automatic state rehydration
1
Run the CLI with Persistence
2
Start the Create Zustand CLI tool:
3
create-zustand-store
4
Enable Persistence
5
When prompted, enable persistence:
6
Store Name
 What is the name of your store?
useCartStore
File Type
 Choose the file type:
JavaScript
Persistence (Important!)
 Do you want to add persistence?
Yes
Initial State
 Define initial state properties (as JSON):
{"items": [], "total": 0}
Actions
 Define actions (comma-separated):
addItem,removeItem,clearCart
7
Review the Persistent Store
8
The CLI generates a store wrapped with persist middleware:
9
import { create } from "zustand";
import { persist } from "zustand/middleware";

const useCartStore = create(
  persist(
    (set) => ({
      items: [],
      total: 0,
      actions: {
        addItem: () => set((state) => ({})),
        removeItem: () => set((state) => ({})),
        clearCart: () => set((state) => ({}))
      },
    }),
    {
      name: "useCartStore",
    }
  )
);

export default useCartStore;
10
Implement Cart Actions
11
Add logic to manage cart items:
12
import { create } from "zustand";
import { persist } from "zustand/middleware";

const useCartStore = create(
  persist(
    (set) => ({
      items: [],
      total: 0,
      actions: {
        addItem: (item) => set((state) => {
          const newItems = [...state.items, item];
          const newTotal = state.total + item.price;
          return { items: newItems, total: newTotal };
        }),
        removeItem: (itemId) => set((state) => {
          const itemToRemove = state.items.find(i => i.id === itemId);
          const newItems = state.items.filter(i => i.id !== itemId);
          const newTotal = state.total - (itemToRemove?.price || 0);
          return { items: newItems, total: newTotal };
        }),
        clearCart: () => set({ items: [], total: 0 })
      },
    }),
    {
      name: "useCartStore",
    }
  )
);

export default useCartStore;
13
Use the Persistent Store
14
Your cart state will persist across page refreshes:
15
import useCartStore from '../store/useCartStore';

function ShoppingCart() {
  const items = useCartStore((state) => state.items);
  const total = useCartStore((state) => state.total);
  const { addItem, removeItem, clearCart } = useCartStore(
    (state) => state.actions
  );

  const handleAddItem = () => {
    addItem({
      id: Date.now(),
      name: "Product",
      price: 29.99
    });
  };

  return (
    <div>
      <h2>Shopping Cart</h2>
      <p>Total: ${total.toFixed(2)}</p>
      
      <ul>
        {items.map((item) => (
          <li key={item.id}>
            {item.name} - ${item.price}
            <button onClick={() => removeItem(item.id)}>Remove</button>
          </li>
        ))}
      </ul>
      
      <button onClick={handleAddItem}>Add Item</button>
      <button onClick={clearCart}>Clear Cart</button>
    </div>
  );
}

export default ShoppingCart;

TypeScript Persistent Store

You can also create persistent stores with TypeScript:
store/useCartStore.js
import { create } from "zustand";
import { persist } from "zustand/middleware";

const useCartStore = create(
  persist(
    (set) => ({
      items: [],
      total: 0,
      actions: {
        addItem: (item) => set((state) => ({ 
          items: [...state.items, item],
          total: state.total + item.price 
        })),
      },
    }),
    { name: "useCartStore" }
  )
);

export default useCartStore;

Understanding Persist Middleware

The persist middleware template from templates/store-persist.js:
import { create } from "zustand";
import { persist } from "zustand/middleware";

const use__STORE_NAME__ = create(
  persist(
    (set) => ({
      __INITIAL_STATE__,
      actions: {
        __ACTIONS__,
      },
    }),
    {
      name: "__STORE_NAME__",
    }
  )
);

export default use__STORE_NAME__;
Key features:
  • Automatic saving: State is saved to localStorage on every change
  • Rehydration: State is restored when the store is initialized
  • Storage key: The name option sets the localStorage key

Customizing Persistence

You can customize the persist middleware after generation:
const useCartStore = create(
  persist(
    (set) => ({ /* state */ }),
    {
      name: "cart-storage", // localStorage key
      
      // Partial state persistence
      partialize: (state) => ({
        items: state.items,
        total: state.total,
        // Don't persist actions
      }),
      
      // Custom storage (default is localStorage)
      storage: sessionStorage,
    }
  )
);
The persist middleware stores data in localStorage, which has a size limit (typically 5-10MB). For large datasets, consider using IndexedDB or a backend API.

Next Steps

Actions & State

Learn action patterns

Basic Store

Start with the basics

Build docs developers (and LLMs) love