Immutability is not a new concept in programming. It serves as the basis for programming paradigms, such as pure functional programming. The whole idea is to avoid direct change to data after it has been created.
Below is a breakdown of what we’re going to discuss in this article:
- Immutability in JavaScript
- An introduction to Immer and Immutable.js libraries
- A comparison between Immer and Immutable.js
Immutability in JavaScript
JavaScript primitives like strings and numbers are known to be immutable. This is true because strings, for instance, can’t be changed by any method or operation. You can only create new strings.
Let’s consider the variable below:
var name = "mark cuban" name = "John Steve"
You could argue that the data is mutable because the name variable was reassigned to another string, but this is not the case.
Reassignment is different from immutability. This is because even though the variable was reassigned, it didn’t change the fact that the string “Eze Sunday” exists. It’s the same reason why adding 3 to 13 wouldn’t change the original variable 13, or you turning 18 doesn’t change the fact that you were 17 before.
Even though variables may be reassigned, the immutable data still remains the same.
We’ve established from the example above that primitives are immutable, but that isn’t the end of the story. There are data structures in JavaScript that are mutable. One of them is arrays.
To demonstrate this, let’s declare a variable and set its value to be an empty array as shown below:
let arrOne = []
We can easily update the content of the above array by using the .push()
function:
arrOne.push(2)
This will add the data, 2, to the end of the array, altering the original array that we previously had.
Intro to the Immer and Immutable.js libraries
JavaScript wasn’t written for its data to be exclusively immutable, but there are instances where you need an immutable array or map to easily keep track or keep a record of changes in a data set.
This is evident in the React framework, especially when dealing with states and props. This is where immutability libraries kick in. These libraries help optimize our application, making it easier to track changes in our application. In this article, will be looking at two major immutability libraries. Namely, Immer and Immutable.js.
Immer
Immer is one of the many immutability libraries out there that you can use in your application. According to its official website, Immer is based on the copy-on-write mechanism. The whole idea revolves around applying changes to a temporary draftState
, which serves as a proxy to the current state. Immer will let you easily interact with your data while keeping all the benefits that come with immutability.
Installation
To use Immer instantly in your application use the following command:
<script src="https://cdn.jsdelivr.net/npm/immer"></script> // It can also be installed in your application using NPM; npm install immer Or with yarn; yarn add immer
Usage
With Immer, most immutability works are done with the help of a default function:
produce(currentState, producer: (draftState) => void): nextState
This function takes in the currentState
and draftState
and updates the nextState
to reflect changes made to the draftState
.
Example
Consider the code below:
import produce from "immer" const baseState = [ { todo: "Learn typescript", done: true }, { todo: "Try immer", done: false } ]
New data can be added to the state using the Immer default function, as follows:
const nextState = produce(baseState, draftState => { draftState.push({todo: "Tweet about it"}) draftState[1].done = true })
The baseState
in this case stays untouched, while the nextState
would be updated to reflect changes made to draftState
. You can learn more about Immer from its official website here.
Immutable.js
Immutable.js is another option to consider when looking for an immutability library. Immutable.js serves the same purpose as Immer, but it takes a different approach. It provides you with an API for data structures like maps and lists.
Installation
Immutable.js can be installed using npm:
npm install immutable
Example
We can perform mapping operations with Immutable.js by requiring map
from the installed package and making use of it, like this:
const { Map } = require('immutable'); const map1 = Map({ a: 1, b: 2, c: 3 }); const map2 = map1.set('b', 50); map1.get('b') + " vs. " + map2.get('b'); // 2 vs. 50
From the example above, our object { a: 1, b: 2, c: 3 }
is wrapped with the Map()
function. we went on to perform get
and set
operations on it while keeping the data Immutable.
In addition to objects, we can create immutable arrays using the List
function as shown below:
List(['apple','orange','grape'])
The above is an array implementation in Immutable.js using the List
function.
fromJS function
helps bypass the need for wrapping our objects and arrays with Map({})
and List([])
functions by converting them directly into immutable data.
fromJS(['apple','orange','grape'])
The above converts the array directly into immutable data.
Immer v. Immutable.js: Which should you choose?
Now here is the big question: which should you choose between these two libraries? To start, let’s list out the benefits and downsides to these libraries individually. We’ll start with Immer.
Benefits that comes with Immer
There are lots of benefits that come with using Immer as opposed to making use of other libraries like Immutable.js. Some of these include:
- Boilerplate reduction: With Immer, you write more precise code with no extra boilerplate, leading to an overall reduction in codebase
- Immutability works with normal JavaScript data types and structures: Immer allows for the use of normal JavaScript, objects, maps and arrays without any need to learn a new API
- Immer is strongly typed with no string-based paths selectors
- Support for patches
Downsides to Immer as a library
There are a couple things that make using Immer difficult. For one thing, you need an environment that supports proxy objects to use Immer. Also, Immer does not provide support for complex object types like class instance.
Benefits that comes with Immutable.js
Just like Immer, Immutable.js has its benefits. Some of them includes:
- In addition to other conventional javaScript data structures, Immer provides you with data structures that are not native to JavaScript. Some of them include ordered maps and record
- Immutable,js lets you know the precise data that have been changed in your reducer, making development easier
- Immutable.js writes data at record speed when compared to other immutable libraries
Downsides to Immutable.js
Though Immutable.js is fast at writing data, it is much slower when performing read operations.
More great articles from LogRocket:
- Don't miss a moment with The Replay, a curated newsletter from LogRocket
- Learn how LogRocket's Galileo cuts through the noise to proactively resolve issues in your app
- Use React's useEffect to optimize your application's performance
- Switch between multiple versions of Node
- Discover how to animate your React app with AnimXYZ
- Explore Tauri, a new framework for building binaries
- Advisory boards aren’t just for executives. Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Also, Immutable.js forces you to learn new and sometimes complex syntax and APIs just to perform basic operations. For instance, adding an extra data to an array will require the use of a .set()
method, which isn’t traditional for JavaScript.
Immutable.js also forces you to use a unique construction type everywhere in your application. This means that for every immutable collection that you construct, you must make use of the appropriate Immutable.js collection rather than the traditional ones. This can cause a lot of stress, especially when migrating your code to another codebase that doesn’t use these collections.
Immer, on the other hand, offers roughly the same thing with much more flexibility. This is why many developers stick with it. It lets you create collections with classical objects that you’re already used to.
Conclusion
If you need faster writing speed in your application, you can go for Immutable.js. On the other hand, if you want to write less code while sticking with traditional JavaScript data structures and object types, then Immer is for you.
Overall, both Immer and Immutable.js are great libraries that you should try using in your application.
LogRocket: Debug JavaScript errors more easily by understanding the context
Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.
LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exactly what the user did that led to an error.

LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
Try it for free.
It is not correct to say that assignment does not imply mutation. Mutation simply means changing something. Assignment involves a mutation of the environment in which code executes; either a new name is installed which maps to the value corresponding to the right hand side of the assignment expression, or else the value installed under that name is updated to the new value.
Before you say this is pedantic and unimportant, consider that the example given for assignment used the var keyword, which can easily result in updates to the global environment. The effect could be that a function in some other module which could have previously been idempotent in effect loses this property, ie. that now running it before the assignment occurs has a different effect than running it after.
This is analogous to modifying prototypes owned by other modules, such as that of Array or Object; as it may cause undesirable behaviour it should not be done.
The scope of a mutation’s effects may be limited sufficiently by use of strict mode, and for example, the use of const and let instead of var.