Upgrade to Node.js 20
Node.js 20 reached end-of-life on 2026-04-30 and is no longer a recommended target — upgrade to the active Node 24 LTS instead. This page is kept for teams documenting the Node 20 step; the same native-module rebuild, OpenSSL 3, and removed-API mechanics apply when moving onto any newer major.
Last verified · Updated May 22, 2026
⚠ Node 20 is end-of-life — target Node 24 instead
Node 20 left maintenance and reached end-of-life on 2026-04-30, so it no longer receives security patches. Do not land on Node 20 today. Use the Upgrade to Node.js 24 hub; this page remains for reference and because the rebuild/OpenSSL 3/removed-API mechanics it describes still apply to any modern major.
Node 20 was the active LTS from 2023 until it reached end-of-life on 2026-04-30. Most breakage on the Node 20 step came from native-module ABI rebuilds, OpenSSL 3 stricter defaults, and removed deprecated APIs — not from rewriting code. Those same mechanics apply when you move on to the current Node 24 LTS, which is now the recommended target.
Who should upgrade
- Everyone on Node 20 — it is now end-of-life. Move on to the active Node 24 LTS via the Upgrade to Node.js 24 hub.
- Anyone still on Node 16 or 18 — both are end-of-life and receive no security patches.
- Services that want built-in fetch and to drop a node-fetch/axios polyfill dependency.
Who should wait
- Apps blocked by a critical native dependency without a prebuilt binary for the target major — but do not stay on EOL Node 20; pin to the Node 22 maintenance LTS as a stopgap instead.
- Builds pinned to an OpenSSL 1.1 behavior that breaks under OpenSSL 3's stricter defaults until the code is fixed.
What changed
- Stable built-in test runner via the node:test module — no external test framework required for basic suites.
- Global fetch, Request, Response, and Headers are available without a polyfill.
- Several previously --experimental flags graduated toward stable.
- Experimental Permission Model (--experimental-permission) to restrict file system, child process, and worker access.
- Newer V8 engine with updated language and performance features.
- Ships with an updated bundled npm and is built against OpenSSL 3.
⚠ Rebuild native modules before debugging runtime failures
A new Node major bumps the V8/N-API ABI, so any package with native bindings (binding.gyp, prebuilt .node files) must be reinstalled or rebuilt with
npm rebuild. Many 'mysterious' crashes right after an upgrade are stale native addons, not application bugs.
Recommended upgrade path
Fast path for a service moving onto the Node 20 LTS
# 1. Pin the new version locally
nvm install 20 && nvm use 20
node --version
# 2. Reinstall and rebuild native modules against the new ABI
rm -rf node_modules && npm ci
npm rebuild
# 3. Run the test suite on Node 20
npm testLTS support matrix
| Version | Status | LTS | Released | End of life |
|---|---|---|---|---|
| Node 16.x | End-of-life | Yes | 2021-04-20 | 2023-09-11 |
| Node 18.x | End-of-life | Yes | 2022-04-19 | 2025-04-30 |
| Node 20.x | End-of-life | Yes | 2023-04-18 | 2026-04-30 |
| Node 22.x | Maintenance LTS | Yes | 2024-04-24 | 2027-04-30 |
| Node 24.x | Active LTS | Yes | 2025-05-06 | 2028-04-30 — target this |
AI-assisted migration workflow
Upgrade this project to Node.js 20 LTS. First inspect engines.node, .nvmrc, the CI node-version matrix, the Docker base image, and any native dependencies. Then bump the engine and pin .nvmrc, update CI and Docker, run `npm ci` followed by `npm rebuild`, and run the test suite. Triage failures: rebuild native modules first, then check for removed deprecated APIs and OpenSSL 3 fallout. Run install and tests after each step and report before continuing.Safety: Incremental edits only. Pause for review after the engine/CI changes and after the native rebuild. Do not silently upgrade unrelated dependencies.
PR review checklist
- engines.node, .nvmrc, the CI matrix, and the Docker base image all reference Node 20
- node_modules was reinstalled and native modules rebuilt against the new ABI
- No removed/deprecated Node APIs remain in changed code paths
- Any node-fetch/axios used only as a fetch polyfill was reviewed against built-in fetch
- No new Node deprecation warnings appear in the test output
Rollback strategy
- Keep the engine bump, CI/Docker changes, and native rebuild in separate commits.
- Revert .nvmrc and the Docker base image to the previous LTS and reinstall if a blocking native incompatibility appears.
- Hold the upgrade behind a release branch until the full test suite is green on Node 20 in CI.
Common errors
- 'Module did not self-register' or 'NODE_MODULE_VERSION' mismatch — rebuild native modules with npm rebuild.
- TLS/crypto errors after OpenSSL 3 — see the fix-node-dependency-errors workflow.
- 'engine "node" is incompatible' from a dependency — find a Node 20-compatible release or replacement.
Related migration paths
- Migrate Node.js CommonJS to ES Modules — Next step forward
- Node.js 16 to Node.js 20 Migration Guide — Upgrade path to same target
- Node.js 18 to Node.js 20 Migration Guide — Upgrade path to same target
- Node.js 18 to Node.js 24 Migration Guide — Related version path
- Node.js 20 to Node.js 24 Migration Guide — Next step forward
- Upgrade to Node.js 24 — Related version path
- Fix Node.js Dependency Errors — Earlier step in the upgrade chain
Official sources
- Node.js releases — nodejs/node (reliability 92%)
- Node.js 20 is now available — nodejs.org (reliability 98%)
- Node.js ECMAScript Modules — nodejs.org (reliability 98%)
- Node.js Release Working Group — release schedule — nodejs/Release (reliability 98%)
Copy-ready AI prompts
Structured prompts for an AI coding assistant. Inspect first, then execute incrementally, and keep a human in the review loop.
Repo inspection: Repo inspection prompt
You are helping with a Node.js migration: upgrade to Node.js 20 LTS.
Do not edit files yet. First inspect the repository and report:
1. The current Node version targets: the "engines.node" field in package.json, the .nvmrc / .node-version file, and the node-version used in CI (.github/workflows/*.yml) and any Dockerfile base image.
2. The module system: whether package.json sets "type": "module", and the mix of .js / .cjs / .mjs files.
3. Native modules (packages with binding.gyp or install scripts) that must be rebuilt against the new ABI.
4. Usage of deprecated or removed APIs surfaced by the new major's deprecations (e.g. legacy url.parse patterns, the old assert API, removed crypto/buffer constructors).
5. The install, build, and test commands and whether the lockfile is committed.
Return: a risk summary, the highest-risk files and dependencies, a suggested migration order, the commands to run before editing, and any questions that need human confirmation.Safety: Inspection only. The agent must not modify files in this step.
Works with Claude Code, Cursor, GitHub Copilot.
Migration execution: Migration execution prompt
Perform the migration (upgrade to Node.js 20 LTS) one concern at a time.
Work in this order and pause for review after each: (1) bump "engines.node" in package.json and pin the new version in .nvmrc, (2) update every CI matrix entry and Docker base image to the new Node version, (3) reinstall and rebuild native modules with `npm rebuild`, (4) run the test suite and triage runtime failures, (5) replace any deprecated/removed APIs surfaced during inspection.
After each step run the project's install and test commands and report results before continuing. Do not bundle unrelated refactors or upgrade dependencies that are not required by the Node bump.Safety: Apply changes incrementally and keep each step reviewable. Rebuild native modules before assuming a failure is a code problem.
Works with Claude Code, Cursor, GitHub Copilot.
Test plan
Commands
node --versionnpm cinpm rebuildnpm testnpm run build
Manual checks
- Native modules: confirm packages with native bindings load without ABI/version errors at runtime.
- Startup: boot the app on the new Node version and watch for new deprecation warnings.
- Globals: verify code relying on built-in fetch, the test runner, or other newly-stable APIs behaves the same locally and in CI.
Regression risks
- Native addons compiled against the old ABI failing to load until rebuilt.
- Deprecated APIs removed in the new major breaking code paths not covered by tests.
- Dependencies that declare an engines range excluding the new Node version.
Acceptance criteria
- Install, build, and the full test suite pass on the target Node version.
- CI, .nvmrc, and the Docker image all reference the same Node version.
- No new Node deprecation warnings appear in the test output.
Frequently asked questions
Should I still upgrade to Node 20?
No — Node 20 reached end-of-life on 2026-04-30 and no longer receives security patches. Skip it and go straight to the active Node 24 LTS (use the Upgrade to Node.js 24 hub). If a dependency is not yet Node 24-ready, pin to the Node 22 maintenance LTS rather than staying on EOL Node 20.
Do I have to remove node-fetch now that fetch is built in?
No. Built-in fetch was added experimentally in Node 18 and marked stable in Node 21, so it is stable on the current Node 22/24 LTS lines — but keeping a node-fetch/axios dependency still works. Removing the polyfill is an optional cleanup you can do incrementally once you have confirmed the built-in matches your usage.