Zustand provides two primary ways to create stores: create() for React applications and createStore() for vanilla JavaScript/TypeScript.
Creating React Stores with create()
The create() function creates a React Hook that manages state and provides API utilities.
Type Signature
type Create = {
< T , Mos extends [ StoreMutatorIdentifier , unknown ][] = []>(
initializer : StateCreator < T , [], Mos >,
) : UseBoundStore < Mutate < StoreApi < T >, Mos >>
}
Basic Usage
Import create
Import the create function from Zustand. import { create } from 'zustand'
Define your state creator
The state creator function receives three arguments:
set: Function to update state
get: Function to read current state
store: The store API object
type BearStore = {
bears : number
increasePopulation : () => void
removeAllBears : () => void
}
const useBearStore = create < BearStore >(( set ) => ({
bears: 0 ,
increasePopulation : () => set (( state ) => ({ bears: state . bears + 1 })),
removeAllBears : () => set ({ bears: 0 }),
}))
Use the hook in components
The returned hook can be used directly in React components. function BearCounter () {
const bears = useBearStore (( state ) => state . bears )
return < h1 > { bears } bears around here... </ h1 >
}
Understanding the State Creator Function
The state creator is the heart of your store. It defines the initial state and actions.
Basic State Creator
With Actions
Using get
const useCountStore = create <{ count : number }>(( set ) => ({
count: 0 ,
}))
The set Function
The set function is how you update state in Zustand. It accepts two arguments:
partial
T | Partial<T> | (state: T) => T | Partial<T>
The new state or a function that returns the new state
Whether to replace the entire state instead of merging
Partial Update
Function Update
Replace Mode
By default, set performs a shallow merge: set ({ count: 1 }) // Merges { count: 1 } with existing state
Use a function when the new state depends on the previous state: set (( state ) => ({ count: state . count + 1 }))
Use the second parameter to replace the entire state: set ({ count: 1 }, true ) // Replaces entire state
The get Function
The get function returns the current state:
const useStore = create <{ count : number ; double : () => number }>(( set , get ) => ({
count: 5 ,
double : () => get (). count * 2 ,
}))
The get function is useful for actions that need to read the current state without causing re-renders.
Creating Vanilla Stores with createStore()
The createStore() function creates a vanilla store that can be used outside of React.
Type Signature
type CreateStore = {
< T , Mos extends [ StoreMutatorIdentifier , unknown ][] = []>(
initializer : StateCreator < T , [], Mos >,
) : Mutate < StoreApi < T >, Mos >
}
Basic Usage
import { createStore } from 'zustand/vanilla'
type CounterState = {
count : number
increment : () => void
}
const counterStore = createStore < CounterState >()(( set ) => ({
count: 0 ,
increment : () => set (( state ) => ({ count: state . count + 1 })),
}))
// Access state directly
counterStore . getState (). count // 0
// Call actions
counterStore . getState (). increment ()
// Subscribe to changes
const unsubscribe = counterStore . subscribe (( state , prevState ) => {
console . log ( 'count changed from' , prevState . count , 'to' , state . count )
})
StoreApi Interface
Both create() and createStore() return a store that implements the StoreApi interface:
interface StoreApi < T > {
setState : SetStateInternal < T >
getState : () => T
getInitialState : () => T
subscribe : ( listener : ( state : T , prevState : T ) => void ) => () => void
}
The main difference between create() and createStore() is that create() returns a React Hook with the StoreApi attached, while createStore() returns just the StoreApi.
TypeScript Support
Zustand has excellent TypeScript support. You can define your state types explicitly:
Separate Types
Inline Types
type State = {
count : number
text : string
}
type Actions = {
increment : () => void
setText : ( text : string ) => void
}
type Store = State & Actions
const useStore = create < Store >()(( set ) => ({
count: 0 ,
text: '' ,
increment : () => set (( state ) => ({ count: state . count + 1 })),
setText : ( text ) => set ({ text }),
}))
When using TypeScript, make sure to use the curried version create<T>()((set) => ...) to get proper type inference.
Common Patterns
Separating State and Actions
type State = {
firstName : string
lastName : string
}
type Actions = {
updateFirstName : ( firstName : State [ 'firstName' ]) => void
updateLastName : ( lastName : State [ 'lastName' ]) => void
}
const usePersonStore = create < State & Actions >(( set ) => ({
firstName: '' ,
lastName: '' ,
updateFirstName : ( firstName ) => set ({ firstName }),
updateLastName : ( lastName ) => set ({ lastName }),
}))
Using Primitives as State
const useCount = create < number >(() => 0 )
// Update with replace flag
useCount . setState (( count ) => count + 1 , true )
When your state is a primitive value, always use the replace flag set to true when calling setState.
Next Steps
Reading State Learn how to read and select state in components
Updating State Master state updates and immutable patterns