npm / mutative
mutative
What changed in mutative 2, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-18.
11 breaking1 deprecations13 behavior and defaults4 fixes and other
See which of these apply to your code, ranked, in your agent:
npx @unstale/cli initmutative 229 changes
Breaking changes 11
apply() rejects paths ending in __proto__, reads Set items only at their indices, and copies symbol and own __proto__ keys of patch values.
An explicit state type with an async recipe, including the curried form, now returns Promise<State>.
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.
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.
Builds now target ES2018 instead of ES2015; engines that support Proxy but not ES2018 syntax need Mutative transpiled by the build.
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.
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.
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.
With enableAutoFreeze, production builds no longer search frozen returned objects for drafts, while development builds throw if they find one.
Assigning undefined to a key removed by delete, shift, unshift, or a shrinking splice now adds the key back.
A nested unsafe() call no longer ends the access of the outer call.
Deprecations 1
create() warns once when given a draft with a recipe because it drafts a copy of the draft's current state.
Behavior and default changes 13
apply() types frozen and in-place results: enableAutoFreeze: true returns Immutable<State>, while mutable typed as boolean returns State | void.
shift, unshift, splice, and reverse move elements natively on a plain array's draft copy; indexOf, lastIndexOf, and includes search it natively.
With an explicit state type, a recipe that may return a Promise now gives State | Promise<State>.
current() of a changed array copies the current array, enabling searches without creating a draft for each element.
Map and Set instances are frozen too, and later producers skip them.
In development, when pathAsArray is false, patches whose paths would contain a non-string Map key or symbol key throw.
In Node.js, import resolves a module re-exporting the CommonJS build, so import and require share one instance and both follow NODE_ENV.
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().
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.
Production bundles omit development checks and warnings; production errors use short codes and link to the errors page.
Production builds throw Minified Mutative error codes with a link instead of full messages; code matching production error messages must match codes instead.
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.
Strict mode warns once when a recipe leaves 1,000 or more drafts unchanged.
Fixes and other changes 4
Patches now reproduce array states when indices shrink and grow again, distinguish 0 from -0, and omit patches for elements that remain NaN.
current() now snapshots drafts whose state holds a plain Set with drafts, and assigned draftable objects together with the drafts they hold.
A curried recipe that annotates its draft and returns a new state now returns State instead of being typed as a manual draft.
Node.js 14.0 or later remains required.