pmndrs /zustand
🐻 Bear necessities for state management in React
★ 58,909⑂ 2,191👁 190⑃ 1,240● 699▤ 107◈ 1,528
58,909
stars
+2
2,191
forks
190
watchers
1,240
prs
699
issues
107
releases
1,528
discussions
README
A small, fast and scalable bearbones state-management solution using simplified flux principles. Has a comfy API based on hooks, isn't boilerplatey or opinionated.
Don't disregard it because it's cute. It has quite the claws, lots of time was spent dealing with common pitfalls, like the dreaded zombie child problem, react concurrency, and context loss between mixed renderers. It may be the one state-manager in the React space that gets all of these right.
You can try a live demo and read the docs.
bash
npm install zustand
:warning: This readme is written for JavaScript users. If you are a TypeScript user, be sure to check out our TypeScript Usage section.
First create a store
Your store is a hook! You can put anything in it: primitives, objects, functions. State has to be updated immutably and the set function merges state to help it.
jsx
import { create } from 'zustand'
const useBearStore = create((set) = ({
bears: 0,
increasePopulation: () = set((state) = ({ bears: state.bears + 1 })),
removeAllBears: () = set({ bears: 0 }),
}))
Then bind your components, and that's it!
Use the hook anywhere, no providers are needed. Select your state and the component will re-render on changes.
jsx
function BearCounter() {
const bears = useBearStore((state) = state.bears)
return {bears} around here ...
}
function Controls() {
const increasePopulation = useBearStore((state) = state.increasePopulation)
return one up
}
Why zustand over redux?
- Simple and un-opinionated
- Makes hooks the primary means of consuming state
- Doesn't wrap your app in context providers
- Can inform components transiently (without causing render)
Why zustand over context?
- Less boilerplate
- Renders components only on changes
- Centralized, action-based state management
---
Recipes
Fetching everything
You can, but bear in mind that it will cause the component to update on every state change!
jsx
const state = useBearStore()
Selecting multiple state slices
It detects changes with strict-equality (old === new) by default, this is efficient for atomic state picks.
jsx
const nuts = useBearStore((state) = state.nuts)
const honey = useBearStore((state) = state.honey)
If you want to construct a single object with multiple state-picks inside, similar to redux's mapStateToProps, you can use useShallow to prevent unnecessary rerenders when the selector output does not change according to shallow equal.
jsx
import { create } from 'zustand'
import { useShallow } from 'zustand/react/shallow'
const useBearStore = create((set) = ({
nuts: 0,
honey: 0,
treats: {},
// ...
}))
// Object pick, re-renders the component when either state.nuts or state.honey change
const { nuts, honey } = useBearStore(
useShallow((state) = ({ nuts: state.nuts, honey: state.honey })),
)
// Array pick, re-renders the component when either state.nuts or state.honey change
const [nuts, honey] = useBearStore(
useShallow((state) = [state.nuts, state.honey]),
)
//Top issues
Discussions
#3594Optional vanilla-store subscription regression traces0 comments · 2026-10-25#3579devtools.cleanup() disconnects other stores sharing the same connection2 comments · 2026-09-11#3577persist: Dexie migration Promises silently overwrite saved state with defaults3 comments · 2026-09-10#3576A11yKit: 15 Free, Zero-Upload Accessibility & WCAG 2.2 / APCA Contrast Tools for Zustand Apps0 comments · 2026-09-08#3571Looking to make my first contribution to Zustand1 comments · 2026-08-24#3566Broken link in README: ./docs/migrations/migrating-to-v5.md (migration guides moved under docs/reference/)2 comments · 2026-08-18#3564Typo error in docs1 comments · 2026-08-17#3562General performance improvement ideas2 comments · 2026-08-15
Latest release
v5.1.0 v5.1.0 2026-11-06The persist and devtools middleware are improved thanks to @Tnalxmsk and @dgesteves! Release note - The persist middleware now supports PromiseLike results from storage reads, migrations, and migration writes. persist.rehydrate() now returns a native Promise, which you can await to ensure hydration is complete. - The devtools middleware now supports dispatching store actions directly from Redux DevTools using the new actionCreators option. It also supports nested actions and arguments. What's Changed fix(middleware): persist migration supporting promise-like by @dai-shi in https: