Redux
Redux is a predictable state-management library for JavaScript apps — most associated with React, but usable anywhere. It puts all your application state in a single store, and the only way to change it is to dispatch an action describing what happened, which a pure reducer function turns into the next state. That one-way, explicit flow makes state changes traceable, debuggable, and testable.
Redux dominated React state management for years, became a byword for boilerplate, and then reinvented itself: Redux Toolkit (RTK) is now the official, batteries-included way to write Redux, cutting the ceremony dramatically. Understanding Redux matters both because a huge amount of production code uses it and because its ideas (immutable updates, actions, the reducer pattern) shaped the whole ecosystem — see State Management for the broader landscape.
TL;DR
- Redux centralizes state in one store; you change it only by dispatching actions, which reducers (pure functions) apply to produce new state — never mutate directly.
- The flow is strictly one-way: UI → dispatch(action) → reducer → new state → UI re-renders. Predictable and traceable.
- Redux Toolkit (RTK) is the modern standard —
createSlicegenerates actions + reducers, Immer lets you "mutate" safely, and the old boilerplate is gone. Write RTK, not classic Redux. - RTK Query handles data fetching/caching, overlapping heavily with what React Query does.
- Redux's superpowers: time-travel debugging (DevTools), predictable testing, and one source of truth for complex shared state.
- You often don't need it. For most apps, React's built-in state + Context, or a lighter library (Zustand, Jotai), is enough — reach for Redux when state is genuinely complex, shared widely, and benefits from strict structure.
Quick Example
Modern Redux with Redux Toolkit — a slice, the store, and a component:
Compare this to classic Redux (action type constants, action creators, switch-statement reducers, mapStateToProps) and the RTK improvement is obvious — same architecture, a fraction of the code.
Core Concepts
The Three Principles
Redux rests on three rules that produce its predictability:
- Single source of truth — all state lives in one store (a plain object tree).
- State is read-only — you never mutate it; you dispatch an action to request a change.
- Changes via pure reducers —
(state, action) => newState, with no side effects, so the same inputs always give the same output.
Because every change is an explicit, serializable action run through a pure function, you get time-travel debugging (replay actions), trivial testing (call the reducer with inputs, assert output), and a complete audit of what happened and when.
Store, Actions, Reducers, Selectors
Redux Toolkit: How Redux Is Actually Written
RTK exists because classic Redux made you write the same boilerplate endlessly. It provides:
createSlice— define initial state + reducer functions, get action creators and the reducer generated for you.- Immer built in — write "mutating" code (
state.value += 1) that RTK converts to correct immutable updates, eliminating the error-prone spread-operator gymnastics. configureStore— sensible defaults (DevTools, Thunk middleware) with zero config.createAsyncThunk— standardized async action handling (pending/fulfilled/rejected).
The official guidance is unambiguous: use RTK. Hand-written classic Redux is legacy — you'll read it, but you shouldn't write new code that way.
RTK Query: Data Fetching
RTK Query (part of RTK) handles server data — fetching, caching, invalidation, loading states — declaratively:
This overlaps heavily with React Query/TanStack Query — an important point below.
When You Actually Need Redux
The most valuable Redux knowledge is when not to use it. Redux adds structure and ceremony that pays off only for certain problems:
Reach for Redux when:
- State is complex, deeply interrelated, and shared across many distant components.
- You need time-travel debugging, action logging, or an auditable history of state changes.
- Many parts of the app update the same state in intricate ways.
- The team benefits from strict, enforced structure on a large codebase.
Skip Redux (use lighter tools) when:
- Most of your "state" is actually server data — React Query/TanStack Query or RTK Query is the better fit, not a hand-rolled Redux cache.
- State is mostly local to components —
useState/useReduceris enough. - You need simple global state — Zustand or Jotai give you a store with a fraction of Redux's ceremony.
- The app is small-to-medium — Context + hooks likely suffice.
The industry has broadly moved from "Redux by default" to "Redux when the complexity justifies it," with Zustand and server-state libraries absorbing the cases Redux was overkill for. See State Management for the full comparison.
Common Mistakes
Writing Classic Redux in 2026
Action-type constants, hand-written action creators, switch-statement reducers, connect/mapStateToProps — this is the boilerplate RTK eliminated. New Redux code should be createSlice + hooks. If a tutorial has you writing const INCREMENT = "INCREMENT", it's outdated.
Putting Server Data in Redux Manually
Fetching in thunks and hand-managing loading/error/cache state in the store is reinventing (badly) what RTK Query and React Query do. Server state and client state are different problems — use a data-fetching library for the former.
Reaching for Redux Reflexively
Adding Redux to a small app "because that's what you do with React" imposes real overhead for no benefit. Start with local state and Context; adopt Redux (or Zustand) when you feel the actual pain of complex shared state.
Mutating State Outside Immer
Classic reducers must return new objects ({ ...state, value: ... }); mutating directly breaks Redux silently. RTK's Immer lets you write mutations inside createSlice only — mutating state elsewhere is still a bug.
Over-normalizing or Under-normalizing
Deeply nested state is painful to update; RTK's createEntityAdapter provides normalized storage for collections. But normalizing trivial state adds complexity for nothing — match the structure to the actual data shape.
FAQ
Is Redux dead?
No — but it's no longer the default. It powers enormous amounts of production code, RTK made it far pleasanter, and it remains the right tool for genuinely complex shared state. What died is "Redux for everything"; it's now one option among several (Zustand, Jotai, Context, server-state libraries), chosen when its structure earns its cost.
Redux Toolkit vs classic Redux?
RTK is classic Redux with the boilerplate removed and best practices built in — same architecture and mental model, dramatically less code, plus Immer, DevTools, and thunks preconfigured. There is no reason to write classic Redux for new code; the Redux team itself says use RTK.
Redux or Zustand?
Zustand is a much lighter global-state library (a hook-based store, minimal boilerplate, no providers) that covers many cases Redux was overused for. Choose Redux when you want its strict structure, ecosystem, DevTools time-travel, or already use it; choose Zustand for simpler global state without the ceremony. Both are excellent.
Redux or React Query?
They solve different problems and often coexist. React Query/TanStack Query manages server state (fetching, caching, sync). Redux manages client state (UI state, complex app logic). Many apps use React Query for data and a little Redux/Zustand for the rest. Don't use Redux as a manual server cache.
Do I need to learn Redux?
Worth understanding because so much code uses it and its concepts (unidirectional flow, reducers, immutability) are foundational. But learn modern RTK, and learn the alternatives too — knowing when to use Redux is more valuable than deep Redux mechanics.
Related Topics
- State Management — The full landscape (Context, Zustand, Jotai, Redux)
- React — Redux's primary home
- Data Fetching — React Query / RTK Query for server state
- TypeScript — RTK's strong typing story
- Solid.js — Fine-grained reactivity, a different state model
- Vue — Where Pinia plays Redux's role