Zustand vs Jotai vs Redux Toolkit: picking your React state layer in 2026
TanStack Query owns server state. The question is what owns the rest. Zustand, Jotai, and Redux Toolkit each have a clear niche — here's how to pick the right one.
The state management conversation has simplified considerably since TanStack Query took over server state. With async data, loading states, and cache management handled by the query layer, what's left — UI state, user preferences, modal open/close, multi-step form progress — is genuinely simpler. Three libraries have emerged as the practical options for that remaining slice: Zustand for global client state, Jotai for fine-grained atomic state, and Redux Toolkit for large teams that need structure and tooling.
Zustand: the settled default for most apps
Zustand is 3KB, has no boilerplate, and doesn't require a Provider wrapper. You define a store as a function, export selectors, and subscribe from any component with a single hook call. The selector pattern means components only re-render when the specific slice they subscribe to changes — fine-grained re-renders without the atom primitive complexity. For teams coming from Redux who want 80% of the benefit at 20% of the code, Zustand is the answer.
import { create } from 'zustand';
interface UIStore {
sidebarOpen: boolean;
activeModal: string | null;
setSidebarOpen: (open: boolean) => void;
openModal: (id: string) => void;
closeModal: () => void;
}
export const useUIStore = create<UIStore>((set) => ({
sidebarOpen: true,
activeModal: null,
setSidebarOpen: (open) => set({ sidebarOpen: open }),
openModal: (id) => set({ activeModal: id }),
closeModal: () => set({ activeModal: null }),
}));
// In any component — no Provider, no context, just a hook
const sidebarOpen = useUIStore((s) => s.sidebarOpen);Jotai: atoms for fine-grained control
Jotai is the right tool when you have many independent pieces of state that different components subscribe to selectively. Each atom is its own unit — components that read atom A don't re-render when atom B changes, without any selector ceremony. It shines in heavily interactive UIs: data tables where each row has independent selection state, canvas editors where each element is a separate atom, or configuration panels with many independent toggles. The tradeoff is that atom management at scale requires discipline — an unorganised atom graph becomes hard to reason about.
Redux Toolkit: the right call for large teams
Redux Toolkit eliminated most of Redux's historical boilerplate and is the correct choice when you need time-travel debugging, strict action-based mutations that are auditable, and consistent patterns across a team of 15+ engineers. The slice pattern, createAsyncThunk, and Redux DevTools are genuinely useful for large applications. The cost is ceremony — for small apps, Zustand's simplicity wins. For a complex enterprise dashboard where multiple engineers need to understand state changes at a glance, Redux Toolkit's structure pays for itself.
- TanStack Query for all server state — async data, loading, error, and cache. No exceptions.
- Zustand for global UI state — sidebar, modals, user preferences, anything that doesn't belong in a URL.
- nuqs (URL state) for filters, tabs, and pagination — shareable and back-button friendly by default.
- Jotai when you have many independent atoms that need surgical re-render control.
- Redux Toolkit only on large teams that will benefit from the audit trail and DevTools investment.
Written by Appesto Engineering.