mrkeyoor.com_
Thu 12 Nov 11:13 UTC
Dev Toolsevaluationupdated 12 Nov 2026

zustand review

Zustand lets JavaScript applications share changing data through stores, with hooks for React components to select the values they need. It is useful when passing state through component props or coordinating Context values becomes awkward.

Verdict

Our Zustand source-install attempt failed after 5 seconds with ERR_UNKNOWN_BUILTIN_MODULE, so it provides no completed application run. The reported migrations make Zustand worth choosing for shared client state if your team owns selector behavior and store scope. Keep a working Redux Toolkit application unless you have a concrete problem to solve, and keep server-data caching with the tool responsible for it.

We ran it

Lab card: what happened when we ran zustandScreenshot of zustand (zustand-demo.pmnd.rs)
Install✗ · 5s
Build—
Repo144 files~11,338 lines of source · 1.9 MB · 8 CI workflows · tests dir

Answers from our run

Does zustand build from source?

The dependency install failed, and the project has no separate build step. We cloned commit 9fed2eb into a clean Debian container with 3 CPUs and no project-specific setup.

Who should not use zustand?

Teams expecting subscriptions to narrow automatically after selecting the whole store: selectors determine what a component observes.

What are the alternatives to zustand?

Redux Toolkit, TanStack Query, Jotai. Our Zustand source-install attempt failed after 5 seconds with ERR_UNKNOWN_BUILTIN_MODULE, so it provides no completed application run.

SetupN/ANot assessed: installation was not reproduced in a supported environment.
Docs4/5The visible documentation rubric awards 4/5 for coverage of selectors, store scoping, middleware and migration choices, without independently reproduced instructions across those paths.
CommunityN/AIssue discussions show maintainer participation, but support responsiveness and capacity were not assessed.
MaturityN/AThe failed setup and blocked hands-on attempt do not assess production reliability or current integration behavior.

Who it’s for

React teams managing shared client state with explicit selectors.
Developers replacing a specific Context subscription problem while retaining TanStack Query for server data.
Component-library authors willing to create isolated stores for reusable controls.

Who it’s NOT for

Teams expecting subscriptions to narrow automatically after selecting the whole store: selectors determine what a component observes.
Next.js developers planning to put request-specific session data in a shared server singleton: issue #182 reports data crossing browser sessions.
Teams wanting native MobX-style computed getters: issue #108 recommends derived selectors or hooks instead.
Teams happy with Redux Toolkit and unable to name a concrete migration benefit.

Setup reality

Our November 11, 2026 install attempt at commit 9fed2eb failed with exit 1 in 5 seconds. The sandbox was configured with 3 CPUs, 8 GB RAM and image label lab-node:22. The log tail shows ERR_UNKNOWN_BUILTIN_MODULE and Node.js v20.20.2, with stack paths under pnpm 11.3.0. The tail does not name the missing built-in module.

Zustand is an application dependency. The README documents a package install and store creation, without an external service or credential requirement for the basic store. Our separate November 12 hands-on runner stopped because its safety rule required a Compose file, and cleanup reported okay.

React integration needs deliberate selectors. Next.js needs isolated request-specific state and coordinated persisted-state hydration. The printed runtime, rather than the image label, identifies the failed source step. Failed setup alone is not evidence that the library is broken.

Zustand is worth choosing for shared client state when you want explicit subscriptions and a small amount of store code. Keep a working Redux Toolkit setup unless you can name a problem the change would solve. Our source-install attempt stopped after 5 seconds, so the recommendation rests on documented behavior and attributed application reports, alongside that failed setup finding.

What people use Zustand for

Developers in the supplied case studies used Zustand for authentication, interface preferences and reusable selection controls, with different reasons for choosing it.

Who used it What they changed Reported outcome
The Frontend Undefined author Replaced Context for authentication and profile storage in the Timo sample app, retaining TanStack Query Added selectors to stop unnecessary profile-screen renders. Timo review
Alexcloudstar Rewrote the Bored portfolio app with DarkMode and Activity state in one file Found the store straightforward to write with little boilerplate. Bored account
TkDodo and colleagues Moved a design-system multi-selection control from local state plus Context to Zustand Reported fixing a performance problem with the same amount of code. Design-system account

Timo is the most useful example for someone choosing a stack. The author changed the way components accessed authentication and profile data while leaving the existing server-data tool in place. Some shared components depended on Context, so they also needed refactoring into pure components and Context-specific wrappers. The work extended beyond replacing the store declaration.

