Predictable state container for JavaScript apps
Redux is a battle-tested state management library that enforces predictable state changes through a single centralized store. With over 20 million weekly downloads, it's widely used in production applications where state consistency, debuggability, and scalability matter. Redux operates on three principles: all state lives in one object tree, state is read-only (modified only via actions), and changes happen through pure reducer functions that return new state immutably.
The library was created to solve the complexity of managing shared state across deeply nested component trees. Instead of passing props through multiple layers or coordinating state between sibling components, Redux provides a single source of truth accessible anywhere in your application. Actions describe what happened, reducers specify how state transforms, and the store holds everything together. This architecture makes state changes traceable and enables powerful debugging tools like time-travel and action replay.
Redux works with any UI framework (React, Vue, Angular) and supports middleware for handling side effects like API calls, logging, and crash reporting. While core Redux requires manual setup of action types, action creators, and switch-statement reducers, Redux Toolkit (RTK) has become the official recommended approach since 2019. RTK drastically reduces boilerplate with utilities like createSlice, built-in Immer for immutable updates, and configureStore that auto-configures middleware and DevTools.
Developers choose Redux for large applications requiring strict state flow, predictable testing, and advanced debugging capabilities. It's particularly valuable in teams where code review benefits from explicit action histories and in apps needing features like undo/redo, state persistence, or server-side rendering with hydration. The learning curve is steeper than simpler alternatives, but the architectural discipline pays dividends in maintainability as applications grow.
// Modern Redux with Redux Toolkit (recommended approach)
import { configureStore, createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { Provider, useSelector, useDispatch } from 'react-redux';
// Async thunk for API calls
const fetchUser = createAsyncThunk('user/fetch', async (userId) => {
const response = await fetch(`/api/users/${userId}`);
return response.json();
});
// Slice combines actions and reducers
const userSlice = createSlice({
name: 'user',
initialState: { data: null, status: 'idle', credits: 100 },
reducers: {
addCredits: (state, action) => {
state.credits += action.payload; // Immer allows "mutations"
},
resetUser: (state) => {
state.data = null;
state.credits = 100;
}
},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => {
state.status = 'loading';
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.data = action.payload;
state.status = 'succeeded';
})
.addCase(fetchUser.rejected, (state) => {
state.status = 'failed';
});
}
});
const store = configureStore({
reducer: {
user: userSlice.reducer
}
});
// Export actions
export const { addCredits, resetUser } = userSlice.actions;
export { fetchUser };
// React component usage
function UserProfile() {
const dispatch = useDispatch();
const { data, credits, status } = useSelector((state) => state.user);
return (
<div>
{status === 'loading' && <p>Loading...</p>}
{data && <h1>{data.name}</h1>}
<p>Credits: {credits}</p>
<button onClick={() => dispatch(addCredits(10))}>Add 10 Credits</button>
<button onClick={() => dispatch(fetchUser(123))}>Load User</button>
</div>
);
}
// App wrapper
function App() {
return (
<Provider store={store}>
<UserProfile />
</Provider>
);
}Enterprise dashboards with complex workflows: Applications like admin panels or CRM systems where multiple features (user management, analytics, notifications) need to coordinate state changes. Redux's single store and action history make debugging user-reported issues reproducible through DevTools recordings.
Real-time collaborative applications: Tools like document editors or project management boards where state synchronization matters. Redux middleware can intercept actions to broadcast changes via WebSockets, and reducers ensure all clients apply updates consistently.
E-commerce checkout flows: Multi-step processes (cart, shipping, payment) where state must persist across route changes and survive page refreshes. Redux pairs with localStorage middleware to maintain session state and enables granular tracking of user actions for analytics.
Applications requiring undo/redo functionality: Graphic editors, form builders, or data manipulation tools benefit from Redux's immutable state history. Each action creates a snapshot, making it trivial to implement time-travel features by replaying or reversing actions.
Server-side rendered apps with state hydration: Next.js or other SSR frameworks can serialize Redux state on the server, send it to the client, and rehydrate the store without prop drilling. This ensures consistent initial state between server and client renders.
👻 Primitive and flexible state management for React
Simple, scalable state management.
Recoil - A state management library for React
The official, opinionated, batteries-included toolset for efficient Redux development
🐻 Bear necessities for state management in React
npm install reduxpnpm add reduxbun add redux