SpikeMe
← Comparisons
State management

Zustand vs Jotai

updated on July 13, 2026

Zustand vs Jotai

Zustand and Jotai compared on mental model, render granularity, persistence, and Suspense support — with real npm data and a verdict by context.

FactZustandJotai
Current version5.0.142.20.1
Downloads/week (npm)36,686,7505,530,878
LicenseMITMIT
Bundle (gzip)0.5 kB4 kB
CriterionZustandJotai
Mental modelsingle store with selectorsindependent, composable atoms
State creationone create() with data + actionsone atom() per unit of state
Granular renderrequires a manual selector per slicegranular by default, no selector
Persistencebuilt-in persist middlewareatomWithStorage in jotai/utils
DevToolsdevtools middleware (Redux DevTools)separate jotai-devtools extension
Suspense/async supportno native integrationnative async atoms

Context

An entire shopping cart usually fits well in a single store; a dashboard with widgets reading distinct slices of data calls for something else — Zustand and Jotai were each designed for one of these shapes of shared state in React. Zustand organizes state into one or more centralized stores: you define an object with data and actions, and each component reads the slice it needs through a selector. Jotai organizes state into independent atoms, each the smallest possible unit of state, which can be combined and derived from one another. The choice between the two is rarely about raw performance — both are lightweight and mature — and almost always about which mental model fits the way your domain's state is structured.

Both libraries came from the same group of maintainers (pmndrs) and share principles: a minimal API, no mandatory Provider wrapping the whole tree, and direct integration with React hooks, without the actions, reducers, and dispatch boilerplate of classic Redux.

When to choose Zustand

Zustand fits well when state is naturally a cohesive unit — a shopping cart, the state of a multi-step wizard, a user session. You create a store with create(), it exposes data and actions in the same place, and any component selects the slice it consumes:

import { create } from "zustand";

const useCart = create<{ items: string[]; add: (id: string) => void }>((set) => ({
  items: [],
  add: (id) => set((s) => ({ items: [...s.items, id] })),
}));

That centralization has a cost: to avoid unnecessary re-renders, each component needs to explicitly select the slice of state it consumes (useCart((s) => s.items)), instead of relying on the atom itself already being the subscription unit. For anyone coming from Redux or a global useReducer, this model is immediately familiar — the single store with cohesive actions is practically the same shape, just without the ceremony of separate actions and reducers. Zustand also has first-class middlewares for persistence (persist) and for Redux DevTools integration, which helps teams that already have that debugging workflow established.

When to choose Jotai

Jotai fits better when state is compositional by nature — several small, independent pieces, some derived from others, with a need for granular re-render without writing manual selectors. Each atom is its own subscription unit: a component that reads countAtom only re-renders when countAtom changes, no matter how many other atoms exist in the application.

import { atom } from "jotai";

const countAtom = atom(0);
const doubledAtom = atom((get) => get(countAtom) * 2);

The second atom above is derived from the first with no manual selection or memoization logic — the dependency graph is resolved by the library itself. That compositionality is Jotai's strength: forms with many independent fields, dashboards with widgets reading distinct slices of data, or any scenario where "a single global state" tends to turn into a monolithic object that's hard to partition. Jotai also has native support for async atoms integrated with Suspense, which avoids manual loading and error boilerplate in several client-side data-fetching cases. The flip side is the learning curve: thinking in terms of an atom graph requires a mental shift for anyone used to the single-store model, and projects with many small atoms can become hard to navigate without some organizing convention — by file or by domain.

Verdict

The shape of the state matters more here than any performance benchmark between the two libraries — and what's already familiar to the team comes right after. If your project's state is predominantly one or a few cohesive units (session, cart, a flow's configuration), and the team already has familiarity with Redux's single-store model, Zustand tends to be productive from day one, with fewer new concepts to learn. If the state is naturally fragmented into many independent or derived parts — large forms, modular dashboards, state that benefits from granular render by default — Jotai avoids the ceremony of manual selectors and scales better as the number of state slices grows.

Nothing stops you from mixing both in the same project — Zustand for the cart and the session, Jotai for a dashboard's independent widgets — and teams already familiar with both pmndrs libraries do exactly that more often than the "which one to choose" question suggests. The question worth asking isn't which one wins, but which slice of your project's state fits better into each mental model.

Zustand

Choose Zustand if…

Choose Zustand if the state is one or a few cohesive units and the team already knows Redux's single-store model.

Jotai

Choose Jotai if…

Choose Jotai if the state is fragmented into many independent or derived parts and you want granular render without writing selectors.

The numbers above came from the registry, with source and date. Still, this comparison is generic: the right answer depends on versions, your team and what already exists in your project.

Generate the spike for YOUR stack

Share

XLinkedIn