Back to roadmaps zustand Course

State Persistence with the Persist Middleware

When users reload a browser page, the in-memory React and Zustand state resets to its initial values. To prevent this, you can use the persist middleware to synchronize and restore the state using the browser storage.


1. Implementing the Persist Middleware

The persist helper is built directly into the Zustand package. Simply wrap your store initializer with persist, and define a unique key name:

// src/stores/useSettingsStore.ts
import { create } from "zustand";
import { persist } from "zustand/middleware";

interface SettingsState {
  theme: "light" | "dark";
  notificationsEnabled: boolean;
  toggleTheme: () => void;
}

export const useSettingsStore = create<SettingsState>()(
  persist(
    (set) => ({
      theme: "light",
      notificationsEnabled: true,
      toggleTheme: () => set((state) => ({ 
        theme: state.theme === "light" ? "dark" : "light" 
      })),
    }),
    {
      // Unique localStorage key name
      name: "user-settings-storage",
    }
  )
);

Under the hood, Zustand automatically intercepts all updates to theme or notifications, serializes the updated store values into a JSON string, and saves them to localStorage under the key "user-settings-storage".


2. Partializing State (Filtering Keys)

By default, the middleware serializes the entire store state. If you want to exclude temporary values (such as a modal open toggle state) from being saved, configure the partialize filter option:

{
  name: "user-settings-storage",
  // Save only the theme value, ignore notificationsEnabled
  partialize: (state) => ({ theme: state.theme }),
}

3. Handling Server-Side Rendering (SSR) Hydration

If you are using Next.js or Astro, servers render pages statically before executing client-side scripts. During this initialization, the server does not have access to the browser localStorage, which can cause styling mismatches (hydration errors).

To prevent hydration issues:

  • Wait for the component to mount in a useEffect hook before displaying values.
  • Or use Zustand built-in .persist.hasHydrated state flags inside your components to verify data availability.
Published on Last updated: