Node.js 16 to 18 Breaking Changes: Complete Changelog Guide for Upgrading

Node.js documents every breaking change for versions 16, 17, and 18 in dedicated changelog files located at doc/changelogs/CHANGELOG_V16.md, CHANGELOG_V17.md, and CHANGELOG_V18.md in the nodejs/node repository.

When upgrading across multiple major versions, you need authoritative sources that track API removals, V8 engine updates, and OpenSSL migrations. The Node.js project maintains version-specific changelogs that catalog every breaking change, deprecation, and behavioral shift for the 16.x (Gallium), 17.x, and 18.x (Hydrogen) release lines.

Where to Find Node.js 16 Breaking Changes

The Node.js 16 changelog file tracks all breaking changes for the Gallium LTS line, including the initial V8 9.0 upgrade, npm 7 integration, and the stabilization of the Timers Promises API.

Locate the comprehensive list at:

doc/changelogs/CHANGELOG_V16.md

Direct link: https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V16.md

Each minor release (e.g., v16.20.2) contains a Notable Changes section that highlights breaking changes. Look for subsections labeled "Breaking Changes" or "Breaking Changes to Internal Elements" to identify API removals and behavioral modifications that affect application code.

Where to Find Node.js 17 Breaking Changes

Node.js 17 introduced one of the most significant breaking changes in recent history: the upgrade to OpenSSL 3.0. This affects cryptographic operations, cipher suites, and TLS/SSL behavior. The changelog file documents every API adjustment and security hardening measure.

Access the complete breaking changes list at:

doc/changelogs/CHANGELOG_V17.md

Direct link: https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V17.md

Critical sections to review include:

  • OpenSSL 3.0 Migration – Details on deprecated cryptographic algorithms and new default cipher configurations
  • V8 9.6 Updates – JavaScript engine changes that may affect performance or deprecated language features
  • Import Assertions – Changes to JSON module imports requiring explicit assertion syntax

Where to Find Node.js 18 Breaking Changes

The Node.js 18 (Hydrogen) LTS line brought global fetch API support, Web Streams API integration, and the node: prefix import standardization. The changelog tracks breaking changes related to these new features as well as V8 10.1 and OpenSSL 3.0.x updates.

Find the authoritative list at:

doc/changelogs/CHANGELOG_V18.md

Direct link: https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V18.md

Key breaking change categories in this file include:

  • Global Fetch Implementation – Behavioral differences from undici and standardization of Request/Response objects
  • Web Streams API – Breaking changes in stream handling and backpressure mechanisms
  • OpenSSL 3.0.x Updates – Continued cryptographic hardening from Node 17
  • Test Runner Module – Experimental status changes and API surface modifications

How to Search for Specific Breaking Changes

When upgrading from Node 16 to 18, you can programmatically scan the changelogs to extract breaking change entries without manually reading every version.

Search for breaking change headers across all three versions:


# Search all three changelogs for breaking change sections

grep -i "breaking changes" -n doc/changelogs/CHANGELOG_V1{6,7,8}.md

Filter for specific APIs or subsystems:


# Find OpenSSL-related breaking changes in Node 17 and 18

grep -i "openssl" doc/changelogs/CHANGELOG_V17.md doc/changelogs/CHANGELOG_V18.md | grep -i "breaking"

Key Breaking Change Categories Across Node 16-18

Understanding the high-level categories of breaking changes helps prioritize your upgrade testing.

V8 Engine Upgrades

  • Node 16: V8 9.0 introduced performance improvements and deprecated certain JavaScript syntax patterns
  • Node 17: V8 9.6 with continued optimizations
  • Node 18: V8 10.1 with new language feature support and potential deoptimization changes

OpenSSL 3.0 Migration

The transition to OpenSSL 3.0 in Node 17 represents the most critical breaking change:

  • Legacy cryptographic algorithms (MD4, DES, RC2, etc.) are disabled by default
  • New provider-based architecture requires explicit configuration for legacy systems
  • Stricter certificate validation and TLS 1.3 handling

HTTP and Networking Changes

  • Node 16: Default server.headersTimeout adjustments and security hardening
  • Node 18: Global fetch implementation with different behavior from node-fetch or undici standalone

Module System Updates

  • Node 16: Stable implementation of assert module promises and timers promises
  • Node 18: Mandatory node: prefix for core module imports in certain contexts and experimental test runner module

Code Examples for Version-Specific Handling

When upgrading across Node 16 to 18, implement runtime checks to handle version-specific behaviors.

Detecting OpenSSL 3.0 Compatibility

Check for OpenSSL 3.0 features introduced in Node 17+:

// utils/checkOpenSSL.js
const crypto = require('crypto');

