What's New in Node.js 22
Tags: node
Published: 2024-05-21 14:08:01

[Node.js 22](https://nodejs.org/en/blog/release/v22.0.0) has been released, offering a compelling upgrade for developers. It takes over the 'Current' release line, while v21 transitions into maintenance mode until its end-of-life in June.

This release delivers advances like a stabilized Watch mode, pattern matching support in the `fs` module, a default-enabled WebSocket client, and a new `--run` flag for script execution. It also offers some performance improvements and the usual V8 engine upgrade.

Let's dive in and explore all that Node.js v22 brings to the table!

## Watch Mode is Stable

![Watch Mode is stable](https://blog.appsignal.com/images/blog/2024-05/watch-mode.png)

[Node.js 18.11.0](https://nodejs.org/en/blog/release/v18.11.0) introduced an incredibly useful `--watch` flag that allowed the
Node.js process to automatically restart any time an imported file was changed.

To use this functionality, you execute a command like this:

```shell
node --watch server.js
```

The command would watch your `server.js` file and restart the process when it detected changes were made to the file or any of its imported modules.

You could also use the companion `--watch-path` flag (supported on macOS and Windows only) to specify the exact paths that should be monitored for changes, like this:

```shell
node --watch-path=./src --watch-path=./tests server.js
```

However, because watch mode was marked as experimental, the below warning resulted whenever it was used:

```text
(node:1710176) ExperimentalWarning: Watch mode is an experimental feature and might change at any time
```

With the release of Node.js 22, this feature has been stabilized, so this warning no longer appears. While you could previously use a third-party tool like [nodemon](https://www.npmjs.com/package/nodemon), this update removes the need for a dependency by adding it directly to Node.js core.

## WebSocket Global Enabled by Default

In the [previous Node 21 release](https://blog.appsignal.com/2023/10/25/whats-new-in-nodejs-21.html), a built-in browser-compatible [WebSocket client](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), as standardized by WHATWG, was added under the `--experimental-websocket` flag.

```javascript
// index.js
const socket = new WebSocket("ws://localhost:8080");

socket.addEventListener("open", (event) => {
  socket.send("Hello Server!");
});

socket.addEventListener("message", (event) => {
  console.log("Message from server ", event.data);
});
```

To use it, you had to run:

```shell
node --experimental-websocket index.js
```

In Node.js 22, you no longer need to use the `--experimental-websocket` flag as the `WebSocket` global is now enabled by default. This means you can now open bidirectional communication channels between client and server without installing external dependencies.

## Support for Running `package.json` Scripts

This release introduces an experimental `--run` flag, which provides a faster alternative to `npm run` for executing scripts defined in `package.json` files. Assuming you have a `test` script in your `package.json`, you can now execute it with:

```shell
node --run test
```

On my machine, this runs twice as fast as `npm run test`:

```shell
hyperfine --warmup 3 'node --run test' 'npm test'
```

```text
Benchmark 1: node --run test
  Time (mean ± σ):     125.1 ms ±   4.4 ms    [User: 146.5 ms, System: 43.5 ms]
  Range (min … max):   116.7 ms … 134.7 ms    25 runs

Benchmark 2: npm run test
  Time (mean ± σ):     255.1 ms ±   8.5 ms    [User: 285.6 ms, System: 62.4 ms]
  Range (min … max):   245.5 ms … 275.9 ms    12 runs

Summary
  node --run test ran
    2.04 ± 0.10 times faster than npm run test
```

Note that the goal of `--run` isn't to match all the behaviors of `npm run`, but to provide better performance in the most common cases. You can see a summary of its limitations in the [Node docs](https://nodejs.org/docs/latest/api/cli.html#intentional-limitations).

## Loading ES Modules with `require()`

To improve interoperability between ES Modules and the older CommonJS system, a new `--experimental-require-module` has been added to import ES Modules through `require()`. Here's how it works:

```javascript
// hello.mjs is an ES Module
export default function () {
  console.log("hello world!");
}
```

```javascript
// index.js is a CommonJS Module
const hello = require("./hello.mjs").default;
hello();
```

When you execute the `index.js` file with the `--experimental-require-module`:

```shell
node --experimental-require-module index.js
```

You will observe the following output:

```text
hello world!
(node:1738449) ExperimentalWarning: Support for loading ES Module in require() is an experimental feature and might change at any time
```

For this to work, the following requirements must be met by the imported ES module:

- It must be explicitly marked as an ES module through the `.mjs` extension, or with `"type": "module"` in the closest `package.json` file.
- It must be fully synchronous, without a top-level `await`.

The goal is to eventually enable this behavior by default in a future release.

## `fs` Module Supports Pattern Matching

Node.js 22 also introduces new APIs to the `node:fs` module for pattern matching. These are the `glob` and `globSync` methods that can be used for matching file paths based on the supplied [glob pattern](https://man7.org/linux/man-pages/man7/glob.7.html).

You can use it via `node:fs` or `node:fs/promises`:

```javascript
import { glob } from "node:fs";

glob("**/*.js", (err, matches) => {
  if (err) throw err;
  console.log(matches);
});
```

```javascript
import { glob } from "node:fs/promises";

for await (const entry of glob("**/*.js")) console.log(entry);
```

Note that this feature is currently marked as experimental, so you may see the following warning message when the API is used:

```text
(node:1748923) ExperimentalWarning: glob is an experimental feature and might change at any time
```

## `AbortSignal` Performance Improvements

Creating `AbortSignal` instances is now significantly faster in Node.js 22. This class is used to notify observers when the `abortController.abort()` method is called. These enhancements directly benefit high-level APIs that utilize this class, such as `fetch` and the Node.js test runner.

## Enhancements to Stream `highWaterMark`

The `highWaterMark` parameter, which controls the internal buffer size for streams, has been increased from 16KiB to 64KiB in Node.js 22. This change offers potential performance improvements across the board. However, the increase might lead to slightly higher memory consumption. For memory-sensitive applications, explicitly setting the buffer size with `setDefaultHighWaterMark` is recommended.

## V8 Upgraded to v12.4

Node.js 22 ships with a customary upgrade to the V8 JavaScript engine, which brings several enhancements:

- [WebAssembly Garbage Collection](https://developer.chrome.com/blog/wasmgc) for improved memory management.
- Support for new JavaScript features, including [Array.fromAsync()](https://tc39.es/proposal-array-from-async/), [Set methods](https://tc39.es/proposal-set-methods/), and [Iterator helpers](https://tc39.es/proposal-iterator-helpers/).
- The [Maglev](https://v8.dev/blog/maglev) compiler is enabled by default for supported architectures, bringing performance boosts for short-lived CLI programs.

## Should You Use Node.js 22 in Production?

Node.js 22, as an even-numbered release, is on track to become a Long-Term Support (LTS) version in October. This means guaranteed support and security updates until April 2027. However, until its LTS promotion, it will remain as the 'Current' release.

It's not necessary to upgrade to Node.js 22 in your production environment on day one. However, we advise that you explore the new features and improvements this version offers and its potential impact on your applications before performing the upgrade at a convenient time.

## How to Upgrade to Node.js 22

Ready to experience the latest features in Node.js 22? Here's how to upgrade:

### Direct Download

- Visit the official [Node.js download page](https://nodejs.org/en/download/current/)
- Choose the installer that matches your operating system and architecture, and install it as you normally would.

![Node.js Download Page](https://blog.appsignal.com/images/blog/2024-05/download-nodejs.png)

### Node.js Version Manager (Recommended)

For greater flexibility in managing multiple versions of Node.js simultaneously, consider a version management tool like [Volta](https://volta.sh/):

![Volta](https://blog.appsignal.com/images/blog/2024-05/volta.png)

- Install the Volta CLI (refer to the [Volta documentation](https://docs.volta.sh/guide/getting-started)).
- Use the following command to install or upgrade to Node.js 22:

```shell
volta install node@22
```

This output confirms the installation is successful:

```text
success: installed and set node@22.0.0 (with npm@10.5.1) as default
```

## Wrapping Up

Node.js v22 introduces numerous improvements in tooling, language features, standard library additions, and performance optimizations. These enhancements further solidify its position as the premier JavaScript runtime for modern web development.

For a complete breakdown of bug fixes, new features, and other changes, refer to the official [Node.js v22 release notes](https://nodejs.org/en/blog/release/v22.0.0).

If you're interested in getting involved with its development, explore [Node's open issues](https://github.com/nodejs/node/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) and the [Node contribution guidelines](https://github.com/nodejs/node/blob/main/CONTRIBUTING.md) on GitHub.

Thanks for reading!

**P.S. If you liked this post, [subscribe to our JavaScript Sorcery list](https://blog.appsignal.com/javascript-sorcery) for a monthly deep dive into more magical JavaScript tips and tricks.**

**P.P.S. If you need an APM for your Node.js app, go and [check out the AppSignal APM for Node.js](https://www.appsignal.com/nodejs).**