One produce call replaces a ladder of shallow copies
Immer v11.1.21 takes a current state and a recipe function. The recipe receives a Proxy draft, so assignments, delete, and mutating collection methods can describe the change. When the recipe ends, Immer returns a new state and leaves the input alone. An untouched branch keeps its old reference, while a changed branch receives a new one.
The gain is clearest several levels down. Updating project.columns[2].cards[4].done by hand means copying each container on that path and preserving the other references. Immer records the write and handles those copies. Its checkout at commit 8848a5b contained about 17,179 lines of source, so the pleasant recipe syntax sits on a real proxy, finalization, freezing, and plugin implementation.
A 7-second build comes after a 445 MB contributor install
Our sandbox needed 97 seconds to install 1,032 Yarn packages, and the environment occupied 445 MB. The repository was 2.8 MB across 167 files before installation. That is contributor cost, not evidence that an application will consume the same space. Cloning Immer to change or audit it brings its documentation, build, formatting, Flow, TypeScript, and test stack.
The build passed in 7 seconds. No credentials, hosted services, database, or daemon were involved, and the unprivileged container had 3 CPUs and 8 GB of RAM. We found 3 CI workflow files and a tests directory, but no Dockerfile. Maintainers reproducing the toolchain need to follow the Yarn setup instead of starting from a project-supplied image.
What happened when we ran it
We ran commit 8848a5b in a fresh Debian container on Node 22. Installation succeeded in 97 seconds, the build succeeded in 7 seconds, and Vitest completed in 18 seconds. The suite reported 3,836 passed, 0 failed, and 8 skipped out of 3,844 tests. Nothing in the supplied result showed an install error, compiler failure, or red test.
Those numbers cover contributor confidence, not application speed. Our run did not benchmark reducers, React rendering, memory retention, or patch throughput. The official performance guide recommends profiling, reading expensive searches from the original state, and opting out for critical reducers. Version 11 also has an optional array methods plugin intended to reduce proxy creation during large scans.
Cycles, shared references, and native objects are outside the model
Immer v11.1.21 expects a unidirectional tree: no cycle, no object appearing twice, and one path from the root to each node. That rules out normalized graphs that intentionally share object identities. Plain objects, arrays, Maps, and Sets are draftable, while custom classes need the immerable marker. DOM nodes, Buffers, and subclasses of built-in collections are excluded. Dates should be replaced rather than mutated inside a recipe.
A draft wraps the original in a Proxy, so comparing the two objects with === does not work. External values inserted from a closure are not automatically drafted, and mutating one can change the caller's object. These rules are documented, but the 3,844-test suite cannot make a mismatched state model safe. Review the data shape before converting every reducer.
Patches support undo, but they are not minimal JSON Patch
Since version 6, patches require one startup call to enablePatches(). produceWithPatches returns the next state, forward patches, and inverse patches for undo, redo, traces, or replay onto a changed base. Map and Set support is enabled with enableMapSet(). The opt-in design avoids loading behavior an application never calls.
Immer's operations resemble RFC 6902, but each path is an array instead of a JSON Pointer string. The docs explain conversion and the escaping required by RFC 6901. They also state that the generated list is correct rather than guaranteed minimal. A protocol that bills by operation count or expects strict RFC input should normalize and, if needed, compress patches.
The October 2 release and 41 open items show live maintenance
GitHub listed 28,984 stars and 41 open issues and pull requests on October 3, 2026. The API result contained 30 issues and 11 pull requests. The repository was pushed on October 2, the day v11.1.21 fixed reads from revoked Map or Set drafts. Two releases minutes earlier corrected deletion bookkeeping and array-method callback behavior.
The documentation is candid about recipe returns, Proxy identity, unsupported graphs, freezing, and patch limits. One seam remains: the FAQ suggests a fallback for engines without Proxy, while the installation guide says version 10 removed it. Open issues also track stale translations. Read the topic guides, not just the short README. Our 18-second green run supports the core, while the guides show whether your state belongs inside it.
Use it when nesting, not fashion, creates the problem
Our run's 3,836 passing tests and 0 failures make Immer easy to trust for tree-shaped application state. Adopt it when a reducer's copying machinery has become harder to read than the update. A draft recipe then makes the change visible and keeps untouched references stable. For a flat object with one or two fields, native spread syntax may remain clearer.
The 1,032-package install belongs to Immer's contributor toolchain. Production still pays for Proxy work, recursive freezing, and enabled plugins. Start at the reducer that hurts, keep a benchmark around the hot path, and stop if the data contains shared references or engine-native objects. Immer is a strong tool when the problem matches the tree model it supports.

