Skip to main content

Redux DevTools: Debugging Zustand and Jotai

Redux DevTools is a browser extension and library for debugging state management. Even though you are using Zustand or Jotai (not Redux), both integrate with DevTools to give you time-travel debugging, action history, and state mutation inspection. This is invaluable for finding bugs in complex state logic.

I spent three hours debugging a state mutation last year until I enabled DevTools and found the bug in seconds. DevTools shows every state change with the exact values before and after, making reproduction impossible without it.

Install Redux DevTools Browser Extension

First, install the Redux DevTools browser extension (available for Chrome, Firefox, Edge). Search "Redux DevTools" in your browser's extension store.

The extension is 600 KB and adds a tab to your browser DevTools. It automatically detects Redux stores and Zustand/Jotai stores that are configured to report to it.

Setup Zustand with Redux DevTools

Zustand ships with DevTools support via middleware. Install the package if not already included:

npm install zustand

Then configure your store:

import { create } from 'zustand';
import { devtools } from 'zustand/middleware';

export const useCounterStore = create(
devtools((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 }), false, 'increment'),
decrement: () => set((state) => ({ count: state.count - 1 }), false, 'decrement'),
}), { name: 'CounterStore' })
);

The devtools() middleware wraps your store. Pass a name option to label the store in DevTools. The third argument to set() is the action name (e.g., 'increment'), which appears in DevTools history.

Now, open your browser DevTools and click the Redux tab. You will see every action dispatched, the state before and after, and be able to jump between states using time-travel.

Setup Jotai with Redux DevTools

Jotai requires the jotai-devtools package:

npm install jotai-devtools

Then add the DevTools component to your app:

import { DevTools } from 'jotai-devtools';
import { useAtom } from 'jotai';
import { countAtom } from './atoms';

export function App() {
return (
<div>
<Counter />
<DevTools />
</div>
);
}

export function Counter() {
const [count, setCount] = useAtom(countAtom);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}

The DevTools component renders an inline panel showing all atom state and values. It also integrates with the Redux DevTools extension if installed.

Time-Travel Debugging in Zustand

With DevTools enabled, Zustand records every state change. You can:

  1. Inspect state: Click on any action in the history to see the state at that moment.
  2. Time-travel: Jump to any point in history by clicking an action.
  3. Compare states: DevTools shows state before and state after for each action in a side-by-side diff.
  4. Dispatch actions: Type action names and state patches directly in DevTools to test behaviors.

Example workflow:

  1. User reports bug: count is 5 but should be 3.
  2. Open DevTools, look at action history.
  3. See that increment was called 5 times, but decrement was called 0 times.
  4. Time-travel to after the 3rd increment and see if the UI is correct (it is).
  5. Conclude: either the logic for decrement is broken, or the user is using the app incorrectly.

Advanced: Custom Action Names

For complex stores, name actions descriptively:

import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';

export const useStore = create(
devtools(
immer((set) => ({
todos: [],
addTodo: (text) => set((state) => {
state.todos.push({ id: Date.now(), text });
}, false, 'addTodo(text)'),

completeTodo: (id) => set((state) => {
const todo = state.todos.find((t) => t.id === id);
if (todo) todo.done = true;
}, false, `completeTodo(${id})`),
})),
{ name: 'TodoStore' }
)
);

Include parameters in action names for clarity: addTodo(text), completeTodo(123). This helps when reviewing history.

Performance Profiling

Redux DevTools also includes a "Dispatch" tab where you can benchmark action performance:

  1. Open the Redux DevTools panel.
  2. Click Dispatch.
  3. Type an action name and press Enter.
  4. DevTools logs the time taken and state change.

This is useful for finding expensive operations in your store.

Key Takeaways

  • Redux DevTools is a browser extension that works with Zustand and Jotai, not just Redux.
  • Configure Zustand with devtools() middleware; name your store and actions descriptively.
  • For Jotai, import and add the DevTools component to your app layout.
  • Time-travel debugging lets you jump between any state in history to understand what went wrong.
  • Use action names to document state mutations for easier debugging later.

Frequently Asked Questions

Does Redux DevTools work in production?

Yes, but typically you only enable it in development. Use environment checks: devtools(..., { name: 'Store', enabled: !isProduction }).

Can I export and import state snapshots?

Yes. The Redux DevTools panel has "Export" and "Import" buttons to save and restore state history. Useful for reproducing bugs or testing scenarios.

Does DevTools slow down my app?

Minimally. The DevTools middleware adds a few microseconds per state change. In production, you typically disable it entirely, so there is no overhead.

Can I commit to a particular state and reset history?

In the Redux DevTools panel, click the "Lock" icon next to an action to pin it. Then right-click to remove earlier actions. This resets the history to that point.

Further Reading