Skip to main content
Although Zustand is unopinionated, we recommend patterns inspired by Flux and Redux. If you’re coming from another library, these patterns should feel familiar.
Zustand differs from Flux and Redux in some fundamental ways, so terminology may not perfectly align with other libraries.

Single Store

Your application’s global state should be located in a single Zustand store.
For large applications, Zustand supports splitting the store into slices.
import { create } from 'zustand'

const useStore = create((set) => ({
  // All your global state in one place
  user: null,
  cart: [],
  theme: 'light',
  // ... actions
}))

Use set / setState to Update the Store

Always use set (or setState) to perform updates to your store. This ensures updates are correctly merged and listeners are properly notified.
const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}))

Colocate Store Actions

In Zustand, state can be updated without dispatched actions and reducers. Store actions can be added directly to the store:
const useBoundStore = create((set) => ({
  storeSliceA: { value: 0 },
  storeSliceB: { value: '' },
  storeSliceC: { value: [] },
  updateX: () => set((state) => ({ storeSliceA: { value: state.storeSliceA.value + 1 } })),
  updateY: () => set({ storeSliceB: { value: 'updated' } }),
}))
Optionally, by using setState, actions can be located external to the store.

Redux-Like Patterns

If you prefer Redux-style reducers, you can define a dispatch function:
const types = { increase: 'INCREASE', decrease: 'DECREASE' }

const reducer = (state, { type, by = 1 }) => {
  switch (type) {
    case types.increase:
      return { grumpiness: state.grumpiness + by }
    case types.decrease:
      return { grumpiness: state.grumpiness - by }
  }
}

const useGrumpyStore = create((set) => ({
  grumpiness: 0,
  dispatch: (args) => set((state) => reducer(state, args)),
}))

const dispatch = useGrumpyStore((state) => state.dispatch)
dispatch({ type: types.increase, by: 2 })

Comparison with Flux/Redux

Flux/Redux: Encourages a single storeZustand: Also recommends a single store, but supports multiple stores if needed
// Single store (recommended)
const useStore = create((set) => ({ /* all state */ }))

// Multiple stores (if needed)
const useUserStore = create((set) => ({ /* user state */ }))
const useCartStore = create((set) => ({ /* cart state */ }))
Flux/Redux: Uses action creators and reducersZustand: Actions are just functions in the store
// Redux-style
const increment = () => ({ type: 'INCREMENT' })
const reducer = (state, action) => {
  switch (action.type) {
    case 'INCREMENT': return { count: state.count + 1 }
  }
}

// Zustand-style
const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}))
Flux/Redux: Requires immutable updates with spread operatorsZustand: Automatically merges top-level state, but you still need to handle nested objects immutably
// Both require immutability for nested objects
set((state) => ({
  nested: { ...state.nested, updated: true }
}))

Side Effects and Async Actions

Another way to update the store is through functions that wrap state updates and handle side effects:
import { create } from 'zustand'

const useStore = create((set, get) => ({
  user: null,
  loading: false,
  error: null,
  
  fetchUser: async (id) => {
    set({ loading: true, error: null })
    
    try {
      const response = await fetch(`/api/users/${id}`)
      const user = await response.json()
      set({ user, loading: false })
    } catch (error) {
      set({ error: error.message, loading: false })
    }
  },
}))
For non-reactive usage outside of components, see the Zustand README.

Best Practices Summary

Single Store

Keep global state in one store, use slices for organization

Use set/setState

Always update state through set for proper reactivity

Colocate Actions

Define actions alongside state for better encapsulation

Handle Side Effects

Wrap async operations in actions for centralized logic

Slices Pattern

Split large stores into modular slices

No Store Actions

Alternative pattern with external actions

Immutable State

Understanding state merging and immutability

Redux Middleware

Use Redux patterns with middleware

Build docs developers (and LLMs) love