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 produce —
produce(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: Performance overhead? A: Proxies add a small overhead, but structural sharing saves memory. Most apps won't notice. On hot paths, you can disable autoFreeze.
Q: What's its relationship with Redux?
A: Redux Toolkit's createSlice uses Immer internally. That's why you can write state.value += 1 directly in a reducer.
Q: Does it support Map/Set?
A: Yes. Call enableMapSet(). v10+ enables common ES collection types by default.
Sources & Credits
- Docs: https://immerjs.github.io/immer
- GitHub: https://github.com/immerjs/immer
- License: MIT