# Split a store into typed slices

Use slices when one store contains several feature areas. Each slice owns a part of the state and its actions, while the spread composition creates one store that components select from.

## When to use this pattern

Split a growing store when its state and actions have clear feature boundaries but still need to work together. Keep the slices as state-creator functions; do not create a separate Zustand store for each slice. The application gets one hook, one state model, and cross-feature actions through `get`.

## 1. Define the slice state and actions

Start with the complete store type, then type each slice as a part of that store. The [`StateCreator`](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/zustand#statecreator) generic receives the full store type and returns only the slice it creates. This lets a bear action update fish state and lets a shared action call actions from both slices.

```ts title="stores/types.ts"
export type BearSlice = {
  bears: number
  addBear: () => void
  eatFish: () => void
}

export type FishSlice = {
  fishes: number
  addFish: () => void
}

export type SharedSlice = {
  addBearAndFish: () => void
}

export type Store = BearSlice & FishSlice & SharedSlice
```

```ts title="stores/bearSlice.ts"
import type { StateCreator } from 'zustand'
import type { BearSlice, Store } from './types'

export const createBearSlice: StateCreator<Store, [], [], BearSlice> = (set) => ({
  bears: 0,
  addBear: () => set((state) => ({ bears: state.bears + 1 })),
  eatFish: () => set((state) => ({ fishes: state.fishes - 1 })),
})
```

```ts title="stores/fishSlice.ts"
import type { StateCreator } from 'zustand'
import type { FishSlice, Store } from './types'

export const createFishSlice: StateCreator<Store, [], [], FishSlice> = (set) => ({
  fishes: 0,
  addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
})
```

```ts title="stores/sharedSlice.ts"
import type { StateCreator } from 'zustand'
import type { SharedSlice, Store } from './types'

export const createSharedSlice: StateCreator<Store, [], [], SharedSlice> = (_set, get) => ({
  addBearAndFish: () => {
    get().addBear()
    get().addFish()
  },
})
```

The bear and fish actions update state through `set`. The shared action reads the current store through `get`, so it can reuse actions from other slices.

## 2. Compose one store

Call [`create`](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/zustand#create) once and spread every slice into its state creator; that single composition is the difference this pattern makes. For the general typed-store use of `create`, see [Typed store patterns](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/typed-store-patterns). The returned `useBoundStore` hook exposes all three slices as one state model.

```ts title="stores/useBoundStore.ts"
import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'
import { createBearSlice } from './bearSlice'
import { createFishSlice } from './fishSlice'
import { createSharedSlice } from './sharedSlice'
import type { Store } from './types'

export const useBoundStore = create<Store>()(
  devtools(
    persist(
      (...args) => ({
        ...createBearSlice(...args),
        ...createFishSlice(...args),
        ...createSharedSlice(...args),
      }),
      { name: 'bound-store' },
    ),
    { name: 'bound-store' },
  ),
)
```

Apply [`persist`](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/zustand-middleware#persist) and [`devtools`](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/zustand-middleware#devtools) around the combined creator, not inside an individual slice. For their general roles and composition inside `create`, see [Typed store patterns](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/typed-store-patterns); the slice-specific rule is to keep middleware at the boundary of the complete store. `persist` stores the combined state under `bound-store`; `devtools` names the same store in Redux DevTools.

The important order is `devtools(persist(...))`: the repository recommends putting `devtools` as far outside the other middleware as possible because it changes `setState`.

## 3. Select slices in React

Select individual fields or actions from the single hook. The mounted component below initially shows `0` bears and `0` fish. **Add a bear** changes only the bear count; **Add both** changes both counts in one action.

```tsx title="App.tsx"
import { useBoundStore } from './stores/useBoundStore'

export function App() {
  const bears = useBoundStore((state: ReturnType<typeof useBoundStore.getState>) => state.bears)
  const fishes = useBoundStore((state: ReturnType<typeof useBoundStore.getState>) => state.fishes)
  const addBear = useBoundStore((state: ReturnType<typeof useBoundStore.getState>) => state.addBear)
  const addBearAndFish = useBoundStore((state: ReturnType<typeof useBoundStore.getState>) => state.addBearAndFish)

  return (
    <main>
      <h1>Animals</h1>
      <p>Bears: {bears}</p>
      <p>Fish: {fishes}</p>
      <button type="button" onClick={addBear}>Add a bear</button>
      <button type="button" onClick={addBearAndFish}>Add both</button>
    </main>
  )
}
```

The selectors keep the component connected to the fields it reads while the actions remain colocated with their state. A slice can therefore grow without changing the component's store import or creating a provider.

## Options that matter here

| Option | Type | Default | What it does |
|---|---|---|---|
| `name` | `string` | Not specified | Names the persisted entry and the Redux DevTools connection in this example. |

## Pitfalls

- Apply middleware only to the combined creator, not inside a slice; see [Typed store patterns](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/typed-store-patterns) for the general middleware pattern.
- Do not call `get` while the initial state creator is running. Use it from a cross-slice action after the store exists; see [Typed store patterns](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/typed-store-patterns) for the general creator and initializer rules.
- Select stable values from the store. A selector that creates a new reference on every render can cause an infinite update loop in v5; see [Selectors and rendering](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/selectors-and-rendering).

## Related

- [Build a React store](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/build-a-react-store)
- [Typed store patterns](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/typed-store-patterns)
- [Compose store middleware](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/compose-store-middleware)
- [Create a vanilla store](https://bench-zustand-56.atloria.app/p/bench-zustand-56-D8Xr4XerWj/developer/create-a-vanilla-store)
