Subscribe to the feed

We are happy to share that the Node.js community is releasing Node.js 23 today and in the week of October 29th Node.js 22 will be promoted to Long Term Support (LTS). It’s all very predictable due to the community’s well defined release process.

We’re sure many people are looking forward to the release of Node.js 23 and the promotion of Node.js 22 to LTS as Node.js continues to be used heavily based on the downloads from nodejs.org over the last year. In our opinion, it’s the best choice for those looking for a widely used and stable backend JavaScript runtime. This is why we make it available in Red Hat Enterprise Linux (RHEL) as well as providing pre-built Node.js containers.

Following the Node.js release process, Node.js 23 will not be promoted to LTS as only even-numbered versions are promoted to LTS. While Red Hat only recommends and supports LTS releases, we hope that you will try out the community Node.js 23 releases and provide feedback on the new functionality and features to help pave the way for later releases.

With Node.js 22 being promoted to LTS, it will now make its way into the next minor release of RHEL. If you want to test out the RHEL version of Node.js 22 in advance, we’ve provided CentOS stream based containers  so that you can do that.

If you follow Red Hat’s work in the Node.js project, or have been following our regular updates, you’ll see that our strategy is to focus our community work on aspects we believe are important to our customers, including:

  • Stable and predictable releases
  • Platform support
  • Security
  • Diagnostics
  • Performance
  • Code quality

Our commitment to these priorities, combined with our internal and customer collaborations, keeping the Node.js infrastructure running, keeping V8 running on the s390 and PPC architectures, integrating support for ubi into buildpacks, as well as our sharing of expertise in the Node.js reference architecture, has been keeping us busy.

At the time of Node.js 23, we are excited to share some recent features and ongoing initiatives that have piqued our interest, or in which our team has played a role. Due to how quickly features flow back into the existing Node.js release line, they all may not be technically new in Node.js 23 but they are worth mentioning as having landed since the last major release.

Highlights of recent additions and changes

Progress on ESM compatibility

A number of experimental EcmaScript Modules (ESM) compatibility features added in Node.js 22 are now enabled by default in Node.js 23.

require(esm)

Node.js 22.0.0 added support to allow CommonJS modules to be able to require synchronous ESM graphs (that is, modules that do not use await) behind an --experimental-require-module command line flag. This experimental feature was subsequently backported to Node.js 20.17.0.

In Node.js 23 this feature is now enabled by default. If you encounter any issues with this experimental feature, it can be turned off using the --no-experimental-require-module command flag. The following code:

// hello.mjs
import util from 'node:util';

export const hello = util.format('hello %s', 'world');

// index.cjs
'use strict';

console.log(require('./hello.mjs').hello);

would previously have thrown an error:

$ node index.cjs
node:internal/modules/cjs/loader:1285
   throw new ERR_REQUIRE_ESM(filename, true);
   ^
   
Error [ERR_REQUIRE_ESM]: require() of ES Module /tmp/testing/hello.mjs not supported.
Instead change the require of /tmp/testing/hello.mjs to a dynamic import() which is available in all CommonJS modules.
   at Object.<anonymous> (/tmp/testing/index.cjs:3:13) {
 code: 'ERR_REQUIRE_ESM'
}

Node.js v20.18.0

But in Node.js 23:

$ node index.cjs
hello world
(node:3469988) ExperimentalWarning: Support for loading ES Module in require() is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)

Module syntax detection for extensionless or .js files

In the past Node.js would treat an extensionless file, or a file ending with a .js extension as CommonJS if the nearest package.json file did not specify "type": "module".

#!/usr/bin/env node
// hello (no extension)
import util from 'node:util';
console.log(util.format('hello %s', 'world'));

Previously (Node.js 20.18.0):

$ ./hello
(node:3486552) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/tmp/testing/hello:3
import util from 'node:util';
^^^^^^

