Introduction
React state management has evolved significantly. Redux, once the default choice for complex applications, now competes with simpler alternatives like Zustand and Jotai. Each takes a different approach: Redux centralizes state with strict patterns, Zustand provides a minimal store with hooks, and Jotai offers atomic, Recoil-inspired state management. This comparison helps you choose the right state management approach.
Redux Toolkit
Redux Toolkit (RTK) is Redux's modern incarnation, eliminating much of the boilerplate that plagued classic Redux.
**Philosophy:** Single centralized store with predictable updates through reducers and actions.
import { createSlice, configureStore } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter",
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1; },
incrementBy: (state, action) => { state.value += action.payload; },
},
});
const store = configureStore({
reducer: { counter: counterSlice.reducer },
});
export const { increment, incrementBy } = counterSlice.actions;
export type RootState = ReturnType<typeof store.getState>;
// In component:
function Counter() {
const count = useSelector((state: RootState) => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<p>{count}</p>
<button onClick={() => dispatch(increment())}>+1</button>
</div>
);
}
**Strengths:**
**Weaknesses:**
Zustand
Zustand provides a minimal store with React hooks, no providers needed.
**Philosophy:** A small, fast, and scalable state management solution with no boilerplate.
import { create } from "zustand";
interface CounterState {
count: number;
increment: () => void;
incrementBy: (amount: number) => void;
}
const useCounterStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
incrementBy: (amount) => set((state) => ({ count: state.count + amount })),
}));
// In component — no Provider needed
function Counter() {
const count = useCounterStore((state) => state.count);
const increment = useCounterStore((state) => state.increment);
return (
<div>
<p>{count}</p>
<button onClick={increment}>+1</button>
</div>
);
}
**Strengths:**
**Weaknesses:**
Jotai
Jotai takes an atomic approach — each piece of state is an independent atom.
**Philosophy:** Build state by composing primitive atoms, much like React's useState but shared.
import { atom, useAtom } from "jotai";
// Primitive atom
const countAtom = atom(0);
// Derived atom (computed state)
const doubleCountAtom = atom((get) => get(countAtom) * 2);
// Async atom
const userAtom = atom(async () => {
const response = await fetch("/api/user");
return response.json();
});
// In component
function Counter() {
const [count, setCount] = useAtom(countAtom);
const [doubleCount] = useAtom(doubleCountAtom);
return (
<div>
<p>Count: {count}</p>
<p>Double: {doubleCount}</p>
<button onClick={() => setCount((c) => c + 1)}>+1</button>
</div>
);
}
**Strengths:**
**Weaknesses:**
Comparison Table
| Aspect | Redux Toolkit | Zustand | Jotai |
|--------|--------------|---------|-------|
| Architecture | Centralized store | Multiple stores | Atomic atoms |
| Boilerplate | Moderate | Minimal | Minimal |
| Bundle size | ~12KB | ~1KB | ~3KB |
| Learning curve | Steep | Gentle | Moderate |
| DevTools | Built-in | Add-on | Add-on |
| Middleware | Rich ecosystem | Immer, persist | None needed |
| Async support | Thunks/Sagas | Native in store | Native atoms |
| TypeScript | Excellent | Excellent | Good |
| Provider needed | Yes | No | No (optional) |
| External use | Yes (store) | Yes (store) | Limited |
When to Choose What
**Choose Redux Toolkit when:**
**Choose Zustand when:**
**Choose Jotai when:**
Conclusion
The state management landscape in 2026 has moved beyond "one size fits all." Redux Toolkit remains the right choice for large applications that need structure and a rich ecosystem. Zustand has become the default recommendation for most new React projects due to its simplicity and performance. Jotai offers the most React-idiomatic experience for applications with highly granular state needs. Consider your team size, application complexity, and whether you need data fetching (RTK Query) or async workflows (Jotai's async atoms) when making your choice.