Back to the blog
React· Jul 3, 2026· 7 min read

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.

#react#state-management#zustand#typescript

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.