SyntaxError: Cannot use import statement outside a module
   at wrapSafe (node:internal/modules/cjs/loader:1378:20)
   at Module._compile (node:internal/modules/cjs/loader:1428:41)
   at Module._extensions..js (node:internal/modules/cjs/loader:1548:10)
   at Module.load (node:internal/modules/cjs/loader:1288:32)
   at Module._load (node:internal/modules/cjs/loader:1104:12)
   at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12)
   at node:internal/main/run_main_module:28:49
   
Node.js v20.18.0

Node.js 20.10.0 and Node.js 22.0.0 added a flagged experimental feature which, when the nearest package.json file does not specify the type field (either as module or commonjs), attempted to first load the file as CommonJS, but if that failed due to a parsing error due to use of ES module syntax reattempted to run the file as an ES module.

For example, with Node.js 20.18.0:

$ NODE_OPTIONS=--experimental-detect-module ./hello
hello world

Starting from Node.js 22.7.0 and Node.js 23.0.0, this feature is now enabled by default.

$ ./hello
hello world

Due to the potential for this feature to load the file twice (once as CommonJS and then as an ES module), the recommendation is to specify "type": "module" in package.json where possible to avoid the small performance overhead.

Many thanks to Joyee Cheung who worked on these features.

Experimental TypeScript Support

Recent releases of Node.js have added experimental support for running “.ts” files with a limited subset of TypeScript. Developers often want to use TypeScript types in their code but have long wanted to be able to run that code easily without having to install additional tooling. This is particularly true for developers working for customers of Red Hat as they often have prior experience with more strongly typed languages like Java.

Two options have been added:

  • --experimental-strip-types This option strips types by replacing them with white space in a way that does not require source maps.

  • --experimental-transform-types This option adds support for transforming TypScript-only syntax into JavaScript, for example enum and namespaces. Enabling this option also enables source maps which may affect performance.

Together these allows Node.js to run Typescript code like the following directly:

hello.js

import { GreetOptions } from './greeter.ts'
import greeter from './greeter.ts'

const message: string = 'World';
const greeting: string = greeter(GreetOptions.Hello,
       message);
       
console.log(greeting);

greeter.js

export enum GreetOptions {
 Hello,
 Goodbye
};

export default function (helloType: GreetOptions, greeting: string) : string {
 let world: string;
 if (helloType === GreetOptions.Hello) {
   world = 'Hello ' + greeting;
   return world;
 };
 throw Error('Unknown GreetOption');
};
>node --experimental-strip-types --experimental-transform-types hello.ts
(node:1216886) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Hello World

Many thanks to Marco Ippolito who worked so hard on this feature.

Experimental Web Storage API

As we’ve mentioned in earlier blog posts, the project continues to work on improving Web compatibility when and where it makes sense in Node.js. As part of that work, an experimental browser-compatible implementation of the Web Storage API has been added. This gives developers simple key/value storage. This allows you to write code like the following using getItem/setItem to store data for the session or persistently to disk:

// persistent
localStorage.setItem('RuleToLiveBy', 'Never bet against Node.js');
console.log(localStorage.getItem('RuleToLiveBy'));

// in memory
sessionStorage.setItem('RuleToLiveBy', 'I told you never bet against Node.js');
console.log(sessionStorage.getItem('RuleToLiveBy'));

As the API is still experimental the functionality is guarded by the --experimental-webstorage flag and you must also pass --localstorage-file to indicate where the data will be stored if localStorage is used. For example:

>node --experimental-webstorage --localstorage-file=data.bin test-local-storage.js
Never bet against Node.js
I told you never bet against Node.js
(node:1267479) ExperimentalWarning: Web Storage is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)

Many thanks to Colin Ihrig who worked on this feature.

SQLite

SQLite is a popular and lightweight SQL database engine that has been built into a number of runtimes (for example Python, php etc.). SQLite was added as a dependency for Node.js in order to support the Web Storage APIs. Building on that effort an experimental SQLite API has been added to Node.js.

This API allows you to use SQL queries to populate and query either an in memory (‘:memory:’)  or on disk database (by providing a filename). You can read more about the full API in the  SQLite section of the Node.js documentation. An example of using the API is as follows:

