{"id":11373,"library":"mutative","title":"Mutative","description":"Mutative is a JavaScript library designed for performing efficient immutable updates on data structures, drawing inspiration from libraries like Immer but with a strong focus on performance. It allows developers to write 'mutative' logic inside a producer function, and Mutative handles the underlying copy-on-write mechanism to return a new, immutably updated state. The library is currently at version 1.3.0 and exhibits an active release cadence, with frequent patch and minor updates. Key differentiators include its reported performance benefits, claiming to be 2-6x faster than naive handcrafted reducers using spread operators and over 10x faster than Immer, primarily through shallow copy optimization, lazy drafts, and an optimized finalization process. It aims to address issues like Immer's mandatory auto-freeze and improve type inference and handling of various immutability edge cases.","status":"active","version":"1.3.0","language":"javascript","source_language":"en","source_url":"https://github.com/unadlib/mutative","tags":["javascript","immutable","mutable","copy-on-write","mutative","immutability","mutation","typescript"],"install":[{"cmd":"npm install mutative","lang":"bash","label":"npm"},{"cmd":"yarn add mutative","lang":"bash","label":"yarn"},{"cmd":"pnpm add mutative","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The primary function for creating immutable updates. Always use named import.","wrong":"const create = require('mutative')","symbol":"create","correct":"import { create } from 'mutative'"},{"note":"Used for applying a list of patches to a base state, often generated by `enablePatches`.","wrong":"const apply = require('mutative')","symbol":"apply","correct":"import { apply } from 'mutative'"},{"note":"A utility function to retrieve the original (non-draft) object from within a draft context. It's a named export.","wrong":"import original from 'mutative'","symbol":"original","correct":"import { original } from 'mutative'"},{"note":"Used for type hinting when working with patches; should be imported as a type.","wrong":"import { IPatch } from 'mutative'","symbol":"IPatch","correct":"import type { IPatch } from 'mutative'"}],"quickstart":{"code":"import { create, original } from 'mutative';\n\ninterface TodoItem {\n  id: number;\n  text: string;\n  completed: boolean;\n}\n\ninterface AppState {\n  todos: TodoItem[];\n  filter: 'all' | 'active' | 'completed';\n  user: { name: string; id: string };\n}\n\nconst initialState: AppState = {\n  todos: [\n    { id: 1, text: 'Learn Mutative', completed: false },\n    { id: 2, text: 'Build Something', completed: true },\n  ],\n  filter: 'all',\n  user: { name: 'John Doe', id: 'user-123' },\n};\n\n// Update an item and add a new one\nconst newState = create(initialState, (draft) => {\n  const todoToUpdate = draft.todos.find(todo => todo.id === 1);\n  if (todoToUpdate) {\n    todoToUpdate.completed = true;\n    todoToUpdate.text = 'Learn Mutative (done!)';\n  }\n  draft.todos.push({ id: 3, text: 'Deploy App', completed: false });\n  draft.user.name = 'Jane Doe';\n});\n\nconsole.log('Initial State:', original(initialState));\nconsole.log('New State:', newState);\nconsole.log('Are states different?', initialState !== newState); // true\nconsole.log('Is todos array different?', initialState.todos !== newState.todos); // true\nconsole.log('Are other parts (e.g., filter) unchanged by reference?', initialState.filter === newState.filter); // true\nconsole.log('Original todo 1 text (from initial state):', initialState.todos[0]?.text); // Learn Mutative\nconsole.log('New todo 1 text (from new state):', newState.todos[0]?.text); // Learn Mutative (done!)\n","lang":"typescript","description":"Demonstrates how to use `create` to immutably update nested objects and arrays, showcasing efficient partial updates and reference preservation for unchanged parts."},"warnings":[{"fix":"Always benchmark Mutative against your specific use cases and existing update patterns to confirm actual performance benefits in your application.","message":"Mutative's significant performance claims (e.g., '10x faster than Immer', '6x faster than naive handcrafted reducer') are highly dependent on the specific benchmark scenarios and comparison implementations. Real-world performance may vary, and for simple updates, the difference might be negligible or even in favor of highly optimized manual spread operations.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Encapsulate all state mutation logic within the `create` callback. Treat the object returned by `create` as strictly immutable.","message":"When working with `mutative`, ensure all modifications occur strictly within the producer function provided to `create`. Attempting to modify the draft object or any part of the returned immutable state outside this function will lead to errors or unexpected behavior due to proxy revocation or frozen objects.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Upgrade to the latest stable version of Mutative (v1.1.0 or newer) to ensure reliable and correct functionality of the `current()` API.","message":"The `current()` API underwent multiple refactorings and a temporary revert in early 1.x versions (specifically around v1.0.7-v1.0.8). While now stable in later 1.x releases, developers on older patch versions might encounter inconsistencies or incorrect behavior when using `current()` to access the latest draft state.","severity":"deprecated","affected_versions":"<=1.0.8"},{"fix":"Thoroughly test Mutative with any custom classes or non-standard JavaScript objects in your state. For complex scenarios, inspect the `original()` reference or the final state to ensure expected immutability and data integrity.","message":"Mutative uses JavaScript Proxies for its copy-on-write mechanism. While powerful, Proxies can sometimes have subtle interactions or edge cases with certain non-plain JavaScript objects (e.g., custom classes, complex data structures with internal state not exposed via standard properties) or when strict equality checks are used in specific contexts.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure all modifications to the draft state are confined within the producer function passed to `create`. Do not store or attempt to modify the `draft` object reference after `create` returns.","cause":"Attempting to modify a Mutative draft object or its properties after the producer function has completed and the proxy has been revoked (finalized).","error":"TypeError: Cannot perform 'set' on a proxy that has been revoked"},{"fix":"Always use the `create` function with a producer callback to make changes. The return value of `create` is the new, immutable state.","cause":"Trying to directly mutate the object returned by `create`. This object is frozen and immutable, meaning its properties cannot be changed directly.","error":"TypeError: Cannot assign to read only property 'propertyName' of object '[object Object]'"},{"fix":"For ES Modules, use `import { create } from 'mutative'`. For CommonJS in environments where it's supported, use `const { create } = require('mutative')`.","cause":"Incorrect import statement for the `create` function, particularly common with CommonJS `require` when `mutative` is primarily an ESM package, or if using a default import instead of a named import.","error":"TypeError: create is not a function"}],"ecosystem":"npm"}