# Split a store into slices

Use slices when your global store grows too large to maintain in one state creator. Keep state and actions together in each slice, then compose the slice creators into one store. This example renders bear and fish counts, calls actions across slices, and adds persistence at the combined-store boundary.

## 1. Define typed slice creators

For slices, use [`StateCreator`](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/zustand#statecreator) with the combined `BoundState` as its first type argument and the individual slice's return type as its fourth; see [How Zustand works](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/how-zustand-works) for state creators and their `set` and `get` arguments.

Create this file in your React TypeScript project:

```ts title="slices.ts"
import type { StateCreator } from 'zustand'

export type BearSlice = {
  bears: number
  addBear: () => void
  eatFish: () => void
}

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

export type SharedSlice = {
  addBoth: () => void
  getBoth: () => number
}

export type BoundState = BearSlice & FishSlice & SharedSlice

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

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

export const createSharedSlice: StateCreator<BoundState, [], [], SharedSlice> = (
  _set,
  get,
) => ({
  addBoth: () => {
    get().addBear()
    get().addFish()
  },
  getBoth: () => get().bears + get().fishes,
})
```

`eatFish()` updates a field owned by the fish slice. `addBoth()` reads the combined store with `get()` and calls both slices' actions. Each action returns `void`; `getBoth()` returns the current sum as a `number`. The two calls inside `addBoth()` perform two store updates, not one atomic update.

## 2. Compose one hook and render its state

Use [`create`](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/zustand#create) with `create<BoundState>()(...)`. Pass the same `set`, `get`, and store arguments to every slice creator, then spread their results into one state object. The result is a bound store hook, not a separate store for each slice.

```ts title="store.ts"
import { create } from 'zustand'
import {
  createBearSlice,
  createFishSlice,
  createSharedSlice,
  type BoundState,
} from './slices'

export const useBoundStore = create<BoundState>()((...args) => ({
  ...createBearSlice(...args),
  ...createFishSlice(...args),
  ...createSharedSlice(...args),
}))
```

Select each count and action from that hook. This browser entry point mounts the component into a sized container:

```tsx title="main.tsx"
import { createRoot } from 'react-dom/client'
import { useBoundStore } from './store'

function App() {
  const bears = useBoundStore((state) => state.bears)
  const fishes = useBoundStore((state) => state.fishes)
  const total = useBoundStore((state) => state.bears + state.fishes)
  const addBear = useBoundStore((state) => state.addBear)
  const addFish = useBoundStore((state) => state.addFish)
  const eatFish = useBoundStore((state) => state.eatFish)
  const addBoth = useBoundStore((state) => state.addBoth)

  return (
    <main>
      <h1>Bear and fish store</h1>
      <p>Number of bears: {bears}</p>
      <p>Number of fishes: {fishes}</p>
      <p>Total: {total}</p>
      <button onClick={addBear}>Add a bear</button>
      <button onClick={addFish}>Add a fish</button>
      <button onClick={eatFish} disabled={fishes === 0}>Eat a fish</button>
      <button onClick={addBoth}>Add both</button>
    </main>
  )
}

const container = document.createElement('div')
container.style.height = '400px'
document.body.appendChild(container)
createRoot(container).render(<App />)
```

The initial counts and total are zero. Click **Add both** to see one bear, one fish, and a total of two. Click **Eat a fish** to see the fish count fall to zero while the bear count stays at one. The button disables at zero; the store action itself does not enforce that limit.

## 3. Apply middleware to the combined store

Replace `store.ts` with this version to persist the counts using the shipped [`persist`](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/zustand-middleware#persist) middleware. Keep the slice creators and `main.tsx` unchanged.

```ts title="store.ts"
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import {
  createBearSlice,
  createFishSlice,
  createSharedSlice,
  type BoundState,
} from './slices'

export const useBoundStore = create<BoundState>()(
  persist(
    (...args) => ({
      ...createBearSlice(...args),
      ...createFishSlice(...args),
      ...createSharedSlice(...args),
    }),
    {
      name: 'bear-fish-slices',
      partialize: (state) => ({ bears: state.bears, fishes: state.fishes }),
    },
  ),
)
```

In the browser, with `localStorage` available, change the counts and reload to see them restored. `partialize` saves only the two counts; the slice creators supply the actions again when the store is created.

### Persistence options

The storage adapter uses [`PersistStorage`](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/zustand-middleware#persiststorage); [`createJSONStorage`](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/zustand-middleware#createjsonstorage) supplies JSON serialization for a storage engine.

| Option | Type | Default | What it does |
| --- | --- | --- | --- |
| `name` | `string` | Required | Sets the unique storage key for this combined store. |
| `storage` | `PersistStorage<PersistedState, PersistReturn> \| undefined` | `createJSONStorage(() => window.localStorage)` | Selects the storage adapter. |
| `partialize` | `(state: S) => PersistedState` | `(state) => state` | Filters the state before saving it. |

For storage and hydration configuration, see [Persist store data](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/persist-store-data).

## Pitfalls

- Keep slice creators unwrapped and put middleware around the combined creator, as above. See [Type stores and middleware](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/type-stores-and-middleware) for middleware composition rules. When using [`devtools`](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/zustand-middleware#devtools), annotate each slice's incoming mutator tuple as `[['zustand/devtools', never]]` instead of `[]`.
- Keep `get()` calls inside actions such as `addBoth()` and `getBoth()`. For initialization-time reads, see [Reset store state](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/reset-store-state).
- Keep slice field names distinct. Object spreading makes a later slice's value overwrite an earlier value with the same key.

## Related

- [How Zustand works](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/how-zustand-works) — the single-store model and colocated actions.
- [State and actions](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/state-and-actions) — updates and shallow merging.
- [Selectors and subscriptions](https://bench-zustand-61.atloria.app/p/bench-zustand-61-pSJCWrWW5Y/developer/selectors-and-subscriptions) — selecting values from the combined hook.
