Node.js 20: New Features, Updates, and Improvements

ITMAGINATION
Geek Culture
Published in
9 min readApr 25, 2023

The recent release of Node.js 20 has brought a plethora of new features, updates, and improvements to the popular JavaScript runtime. Among the highlights are the introduction of the Node.js Permission Model, synchronous import.meta.resolve, a stable test_runner, updates to the V8 JavaScript engine, and the launch of Ada 2.0.

As an outsourcing company dedicated to staying informed about the latest developments in the tech industry, this article delves into the noteworthy changes in Node.js 20 and their potential impact on various applications.

The Most Notable Changes in Node.js 20

Permission Model

The Node.js Permission Model, introduced as an experimental feature in the Node.js 20 release, aims to enhance the security of applications by providing a mechanism for restricting access to specific resources during execution. This added layer of control allows developers to limit access to various system resources, such as the file system, child_process, worker_threads, and native addons. By implementing these restrictions, developers can better protect sensitive data and reduce the risk of unauthorized access or manipulation.

To enable the Permission Model, developers can use the — experimental-permission flag along with the desired permissions. For instance, if they wish to restrict access to the file system (both read and write), they can use the — allow-fs-read and — allow-fs-write flags. This granular control allows developers to fine-tune the level of access their Node.js processes have to specific parts of the file system.

Developers can also specify particular paths for file system access by passing in comma-separated values to the flags. For example, they can allow write access to the /tmp/ folder and read access to the /home/index.js file using the following command:

node --experimental-permission --allow-fs-write=/tmp/ --allow-fs-read=/home/index.js index.js

Additionally, wildcard patterns can be used to grant access to multiple files or folders simultaneously. For example, granting read access to all files and folders in the /home/ directory that start with “test” can be done using this command:

node --experimental-permission --allow-fs-read=/home/test* index.js

When the Permission Model is enabled, developers can use the new permission property of the process object to check if a certain permission has been granted at runtime. For example:

process.permission.has('fs.write'); // true 
process.permission.has('fs.write', '/home/nodejs/protected-folder'); // true

It is important to note that the Permission Model is still experimental, and its implementation may change in future releases of Node.js. However, its introduction signifies a step forward in providing developers with more control and security over their applications. By exploring and utilizing the Permission Model, developers can better safeguard their applications against potential threats and ensure the integrity of their data.

Critics will say that “hey, Deno had it for so long.” They will be right, and in fact Deno was created to address the major shortcomings of Node, and security was one of them. Let’s look at it from Node’s side. They have so many developers relying on them, and so many large businesses running critical code on their platform, that they had to take this much time to make sure everything was ready for the release, and even after all this time, it’s released as an experimental feature, to be sure they will get it right.

Single Executable Apps (SEA)

Single Executable Apps (SEA) is an experimental feature in Node.js that aims to simplify the deployment and distribution of applications by bundling all necessary files and resources into a single executable binary. This approach offers several benefits, including ease of installation, reduced dependency management, and improved portability across different platforms.

In Node.js 20, the process of building a SEA has been refined by requiring the injection of a blob prepared by Node.js from a JSON config instead of injecting the raw JavaScript file directly. This change enables the possibility of embedding multiple co-existing resources into the SEA, opening up new use cases for developers and allowing for more flexible application packaging.

To create a SEA in Node.js 20, developers must first create a JSON configuration file that specifies the main entry point of the application, as well as the output file for the generated blob. For example:

{ "main": "hello.js", "output": "sea-prep.blob" }

Next, developers can use the — experimental-sea-config flag with Node.js to generate the blob based on the JSON configuration:

$ node --experimental-sea-config sea-config.json

This command will create a blob file (sea-prep.blob in this example) that contains all necessary resources for the application. The generated blob can then be injected into the binary, resulting in a single executable app.

By building self-contained applications, developers may now run the apps they built on systems, where Node.js is not installed. This can lead to more efficient and streamlined applications that are easier to deploy, manage, and distribute.

However, it is essential to remember that the SEA feature is still experimental and may undergo further changes in future releases of Node.js. Developers interested in leveraging SEAs should stay informed about updates and refinements to ensure they are utilizing the most effective and secure methods for their applications.

Importantly, SEAs might not work on Alpine Linux. If you want to use your contained app in a Docker container, it’s perhaps better to use containers based on Debian Bullseye or Debian Buster.

Stable Test Runner

The stable test runner in Node.js 20 is a huge enhancement for developers since it provides a solid framework for authoring, organizing, and running tests within their applications. Node.js provides a reliable and efficient testing infrastructure that developers can confidently integrate into their projects by declaring the test_runner module as stable.

The following are essential components of a stable test runner:

1. Explain, it/test, and hooks: These building elements aid in the structure of test files and the organization of test cases in a clear and logical manner. The ‘describe’ function groups similar tests, whereas the ‘it’ or ‘test’ functions specify individual test cases. Hooks like ‘before’, ‘after’, ‘beforeEach’, and ‘afterEach’ can be used to set up or clear up any resources that are required before or after executing tests.

2. Mocking: Mocking capabilities are provided by the test runner, allowing developers to substitute pieces of their application with mock objects during testing. To ensure reliable test results, this functionality is especially useful for isolating certain components, mimicking external dependencies, and manipulating the behavior of functions or modules.

