Why and How to Upgrade to Node.js from v18.x to v20.x
Node.js has always been an essential part of the tech stack for many companies and developers. And here at OmbuLabs and UpgradeJS we use it too, due to its efficiency, scalability, and the robust ecosystem it provides.
Recently, the Node.js team released version 20 , bringing with it a host of new features and improvements. In this post, we’ll highlight some notable changes and explain why and how to upgrade to Node.js 20.x.
Why upgrade?
The latest version introduces several new features and enhancements that make Node.js more secure, efficient, and improve the overall development experience. Below is the list of the notable introduced features.
Permission model
The Node.js Permission Model is an experimental feature that provides developers with more control over file system access by allowing them to restrict access to specific resources. This enables more secure and granular control over access to resources such as the file system, child processes, worker threads, and native addons.
V8 11.3
The update to V8 engine version 11.3 brings performance improvements and new language features. Also included are new methods on Array.prototype
and TypedArray.prototype
to enable changes on the array by returning a new copy of it with the change, and more.
Stable test runner
The test_runner
module in Node.js version 20 has been marked as stable, providing a solid foundation for authoring and running tests.
Performance
Node.js 20 includes performance improvements to fundamental runtime elements like URL
, fetch()
, and EventTarget
. These improvements can lead to a better user experience and lower resource usage. The Performance team is also actively seeking contributors, offering opportunities for developers to directly influence and improve Node.js’ performance.
Single Executable Apps (SEA)
Support for Single Executable Applications (SEA) has been added to Node.js. This feature, still experimental, allows for the creation of standalone applications, which can simplify distribution and execution, potentially expanding the use cases for Node.js applications.
Web Crypto API
Node.js 20 improves interoperability with other JavaScript environments by aligning the coercion and validation of Web Crypto API functions’ arguments with their WebIDL definitions. This can facilitate the integration of Node.js applications with other systems and standards, potentially leading to more flexible and versatile applications.
Official support for ARM64 Windows
Node.js now officially supports ARM64 Windows, providing native execution on this platform. This can extend the reach of Node.js applications by allowing them to run on a wider range of platforms and architectures.
How to upgrade
The upgrade of the Node.js version is different for every application, the process can’t look like a one-size-fits-all solution. However, there are some general steps that you can follow to make the upgrade process as smooth as possible. In our The Basics Of The Node.js Version Upgrade Process blog post we have explained the general steps that you can follow to upgrade your Node.js version. We recommend that you read it before you start the upgrade process.
To make the process less complicated we have collected all the changes that were made after the release of Node.js 18.16.1. Read the next section - Changes to address - to learn more about them. With this knowledge in hand, you will be able to upgrade your Node.js version with more confidence.
Changes to address
Assert Module
assert.CallTracker
: The assert.CallTracker class has been deprecated and will be removed in a future version, consider usingmock
instead.
Asynchronous context tracking
AsyncResource.bind()
: TheasyncResource
property added to the returned bound function has been deprecated and will be removed in a future version with no replacement.
Buffer
Buffer.alloc()
,Buffer.allocUnsafe()
,Buffer.allocUnsafeSlow()
: Now throwsERR_OUT_OF_RANGE
instead ofERR_INVALID_ARG_VALUE
for invalid input arguments.
Command-line API
--no-network-family-autoselection
: The flag was renamed from--no-enable-network-family-autoselection
(added in v19.4.0) to--no-network-family-autoselection
. The old name can still work as an alias.--experimental-global-customevent
and--experimental-global-webcrypto
: These options were removed and the classes are now available by default, to disable them use--no-experimental-global-customevent
and--no-experimental-global-webcrypto
.--experimental-specifier-resolution
: Flag was removed .--experimental-test-coverage
: Now can be used with--test
.--experimental-wasi-unstable-preview1
: This option is no longer required as WASI is enabled by default, but can still be passed.--test
.--test-name-pattern
,--test-reporter
,--test-reporter-destination
,--test-only
, : The test runner is now stable.
Crypto
crypto.DEFAULT_ENCODING
: property was removed with no replacement.'hash'
and'mgf1Hash'
rsa-pss keygen parameters: Were replaced withhashAlgorithm
andmgf1HashAlgorithm
, and old parameters are deprecated in runtime.
ECMAScript modules
import.meta.resolve()
: Now returns a string synchronously instead of a Promise.resolve()
: Now returns object or promise, additionally the returned object has a new property -importAssertions
.
File system
filehandle.readableWebStream()
: Added option to create a ‘bytes’ stream.fsPromises.cp()
,fs.cpSync()
, andfs.cp()
: Now accept an additionalmode
option.fsPromises.opendir()
,fsPromises.readdir()
,fs.opendirSync()
,fs.readdirSync()
,fs.readdir()
, andfs.opendir()
: Addedrecursive
option.fsPromises.symlink()
: If thetype
argument isnull
or omitted, Node.js will autodetecttarget
type and automatically selectdir
orfile
.fs.watch()
: Added recursive support for Linux, AIX and IBMi.fs.write()
,fs.writeFileSync()
, andfs.writeFile()
: Passing to thestring
parameter an object with an owntoString
function is no longer supported .
Global objects
Crypto
,crypto
,CryptoKey
,SubtleCrypto
: No longer behind--experimental-global-webcrypto
CLI flag, enabled by default.CustomEvent
: No longer behind--experimental-global-customevent
CLI flag, enabled by default.
HTTP
http.createServer()
: ThehighWaterMark
option is supported now .http.globalAgent
: The agent now uses HTTP Keep-Alive by default.
HTTP/2
- event:
'unknownProtocol'
: This event will only be emitted if the client did not transmit an ALPN extension during the TLS handshake.
HTTPS
https.globalAgent
: The agent now uses HTTP Keep-Alive by default.
Net
socket.connect()
: The default value for theautoSelectFamily
option is nowtrue
, also the default value forautoSelectFamily
option can be changed at runtime usingsetDefaultAutoSelectFamily
or via the command line option--network-family-autoselection
.net.createServer()
: ThehighWaterMark
option is supported now .
Path
path.format()
: The dot will be added if it is not specified inext
.
Performance measurement APIs
- A lot of
performance*.*()
methods now must be called with the proper object as the receiver. performance.mark()
: The name argument is no longer optional.
Process
process.config
: The object is now frozen.process.exit()
andprocess.exitCode
: Coercion to integer was removed, now it only accepts a code of type number, or of type string if it represents an integer.
Stream
stream.finished()
: Added support forReadableStream
andWritableStream
.stream.Duplex.from()
: Thesrc
argument can now be aReadableStream
orWritableStream
.
Test runner
- The test runner is now stable.
- Reporters are now exposed at
node:test/reporters
. run()
: Added atestNamePatterns
option.
TLS
tls.createServer()
: IfALPNProtocols
is set , incoming connections that send an ALPN extension with no supported protocols are terminated with a fatalno_application_protocol
alert.
URL
new URL()
,url.domainToASCII()
,url.domainToUnicode()
: ICU requirement is removed .url.parse()
: Added support for--pending-deprecation
, also use of invalid ports in now deprecated in runtime.url.urlToHttpOptions()
: The returned object will also contain all the own enumerable properties of theurl
argument.
Util
util.parseArgs()
: The API is no longer experimental.
V8
v8.getHeapSnapshot()
andv8.writeHeapSnapshot()
: Now support options to configure the heap snapshot.
WebAssembly System Interface (WASI)
new WASI()
: Version field added to options, the version option is now required and has no default value, default value of returnOnExit changed totrue
.
Web Crypto API
- No longer experimental except for the
Ed25519
,Ed448
,X25519
, andX448
algorithms, WebCryptoAPI functions’ arguments are now coerced and validated as per their WebIDL definitions like in other Web Crypto API implementations.
Worker threads
worker.getHeapSnapshot()
: Now supports options to configure the heap snapshot.
Conclusion
Upgrading to Node.js 20 provides the chance to take advantage of numerous innovative features and improvements. However, like any significant upgrade, it requires thoughtful preparation, a tactical strategy, and appropriate tools.
Note that the cornerstone of a triumphant upgrade is in detailed readiness, rigorous testing, and a measured, systematic rollout.
If you’re seeking help upgrading to Node 18 or 20, we’re here to assist! We offer consulting services aimed at addressing technical debt and modernizing outdated Node.js applications !