State Management in Production: Redux Toolkit vs Zustand
After shipping production apps with both, here's my honest comparison of Redux Toolkit and Zustand for large React Native applications — including the messy parts the tutorials skip.
The state management question in React Native is one of those debates that gets surprisingly heated. Everyone has their favorite, and everyone has horror stories about their previous choice. I've shipped a production app with Redux + Saga for three years. I shipped another with Zustand for two. Here's what I actually learned, without the marketing.
Redux Toolkit + Saga: the workhorse
Redux gets a lot of flak for being verbose, and Redux Toolkit largely fixes that. createSlice reduces boilerplate, createAsyncThunk handles the most common async patterns, and the Redux DevTools are still the best in the industry. Time-travel debugging is not just a party trick — when a state-related bug shows up in production, the ability to replay actions and see the exact state at each step is invaluable.
Where Saga earns its keep is in complex async flows. Imagine a checkout flow: validate cart, reserve inventory, charge payment, show confirmation, send receipt, and handle the failure case for each step. With Saga, you write this as a single generator function that watches for actions and uses call, put, and select to express the flow declaratively. The flow is readable, testable, and cancelable in one place.
The downside is the learning curve. New developers take longer to ramp up on Saga than on plain Redux. And the boilerplate, even with Toolkit, is real. You write a lot of types for every action, every reducer, every selector. For a small app, it feels like overkill.
Zustand: the upstart
Zustand is the opposite of Redux in almost every way. It's a single hook, useStore, that lets you define a store with state and actions in one place. No providers, no actions, no reducers. The mental model is "just JavaScript" — state is a plain object, actions are functions that mutate it.
For most apps, Zustand is enough. Any component can subscribe to any slice of state with a selector. The code is dramatically shorter than equivalent Redux. Performance is comparable for most use cases.
The downside shows up when your state gets complex. Zustand doesn't have a built-in pattern for orchestrating multiple async operations. You end up writing async functions inside your actions, and those can get messy. Some teams use Zustand + TanStack Query to split server state from client state, which works well — but it's two libraries to learn instead of one.
The decision framework
After several projects, I now ask three questions before choosing.
First, how complex are your async flows? If you have multi-step flows that need to be cancelable, retryable, and observable, Saga pays for itself. If your state is mostly UI state with a few API calls, Zustand is plenty.
Second, how big is your team? Redux's structure pays off in teams of 5+ where everyone needs to follow the same patterns. For solo developers or small teams, Zustand is faster to write and easier to refactor.
Third, what does your state look like? If it's mostly server state (data from an API), reach for TanStack Query first and add Zustand for the UI state on top. If it's mostly client state with derived data, Redux's selectors and memoization are still hard to beat.
The real answer
There's no universal answer. Redux is still the right choice for some apps. Zustand is right for others. I've shipped both successfully. The thing I'd warn against is choosing a state management library based on hype — pick the one that fits your team's mental model and your app's actual complexity. Both are mature, well-maintained, and battle-tested. The right answer is the one your team can ship the fastest with.