ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 17

  1. Blog

Immer vs Mutative: 86 us vs 3 us per Update

Aditya Challa·5 October 2026·4 min read

Hands-on
On this page
  1. What I tested
  2. How wide was the produce gap?
  3. Does the bundle size change the call?
  4. Which one should you pick?
  5. Sources
  6. Related

I bumped one user score in a 1,000-user tree on this box: Immer 11.1.21 median about 86 us per produce, Mutative 1.3.0 about 3 us. Both kept structural sharing on untouched branches. Gzip favored Immer slightly (5.3 KB vs 6.5 KB).

Short answer: pick Mutative when produce cost shows up in profiles. Pick Immer when you want the smaller gzip and the wider ecosystem. No affiliate links in this post.

What I tested

  • Machine: 8 vCPU Intel Xeon / 15 GB RAM shared Linux cloud box, tested 6 Oct 2026 about 00:56–00:57 IST.
  • Versions: immer 11.1.21, mutative 1.3.0, Node 22.20.0, esbuild 0.28.2 minify + gzip -9.
  • Fixture: /workspace/bench-immer-mutative/. State shape: meta object + 1,000 users (id, name, score, tags[], nested profile). Paths: bump one score (5,000 produces × 9 rounds, median); deep path that edits profile.city, pushes a tag, and bumps meta.version. Structural-share check: untouched user refs stay identical after a sibling edit.
  • Findings: bump-one median 431.081 ms vs 14.789 ms for 5,000 updates (86.2 us vs 3.0 us each; about 11.6k vs 338k ops/s). Deep path 505.435 ms vs 43.347 ms (101 us vs 8.7 us). Gzip 5,313 B vs 6,512 B. Structural share true for both.
  • One surprise: Mutative was about 29× faster on the single-field bump, yet the Immer build was about 1.2 KB smaller gzip. Speed and size do not point the same way.
  • Not tested: enableMapSet / Map patches, Redux Toolkit integration, patches/inversePatches, freeze options, React bindings, real browsers, large array replace patterns.

How wide was the produce gap?

Path (5,000 updates, median of 9)ImmerMutative
Bump one score (us per update)86.23.0
Bump one score (ops/s)11,599338,079
Deep edit (us per update)101.18.7
Deep edit (ops/s)9,892115,347

Mutative won the wall-clock race on both paths. Structural sharing matched: after editing users[0], users[1] kept the same object reference in both libraries. Compiler-side cost notes sit next to SWC vs esbuild/Babel when the transform pipeline is the bottleneck instead.

Does the bundle size change the call?

Browser build (esbuild minify)Minifiedgzip -9
immer (produce, enableMapSet)13,964 B5,313 B
mutative (create, rawReturn)19,615 B6,512 B

Immer was smaller on this import set. Disk trees were about 1.1 MB for immer against 908 KB for mutative. Track shipped weight with size-limit vs bundlesize. Schema/validation choices next to reducers: Zod vs Valibot.

Which one should you pick?

SituationMy pick
Hot produce loop in a profileMutative
Smallest gzip for produce+Map helpersImmer
Already on Redux Toolkit / Immer docsImmer
New greenfield immutable updatesMutative
Bundle budget under about 6 KB gzipImmer

Bottom line: Mutative 1.3.0 took about 3 us per bump against Immer 11.1.21 at about 86 us on a 1,000-user tree, while Immer shipped 5.3 KB gzip against Mutative at 6.5 KB. Who should not switch: apps whose Immer produces are rare and already under budget — the API is familiar and the gzip win is real. Lint after a swap with Biome vs ESLint/Prettier. Dead-code check: knip vs depcheck. Test runner: Jest vs Vitest.

How this was made: I installed Immer and Mutative on the ShopperCove box, timed produce/create loops on a 1,000-user fixture, measured esbuild minify+gzip sizes, verified structural sharing, and recorded the JSON. The write-up was drafted with AI help and checked against that output.

Sources

  • https://immerjs.github.io/immer/
  • https://www.npmjs.com/package/immer
  • https://mutative.js.org/
  • https://www.npmjs.com/package/mutative

Related

  • https://www.shoppercove.com/blog/size-limit-vs-bundlesize
  • https://www.shoppercove.com/blog/zod-vs-valibot
  • https://www.shoppercove.com/blog/swc-vs-esbuild-babel
  • https://www.shoppercove.com/blog/knip-vs-depcheck
  • https://www.shoppercove.com/blog/biome-vs-eslint-prettier
  • https://www.shoppercove.com/blog/jest-vs-vitest
  • https://www.shoppercove.com/blog/oxlint-vs-eslint
  • https://www.shoppercove.com/blog/dprint-vs-prettier
immermutativeimmutablestatejavascriptperformancebenchmarkbundle size

Lab evidence

What I found running this

Hands-on on ShopperCove box 6 Oct 2026 ~00:56-00:57 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 22.20.0). immer 11.1.21 vs mutative 1.3.0, esbuild 0.28.2. Fixture /workspace/bench-immer-mutative/: meta + 1,000 users (score, tags[], nested profile). Bump-one: 5,000 produce/create x 9 rounds after warm. Deep: edit profile.city, push tag, bump meta.version. Structural-share check on untouched user refs. Medians: bump 86.2 vs 3.0 us/update; deep 101.1 vs 8.7 us; gzip 5,313 vs 6,512 B. Disk ~1.1 MB vs ~908 KB. Raw: res-bench.json, res-bundle.json. Not tested: Map/Set patches, RTK wiring, patches/inversePatches, freeze options, React bindings, real browsers. No affiliate.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Related links

  • Plate 38

    TanStack Query vs SWR: 10.4 KB vs 5.6 KB Gzip

    5 Oct 2026

  • Plate 48

    Zod vs Valibot: 1.14M vs 0.97M Parses

    zod 4.6.5 vs valibot 1.5.0 on one nested user schema (uuid/email/age/tags/profile/enum). Warm medians after 2k warmup + 9×50k: zod.parse 1,144,494 ops/s vs valibot.parse 968,187 (~1.18×). safeParse fail: valibot 697,760 vs zod 415,523 (~1.7×). esbuild minify+gzip9: 452,999/92,636 B vs 85,126/15,422 B. Package trees ~6.1 MB vs ~1.9 MB. Fixture /workspace/bench-zod-valibot/.

    5 Oct 2026

  • Plate 66

    Jotai vs Zustand: 0.15 ms vs 0.17 ms per Update

    5 Oct 2026

On this page

  1. What I tested
  2. How wide was the produce gap?
  3. Does the bundle size change the call?
  4. Which one should you pick?
  5. Sources
  6. Related
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove