Cloud Parts

Immutable.js

Persistent collections for JavaScript (List, Map, Set, Record and more) built on hash array mapped tries and vector tries, with methods named like JavaScript’s own Array, Map and Set.

What it is
Purely functional data structures (hash array mapped tries)
Type
Open source
Made by
Immutable.js maintainers (started at Facebook by Lee Byron)
License
MIT (BSD before 4.0)
Facts checked
9 October 2026

What it is

Immutable.js gives JavaScript the persistent collections of Clojure and Scala: List, Stack, Map, OrderedMap, Set, OrderedSet and Record. Methods that would mutate an array or map, such as push, set or splice, instead return a new collection, and the old one keeps working. Both share structure through hash map tries and vector tries, so an update copies a few small nodes instead of the whole collection. A lazy Seq chains map and filter without building intermediate collections.

Under the hood a Map starts as a flat array of up to eight entries and then becomes a 32-way hash array mapped trie: bitmap nodes that find a child by counting set bits, full 32-slot nodes when they fill up, and collision nodes for keys with equal hashes. Collections are values: a.equals(b) compares contents, while === only tests identity. An update that changes nothing returns the very same object, so === is a cheap “definitely unchanged” test for memoization and UI change detection. withMutations applies a batch of set or push calls to a temporary mutable copy and returns an immutable result, so building a large collection doesn’t allocate a new version per step.

Lee Byron started the library at Facebook in 2014, inspired by Phil Bagwell’s research. After 3.8.2 in October 2017 it went four years without a major release; 4.0.0 arrived in October 2021 with new maintainers, an MIT licence and better TypeScript types. It is actively maintained: 5.0.0 came out in November 2024, 5.1.9 in June 2026, and a 6.0.0 beta in August 2026.

Why teams pick it

  • Copies are free and unchanged updates return the same object, so === checks make memoization and change detection cheap
  • An API that mirrors ES2015 Array, Map and Set, with TypeScript definitions included
  • withMutations batches many updates through one temporary mutable copy, the same way the library implements its own bulk operations
  • Lazy Seq chains of map and filter avoid intermediate collections

Watch out for

  • Collections are not plain objects: code reads them with get and getIn, compares them with .equals(), and converts at the boundaries with fromJS and toJS
  • Every non-batched update allocates new nodes; the README itself warns of “a minor performance penalty” for creating new objects
  • A long pause between 3.8 (2016–2017) and 4.0 (2021), and 5.0 changed the TypeScript typing of Map, a breaking change for TypeScript users

Update a nested value, share the rest, and batch a build · js

import { Map, List } from "immutable";

const v1 = Map({ user: Map({ name: "Ada", plan: "free" }), cart: List(["tea"]) });
const v2 = v1.setIn(["user", "plan"], "pro");

console.log(v1.getIn(["user", "plan"]), v2.getIn(["user", "plan"])); // free pro
console.log(v1.get("cart") === v2.get("cart")); // true: untouched branch is shared
console.log(v1.get("user") === v2.get("user")); // false: changed branch was copied

// a no-op update returns the same object, so === is a cheap "unchanged" test
console.log(v2.set("cart", v2.get("cart")) === v2); // true
console.log(v1.equals(Map({ user: Map({ name: "Ada", plan: "free" }), cart: List(["tea"]) }))); // true

// batch many updates through one temporary mutable copy
const big = List().withMutations((l) => { for (let i = 0; i < 100000; i++) l.push(i); });
console.log(big.size, big.get(99999)); // 100000 99999

See it in a real stack

No architecture uses Immutable.js yet. Drop it into the playground and wire it up yourself.Open playground →
Where it came from2014–2026

By 2014 Clojure and Scala had shown that persistent hash maps and vectors could be fast enough for everyday code, but JavaScript had nothing comparable. Lee Byron made the first commit to Immutable.js on 29 May 2014, under a Facebook copyright, and the README still thanks Phil Bagwell “for his inspiration and research in persistent data structures”. The npm name immutable came from Hugh Jackson, whose earlier package of that name is now unsupported; Facebook’s 2.0.0 was published in July 2014 and 3.0.0 in October.

The README pitched it for React and Flux apps. If application state is immutable, a component only needs to compare references to know whether its data changed, and an undo stack is just a list of old versions. Development slowed after 3.8: 3.8.2 shipped in October 2017 and 4.0.0 only in October 2021, when new maintainers joined and the project was relicensed from BSD to MIT. Version 5.0.0 followed in November 2024.

Why it’s built this way

Hash tries and vector tries, as in Clojure and Scala
Structural sharing lets an update copy only a few nodes, so persistent collections can be used everywhere instead of copying or caching data defensively.
A JavaScript-first API
Rather than a Lisp-style API, method names mirror ES2015 Array, Map and Set, and methods that would mutate return a new collection instead.
Value equality, with a reference shortcut
Collections are values compared with equals, but no-op updates return the existing object so === can still prove nothing changed, which suits memoization.
Transient batches with withMutations
Building a collection one immutable step at a time creates garbage; a temporary mutable copy is safe as long as nobody else can see it, an argument the README quotes from Rich Hickey.

Timeline

  1. 2014

    Lee Byron’s first commit (May); 2.0.0 on npm in July and 3.0.0 in October

  2. 2017

    3.8.2, the last 3.x release for over eight years

  3. 2021

    4.0.0: new maintainers, MIT licence, better TypeScript types

  4. 2024

    5.0.0 tightens the TypeScript typing of Map

  5. 2026

    5.1.9 in June and a 6.0.0 beta in August

Sources7 · facts checked 9 October 2026

Improve this page on GitHub