Separate domain state
A large application has unrelated domains such as bears and fish.
Zustand · Const
The slices pattern splits a large Zustand store into focused creator functions and combines them into one bounded store. This keeps state modular while allowing actions to coordinate across slices.
The slices pattern divides a large Zustand store into focused creator functions. Each creator receives the store arguments such as set and get, returns its state and actions, and the combined store spreads all slice results into one create call. Cross-slice actions can use get to call actions from other slices.
create((...args) => ({ ...createSliceA(...args), ...createSliceB(...args) }))A single Zustand store containing the state and actions returned by all composed slice creators.
import { create } from 'zustand'
const createFishSlice = (set) => ({
fishes: 0,
addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
})
const createBearSlice = (set) => ({
bears: 0,
addBear: () => set((state) => ({ bears: state.bears + 1 })),
eatFish: () => set((state) => ({ fishes: state.fishes - 1 })),
})
export const useBoundStore = create((...args) => ({
...createBearSlice(...args),
...createFishSlice(...args),
}))
This runnable store composes bear and fish slice creators into one Zustand store; actions from either slice can update the combined state.
A large application has unrelated domains such as bears and fish.
Several actions need to coordinate changes across domains.
A store is becoming difficult to maintain as one object.
The pattern splits a store into smaller creator functions, such as separate bear and fish slices. The final Zustand store combines their returned objects with spread syntax inside one create call.
Follow-up: How can a slice coordinate with another slice? Define a creator that receives get and call another slice's action through get(), then include that creator in the combined store.
Each slice creator receives the same store arguments and returns its own state fields and actions. Passing the arguments through with a rest/spread form lets every slice use the shared store API.
Follow-up: Why is the combined store bounded? Although implementation is split across files or creators, the spread results become one store exposed by a single hook.
Middleware should wrap the combined store rather than individual slices. Applying middleware inside slices can produce unexpected behavior according to the guide.
Follow-up: How would you type middleware-enabled slices? Use the appropriate StateCreator mutator tuple for the middleware, then apply the middleware at the combined-store level.
createsetgetbounded storeStateCreatormiddleware