const { DatabaseSync } = require ('node:sqlite');
const db = new DatabaseSync(':memory:');

db.exec(`
 CREATE TABLE data(
   key TEXT PRIMARY KEY,
   value TEXT
 ) STRICT
`);

const insertStmt = db.prepare(
 'INSERT INTO data (key,value) VALUES (?, ?)');
 
const readStmt = db.prepare(
 'SELECT * FROM data ORDER BY key');
 
insertStmt.run('RULE TO LIVE BY 2',
              'I told you never bet against Node.js');
insertStmt.run('RULE TO LIVE BY 1',
              'Never bet against Node.js');
              
console.log(readStmt.all());

While many enterprise applications will use external replicated SQL databases, the addition of this API expands the use cases that Node.js can be used without having to install additional npm dependencies in order to manage a local database.

Many thanks to Colin  Ihrig who worked on this feature.

Continued progress on performance

SemVer major releases always include an updated version of V8, which often bring improved performance. This release is no different and includes an update to V8 12.9.

In this release there are also performance improvements in the Node.js codebase. Improvements of note include:

  • Opt-in support on-disk caching to improve startup performance
  • Performance in buffer
  • FS improvements

Opt-in support on-disk caching to improve startup performance

Node.js 23 and 22.8.0 introduce new opt-in support for on-disk code caching. This can significantly speed up subsequent module loads at a small cost for the first load providing the contents of the module do not change. This is a built-in alternative to the v8-compile-cache/v8-compile-cache-lib packages, but has better performance and supports ESM.

For users, this can be controlled via the NODE_COMPILE_CACHE and NODE_DISABLE_COMPILE_CACHE environment variables.

Application and library authors can programmatically use module.enableCompileCache().

For more information, see the module compile cache documentation.

Many thanks for the contribution by Joyee Cheung.

Performance Improvements to Buffer

Performance of Node.js Buffers have been optimized through multiple changes with significant improvements to the Buffer.copy() and Buffer.write() methods. These are used throughout the codebase and should give a nice boost across the board.

Thanks to Robert Nagy for making this work.

Significant improvements to the performance of buffer encoding/decoding/transcoding have been made by Daniel Lemire and  Yagiz Nizipli.

FS improvements

Work continues to improve the performance of the node:fs module by reducing the number of C++ calls for operations.

If you are interested in Node.js performance, follow or consider joining the Performance team.

Progress on web compatibility

As mentioned earlier when we covered the addition of the Web Storage API, the project continues to work on adding APIs for web compatibility. Since the last Node.js major release the project promoted the browser-compatible Web Socket API to stable. You can read more about this API in the Node.js API docs in the WebSocket section.

Node Run

The package.json file for an application is often used to manage scripts that are used to run an application. While this is useful for testing and development, the best practice is to avoid using npm to start applications in production, particularly when using containers. You can read more about this in the Red Hat Node.js reference architecture.

Node.js has recently added the “--run” command line option to run scripts from the package.json for an application without using npm and is now stable in Node.js 23.

For example if you have a simple package.json for your application like this:

{
 "name": "my-great-app",
 "version": "0.0.1",
 "scripts": {
   "start": "node doit.js"
 }
}

You can start the application with:

>node --run start
I ran

Many thanks to Yagiz Nizipli who worked on this feature.

Deprecations

SemVer major releases are an opportunity to introduce and/or progress deprecations. You can get the full list from the changelog, some deprecations of note include:

Doc-only Deprecation of OpenSSL Engine-based APIs

OpenSSL 3 deprecated support for custom engines with a recommendation to switch to its new provider model.

The clientCertEngine option for https.request()tls.createSecureContext(), and tls.createServer(); the privateKeyEngine and privateKeyIdentifier for tls.createSecureContext(); and crypto.setEngine() all depend on this functionality from OpenSSL.

Experimental Policy Feature

The --experimental-policy option was removed. It was an experimental feature that had been tried out over the last few years. Recently there were fewer maintainers with cycles to be involved, and issues were regularly reported. The decision was made to remove it as progress on making it a usable option had stalled.