The selection control explains why you might scope a store to part of an application. TkDodo describes a control that became sluggish with fifty or more items. Multiple instances of that control also needed independent state. His solution shares a stable store instance through Context and lets Zustand handle the subscriptions inside that subtree. Those are his application observations, rather than our benchmark.

What happened when we ran it

Our November 11, 2026 source-install attempt at commit 9fed2eb failed with exit 1 after 5 seconds. The later November 12 hands-on attempt stopped at a safety check requiring a Compose file.

Recorded check Result What it tells a reader
Source dependency installation Failed, exit 1, 5 seconds This checkout did not complete setup in our sandbox
Sandbox configuration 3 CPUs, 8 GB RAM, image label lab-node:22 These are configured resources and an image label
Install log tail ERR_UNKNOWN_BUILTIN_MODULE, followed by Node.js v20.20.2 The tail identifies the actual Node runtime for the failed step
Package-manager stack Paths under Corepack's pnpm/11.3.0/dist/pnpm.mjs The exposed stack runs through pnpm internals
Repository scan 144 files, approximately 11,338 source lines, 1.9 MB This describes the checked-out repository
Repository signals 8 CI workflow files, a tests directory, workspaces, no Dockerfile These are structural observations, not successful execution results
November 12 hands-on safety step Failed: no compose.yaml, compose.yml, docker-compose.yaml or docker-compose.yml The runner required a Compose file before continuing
November 12 teardown teardown: ok The cleanup record reports completion

The source log shows a package-manager stack ending in an unknown built-in-module error. It does not identify the missing module in the supplied tail. Calling this a Zustand application crash would turn a setup failure into a different finding. The discrepancy between the image label and the printed Node version also matters: lab-node:22 cannot serve as evidence that this step ran on Node 22.

The hands-on safety record labels the repository unsafe because none of the accepted Compose filenames exists. That wording belongs to the runner's deployment rule. Zustand is a library you add to an application, so the rule's refusal is not a security judgment about the library.

The November 12 summary says it was deployed with its own Docker Compose and ports bound to localhost. That conflicts with the failed prerequisite. We treat the explicit failed step as the outcome, rather than claim a successful deployment. The teardown record says cleanup was okay.

Where people get stuck: subscriptions, hydration and store lifetime

The strongest failure reports concern fresh selector results and incorrectly shared stores, with fixes that change how the application uses Zustand.

Symptom and source What the thread supports Practical response
v5 RC migration crashes, issue #2741 A fresh array selector produced an update loop, and the reporter confirmed the suggested fix worked Wrap a grouped selection with useShallow, or select values separately
Persisted Next.js UI disagrees with server HTML, issue #938 The original reporter confirmed a hydration hook solved it, while another participant needed a different workaround Coordinate persisted-state restoration with the first client render
Session values appear in another browser, issue #182 A maintainer identified the imported store as a singleton and accepted Context as a way to avoid it Create isolated store instances for request-specific data
Derived getter stays stale, issue #108 Maintainers recommend calculating derived values in components, hooks or selectors Subscribe to the inputs through a selector instead of expecting MobX-style getters

The v5 RC story is particularly easy to recognize in an upgrade. A developer selected a search value and its setter by returning a new array. Opening the page produced “Maximum update depth exceeded.” A maintainer identified the new array on each render and suggested useShallow. After trying the grouped wrapper, the reporter said v5 worked. Another participant described the warning “The result of getSnapshot should be cached to avoid an infinite loop” and also reported success with useShallow. RC discussion

That is more actionable than advice to memoize everything. Inspect what your selector returns. A primitive selection and a newly allocated array have different reference behavior. Keep related values grouped when that makes the component clearer, but use the grouping pattern intended for your version.

Hydration needs a separate diagnosis. The initial HTML can describe default state while the browser restores saved state. Issue #938 contains successful mounting or hydration gates, plus a user for whom the earlier suggestions failed. Treat those as application workarounds with different scopes, rather than a universal configuration switch.

Store scope determines who can see session data

A module-level server store can share request-specific session data across clients, as the reporter in issue #182 discovered.

The reporter logged in using one browser and saw the same session data when loading the page in another. The maintainer's explanation was direct: the exported hook was also the store itself, making it a singleton. Later discussion accepted creating a store instance and distributing it with Context to avoid that global singleton. The thread records an architectural workaround, rather than an automatic isolation guarantee. Session discussion

For a reusable dashboard or selection control, the same scoping choice affects correctness even without session data. TkDodo's provider creates the vanilla store once in a component initializer, supplies its initial props, then passes that stable instance through Context. Each provider instance gets its own store. Recreating the store on every render would defeat that design. Scoped-store example

