This guide will get you up and running with Zustand in just a few minutes. You’ll create a store, use it in components, and see how simple state management can be.
Your first store
Creating a store in Zustand is straightforward. Your store is a hook that you can use anywhere in your application.
Install Zustand
First, install Zustand in your project:
Create a store
Import create from zustand and define your store. You can put anything in it: primitives, objects, functions. import { create } from 'zustand'
const useBearStore = create (( set ) => ({
bears: 0 ,
increasePopulation : () => set (( state ) => ({ bears: state . bears + 1 })),
removeAllBears : () => set ({ bears: 0 }),
}))
The set function merges state by default. You can update just the properties you want to change.
Use the store in components
Use the hook anywhere in your app. No providers needed! Components will re-render when the selected state changes. function BearCounter () {
const bears = useBearStore (( state ) => state . bears )
return < h1 > { bears } around here... </ h1 >
}
function Controls () {
const increasePopulation = useBearStore (( state ) => state . increasePopulation )
return < button onClick = { increasePopulation } > one up </ button >
}
Complete example
Here’s a complete working example you can copy and run:
import { create } from 'zustand'
// Create your store
const useStore = create (( set ) => ({
count: 1 ,
inc : () => set (( state ) => ({ count: state . count + 1 })),
}))
// Use it in your components
function Counter () {
const { count , inc } = useStore ()
return (
< div >
< span > { count } </ span >
< button onClick = { inc } > one up </ button >
</ div >
)
}
export default Counter
import { create } from 'zustand'
// Define your store's type
type Store = {
count : number
inc : () => void
}
// Create your store with type safety
const useStore = create < Store >()(( set ) => ({
count: 1 ,
inc : () => set (( state ) => ({ count: state . count + 1 })),
}))
// Use it in your components
function Counter () {
const { count , inc } = useStore ()
return (
< div >
< span > { count } </ span >
< button onClick = { inc } > one up </ button >
</ div >
)
}
export default Counter
Notice the create<Store>() syntax with an extra (). This is needed for proper TypeScript inference.
Understanding selectors
Selectors are functions that pick specific values from your store. They’re crucial for performance:
// ✅ Good: Only re-renders when bears changes
const bears = useBearStore (( state ) => state . bears )
// ✅ Good: Only re-renders when increasePopulation changes (never, it's a function)
const increasePopulation = useBearStore (( state ) => state . increasePopulation )
// ⚠️ Careful: Re-renders on ANY state change
const state = useBearStore ()
Fetching the entire state without a selector will cause your component to re-render on every state change, even if the component only uses a small part of the state.
Updating state
There are multiple ways to update state in Zustand:
Partial updates
The set function merges state by default:
const useStore = create (( set ) => ({
firstName: 'John' ,
lastName: 'Doe' ,
updateFirstName : ( name ) => set ({ firstName: name })
// lastName remains unchanged
}))
Functional updates
When the new state depends on the previous state, use a function:
const useStore = create (( set ) => ({
count: 0 ,
increment : () => set (( state ) => ({ count: state . count + 1 })),
incrementBy : ( amount ) => set (( state ) => ({ count: state . count + amount })),
}))
Complete replacement
Pass true as the second argument to replace the entire state:
const useStore = create (( set ) => ({
count: 0 ,
reset : () => set ({ count: 0 }, true ) // Replaces entire state
}))
Be careful with complete replacement - it will remove all state properties, including your action functions!
Async actions
Async actions work naturally - just call set when you’re ready:
const useStore = create (( set ) => ({
fishies: {},
fetch : async ( pond ) => {
const response = await fetch ( pond )
set ({ fishies: await response . json () })
},
}))
Reading state in actions
Use the get parameter to read the current state inside actions:
const useStore = create (( set , get ) => ({
sound: 'grunt' ,
action : () => {
const sound = get (). sound
// Use the current sound value
console . log ( sound )
},
}))
Multiple state slices
You can select multiple values efficiently:
// Multiple separate selectors (recommended)
const nuts = useBearStore (( state ) => state . nuts )
const honey = useBearStore (( state ) => state . honey )
// Or use useShallow for object selectors
import { useShallow } from 'zustand/react/shallow'
const { nuts , honey } = useBearStore (
useShallow (( state ) => ({ nuts: state . nuts , honey: state . honey }))
)
Using state outside components
You can read and update state outside React components:
const useDogStore = create (() => ({ paw: true , snout: true , fur: true }))
// Get current state
const paw = useDogStore . getState (). paw
// Update state
useDogStore . setState ({ paw: false })
// Subscribe to changes
const unsub = useDogStore . subscribe ( console . log )
// Unsubscribe
unsub ()
This is useful for integrating with non-React code, logging, or creating side effects.
Common patterns
Separate actions from state
Keep your store organized by grouping related logic:
const useStore = create (( set , get ) => ({
// State
count: 0 ,
user: null ,
// Actions
increment : () => set (( state ) => ({ count: state . count + 1 })),
decrement : () => set (( state ) => ({ count: state . count - 1 })),
setUser : ( user ) => set ({ user }),
}))
Computed values
Create derived state with selectors:
const useStore = create (( set ) => ({
firstName: 'John' ,
lastName: 'Doe' ,
}))
// In your component
const fullName = useStore (
( state ) => ` ${ state . firstName } ${ state . lastName } `
)
Resetting state
Store the initial state and reset to it:
const initialState = {
bears: 0 ,
fish: 0 ,
}
const useStore = create (( set ) => ({
... initialState ,
increase : () => set (( state ) => ({ bears: state . bears + 1 })),
reset : () => set ( initialState ),
}))
Next steps
You now know the basics of Zustand! Here’s where to go next:
Comparison See how Zustand compares to Redux, Jotai, and other state managers
TypeScript guide Learn TypeScript best practices with Zustand
Middleware Add persistence, devtools, and more with middleware
API reference Explore the complete API documentation