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.
What it is
Immer is a JavaScript library that simplifies immutable state management. Instead of writing spread operators and nested object copies, you write normal mutable code inside a produce function. Immer intercepts your mutations via a Proxy, applies structural sharing, and returns a new immutable object.
Immer is the state management engine behind Redux Toolkit. If you use createSlice or createReducer in Redux Toolkit, you are already using Immer. It targets any JavaScript or TypeScript project that needs immutable data patterns without the verbosity.
How it saves time or tokens
Immutable updates in plain JavaScript are verbose and error-prone. Updating a nested property requires spreading every level of the object tree. Immer eliminates this boilerplate: you mutate the draft object directly, and Immer handles the rest. This reduces both code size and the chance of missing a spread operator.
For AI-generated code, Immer produces simpler, more readable state updates that are easier for LLMs to generate correctly.
How to use
- Install Immer:
npm install immer
- Use the
producefunction:
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('superadmin');
draft.users.push({ id: 3, name: 'Charlie', tags: ['user'] });
});
// state is unchanged
// nextState has the updates with structural sharing
- In Redux Toolkit, Immer is built in:
const userSlice = createSlice({
name: 'users',
initialState: { list: [] },
reducers: {
addUser(state, action) {
// This looks like a mutation but Immer handles it
state.list.push(action.payload);
}
}
});
Example
import { produce, enableMapSet } from 'immer';
// Enable Map and Set support
enableMapSet();
const state = new Map([['a', 1], ['b', 2]]);
const next = produce(state, draft => {
draft.set('c', 3);
draft.delete('a');
});
// state: Map { 'a' => 1, 'b' => 2 }
// next: Map { 'b' => 2, 'c' => 3 }
Related on TokRepo
- AI Tools for Coding -- Developer tools and libraries for AI-assisted development
- Featured Workflows -- Discover more curated development resources
Common pitfalls
- Do not return a value from the produce callback if you also mutate the draft. Either mutate the draft or return a new value, never both. Immer throws an error if you do both.
- Map and Set support requires calling
enableMapSet()before using produce with Maps or Sets. Without it, Immer ignores Map/Set mutations. - Immer uses Proxies, which have a small performance overhead. For hot paths processing thousands of updates per second, benchmark against manual immutable updates.
Frequently Asked Questions
No. Immer is the immutability library that Redux Toolkit uses internally. You can use Immer standalone in any JavaScript project, with React useState, with MobX, or anywhere you need immutable state updates.
Yes. Immer has full TypeScript support with correct type inference. The produce function preserves the type of your state object, and draft types are automatically mutable versions of your immutable types.
When Immer creates the next state, it only copies the objects that changed. Unchanged parts of the tree are shared by reference with the previous state. This is memory-efficient and enables fast equality checks via reference comparison.
Yes. That is where Immer provides the most value. Instead of spreading five levels deep to update a nested property, you mutate the draft directly: `draft.level1.level2.level3.value = 'new'`.
Immer adds a small overhead due to Proxy creation. For typical UI state updates, the overhead is negligible. For bulk operations processing thousands of objects, consider using `produce` once for the entire batch rather than calling it per item.
Citations (3)
- Immer GitHub Repository— Immer creates immutable state via Proxy-based draft objects
- Redux Toolkit Documentation— Immer is built into Redux Toolkit as the default immutability layer
- Immer Documentation— Structural sharing minimizes memory usage for state updates
Related on TokRepo
Discussion
Related Assets
Conda — Cross-Platform Package and Environment Manager
Install, update, and manage packages and isolated environments for Python, R, C/C++, and hundreds of other languages from a single tool.
Sphinx — Python Documentation Generator
Generate professional documentation from reStructuredText and Markdown with cross-references, API autodoc, and multiple output formats.
Neutralinojs — Lightweight Cross-Platform Desktop Apps
Build desktop applications with HTML, CSS, and JavaScript using a tiny native runtime instead of bundling Chromium.