Create your next immutable state by mutating the current one
Immer is a JavaScript library that revolutionizes immutable state management by letting you write code that looks like standard mutations while maintaining immutability under the hood. Instead of manually spreading objects at every nesting level or using specialized immutable data structures, you work with a proxy draft of your state using normal JavaScript syntax—Immer handles the immutable updates automatically.
The library implements a copy-on-write mechanism through its core produce function. You provide your current state and a recipe function that receives a draft proxy. Any changes you make to this draft are tracked, and Immer produces a new immutable state based on those mutations. Unchanged portions of your data tree are structurally shared between versions, making the operation memory-efficient despite creating new objects.
With over 26 million weekly downloads, Immer has become a staple in the React and Redux ecosystems. It won the "Breakthrough of the year" React open source award and "Most impactful contribution" JavaScript open source award in 2019. The library weighs only 3KB gzipped and works with plain JavaScript objects, arrays, Maps, and Sets without requiring you to learn special APIs or convert your data structures.
Immer automatically freezes the produced state to prevent accidental mutations and includes built-in mutation detection that throws errors when you try to modify state outside the draft context. It also supports advanced features like JSON Patch generation for implementing undo/redo functionality, change tracking, and state synchronization across distributed systems.
import { produce, enableMapSet } from 'immer';
enableMapSet();
const baseState = {
users: [
{ id: 1, name: 'Alice', preferences: { theme: 'dark' } },
{ id: 2, name: 'Bob', preferences: { theme: 'light' } }
],
activeUserId: 1,
settings: new Map([['notifications', true]])
};
const nextState = produce(baseState, draft => {
const activeUser = draft.users.find(u => u.id === draft.activeUserId);
activeUser.preferences.theme = 'light';
activeUser.lastUpdated = new Date().toISOString();
draft.users.push({
id: 3,
name: 'Charlie',
preferences: { theme: 'dark' }
});
draft.settings.set('notifications', false);
draft.activeUserId = 3;
});
console.log(baseState.users.length); // 2
console.log(nextState.users.length); // 3
console.log(baseState.users[0].preferences.theme); // 'dark'
console.log(nextState.users[0].preferences.theme); // 'light'
console.log(baseState.users[0] === nextState.users[1]); // false (modified user)
console.log(baseState.users[1] === nextState.users[1]); // true (unchanged user, structural sharing)Redux Reducers: Replace verbose spread operations in Redux reducers with straightforward mutations. Instead of return { ...state, user: { ...state.user, name: action.payload } }, write draft.user.name = action.payload inside a produce function, dramatically improving readability in complex state trees.
React useState with Complex Objects: When managing nested state in React components, Immer simplifies updates. Rather than carefully spreading at each level to trigger re-renders, wrap your setState calls with produce to mutate a draft directly while maintaining immutability guarantees React requires.
Undo/Redo Systems: Enable JSON Patch generation to record every state change as a series of patches and inverse patches. Store these patches to implement full undo/redo functionality without keeping copies of entire state trees in memory, making history management efficient.
Real-time Collaboration Tools: Generate patches from local state changes and transmit them over the network to synchronize state across multiple clients. Other clients can apply these patches to their local state, enabling collaborative editing features similar to Google Docs.
Form State Management: Handle complex form state with nested fields, conditional sections, and dynamic arrays. Immer lets you modify deeply nested form values without the cognitive overhead of maintaining immutability manually, reducing bugs in form validation and submission logic.
npm install immerpnpm add immerbun add immer