Why I Stopped Using Redux (And What I Use Instead)
September 5, 2025 · 6 min read
Redux Isn't Bad. It's Just Heavy.
I used Redux for 4 years across 6 production apps. It's predictable, debuggable, and the DevTools are genuinely excellent. But every time I start a new project, I don't reach for it anymore.
Here's why — and what I use instead.
The Boilerplate Tax
A basic Redux setup for a feature requires: an action type constant, an action creator, a reducer case, a selector, a mapStateToProps, and a useDispatch call. For a shopping cart. Six files touched to add one piece of state.
Redux Toolkit helped significantly. But even with RTK, you're still writing more than you need to.
What I Migrated To
Zustand for Global UI State
For state that's genuinely global — current user, theme, modal visibility — Zustand is the answer.
const useStore = create<AppState>((set) => ({
user: null,
setUser: (user) => set({ user }),
theme: "light",
toggleTheme: () => set((s) => ({ theme: s.theme === "light" ? "dark" : "light" })),
}))That's it. No actions. No reducers. No selectors. Just state and functions that update it. The bundle is 1.1kb.
TanStack Query for Server State
This was the bigger unlock. Most of what I was putting in Redux was server state — data fetched from an API. Redux handles that awkwardly. TanStack Query handles it brilliantly:
const { data: user, isLoading } = useQuery({
queryKey: ["user", userId],
queryFn: () => fetchUser(userId),
staleTime: 5 * 60 * 1000,
})Caching, background refetching, loading states, error states — all built in. I deleted ~40% of my Redux store the day I migrated.
Jotai for Local-ish State
When state is shared between a few components but not globally, Jotai's atom model is perfect. No Provider ceremony, just atoms:
const countAtom = atom(0)
function Counter() {
const [count, setCount] = useAtom(countAtom)
return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}When I'd Still Use Redux
Large teams where the strict action/reducer pattern prevents accidental state mutations. Apps with complex cross-cutting state logic where time-travel debugging actually matters. That's a narrow slice.
The Rule I Now Follow
- Server data: TanStack Query
- Global UI state: Zustand
- Component-level shared state: Jotai or React Context
- Local component state: useState
Redux doesn't appear on that list. Not because it's bad — but because each of the above tools does its specific job better.
← Back to Blog