ConfigsApr 11, 2026·1 min read

Immer — Immutable State with Mutable Syntax

Immer lets you create the next immutable state by mutating the current one. Write mutating code as if it were normal JS and Immer produces a new immutable object via structural sharing. Built into Redux Toolkit and Zustand.

AI
AI Open Source · Community
Quick Use

Use it first, then decide how deep to go

This block should tell both the user and the agent what to copy, install, and apply first.

npm i immer
import { produce } from "immer";

const state = {
  users: [
    { id: 1, name: "Alice", tags: ["admin"] },
    { id: 2, name: "Bob", tags: ["user"] },
  ],
};

const nextState = produce(state, (draft) => {
  draft.users[0].tags.push("verified");
  draft.users.push({ id: 3, name: "Carol", tags: ["user"] });
});

// state is unchanged, nextState has the updates
console.log(state.users.length);     // 2
console.log(nextState.users.length); // 3
console.log(state === nextState);    // false
Intro

Immer is a tiny library that makes working with immutable state easy. Instead of writing verbose spread/concat code, you write mutating code against a draft and Immer produces a new immutable state via structural sharing. Created by Michel Weststrate (also creator of MobX), now the backbone of Redux Toolkit, Zustand, and many state libraries.

What Immer Does

  • produce — take state + recipe, return new state
  • Structural sharing — only changed paths are copied
  • Freeze — returned state is deeply frozen in dev
  • Patches — capture the diff for undo/redo or sync
  • Curried produceproduce(recipe) returns a reducer
  • setAutoFreeze — disable freezing in production for speed
  • castDraft / castImmutable — TypeScript helpers

Architecture

Proxy-based draft: when you access or modify the draft, Immer lazily clones the touched path and tracks mutations. On commit, a new tree is built. Untouched subtrees are shared (structural sharing), so the new state is memory-efficient.

Self-Hosting

Library ships with your app.

Key Features

  • Write mutating code, get immutable result
  • Structural sharing (memory efficient)
  • Deep freezing in dev
  • Patch-based diffs (undo/redo)
  • Curried produce for reducers
  • TypeScript types
  • Tiny (~3KB gzipped)
  • Used by Redux Toolkit, Zustand, Valtio

Comparison

Approach Syntax Memory Type Safety
Immer Mutating draft Structural sharing Yes
Manual spread Verbose Manual Yes
Immutable.js Own types OK Wrapped types
Seamless-immutable Light OK Limited
Mori Clojure-like Persistent Limited

常见问题 FAQ

Q: 性能开销? A: Proxy 有少量开销,但结构共享节省内存。大部分应用感受不到。Hot path 可以关 autoFreeze。

Q: 和 Redux 关系? A: Redux Toolkit 的 createSlice 内部用 Immer。这就是为什么你在 reducer 里可以直接 state.value += 1

Q: 支持 Map/Set 吗? A: 支持。需要 enableMapSet()。v10+ 默认启用常见 ES 集合类型。

来源与致谢 Sources

Discussion

Sign in to join the discussion.
No comments yet. Be the first to share your thoughts.

Related Assets