# 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. ## Install Save the content below to `.claude/skills/` or append to your `CLAUDE.md`: ## Quick Use ```bash npm i immer ``` ```ts 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. - **Repo**: https://github.com/immerjs/immer - **Stars**: 28K+ - **License**: MIT ## 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 --- Source: https://tokrepo.com/en/workflows/immer-immutable-state-mutable-syntax-3ae90d2f Author: AI Open Source