On this Page
- What is Middleware in Zustand?
- Creating a Logging Middleware
- Composing Multiple Middleware Layers
- When and Where to Use Middleware
- Example: Action Tracking in Production
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)
What is Middleware in Zustand?
Middleware in Zustand lets you enhance or wrap your store behavior by intercepting:
- Actions (
set) - State updates
- Store creation
Zustand includes built-in middleware like devtools, persist, and immer, but you can also write your own.
Creating a Logging Middleware
Here’s how to create a simple logger:
import { StateCreator } from "zustand";
const logger =
<t>(config: StateCreator<t>): StateCreator<t> =>
(set, get, api) =>
config(
(args) => {
console.log("[Zustand] Action:", args);
set(args);
},
get,
api
);
Use it like this:
const useStore = create<todostore>()(
logger((set) => ({
todos: [],
addTodo: (text) => set((s) => ({ todos: [...s.todos, { text }] })),
}))
);
Composing Multiple Middleware Layers
You can compose multiple layers easily:
import { devtools, persist, immer } from "zustand/middleware";
create(
devtools(
persist(
immer(
logger((set) => ({
count: 0,
inc: () => set((s) => ({ count: s.count + 1 })),
}))
),
{ name: "counter" }
)
)
);
Order matters: outermost wraps everything.
When and Where to Use Middleware
✅ Use middleware for:
- Analytics & logging
- Debugging
- Custom storage or side effects
- Code organization (ex: splitting effects vs state)
🚫 Avoid using middleware for:
- Rendering or UI-related logic
- Over-complicating small stores
Example: Tracking Actions in Production
You can send store actions to analytics:
const tracking =
<t>(config: StateCreator<t>): StateCreator<t> =>
(set, get, api) =>
config(
(args) => {
if (process.env.NODE_ENV === "production") {
sendToAnalytics(args); // e.g., LogRocket, Segment, etc.
}
set(args);
},
get,
api
);
Summary
- Zustand middleware gives you clean extensibility
- Use it for logging, analytics, debugging, and advanced state behavior
- You can create and stack your own middleware
- Middleware logic stays separate from UI
Next: Lesson 14 – Subscribing to External State Changes