Skip to content
masterclassBuddyTech Buzz5 fresh blogs · 5:00 AM IST

Zustand · Const

nested updates

Zustand nested updates are immutable: copy each object along the path with spreads, then replace the target value. The set function shallowly merges the returned top-level object, so nested levels must be merged explicitly.

How it works

A nested update must preserve every object level between the store root and the changed value. Use the previous state in an updater function, spread each containing object, and replace only the targeted property; Immer, optics-ts, or Ramda can reduce this boilerplate.

Syntax

set((state) => ({ nested: { ...state.nested, value: nextValue } }))

Returns

The updater returns a partial state object containing replacement objects along the changed path.

Key points

  • Use set to submit the update; Zustand combines the returned top-level fields with the existing store.
  • For a deep path, create a new object at every containing level rather than modifying the original structure.
  • The spread operator retains existing fields while the returned leaf value supplies the change.
  • Immer can reduce the amount of manual copying needed when nested state becomes cumbersome.

Common mistakes

  • Shallow merging does not recursively preserve nested objects, so explicitly spread each nested level you update.
  • Do not mutate a nested object in place; create replacement objects along the path to the changed value.
  • Immer is an optional alternative for deeply nested updates, not a requirement for Zustand.

Example: Immutable nested update

import { create } from 'zustand'

type Store = {
  deep: { nested: { obj: { count: number } } }
  increment: () => void
}

export const useStore = create<Store>((set) => ({
  deep: { nested: { obj: { count: 0 } } },
  increment: () =>
    set((state) => ({
      deep: {
        ...state.deep,
        nested: {
          ...state.deep.nested,
          obj: {
            ...state.deep.nested.obj,
            count: state.deep.nested.obj.count + 1,
          },
        },
      },
    })),
}))

The action copies every containing object before changing the deeply nested count, preserving immutable updates.

When to use it

Update a deep object property

A store contains objects nested several levels deep and one leaf needs changing without affecting sibling fields.

Derive a nested update from previous state

A counter, form field, or other leaf value depends on its current nested value.

Simplify updates with Immer

Manual spreads become difficult to maintain as the state shape grows deeper.

Interview questions

QHow do you update a deeply nested Zustand value immutably?

Use an updater function with set, then copy each object from the root to the changed property using spreads. Replace the leaf value while retaining sibling properties.

Follow-up: What does Zustand merge automatically? Only the top-level state object; nested objects require explicit merging.

QWhy are spreads needed at every nested level?

The default set behavior shallowly merges the returned object. It does not recursively merge nested objects, so omitting a nested sibling can lose that data.

Follow-up: How could you shorten repetitive nested copying? Use the documented Immer, optics-ts, or Ramda approaches.

QWhat alternative does the documentation show for nested updates?

Immer lets the update use mutation-like syntax while producing an immutable result. The documented pattern wraps the state creator with the immer middleware and updates the draft inside set.

Follow-up: What tradeoff does the manual spread approach avoid? It avoids adding a helper library, at the cost of more boilerplate.

  • set
  • Immer
  • optics-ts
  • Ramda
  • immutable state and merging

Source: Updating state - Zustand Docs. Checked 2026-10-15.