# What changed in mutative

> 29 changes in mutative 2 from its official release notes, upgrade guides and advisories: 11 breaking, 1 deprecations. Each one cited. Sources checked 2026-10-18. HTML: https://unstale.sh/npm/mutative/

To see which of these apply to a repository, run `npx @unstale/cli init` in it.

## mutative 2

### Breaking changes

- apply() rejects paths ending in __proto__, reads Set items only at their indices, and copies symbol and own __proto__ keys of patch values. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- An explicit state type with an async recipe, including the curried form, now returns Promise<State>. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- This ESM file reads process.env.NODE_ENV when loaded and throws process is not defined in runtimes without process; use the production ESM file or UMD build there. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- This ESM file reads process.env.NODE_ENV when loaded and throws process is not defined in runtimes without process; use the production ESM file or UMD build there. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Builds now target ES2018 instead of ES2015; engines that support Proxy but not ES2018 syntax need Mutative transpiled by the build. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Passing a draft to the set() method of a Map draft now throws because the next state would keep the revoked draft as a key. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Assigning to a key held as an own data property now sets that property as in JavaScript, even if a prototype defines a setter of the same name. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Nested draft patches now precede parent patches; moved drafts emit no patches under their old paths, and patch values that were drafts are the objects held by the next state. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- With enableAutoFreeze, production builds no longer search frozen returned objects for drafts, while development builds throw if they find one. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Assigning undefined to a key removed by delete, shift, unshift, or a shrinking splice now adds the key back. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- A nested unsafe() call no longer ends the access of the outer call. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)

### Deprecations

- create() warns once when given a draft with a recipe because it drafts a copy of the draft's current state. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)

### Behavior and default changes

- apply() types frozen and in-place results: enableAutoFreeze: true returns Immutable<State>, while mutable typed as boolean returns State | void. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- shift, unshift, splice, and reverse move elements natively on a plain array's draft copy; indexOf, lastIndexOf, and includes search it natively. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- With an explicit state type, a recipe that may return a Promise now gives State | Promise<State>. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- current() of a changed array copies the current array, enabling searches without creating a draft for each element. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Map and Set instances are frozen too, and later producers skip them. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- In development, when pathAsArray is false, patches whose paths would contain a non-string Map key or symbol key throw. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- In Node.js, import resolves a module re-exporting the CommonJS build, so import and require share one instance and both follow NODE_ENV. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Map drafts freeze and iterate like built-in Maps; patches preserve array keys as one path segment, and Map keys are used as they are by apply(). (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- The ESM entry checks process.env.NODE_ENV at each development check; Node-targeted bundles that do not define it may include both CommonJS builds. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Production bundles omit development checks and warnings; production errors use short codes and link to the errors page. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Production builds throw Minified Mutative error codes with a link instead of full messages; code matching production error messages must match codes instead. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Set changes and patches now preserve changed items, moved Set drafts, and unchanged-draft assignment behavior; Set drafts freeze and iterate like built-in Sets. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Strict mode warns once when a recipe leaves 1,000 or more drafts unchanged. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)

### Fixes and other changes

- Patches now reproduce array states when indices shrink and grow again, distinguish 0 from -0, and omit patches for elements that remain NaN. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- current() now snapshots drafts whose state holds a plain Set with drafts, and assigned draftable objects together with the drafts they hold. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- A curried recipe that annotates its draft and returns a new state now returns State instead of being typed as a manual draft. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
- Node.js 14.0 or later remains required. (2.0.0) — [release notes](https://github.com/unadlib/mutative/releases/tag/v2.0.0)
