Immutable.js logo

Immutable.js

A library for creating and using persistent immutable data structures in JavaScript.

npm install immutable-js
33.1K411/weekv0.3.1-60BBSD-2-Clause114 issues
Last updated: 2015-08-06
Star history chart for immutable-js/immutable-js

TL;DR

Immutable.js provides a set of immutable, persistent data structures including List, Stack, Map, OrderedMap, Set, OrderedSet, and Record.

Created by Facebook, it is designed to overcome the issues with native JavaScript objects and arrays for implementing immutable state.

Why Immutable.js?

Immutable.js was created to solve the problems of immutability in JavaScript at scale. While JavaScript objects and arrays can be treated as immutable through convention (e.g., spreading), there is no guarantee. Immutable.js provides data structures that are guaranteed to be immutable, bringing predictability to complex applications.

  • Guaranteed Immutability: Any operation that "changes" a data structure actually returns a new, updated data structure. The original remains untouched, preventing accidental mutations.
  • Structural Sharing: It uses tries internally to share data structures, minimizing memory usage and improving performance. When you create a new version of a collection, much of the underlying data is shared with the previous version.
  • Rich API: Provides a comprehensive, chainable API for data manipulation (.set(), .getIn(), .map(), .filter(), etc.), offering powerful ways to interact with your data.
  • Lazy Evaluation: Operations can be deferred until the results are needed, which can save CPU cycles by avoiding the creation of intermediate collections.
  • Deep Updates: The API includes methods like setIn and updateIn that make it straightforward to update deeply nested data without complex manual spreading.

While modern alternatives exist, Immutable.js provides a robust and battle-tested solution for enforcing a strict immutable architecture.

Code Snippet

The core pattern involves creating an Immutable.Map and using its API to perform non-destructive updates.

import { Map } from 'immutable';

// Initial state is an Immutable Map
const state = Map({
  user: Map({
    name: 'Alice',
    isOnline: false,
  }),
  notifications: 0,
});

// The .set() and .setIn() methods return a NEW map
const nextState = state
  .set('notifications', 1)
  .setIn(['user', 'isOnline'], true);

// The original state object remains unchanged
console.log(state.getIn(['user', 'isOnline'])); // false
console.log(nextState.getIn(['user', 'isOnline'])); // true

In this example, state is never mutated. Each method call produces a new immutable Map. To read values, you must use the .get() or .getIn() methods, as direct property access will not work.

Pros and Cons

No library is perfect; understanding the trade-offs is key to selecting the right tool.

Pros

  • Strict Immutability: Provides a strong guarantee that your state cannot be mutated, eliminating a large class of bugs.
  • Performance for Large Collections: The use of hash map tries and structural sharing makes it highly efficient for large, complex datasets.
  • Rich and Powerful API: The extensive collection of methods for data manipulation can simplify complex transformations.
  • Battle-Tested: Has been used in production at Facebook and by many other large applications for years.

Cons

  • ** steep Learning Curve:** Requires developers to learn a completely new API for data manipulation instead of using standard JavaScript idioms.
  • Interoperability Overhead: Requires converting data to and from standard JavaScript objects (.toJS(), fromJS()), which can be slow and verbose.
  • Bundle Size: It adds a significant amount to the bundle size (~60KB), which may be too large for smaller applications.
  • Less Popular Today: The ecosystem has largely shifted towards libraries like Immer that offer a more pragmatic approach with a better developer experience.

Comparison with Other State Management Libraries

The table below outlines the positioning differences between Immutable.js and other popular libraries to help you make an informed decision:

LibraryDesign PhilosophyBest ForPain Points
Immutable.jsPersistent Data Structures
Provides a rich API of data structures that are guaranteed to be immutable.
Enforcing Data Integrity
Large applications where strict, provable immutability is a core requirement.
API friction & Boilerplate
Requires learning a new API and converting data to/from plain JS objects.
ImmerPragmatic Immutability
Simplifies immutable updates using mutable-style "drafts" and standard JS.
Improving DX
Ideal for simplifying reducers in Redux, Zustand, or useReducer.
Proxy "Magic"
Can hide complexity and has a slight performance overhead.
Plain JavaScriptManual Immutability
Using object spread (...) and array methods (.map, .filter) to manually create new objects.
Simple State
Small projects where the overhead of a library is not justified.
Verbose & Error-Prone
Easily leads to deeply nested spreads and accidental mutations.

Verdict: When to Adopt

Adopt Immutable.js in large-scale applications where data integrity and predictable state changes are paramount, and the team is willing to invest in learning its specific API. It is particularly well-suited for applications with very large and deeply nested state trees where its performance characteristics shine. However, for most new projects, more modern libraries like Immer offer a better balance of safety, developer experience, and performance with a much lower barrier to entry.