You Probably Don't Need Redux (And I Say That As Someone Who Loved It)
I spent years reaching for Redux by reflex. Then I realized most of what I'd put in a global store was either local state, a bit of context, or server state that didn't belong in a store at all.
The short answer: Most apps don't need Redux (or any global store) because most of what we put there isn't global state at all — it's local UI state that belongs in a component, a little context, or server state that belongs in a data-fetching layer. The question that dissolves the store is "who actually needs to read this, and how long does it need to live?"
I want to be clear up front: I loved Redux. I wrote the actions, the reducers, the selectors, the thunks. I evangelized it. I onboarded junior devs by walking them through the one-directional data flow diagram like it was scripture. So when I say you probably don't need it, it's not a hot take from someone who never gave it a chance. It's a confession from someone who used it for things it was never meant for.
The question I never asked
For years, "where does this state go?" had exactly one answer in my head: the store. New feature? New slice. A boolean for whether a dropdown is open? Honestly, yes, I put some of those in Redux too, because at least it was consistent. The problem is that consistency was hiding the real question I should have been asking: who actually needs to read this, and how long does it need to live?
Once I started asking that, most of my store evaporated. Here's the taxonomy I use now.
Local state is the default, not the fallback
If a piece of state is only read by one component and its children, it lives in that component. Full stop. A dropdown's open flag, a form's draft values, which tab is active — none of that is "application state," it's UI state, and it has no business being global.
The amount of boilerplate I deleted by moving this class of state back into components was genuinely embarrassing. Entire slices, gone.
Context handles the "a few places, rarely changes" case
The legitimate case for shared state is a value that several distant components need and that doesn't change on every keystroke: the current theme, the logged-in user, a feature-flag map. That's what Context is for. It's not a performance tool and it's not a replacement for a store under heavy churn — but for low-frequency, widely-read values, it's exactly right and ships in the box.
Most of your "global state" is actually server state
Here's the big one. The thing I was really using Redux for — the thing that justified all the thunks and loading flags and isFetching booleans — was caching data from an API. And API data is not application state. It's a cache of someone else's state, with its own lifecycle: it goes stale, it needs refetching, it needs deduping, it needs retry. A reducer models none of that. I was hand-rolling a bad cache and calling it architecture.
React Query (and its siblings) does that job properly, and deleting the hand-written version is the single most satisfying refactor I've ever done.
The queryKey is your cache key. Two components asking for the same guests share one request. Navigate away and back and it serves instantly from cache while revalidating. I used to write hundreds of lines to approximate a fraction of that.
So when is a store the right call?
I'm not anti-store. When you have genuinely global, client-owned state that many unrelated parts of the app both read and write — a complex multi-step editor, a collaborative canvas, an undo/redo stack — a dedicated store earns its keep. These days I reach for something lighter like Zustand, but Redux Toolkit is a perfectly reasonable choice if the team knows it. The point was never the library.
The point is the order of operations. Start with local state. Lift to context when a few distant components need a slow-changing value. Put server data in a server-state cache. And only after all three fail to fit do you introduce a global store — for the small slice of truly shared, client-owned, high-churn state that's left. Nine times out of ten, there isn't one. That's the part younger me didn't believe, and it's the part I'd most want to go back and tell him.