function checkOpenSSL3Compatibility() {
  // OpenSSL 3.0 was introduced in Node.js 17.0.0
  const nodeVersion = process.version;
  const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0], 10);
  
  if (majorVersion >= 17) {
    try {
      // Attempt to use a modern cipher that may behave differently in OpenSSL 3.0
      crypto.createCipheriv('aes-256-gcm', 
        crypto.randomBytes(32), 
        crypto.randomBytes(16)
      );
      console.log('OpenSSL 3.0+ crypto operations compatible');
    } catch (error) {
      console.error('OpenSSL 3.0 compatibility issue:', error.message);
    }
  } else {
    console.log(`Running on Node.js ${nodeVersion} (pre-OpenSSL 3.0)`);
  }
}

module.exports = { checkOpenSSL3Compatibility };

Checking for Global Fetch Availability

Node 18 introduced global fetch. Detect its availability for cross-version compatibility:

// utils/fetchCompat.js
function getFetchImplementation() {
  // Node 18.0.0+ has global fetch
  if (globalThis.fetch) {
    return globalThis.fetch;
  }
  
  // Fallback for Node 16-17
  console.warn('Global fetch not available. Consider upgrading to Node 18+ or installing undici.');
  return null;
}

async function makeRequest(url) {
  const fetch = getFetchImplementation();
  if (!fetch) {
    throw new Error('Fetch implementation not available');
  }
  
  const response = await fetch(url);
  return response.json();
}

module.exports = { makeRequest, getFetchImplementation };

Validating Node Version for Upgrade

Programmatically verify your runtime meets Node 18 requirements before deployment:

// utils/validateVersion.js
const semver = require('semver');

const REQUIRED_VERSION = '18.0.0';
const currentVersion = process.version;

if (semver.lt(currentVersion, REQUIRED_VERSION)) {
  console.error(
    `ERROR: Node.js ${currentVersion} is below the required ${REQUIRED_VERSION}. ` +
    `Review breaking changes in CHANGELOG_V16.md, CHANGELOG_V17.md, and CHANGELOG_V18.md ` +
    `at https://github.com/nodejs/node/tree/main/doc/changelogs/`
  );
  process.exit(1);
}

console.log(`Node.js ${currentVersion} meets upgrade requirements.`);

Summary

Frequently Asked Questions

Where are the official Node.js 16 to 18 breaking changes documented?

The official breaking changes for Node.js 16, 17, and 18 are documented in the version-specific changelog files located in the doc/changelogs/ directory of the nodejs/node repository. Specifically, reference CHANGELOG_V16.md for Node 16 (Gallium), CHANGELOG_V17.md for Node 17, and CHANGELOG_V18.md for Node 18 (Hydrogen). Each file contains "Notable Changes" and "Breaking Changes" sections that detail API removals, behavioral modifications, and deprecation notices.

What is the most critical breaking change when upgrading from Node 16 to Node 18?

The most critical breaking change when upgrading from Node 16 to Node 18 is the OpenSSL 3.0 migration, which was introduced in Node 17 and carried forward into Node 18. OpenSSL 3.0 disables legacy cryptographic algorithms (such as MD4, DES, and RC2) by default and enforces stricter certificate validation. This can cause applications using older crypto functions or connecting to legacy TLS servers to fail. Additionally, Node 18 introduces the global fetch API, which may conflict with existing polyfills or libraries that previously defined global fetch.

How can I programmatically check for breaking changes in the Node.js source?

You can programmatically scan the Node.js changelog files for breaking changes using command-line tools like grep or by parsing the markdown files with a script. For example, to find all breaking change entries across Node 16, 17, and 18, run:

grep -i "breaking changes" -n doc/changelogs/CHANGELOG_V1{6,7,8}.md

To search for specific subsystems like OpenSSL or V8:

grep -i "openssl" doc/changelogs/CHANGELOG_V17.md doc/changelogs/CHANGELOG_V18.md | grep -i "breaking"

This approach allows you to extract line numbers and context for automated migration auditing.

Are there breaking changes in Node.js 18's global fetch implementation that affect existing code?

Yes, Node.js 18 introduces a global fetch API based on the undici HTTP client, which brings several breaking changes compared to third-party polyfills like node-fetch or cross-fetch. The native implementation strictly follows the Fetch Standard, meaning:

  • Response bodies are now ReadableStream instances rather than Node.js streams, requiring different handling for piping or consuming data.
  • Header casing is normalized to lowercase automatically, which may break code expecting case-sensitive header access.
  • Redirect behavior defaults to follow with a maximum of 20 redirects, differing from some polyfill defaults.
  • URL parsing is stricter, rejecting certain malformed URLs that previous implementations might have accepted.

Applications using existing fetch polyfills should test thoroughly when upgrading to Node 18 and may need to remove polyfills to avoid conflicts with the global implementation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →