Node.js 20 End of Life: Upgrade Safely
Node.js 20 reached end of life on April 30, 2026, which means it no longer gets security fixes, and you should move to Node.js 22 or Node.js 24 as soon as you reasonably can.
This guide is for site owners, developers, and agencies who still have an app, API, or build pipeline running on Node.js 20 (or who just got an alert saying it's unsupported). You'll get the official release schedule with exact dates, a plain explanation of what "end of life" actually means, and a safe, step-by-step order for upgrading both a regular app and a Docker container without breaking production.
Why this matters right now
Node.js is the JavaScript runtime that powers a huge share of web backends, from small Express APIs to full e-commerce platforms. Like most software projects, it releases a new major version roughly every six months, and each version has a limited support window. Once that window closes, the Node.js project stops shipping security patches for it, no matter how serious the next bug turns out to be.
Node.js 20 end of life isn't a guess or a marketing term. It's a published date set by the Node.js Release Working Group, the group that maintains the official schedule at github.com/nodejs/Release. If your app or your hosting still shows Node 20 when you check the version, it is currently running on a line that will never receive another fix.
The four stages of a Node.js release
Every Node.js major version moves through the same four stages before it's retired:
- Current: the newest release. It gets new features fast but isn't recommended for production yet, since it hasn't had time to stabilize.
- Active LTS (Long-Term Support): the version most production apps should run. It gets bug fixes, security patches, and some performance improvements, but no breaking changes.
- Maintenance LTS: the version still gets critical bug fixes and security patches, but new features stop. This is a safe place to sit for a while, but it's also the last stop before end of life.
- End of life (EOL): support stops completely. No more security patches, no more bug fixes, ever, for that line. Staying on an EOL version doesn't crash your app, but it does mean nobody is watching your back when the next vulnerability is found.
Node.js release and end-of-life dates
Here's the current schedule, straight from the Node.js Release Working Group's schedule file, read on October 24, 2026:
| Version | Started | Active LTS from | Maintenance LTS from | End of life |
|---|---|---|---|---|
| Node.js 18 | - | - | - | 2025-04-30 (already past) |
| Node.js 20 | 2023-04-18 | 2023-10-24 | 2024-10-22 | 2026-04-30 (already past) |
| Node.js 22 | 2024-04-24 | 2024-10-29 | 2025-10-21 | 2027-04-30 |
| Node.js 24 | 2025-05-06 | 2025-10-28 | 2026-10-20 | 2028-04-30 |
| Node.js 26 | 2026-05-05 | 2026-10-28 | 2027-10-20 | 2029-04-30 |
| Node.js 25 (odd, never LTS) | 2025-10-15 | never | never | 2026-06-01 (already past) |
Two things worth noticing. First, odd-numbered lines like Node.js 25 never become LTS at all. They're short-lived releases meant for experimentation, so they are the wrong choice for a production app even while they're new. Second, Node.js 22 and Node.js 24 are both currently in Maintenance LTS, and Node.js 26 is about to become Active LTS on October 28, 2026. If you're reading this after that date, Node 26 is likely your newest fully supported option.
What "no more fixes" actually means
It's tempting to think an EOL version is fine as long as it still runs. It isn't, because the risk isn't about the code breaking, it's about the code staying broken. The Node.js project's own October 2026 security release post makes this explicit: when a security release goes out, every end-of-life version is considered affected, whether or not anyone checks it. That release fixed ten CVEs (publicly tracked vulnerability identifiers) across v22.23.4, v24.22.1, and v26.12.1, four of them rated high severity. Node.js 20 and Node.js 18, both already EOL, got nothing. If one of those ten issues also exists in Node 20's code, which is likely for anything that's been in the runtime for a while, it simply stays unpatched there.
This is the same pattern that shows up across any outdated software stack, not just Node.js. If you want a broader sense of what an attacker actually looks for on a typical small business site, our guide on whether your website is hackable walks through the common entry points, and outdated server software is consistently one of them.
Which Node.js version should you move to
As of today, your realistic options are:
- Node.js 22: Maintenance LTS, supported until April 30, 2027. A smaller jump from Node 20, good if your app or dependencies are older and you want the least disruptive move.
- Node.js 24: Maintenance LTS, supported until April 30, 2028. The better choice if you want more runway before you have to think about this again.
- Node.js 26: becomes Active LTS on October 28, 2026, supported until April 30, 2029. The longest runway, but newer, so give it a little more testing time before production if you're risk-averse.
Avoid Node.js 25 and any other odd-numbered version for anything that needs to stay running reliably. Those lines never reach LTS and already have short, fixed lifespans.
Step 1: check what you're actually running
Before doing anything else, confirm the real version in production, not just what's in your package.json engines field. Run:
node -v
Run it on the actual server or inside the actual container that serves traffic. This matters because a Docker base image keeps whatever Node.js version was baked into it until someone rebuilds and redeploys that image. Your Dockerfile can say FROM node:22 while the container that's actually running in production is still on an old build from months ago. Check the running container directly, not just the source files.
Step 2: safe upgrade order for an app
Don't just bump the version number and deploy. Follow this order:
- Read the release notes for the target version and look specifically for removed or changed APIs that might affect your code.
- Run your test suite against the new version in CI before touching anything else, so you catch breakage in an automated pipeline instead of in production.
- Run
npm ciandnpm auditto reinstall dependencies cleanly from your lockfile and check for known vulnerabilities in your packages themselves. - Deploy to staging and exercise the app the way real users would, including anything that touches native modules (packages with compiled C/C++ code), since those need to be rebuilt for the new Node.js major version.
- Deploy to production, but keep the old image or deployment available so you can roll back fast if something unexpected surfaces.
Your npm lockfile (package-lock.json) pins exact package versions, which keeps npm ci deterministic. That's useful here because it means the only real variable you're testing is the Node.js version itself, not shifting dependency versions at the same time.
Step 3: safe upgrade order for containers
If your app runs in Docker, the steps are the same, with one extra wrinkle: the base image.
- Update the
FROM node:20(or similar) line in your Dockerfile to the target version, for exampleFROM node:24. - Rebuild the image from scratch, don't just restart the old container, since a restart keeps the old Node.js binary.
- Run the image locally or in CI and confirm
node -vinside the container matches what you expect. - Rebuild any native modules inside the new image (this usually happens automatically during
npm ciif your build steps are in the right order, but check for prebuilt binaries that assume the old Node ABI). - Push the new image to staging, test, then roll it out to production, keeping the previous image tagged and available for rollback.
A quick pre-upgrade checklist
- [ ] Confirmed the live Node.js version with
node -von the actual server or container - [ ] Read the target version's release notes for removed APIs
- [ ] Full test suite passes in CI on the new version
- [ ]
npm ciandnpm auditrun clean (or flagged issues are understood and accepted) - [ ] Native modules rebuilt against the new Node.js version
- [ ] Staging deployment tested under real usage patterns
- [ ] Old image or deployment kept available for rollback
- [ ] Production deployment monitored after rollout
If your team is also responsible for the server configuration around the app, it's worth a quick pass on basics like security headers while you're already in there. Our free security headers checker is a fast way to see what's missing.
Key takeaways
- Node.js 20 reached end of life on April 30, 2026, per the official Node.js release schedule, and it will never receive another security fix.
- Move to Node.js 22 (supported to April 2027), Node.js 24 (to April 2028), or Node.js 26 once it's Active LTS on October 28, 2026 (to April 2029). Skip odd-numbered versions like Node.js 25, they never become LTS.
- Check the real running version with
node -von the actual server or inside the container, since a Docker image keeps its old Node.js until it's rebuilt and redeployed. - Upgrade in order: read release notes, test in CI, run
npm ciandnpm audit, rebuild native modules, deploy to staging, then production, with a rollback plan ready. - End-of-life Node versions are affected by every new security release, as the Node.js project's own October 2026 security post confirms, even though they never get the patch.
Upgrading your Node.js version fixes one specific risk. It won't tell you whether your login forms, API endpoints, or server configuration have separate problems. If you want an honest, affordable second opinion, a real person manually reviewing your site for $49 through our pricing is a reasonable next step, and you can also run a free passive security check first with no card and no login required.
A real human security engineer audits your whole site by hand and sends a full report: every issue, its severity, and the exact fix. From $49, with a 14-day money-back guarantee.
See pricing