Published Sep 16, 2025 ⦁ Updated Oct 11, 2026 ⦁ 16 min read
Redux DevTools: Install, Set Up and Debug Your Store (Best Practices)

Redux DevTools: Install, Set Up and Debug Your Store (Best Practices)

Redux DevTools is a free browser extension that shows every action your Redux store dispatches, the state before and after, and a diff, and lets you jump back to any earlier state ("time travel"). Install the Redux DevTools Chrome extension (or the Firefox add-on). If you create your store with Redux Toolkit's configureStore, it connects automatically, with no code changes (Redux docs).

Install the Redux DevTools extension

Browser Where to get it
Chrome, Brave, Arc, other Chromium browsers Chrome Web Store
Microsoft Edge Install the Chrome Web Store version (Edge allows Chrome extensions)
Firefox Mozilla Add-ons
Safari, React Native, Node No extension; use the remote setup below

After installing, open your app, open the browser's developer tools (F12 or Cmd+Option+I), and select the Redux tab. You can also click the toolbar icon for a popup. If the tab says "No store found", the app isn't connected; see the setup sections below.

Set up with Redux Toolkit (the default)

Redux Toolkit is the officially recommended way to write Redux. Its configureStore has a devTools option that defaults to true, so this is all you need:

import { configureStore } from '@reduxjs/toolkit'
import todosReducer from './todosSlice'

export const store = configureStore({
  reducer: { todos: todosReducer },
})

Pass an object instead of true to configure the extension (options reference):

export const store = configureStore({
  reducer: { todos: todosReducer },
  devTools: process.env.NODE_ENV !== 'production' && {
    name: 'Todo app',
    maxAge: 100,
    actionsDenylist: ['ui/mouseMoved'],
  },
})

When DevTools is enabled, configureStore also turns on action stack traces in development builds, so you can see which line of code dispatched each action.

Set up with plain Redux (createStore)

Older codebases using createStore must wire the extension in manually. The recommended way is the @redux-devtools/extension npm package. It replaced the old redux-devtools-extension package, which is deprecated.

npm install @redux-devtools/extension
import { createStore, applyMiddleware } from 'redux'
import { thunk } from 'redux-thunk'
import { composeWithDevTools } from '@redux-devtools/extension'
import rootReducer from './reducers'

const store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleware(thunk)),
)

Without the package, use the global the extension injects, falling back to Redux's compose when the extension isn't installed:

import { createStore, applyMiddleware, compose } from 'redux'
import { thunk } from 'redux-thunk'
import rootReducer from './reducers'

const composeEnhancers =
  (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose

const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)))

window.devToolsExtension, which still shows up in old tutorials, was replaced by these names years ago (extension README).

Using Redux DevTools to debug

  • Inspector: the action list on the left. Click an action to see its payload (Action), the full state after it (State), and what changed (Diff). Diff is usually the fastest way to spot a reducer bug.
  • Time travel: use the slider at the bottom, or Jump on any action, to put the app back into that state. Skip removes an action from history and recomputes the state without it, which helps answer "what if this action never fired?"
  • Trace: shows the call stack that dispatched the selected action. Click a frame to open the source.
  • Dispatcher: dispatch a hand-written action, such as { "type": "todos/added", "payload": "test" }, to test a reducer without touching the UI.
  • Persist: keeps the action history across page reloads, useful for bugs that happen during startup.
  • Export/Import: save the action history to a JSON file and load it on another machine. Attach it to a bug report so a teammate can replay exactly what you saw.

Options worth knowing

All options are documented in the arguments reference.

Option Default Use it to
name document.title Tell stores apart when a page has several
maxAge 50 Keep more (or fewer) actions in history; more costs memory
trace false (RTK: on in development) Record the stack trace for each action
traceLimit 10 Limit stack depth
actionsDenylist none Hide noisy actions by type (strings are treated as regex)
actionsAllowlist none Show only matching actions; overrides the denylist
predicate none (state, action) => boolean for custom filtering
actionSanitizer, stateSanitizer none Replace large or secret values before they reach the extension
serialize JSON.stringify Handle Map, Set, dates, Immutable.js structures
features all on Turn off specific features, such as jump or dispatch

Filtering high-frequency actions like scroll, mouse move, or timer ticks with actionsDenylist keeps the action list readable and the extension fast.

Best practices

  1. Keep state serializable. DevTools serializes state to show and replay it. Class instances, functions, and Promises in state display badly and break time travel. Redux Toolkit's serializability check warns you about this in development.
  2. Name actions by domain and event. todos/added filters and reads better than ADD. createSlice does this for you.
  3. Sanitize big or sensitive data. Large blobs (file contents, huge lists) slow the extension. Tokens and personal data in state are visible to anyone with DevTools open. Use stateSanitizer and actionSanitizer:
devTools: {
  stateSanitizer: (state) =>
    state.auth ? { ...state, auth: { ...state.auth, token: '<redacted>' } } : state,
}
  1. Decide on production deliberately. Because devTools defaults to true, a Redux Toolkit app exposes its state history in production to any visitor who has the extension installed. Most apps should set devTools: process.env.NODE_ENV !== 'production', which is what the Redux docs' full example does. If you do keep it on in production for support, sanitize state and consider the features option to disable dispatch, jump, and import.
  2. Raise maxAge only when needed. Long sessions with a high maxAge use a lot of memory.

Redux DevTools in Safari and React Native

There's no Safari extension. For Safari, React Native, or any other environment, use @redux-devtools/remote with the @redux-devtools/cli server:

import { createStore } from 'redux'
import { devToolsEnhancer } from '@redux-devtools/remote'

const store = createStore(
  rootReducer,
  devToolsEnhancer({ realtime: true, hostname: 'localhost', port: 8000 }),
)

Run the CLI on the same port, then open its monitor (or click Remote in the browser extension) to see the store. Remote monitoring is on by default only when NODE_ENV is development.

For other debugging and state tools, see browser extensions on DevHunt and frameworks and libraries. For catching Redux errors that happen to real users, monitoring tools cover what DevTools can't.

FAQ

Is Redux DevTools free?

Yes. The extension and all @redux-devtools/* packages are open source under the MIT license, maintained in the reduxjs/redux-devtools repository.

Why does Redux DevTools say "No store found"?

The page has no store connected. Check that you use configureStore (with devTools not set to false), or that you added composeWithDevTools or __REDUX_DEVTOOLS_EXTENSION_COMPOSE__ to createStore. Then reload the page with DevTools open. A production build with devTools disabled also shows this.

What happened to the redux-devtools-extension npm package?

It moved to @redux-devtools/extension. The API is the same (composeWithDevTools, devToolsEnhancer), so switching is an import change. Redux Toolkit users need neither package.

Does Redux DevTools work with Zustand or other state libraries?

Several libraries integrate with the same extension. Zustand has a devtools middleware that connects to it, for example. The features available depend on the library's integration.

Should I disable Redux DevTools in production?

Usually yes: set devTools: process.env.NODE_ENV !== 'production' in configureStore. Otherwise anyone with the extension can read your app's state and action history.