javascript

What's New in Node.js 21

Damilola Olatunji

Damilola Olatunji on

What's New in Node.js 21

Node.js v21, the latest Node update, is now available as a stable release. It supersedes v20 in the 'Current' release line, which has been promoted to the long-term support (LTS) channel as of 24 October.

This new version stabilizes the fetch and WebStreams API, adds a built-in WebSocket client, improves support for ES modules, and brings some notable performance improvements (as well as a customary update of Node.js dependencies such as V8).

Without further ado, let's jump in and see what Node 21 has in store for us!

Stable Fetch API Status

Fetch API is now stable

A browser-compatible implementation of the Fetch API was introduced in Node.js in v17.5.0 through an --experimental-fetch flag, which brought the fetch, Headers, Request, and Response globals. From v18.x to v20.x, the flag was no longer required (but the Fetch API continued to be marked as experimental).

With the release of Node.js 21, the Fetch API is finally promoted to stable status. If you've hesitated to use Fetch due to its experimental nature, you can now confidently adopt it in your applications:

javascript
const res = await fetch("https://jsonplaceholder.typicode.com/todos/1"); if (res.ok) { const data = await res.json(); console.log(data); }

Web Streams API Is Stable

Webstreams API is now stable

The Fetch API implementation is dependent on the AbortController interface (for aborting fetch requests) and a browser-compatible Web Streams API, which were both added in v15.0.0 and v16.5.0, respectively. While AbortController quickly became stable in v15.4.0, the Web Streams API has only just been stabilized in v21.

javascript
import { TextDecoderStream } from "node:stream/web"; async function streamExample() { const response = await fetch("https://jsonplaceholder.typicode.com/todos/1"); const stream = response.body; const textStream = stream.pipeThrough(new TextDecoderStream()); for await (const chunk of textStream) { console.log(chunk); } } streamExample();

Note that the older Node.js streams API hasn't been deprecated or removed. It will co-exist with the new API, and it even provides a way to convert from a web stream and vice versa using the .fromWeb() and .toWeb() methods (both added in Node 17, although both methods still retain their experimental status).

A Built-in WebSocket Client

Node.js continues its trend of implementing standard web platform APIs with the recent addition of the --experimental-websocket flag, introducing a WebSocket global, as standardized by WHATWG.

This latest effort complements existing web platform APIs such as the aforementioned Fetch and Web Streams APIs, AbortController APIs, the WHATWG URL parser, EventTarget, Web Crypto API, and more.

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); });

While it's currently not recommended for production use, you can start experimenting with it right away:

shell
node --experimental-websocket index.js

ES Modules Improvements

Node.js 21 introduces a new --experimental-default-type flag that allows you to modify the default behavior for input files not explicitly defined as ES modules or CommonJS. Prior to this update, such input was implicitly interpreted as CommonJS. With --experimental-default-type=module, you can enable a complete ES module implementation in the following scenarios:

  • String input provided via --eval or STDIN, if --input-type is unspecified.
  • Files ending in .js or with no extension, if there is no package.json or the nearest parent package.json field lacks a type field (except if in node_modules).
shell
node --experimental-default-type=module index.js

These improvements pave the way to eventually supporting ES module syntax by default with minimal breaking changes.

Test Runner Improvements

Building on its stabilization in Node.js v20, the native test runner undergoes further enhancements in version 21.

It now supports glob expressions, allowing you to easily match multiple test files using custom glob patterns besides the predefined defaults.

shell
node --test **/*.test.js **/*.spec.js

Module Customization Improvements

This release simplifies module customization by removing the confusing globalPreload hook in favor of the register API for sending data from the application thread to the customization hooks, and the initialize hook to establish communication channels between threads.

llhttp v9.1.2 Strict Mode Enforcement

In the llhttp v9.1.2 update for Node.js, strict mode enforcement was introduced as the default setting, enabling previously included strict mode features for enhanced code reliability and security.

Notable changes include a mandatory \r\n presence after headers and chunks, ensuring consistent data processing, and disallowing data transmission after a message with the Connection: close header, improving protocol adherence and connection handling.

To maintain backward compatibility with older releases, you can use the --insecure-http-parser flag to disable these changes.

Performance Improvements to Key APIs

The Node.js performance team landed a few key improvements in this release:

  • The Streams API underwent optimizations, achieving approximately a 10% speedup by eliminating redundant checks, utilizing bitmaps, and scheduling callbacks more efficiently.
  • When uncorking a response, splitting chunked responses into multiple parts is avoided, which helps reduce unnecessary overhead on both the client and server side.

V8 Upgraded to v11.8

The V8 engine has been upgraded to v11.8, which brings improved performance and the following JavaScript features:

  • Array grouping to combine like data into groups using Object.groupBy() and Map.groupBy().
  • A new programmatic API (ArrayBuffer.prototype.transfer) for transferring ownership of ArrayBuffers, optimized reallocations, and fixing resizable ArrayBuffers into fixed-length ones.
  • WebAssembly extended-const expressions.

NPM Upgraded to v10.2.0

Node.js v21 includes npm v10.2.0, which notably introduces a new sbom command that allows you to generate a Software Bill of Materials (SBOM) for the current project. You can read more about the changes in recent NPM releases on GitHub.

Node.js 21 Miscellaneous Updates

Other features and improvements available in this release include the following:

  • A partial implementation of the global navigator object, allowing access to hardware concurrency information via navigator.hardwareConcurrency.
  • A flush option is added to the fs.writeFile() family of functions to guarantee that data is flushed to disk at the end of a successful write operation. This prevents redundant data from being read.

Should You Use Node.js v21 in Production?

You probably shouldn't use Node.js v21 in production. As an odd-numbered October release, it will only be supported for one year, unlike the April even-numbered releases (16, 18, 20, etc.), which receive long-term updates for up to three years.

Upgrading to Node.js v21

Should you wish to install or upgrade to Node.js v21, use the relevant link for your operating system and architecture on the Node.js download page.

Alternatively, a better way to manage Node.js releases on your machine is to use an environment management tool like Volta that can install and switch between multiple versions seamlessly.

After installing the Volta CLI, run the command below to install the latest version of Node.js:

shell
volta install node@latest success: installed and set node@21.0.0 (with npm@10.2.0) as default

Wrapping Up

Node.js v21 introduces numerous improvements in tooling, language features, standard library additions, and performance optimizations, enhancing its position as a robust JavaScript runtime and aligning it more closely with modern alternatives like Deno and Bun.

You can examine the complete list of bug fixes, new features, and other changes in the official Node.js 21 release notes.

To learn more about the Node.js community and how you can contribute, check out the project's open issues and contribution guidelines on GitHub.

Thanks for reading!

P.S. If you liked this post, subscribe to our JavaScript Sorcery list 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.

Damilola Olatunji

Damilola Olatunji

Damilola is a freelance technical writer and software developer based in Lagos, Nigeria. He specializes in JavaScript and Node.js, and aims to deliver concise and practical articles for developers. When not writing or coding, he enjoys reading, playing games, and traveling.

All articles by Damilola Olatunji

Become our next author!

Find out more

AppSignal monitors your apps

AppSignal provides insights for Ruby, Rails, Elixir, Phoenix, Node.js, Express and many other frameworks and libraries. We are located in beautiful Amsterdam. We love stroopwafels. If you do too, let us know. We might send you some!

Discover AppSignal
AppSignal monitors your apps