process.versions

Lists the version strings of Node.js and every dependency it was built against, such as V8, libuv and OpenSSL.

Signature
process.versions
  • Added in Node.js v0.2.0

Return value

ObjectAn object mapping component names — node, v8, uv, zlib, openssl, modules, napi and others — to their version strings.

Changelog

  • PHP v9.0.0The v8 property now includes a Node.js-specific suffix, for example '12.4.254.21-node.19'.
  • PHP v4.2.0The icu property is now supported.

process.versions is the full bill of materials for the running binary: node, v8, uv, zlib, openssl, icu, undici, llhttp, napi, modules and more, all as strings. Every value is a string, including modules.

When to reach for it

It is the diagnostic property. Paste it into a bug report and a maintainer can tell instantly whether a TLS handshake failure is an OpenSSL 3 policy change, whether a date-formatting difference is a small-icu build, or whether a crash is a known V8 regression.

The one to know: modules

process.versions.modules is the ABI version. It is bumped whenever the C++ API changes, and Node refuses to load a native addon compiled against a different value — the familiar "was compiled against a different Node.js version" error. Each major Node release generally has its own ABI, which is why node_modules cannot be shared between major versions or copied out of a differently-versioned Docker image. The fix is npm rebuild, not reinstalling the same prebuilt artifact.

What trips people up

The v8 value carries a Node-specific suffix such as -node.19 since v9.0.0, so it will not parse as plain semver. Keys also come and go between releases: assume a key may be missing rather than indexing blindly.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Print a full runtime fingerprint in a bug report or support bundle.
  • Explain a native addon load failure by comparing ABI (modules) versions.
  • Check the OpenSSL version when debugging a TLS or certificate problem.
  • Confirm a build has full ICU before relying on locale-aware date formatting.

Frequently asked questions

What is process.versions.modules used for?

It is the native ABI version, incremented whenever Node's C++ API changes, and Node refuses to load an addon compiled against a different value. If a native module fails with a NODE_MODULE_VERSION error, rebuild it with `npm rebuild` on the runtime you are actually using.

How do I find the V8 version Node is running?

Read process.versions.v8, which since v9.0.0 includes a Node-specific suffix such as '12.4.254.21-node.19'. The suffix marks Node's patched build, so the version will not parse as plain semver.

Why can't I copy node_modules between machines with different Node versions?

Because any package containing a compiled addon is tied to the ABI in process.versions.modules, which changes with each major Node release. Pure-JavaScript packages copy fine; native ones need `npm rebuild`, or a package that uses the stable Node-API instead.

More examples

A runtime fingerprint for bug reports

The output is the block worth pasting into an issue. The `-node.19` suffix on V8 and the `+quic` on OpenSSL show these are Node's patched builds rather than upstream releases, which is why a fix listed in an upstream changelog may not be present. The `?? '(small-icu build)'` fallback matters because a build without full ICU silently formats dates in English only.

Example · javascript
const os = require('node:os');

const report = {
  node: process.version,
  v8: process.versions.v8,
  uv: process.versions.uv,
  openssl: process.versions.openssl,
  icu: process.versions.icu ?? '(small-icu build)',
  abi: process.versions.modules,
  platform: `${process.platform}-${process.arch}`,
  os: `${os.type()} ${os.release()}`,
};

console.log(Object.entries(report).map(([k, v]) => `${k.padEnd(9)}: ${v}`).join('\n'));
// node     : v22.11.0
// v8       : 12.4.254.21-node.19
// uv       : 1.48.0
// openssl  : 3.0.15+quic
// icu      : 75.1
// abi      : 127
// platform : linux-x64
// os       : Linux 6.8.0-45-generic

Diagnosing a native addon ABI mismatch

The output turns an opaque loader failure into an actionable one by putting the ABI the addon expects next to the ABI this runtime provides. ABI 115 is Node 20 and 127 is Node 22, so the numbers themselves reveal that node_modules came from a different major version — typically copied into a Docker image built on another base. Addons written against Node-API (see process.versions.napi) are exempt, because that ABI is stable across major releases.

Example · javascript
try {
  require('some-native-addon');
} catch (err) {
  if (err.code === 'ERR_DLOPEN_FAILED' || /NODE_MODULE_VERSION/.test(err.message)) {
    const wanted = err.message.match(/NODE_MODULE_VERSION (\d+)/)?.[1];
    console.error('Native addon ABI mismatch.');
    console.error(`  this runtime : ${process.version} (ABI ${process.versions.modules})`);
    console.error(`  addon built for ABI: ${wanted ?? 'unknown'}`);
    console.error('  fix: npm rebuild some-native-addon');
  } else {
    throw err;
  }
}
// Native addon ABI mismatch.
//   this runtime : v22.11.0 (ABI 127)
//   addon built for ABI: 115
// Fix: npm rebuild some-native-addon

Discussion

  • Be the first to comment on this lesson.