# Debug with Redux DevTools

Connect a Zustand store to Redux DevTools and inspect its named state updates.

Use this when you want a development timeline of store updates without adopting Redux. Wrap the store's state creator in [`devtools`](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/zustand-middleware#devtools), then create the hook with [`create`](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/zustand#create). Install the Redux DevTools package and the browser extension before running the example:

```bash
npm install zustand @redux-devtools/extension
```

Install the [Redux DevTools browser extension](https://chromewebstore.google.com/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) as well.

## Add the middleware to a React store

For the basic store and component-binding pattern, see [Create and bind a React store](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/create-and-bind-a-react-store). The difference here is the `devtools` wrapper and the third `set` argument: this complete `App.tsx` example renders an article status, and each button records a distinct action type in Redux DevTools.

```tsx
import { createRoot } from 'react-dom/client'
import { create } from 'zustand'
import { devtools } from 'zustand/middleware'

type ArticleStore = {
  status: 'draft' | 'published'
  publish: () => void
  reopen: () => void
}

const useArticleStore = create<ArticleStore>()(
  devtools((set) => ({
    status: 'draft',
    publish: () => set({ status: 'published' }, undefined, 'article/publish'),
    reopen: () => set({ status: 'draft' }, undefined, 'article/reopen'),
  })),
)

function ArticleStatus() {
  const status = useArticleStore((state) => state.status)
  const publish = useArticleStore((state) => state.publish)
  const reopen = useArticleStore((state) => state.reopen)

  return (
    <main>
      <p>Article status: {status}</p>
      <button onClick={publish}>Publish</button>
      <button onClick={reopen}>Reopen</button>
    </main>
  )
}

const container = document.getElementById('root')!
createRoot(container).render(<ArticleStatus />)
```

![The initial draft status appears above the Publish and Reopen buttons.](https://atloriaassets.blob.core.windows.net/assets/a438221c-c1af-407c-b9e6-a56c986db846/aeb75a4a9a09000ad1c2447b828f50b4.png)

Open Redux DevTools and select the store to inspect its state and updates. Clicking **Publish** changes the rendered status to `published` and records `article/publish`; clicking **Reopen** changes it back to `draft` and records `article/reopen`. You can inspect either update or use DevTools time travel.

## Options to identify the connection

Pass the optional second argument to `devtools` when you need a distinct connection name or want to control whether the integration runs.

| Option | Type | Default | What it does |
| --- | --- | --- | --- |
| `name` | `string` | Not specified | Sets a custom identifier for the Redux DevTools connection. |
| `enabled` | `boolean` | `true` in development; `false` in production | Enables or disables the Redux DevTools integration for this store. |
| `anonymousActionType` | `string` | Inferred action type, or `anonymous` if unavailable | Sets the action type used for mutations without a supplied action name. |
| `store` | `string` | Not specified | Sets a custom identifier for this store in Redux DevTools. |

For example, add `{ name: 'CounterStore' }` as the second argument to `devtools` to label the connection. Give updates meaningful action types in `set` as in the example; without a supplied name, DevTools uses an inferred action type when available and otherwise falls back to `anonymous`.

## Pitfalls

- `devtools` requires the `@redux-devtools/extension` package as well as the browser extension. In production, the integration is disabled by default; set `enabled` only when you intentionally want a different setting.
- Redux DevTools displays one store at a time by default. Use its store selector to switch to another store.
- An update without an explicit action type can appear as `anonymous` when Zustand cannot infer a name. Add a third `set` argument, such as `'counter/increment'`, to make its timeline entry explicit.

## Live demo

Try the [Zustand live demo](https://zustand-demo.pmnd.rs/) to see Zustand running in the browser.

## Related

- [Compose middleware](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/middleware-and-composition)
- [Use Redux-style actions](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/use-redux-style-actions)
- [Type a store with TypeScript](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/type-a-store-with-typescript)
- [React quick start](https://bench-zustand-6l.atloria.app/p/bench-zustand-6l-TzFgfybqJX/developer/react-quick-start)
