Mutative

Better immutability
Faster immutable updates

A JavaScript library for efficient immutable updates. Write plain mutations on a draft, and get the next immutable state.

Get StartedGitHub0,000
$npm install mutative

Time for the same updates

Shorter is better

  • Mutative
    1x
  • Immer
    3.6x
  • Immer, auto-freeze
    6.6x
Geometric means over 97 workloads, with the same settings for both libraries, and with each library's defaults, where only Immer freezes. Mutative was faster in 595 of 614 measured cases. See the benchmarks

Simple

Immutable updates without the spread

Mark the last item of a list as done and add a new one. With spread syntax, you copy each level of the state yourself; with Mutative, you change a draft.

Spread syntax

reducer.ts
const nextState = {
  ...state,
  list: [
    ...state.list.slice(0, 2),
    {
      ...state.list[2],
      done: true,
    },
    { text: 'Learn Mutative', done: true },
  ],
};

With Mutative

reducer.ts
import { create } from 'mutative';

const nextState = create(state, (draft) => {
  draft.list[2].done = true;
  draft.list.push({ text: 'Learn Mutative', done: true });
});

Fast

Faster than Immer, by design

Mutative copies each object at most once per update and moves array elements natively on its copy, instead of through a draft proxy.

3.6x

Faster than Immer with matched settings

Faster in 595 of 614 measured cases

6.6x

Faster than Immer with each library's defaults

Faster in 154 of 157 measured cases

97

Benchmarked workloads

Every result checked against hand-written reducers

Time per update, relative to Mutative

Shorter is better

  • Mutative
  • Immer
  • Immer, auto-freeze

200 RTK Query-style updates

100 pending and 100 resolved requests

1.1x faster

Mutative
1x
Immer
1.1x
Immer, auto-freeze
4.8x

Update one field of a small object

A tiny plain object

1.4x faster

Mutative
1x
Immer
1.4x
Immer, auto-freeze
1.9x

Add a number to a Set

A Set of 10,000 numbers

31x faster

Mutative
1x
Immer
31x
Immer, auto-freeze
33x

Remove the first row

An array of 10,000 rows, with shift()

1,052x faster

Mutative
1x
Immer
1,052x
Immer, auto-freeze
1,156x
Medians of three runs on an Apple M1 Max with Node.js 24.16.0 and Immer 11.1.18, each library in a process of its own, without patches. Each bar is a library's time per update relative to Mutative's in its workload, and the table lists the times in microseconds. Mutative and the first Immer bar run without auto-freeze; the second Immer bar shows Immer's default. Hand-written reducers that copy only what they change are faster still in most workloads.

The factors of the cards are geometric means of Immer's time over Mutative's across all 97 workloads. See the benchmarks

In production

From Immer to Mutative

Open-source projects that replaced Immer with Mutative, in their own words.

“Using mutative instead of immer, this has reduced the main thread scripting by about 1 second.”

Replaced Immer with Mutative in its client.

Appsmith

Admin panels, internal tools and dashboards

Pull request, February 2025
“Mutative is about 3ms on a single transaction.”

With Immer, a single transaction took about 8 ms, and about 40 ms as pending transactions were added.

InstantDB

A backend with auth, permissions, storage and presence

Pull request, September 2024
“…you'll notice slight improvements in app responsiveness.”

Replaced Immer with Mutative in version 3.0.11.

Notesnook

An end-to-end encrypted note-taking app

Release notes, July 2024
“All plugin stores now use zustand-mutative for immutable state updates, which is faster than immer.”

Moved its plugin stores to zustand-mutative in version 42.

Plate

A rich-text editor for React

Release, January 2025

Also used by Mol*, OpenRewrite and MSW Data. See who uses Mutative

Ecosystem

Works with your stack

Libraries built on Mutative for React, Zustand, Jotai, XState, Yjs and more.

See the ecosystem

Ready to try Mutative?

Learn the most important Mutative concepts in 5 minutes.