I would make store ownership part of a code review: who creates it, who reads it, and what ends its lifetime? “Global” is a poor default answer for user-specific server data. A small API does not make that ownership decision for you.

More contributors need an agreed async pattern

One multi-product account reports maintenance trouble from inconsistent asynchronous code after initially smooth growth.

The author of Context vs Zustand vs Redux: A Senior Engineer's Story describes colleagues mixing callbacks, promises and custom middleware patterns. The useful lesson is the disagreement between implementations. His approximate component counts describe those projects, not a maximum size Zustand can support. Team account

Before adopting it across a team, agree where fetched data lives, how actions expose errors and who handles cancellation or stale responses. That is my recommendation from the reported maintenance problem. It is much cheaper to settle those conventions while reviewing the first store than after every feature has invented its own approach.

Derived values deserve a convention too. Issue #108 distinguishes a function that reads current state on demand from a component subscription that updates when its inputs change. The maintainer recommends selectors or hooks, with memoization for expensive computations. A function stored in the state object does not by itself express which inputs a consuming component subscribes to. Derived-state discussion

Zustand vs Redux Toolkit, TanStack Query, Context and Jotai

Choose by the state you own and the conventions you need, rather than treating every alternative as a slower version of Zustand.

Alternative Reason to choose it Where Zustand fits
Redux Toolkit Keep an established Redux workflow, or use its included RTK Query data-fetching capability Shared client stores with direct action functions and explicit selectors
TanStack Query Fetch, cache, synchronize and update server state Client state alongside the server-data cache, as in Timo
React Context Distribute a few rarely changing values without another dependency Frequently changing shared state with subscriptions chosen by components
Jotai Compose primitive atoms and their dependencies Keep a store model and select values from it

Zustand vs Redux Toolkit is a choice about application structure, not a requirement to write switch statements. The official Redux Toolkit introduction presents it as the standard way to write Redux logic and includes optional RTK Query. Zustand's own comparison shows both Redux Toolkit and traditional Redux examples. Compare against the Toolkit code your team would actually write.

Zustand vs TanStack Query usually calls for dividing responsibilities. TanStack's overview describes server-state fetching, caching, synchronization and updates. Timo kept TanStack Query during its Zustand migration. Moving an API response into a store does not settle cache freshness or the behavior after a mutation.

Zustand vs React Context depends on update patterns and scope. The supplied side-project discussion weighs easier shared-state handling against keeping dependencies out of a small project. Context also remains useful for distributing a Zustand store instance. Removing every provider is not a sensible success criterion for scoped components.

For Zustand vs Jotai, the official comparison describes store selection versus composable atoms and atom dependencies. It also contrasts Zustand's immutable updates and manual selectors with Valtio's mutable state and property-access optimization. Those mechanisms help explain preferences without claiming a universal speed winner. Official comparison

What the other reviews get wrong

Several supplied tutorials overstate what Zustand handles automatically, especially subscriptions and server rendering.

Lijo N S's Deep Dive into Zustand describes React Context as its foundation. Zustand's official comparison says a provider is not required. Optional Context integration for store ownership does not make Context the underlying subscription mechanism. Original claim, official comparison

Syncfusion's Redux vs Zustand says components automatically subscribe only to the data they use. That skips the selector. Destructuring a field after subscribing to the whole store does not narrow that subscription. The same article's advice to create stores outside components is too broad: TkDodo shows a store created once inside a provider for isolated instances. Syncfusion article, scoping example

GeeksforGeeks presents SSR integration without the request-isolation and hydration conditions documented in issues #182 and #938. Those conditions belong in the recommendation, especially when authentication data is involved. GeeksforGeeks article

Older grouped-selector examples also need version labels. The v5 RC discussion supplies a confirmed useShallow fix, so a fresh object or array example should not be presented as a version-independent recipe. Likewise, Redux comparisons that rely entirely on hand-written reducers miss what Redux Toolkit supplies today.

The November release changes persistence and DevTools

Zustand v5.1.0 adds PromiseLike handling to persistence and action dispatch from Redux DevTools.

The November 6, 2026 release says storage reads, migrations and migration writes accept PromiseLike results. It also says persist.rehydrate() returns an awaitable native promise, and the DevTools middleware gains an actionCreators option with nested actions and arguments. These are upstream release statements.