3. Watch mode: When changes are detected in the source code, the test runner immediately reruns tests. This feature allows developers to obtain rapid feedback on their changes and contributes to a quick and efficient development workflow.

4. Parallel execution: The node — test flag enables developers to run multiple test files concurrently, considerably lowering the time necessary to run all tests inside a project. This capability is very useful for large applications with a high number of test cases.

While the stable test runner in Node.js 20 provides a good framework for testing applications, other components of the module, such as reporters and code coverage, are not yet stable. Developers should expect further upgrades and refinements to these functionalities in future Node.js releases as the test runner evolves.

Developers can assure the dependability and quality of their apps by including the stable test runner into their development process. This complete testing framework streamlines the process of generating, organizing, and running tests, allowing developers to concentrate on producing high-quality, bug-free products.

Other Notable Changes in Node.js 20

Custom ESM Loader Hooks

Custom ES module lifecycle hooks, supplied via loaders ( — experimental-loader=./foo.mjs), now run in a dedicated thread. This isolation ensures that there is no cross-contamination between loaders and application code. In addition, import.meta.resolve() has been updated to return synchronously, aligning with browser behavior. These changes pave the way for marking ESM loaders as stable, as per the absence of significant bugs reported by the community.

V8 11.3 Engine

The new release of the JS runtime features a newer version of the V8 JavaScript engine (version 11.3), which is included with Chromium 113. This update improves performance and adds new language features such as String.prototype.isWellFormed and toWellFormed, copy methods for Array and TypedArray, resizable ArrayBuffer and growable SharedArrayBuffer, RegExp v flag with set notation + string properties, and WebAssembly Tail Call.

Performance Improvements

Node.js 20 demonstrates the renewed emphasis on performance since the previous major release. Significant improvements have been made to basic runtime components such as URL, fetch(), and EventTarget. EventTarget’s initialization cost has been cut in half, resulting in faster access to all subsystems that use it. V8 Fast API methods have also been used to boost performance in APIs such as URL.canParse() and timers.

Web Crypto API

Node.js has enhanced the Web Crypto API functions’ arguments to better interoperability with other JavaScript environments. The parameters are now coerced and validated according to their WebIDL definitions. This version improves compatibility with different Web Crypto API implementations.

Official Support for ARM64 Windows

Node.js now officially supports ARM64 Windows, allowing for native execution on the platform. The Node.js download site now includes MSI, zip/7z packages, and executables for ARM64 Windows, in addition to all other platforms. The current level of support is Tier 2, which is higher than experimental but lower than Tier 1.

ARM64 architecture is increasingly being adopted in various devices, including laptops, tablets, and IoT devices. Official support for Windows ARM64 in Node.js allows developers to create and deploy applications on a wider range of hardware, ensuring compatibility and optimal performance across different platforms.

Progress on Web Assembly System Interface (WASI)

Node.js’ WASI implementation is evolving, with a command line option no longer required to enable WASI in Node.js 20. This upgrade simplifies use for developers and makes integration into applications easier. As the WASI team prepares for preview2, more modifications have been made to plan for future releases, including the requirement of a version option when calling new WASI().

Node.js 20 Breaking Changes

If you plan to upgrade Node 20 from your Node 18, or Node 16, you must be aware of any breaking changes. This time around, the team behind the JavaScript runtime listed only one change that would cause problems. It’s the deprecation of url.parse() with invalid ports. This time around you will “only” get a warning, but it’s something to keep in mind.

Conclusion

Finally, the release of Node.js 20 offers a slew of new features, upgrades, and enhancements that have the potential to significantly affect applications across a wide range of industries. lisAs an outsourcing company committed to staying current on technological improvements, it is critical for developers and organizations alike to investigate these changes and determine their potential benefits. With Node.js 20 entering long-term support (LTS) in October and serving as the “Current” release for the next six months, now is an excellent opportunity to become acquainted with the enhancements it provides and explore their implications for future projects.

How to Update Node.js?

How to Update Node.js the Official Way?

You may find the links to download the LTS and the current releases at https://nodejs.org/en/download. You will be able to find a Node release for macOS, Windows, different Linux distros, or even AIX on PowerSystems.

Usually, we would recommend installing the LTS version. This time, go straight for version 20, as it will be maintained until… early 2026.

How to Update Node.js with Choco?

The more experienced users on Microsoft’s OS will want to install the new release using Choco. Choco is a package manager for Windows.

If you haven’t already, you may install Choco by following these steps.

You may find the package with the newest here.

To install, simply run:

choco install nodejs

How to Update Node.js with NVM?

As per NVM’s GitHub repo for the tool, “nvm allows you to quickly install and use different versions of node via the command line.”

If you have not installed NVM on your macOS or Linux distribution, you may do that by following these steps.

To install Node.js 20 with NVM, simply run:

nvm install 20

How to Update Node.js with Volta?

Volta is the newest tool among the three listed above. It’s also the only cross-platform tool among the three, which is a huge pro.

If you don’t have Volta installed, you may do that by following steps outline on the official page.

To install Node 20.js with Volta, run:

volta install node@20

To pin Node.js 20 in your projects, to sync the version of the runtime across different machines, run:

volta pin node@20

Originally published at https://www.itmagination.com.

--

--

ITMAGINATION
Geek Culture

We help our clients innovate by providing professional software engineering and technology advisory services.