On this Page
- Why SSR Affects Zustand
- Common Pitfalls in Next.js
- Safe Zustand Store Setup for SSR
- Hydration Strategy with useEffect
- Optional: Using Zustand with
persistin SSR
On this Guide
- Lesson 09: Organizing State with Slices and Modular Stores
- Lesson 10: Persisting State to localStorage or sessionStorage
- Lesson 11: Using Devtools Middleware for Debugging
- Lesson 12: Using Zustand with Immer for Immutable Updates
- Lesson 13: Using Zustand with Middleware: Logging, Tracking, and Side Effects
- Lesson 14: Subscribing to External State Changes
- Lesson 15: Creating Read-Only or Transient State Stores
- Lesson 16: Testing Zustand Stores with React Testing Library
- Lesson 17: Using Zustand in Server-Side Rendering (Next.js)
Why SSR Affects Zustand
Zustand is client-side by default. In SSR frameworks like Next.js, you need to be careful:
- State must not be shared across requests
- Some features like
persistordevtoolsrequirewindow - Hydration mismatches can occur if the store is initialized differently on server and client
Common Pitfalls in Next.js
β Initializing Zustand store globally (shared across users)
β Accessing localStorage in server code
β Using persist() or devtools() without guarding for window
Safe Zustand Store Setup for SSR
Use the store factory pattern:
import { createStore } from "zustand";
type CounterState = {
count: number;
inc: () => void;
};
export const createCounterStore = () =>
createStore<counterstate>((set) => ({
count: 0,
inc: () => set((s) => ({ count: s.count + 1 })),
}));
Now use the factory in each environment independently:
const store = createCounterStore();
You can store the instance in _app.tsx and pass it through a context or provider.
Hydration Strategy with useEffect
If you use client-only logic, make sure you hydrate state safely on the client:
useEffect(() => {
useStore.setState({ ready: true }); // example flag
}, []);
Or initialize inside the component to avoid mismatches.
Optional: Using Zustand with persist in SSR
persist uses localStorage, which doesn’t exist on the server.
You must conditionally enable it:
const isServer = typeof window === "undefined";
const useSettingsStore = create(
!isServer
? persist(
(set) => ({
darkMode: false,
toggle: () => set((s) => ({ darkMode: !s.darkMode })),
}),
{ name: "settings" }
)
: () => ({ darkMode: false, toggle: () => {} })
);
β This prevents hydration issues and ensures safe SSR usage.
Summary
- SSR apps must isolate Zustand stores per request
- Avoid global instances and side effects on the server
- Use factory functions and safe hydration techniques
- Guard
persist()and other browser-only features
π Thatβs the end of the Advanced Guide to Zustand!
Next up: Lesson 18 β Zustand for Authentication and Session Management