The supplied maintainer announcement asks persistence and DevTools users to check the changelog even though typical uses should not break. Maintainer announcement That is a better upgrade habit than carrying middleware assumptions forward from an older tutorial. The repository API records a November 6 push alongside this release, and the RC threads show maintainers addressing migration reports. That combination supports ongoing maintenance, without using stars as a support guarantee.

Questions people ask

Zustand is a selector-based state library with a React hook interface, and its name is a German word for state or condition.

What is Zustand, and what does its name mean in German?

Zustand state management lets components share values and actions through a store. The German noun means “state” or “condition.” The project has English documentation despite the German name. Official introduction, dictionary

How do you pronounce Zustand?

Zustand pronunciation in German is approximately “TSOO-shtahnt.” Wiktionary gives the IPA /ˈt͡suːˌʃtant/ and provides an audio recording. Pronunciation entry

How do I set and get state in a Zustand store?

Create a store, update it through set in an action, and read reactive values with selectors. The README also exposes getState() for reading outside React and setState() for updates. A nonreactive read is different from subscribing a component. For Zustand npm installation, the documented package command is npm install zustand. README

Is Zustand or Redux Toolkit the better choice for my application?

Pick Zustand for direct shared-client-state stores when the team wants to define its conventions. Favor Redux Toolkit when its established workflow or RTK Query is useful. Both use selectors for render optimization, according to Zustand's official comparison. Comparison

What would justify switching an already working Redux Toolkit application to Zustand?

A specific maintenance problem or unwanted subscription behavior is a reason to investigate a change. A working Redux Toolkit app does not need a rewrite simply because Zustand's example is shorter. The supplied Redux discussion includes users who prefer RTK's existing workflow and others who prefer Zustand's setup. User discussion

Should I use Zustand instead of React Context?

Use it when a shared store with selected subscriptions solves your update problem. A few rarely changing Context values can remain simple. You can also use Context to distribute isolated Zustand stores. Scoped-store account

Should I use Zustand, TanStack Query, or both?

Use TanStack Query for server-data caching and Zustand for shared client state when your app needs both. Timo retained TanStack Query while moving authentication and profile storage to Zustand. Timo migration

Can I use Zustand in React Native?

The official docs describe React Native support. During v5 alpha testing, a reporter resolved a Metro module-resolution problem by setting unstable_conditionNames to ['require']. That is a historical workaround for the reported setup, rather than a change every native app needs. Official docs, alpha discussion #2329

What we have not tested yet

Our evidence stops before a successful source installation or a running application, so this review supplies no measured render-speed advantage, build result or passing-test total.

We have not reproduced the case-study migrations, compared alternatives on the same application, tested current React Native integration, exercised Next.js request isolation, or measured hydration behavior on v5.1.0. No dependency or vulnerability audit result is supplied. The install tail cannot establish the exact missing module or a supported-environment fix. The November 12 record contains no completed application task, question-and-answer results or screenshots.

Community outcomes remain their authors' reports. The contrary business-app account in the supplied Reddit evidence describes dissatisfaction followed by a move to Jotai+Bunshi, without comparable measurements or implementation details. Neither that report nor favorable migration stories establishes a universal performance ranking. Discussion

Setup, community support quality and production maturity are unassessed in the scorecard. Documentation receives an editorial 4/5 for covering selection, scoping, middleware and migration choices: on this documentation-only scale, 1 means no usable guidance, 3 means core usage is covered and 5 requires independently reproduced instructions across these paths. Our failed source setup prevents the highest rating. That rating concerns coverage, not application reliability.

Before a team-wide change, take one troublesome shared-state feature and write down its store owner, selectors and server-data boundary. Those decisions are the useful acceptance criteria for adopting Zustand.

Alternatives

ProjectWhat it isPick it when
Redux ToolkitThe standard Redux tooling, with optional RTK Query included.Keep it when its established workflow or included server-data tooling solves your application needs.
TanStack Query gh↗Fetching, caching, synchronizing and updating server state.Choose it for server-data lifecycle work, alongside Zustand when shared client state also needs a store.
JotaiState built from composable primitive atoms and their dependencies.Choose it when an atom model suits your state relationships better than selecting from a store.

What people are saying

  1. [velocity-scout] pmndrs/zustand

Sources

  1. Zustand README
  2. Zustand v5.1.0 release
  3. Redux Toolkit introduction
  4. TanStack Query overview
  5. German meaning and pronunciation
  6. Zustand official comparison
  7. Timo migration
  8. v5 RC selector fix

More dev tools reviews

hydra · improve · modern-web-guidance-src · folly · universal-android-debloater-next-generation · OpenSandbox · the whole board →