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

Zustand · Function

immer

The immer middleware lets Zustand updates use mutable-looking draft syntax while producing immutable state. Wrap a state creator with it to simplify nested updates.

How it works

Wrap a Zustand state creator with immer to write nested updates using mutable-looking draft syntax. The middleware converts those draft mutations into immutable state updates and adds the Zustand Immer mutator type.

Syntax

immer<T>(stateCreatorFn: StateCreator<T, [], []>): StateCreator<T, [['zustand/immer', never]], []>

Parameters

NameTypeDescription
stateCreatorFnStateCreator<T, [], []>A Zustand state creator that receives set, get, and store, and usually returns the state and actions to expose.

Returns

A Zustand state creator function with the Immer mutator [['zustand/immer', never]].

Key points

  • It provides immutable state updates while allowing mutable-looking updater code.
  • The middleware is applied by passing a Zustand state creator to immer.
  • The wrapped creator receives Zustand's set, get, and store arguments.
  • It reduces boilerplate for changes to nested objects by avoiding manual whole-object copying.

Common mistakes

  • Class instances require Immer's immerable marker; otherwise Immer may mutate the existing state without producing a distinct next state, so Zustand can skip subscriptions.
  • Install immer as a direct dependency before importing this middleware.

Example: Using immer with a Zustand store

import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'

type Store = {
  person: { firstName: string; lastName: string }
  setFirstName: (firstName: string) => void
}

export const usePersonStore = create<Store>()(
  immer((set) => ({
    person: { firstName: 'Barbara', lastName: 'Hepworth' },
    setFirstName: (firstName) =>
      set((state) => {
        state.person.firstName = firstName
      }),
  })),
)

The updater can mutate the draft directly; Immer produces the immutable next state.

When to use it

Reduce immutable-update boilerplate

Updating deeply nested objects

Express field changes directly

Managing structured records such as people or todos

Preserve typed middleware composition

Using Zustand with TypeScript

Interview questions

QWhat does the immer middleware do?

immer accepts a Zustand state creator and returns another state creator. Its updater receives an Immer draft, so nested fields can be changed directly while Immer creates the immutable result.

Follow-up: How does the middleware appear in Zustand's type-level mutators? It adds ['zustand/immer', never] to the state creator's mutator tuple.

QWhat is the TypeScript signature and parameter?

The documented signature is immer<T>(stateCreatorFn: StateCreator<T, [], []>): StateCreator<T, [['zustand/immer', never]], []>. The input creator receives set, get, and store, and normally returns the store's exposed state and actions.

Follow-up: What dependency is required? The immer library must be installed separately because the middleware uses it to produce immutable updates.

QHow would you update nested state with it?

Wrap the state creator passed to create or createStore, then call set with a function that mutates the draft. This is especially useful for deeply nested objects because it avoids manually copying each level.

Follow-up: How should middleware ordering work with devtools? The TypeScript guide recommends devtools(immer(...)), putting devtools last so its setState mutation is preserved.

  • create
  • createStore
  • set
  • get
  • devtools
  • immerable
  • StateCreator

Source: immer. Checked 2026-10-15.