Platform support

If you are using the GNU C/C++ compiler to build Node.js from source, Node.js 23 has raised the minimum supported version to gcc 12 in light of adoption of C++20 features both inside Node.js itself and its dependencies, notably V8.

Support for 32-bit Windows has been dropped as the project determined that usage was low enough that it did not justify the additional effort required to continue supporting it.

Security and supply chain security

While security and supply chain security have always been important, there has been growing awareness and interest in these areas in recent years. Within the Node.js project, a significant amount of effort is devoted to security-related work, ranging from identifying and resolving vulnerabilities to executing security releases.

One item of note this year is the work by Rafael funded by the OpenSSF foundation to help automate security releases. This work has made it easier to do security releases faster when necessary.

The project has also made progress on keeping dependencies up to date. Thanks to work of the security working group (and Marco in particular) much of this is now automated and updates occur on a regular cadence.

We’d also like to express our appreciation to the companies and individuals who have stepped up to help with security releases as security release stewards or as part of the security triage team, the Release Working Group, and all those who contribute to the security release efforts.

In line with what is important to our customers, Red Hat is proud to be doing part of this work through our involvement in the triage team, doing security releases and contributing to the efforts of the security working group team along with all of the other contributors across the project.

Next-10

While major releases are the time people look at what’s new, it’s also important to look forward to what’s coming in the future. The project is working on that as part of the Next-10 effort and has defined the constituenciesneeds of those constituencies and the technical priorities based on those needs.

With the technical priorities being well defined and confirmed as in sync with the larger ecosystem by the recent next-10 survey the focus of the team has been less on technical direction and more on advocating and supporting the health of the project. Current initiatives include:

If you want to learn more about these initiatives or get involved you can check out the next-10 repo or join our biweekly meetings.

A big thank you

Our thanks go out to every individual involved in the initial 23.x release of Node.js. The project has a diverse group of contributors who work tirelessly, and each release is a culmination of their collective efforts.

The community changelog for v23.0.0 and OpenJS blog contain more details about the latest enhancements and modifications.

For further insights on the Node.js community and ways to participate, visit the project repository and website. To explore Red Hat's involvement in the Node.js space, refer to the Red Hat Node.js Developers page. Additionally, Red Hat customers can refer to the customer portal for additional information.


About the authors

Michael Dawson is an active contributor to the Node.js project and chair of the Node.js Technical Steering Committee (TSC). He contributes to a broad range of community efforts including platform support, build infrastructure, N-API, Release, as well as tools to help the community achieve quality with speed (e.g., ci jobs, benchmarking and code coverage reporting). As the Node.js lead for Red Hat and IBM, he works with Red Hat and IBM's internal teams to plan and facilitate their contributions to Node.js and v8 within the Node and Google communities. Dawson's past experience includes building IBM's Java runtime, building and operating client facing e-commerce applications, building PKI and symmetric based crypto solutions as well as a number of varied consulting engagements. In his spare time, he uses Node.js to automate his home and life for fun.

Read full bio

Richard Lau is an active member of the Node.js project's Build and Release Working Groups and Technical Steering Committee (TSC). Prior to working at Red Hat he spent 19 years at IBM working on their Java runtime and then Node.js runtime.

Read full bio
UI_Icon-Red_Hat-Close-A-Black-RGB

Keep exploring

Browse by channel

automation icon

Automation

The latest on IT automation for tech, teams, and environments

AI icon

Artificial intelligence

Updates on the platforms that free customers to run AI workloads anywhere

open hybrid cloud icon

Open hybrid cloud

Explore how we build a more flexible future with hybrid cloud

security icon

Security

The latest on how we reduce risks across environments and technologies

edge icon

Edge computing

Updates on the platforms that simplify operations at the edge

Infrastructure icon

Infrastructure

The latest on the world’s leading enterprise Linux platform

application development icon

Applications

Inside our solutions to the toughest application challenges

Original series icon

Original shows

Entertaining stories from the makers and leaders in enterprise tech