Node.js 20 EOL in April: Your Upgrade Gameplan
Node.js 20 EOL lands on April 30, 2026. If your production still rides 20.x, you’re in the red zone. The good news: you have two safe landings—22.x and 24.x—and a handful of decisions that, if made cleanly this month, turn a stressful scramble into a straightforward upgrade. This isn’t theory; it’s a field-tested plan to navigate Node.js 20 EOL with minimal downtime and no surprises.

Why this matters now: dates, versions, and support windows
Here’s the thing: platform clocks don’t stop for backlogs. Node 20 leaves support on April 30, 2026. Node 22 is in Maintenance LTS with security fixes through April 2027. Node 24 is Active LTS and supported through April 2028. If you deploy to major platforms, the ecosystem is already nudging you forward: Vercel defaults to Node 24 for new projects, and Heroku uses 24.x if you don’t pin a version. On AWS Lambda, Node 22 is the long runway; Node 20 runtimes track that April 2026 community EOL and enter AWS’s deprecation window later this year. Translate that into risk: every week you delay increases the chance of blocked builds, surprise CVEs with no upstream fixes, and cloud runtime friction.
Bottom line: treat March and April as your upgrade sprint. Anything longer and you’ll be negotiating exceptions with vendors or running unpatched code.
Should you jump to 22 or 24? A fast decision tree
Pick one, commit, and move. Here’s the decision logic I use with teams:
- Choose Node 22 if you need the shortest validation path and have native addons that lag new ABIs. 22.x is conservative, battle‑tested, and receives fixes to April 2027.
- Choose Node 24 if you want the longest runway and newer platform features with minimal churn. 24.x is Active LTS, supported through April 2028, and is the default on several PaaS setups.
Feature deltas you’ll feel when you choose 24:
- V8 uplift (13.x series) and modern JS niceties that speed hot paths and unlock newer language features.
- npm 11 in the box; it’s faster and can change lockfile/install behavior—great for monorepos, but test your CI cache strategy.
- URLPattern is global, which simplifies routing and URL matching without a helper lib.
- Test runner improvements that auto‑await subtests—less flake, fewer gotchas.
- Permission model maturing behind a simpler
--permissionflag; more on how to adopt it safely below.
If you’re mid‑release or frozen for a customer event, ship 22 now and schedule a calm move to 24 in Q3. If you can tolerate a slightly deeper test cycle today for fewer upgrades tomorrow, go straight to 24.
Node.js 20 EOL: What actually breaks?
“EOL” doesn’t mean your app stops running on May 1. It means you lose upstream security patches and fixes. That cascades:
- Security exposure compounds: a medium‑severity CVE in a transitive dependency plus an unpatched Node runtime becomes a real incident vector.
- Cloud friction: managed runtimes throttle or deprecate 20.x. You can be locked out of new regions or features and face forced cutovers on their schedule.
- Tooling drift: CI images, buildpacks, and serverless frameworks drop testing on 20.x first. Today’s harmless warning becomes tomorrow’s hard error.
There are also behavioral changes moving from 20 → 22/24 you should scan for:
- Native addons (sharp, bcrypt, sqlite3, etc.) often need fresh prebuilds for the new V8/Node-API combos. Pin exact versions or rebuild in CI.
- HTTP and fetch stack updates
- npm 11 changes install/link behavior in edge cases; watch workspace and optional dependency handling.
- ESM/CommonJS interop is smoother in 22/24, but custom loaders and exotic path resolution hacks can regress—test them.
The low‑drama migration framework (two 10‑day sprints)
You don’t need a three‑month program. You need two focused sprints and a clean exit criterion.
Sprint 1 (Days 1–10): Inventory, dual‑track CI, and dependency reality
- Create a runtime matrix: current (20.x) and target (22.x or 24.x). Run your full test suite on both in parallel CI. Gate merges on matrix green.
- Lockfile discipline: regenerate
package-lock.json(orpnpm-lock.yaml/yarn.lock) on the target Node version. Commit it. Cache installs per‑Node in CI to avoid cross‑version poisoning. - Native modules check: audit for packages with native bindings. Pre‑test them on the target version; if prebuilds are missing, switch to maintained forks or compile from source in CI.
- Start a minimal
--permissionpilot (opt‑in only): run a subset of tests undernode --permissionallowing only fs‑read and network to known hosts. Record denials; don’t block the pipeline yet. - Pin engines: add
"engines": { "node": "22.x" }or"24.x"topackage.json. That signals the switch across dev, CI, and PaaS. On Vercel/Heroku, this also aligns deploys with your test runtime.
Sprint 2 (Days 11–20): Fixes, load tests, and canary deploys
- Fix test and type issues: most breakages are path resolution, timers, or subtle HTTP differences. Remove polyfills you no longer need.
- Benchmark real workloads: choose three endpoints or jobs. Compare p95 latency and error rates between 20 and the target version under realistic load. Track CPU and RSS—V8 bumps can shift memory profiles.
- Canary 5–10% of traffic on the new runtime. Watch for memory leaks, unhandled rejections, and queue backlogs. Roll forward by business unit, not by repo size.
- Harden
--permissionfor build/test jobs that run untrusted code (generators, MDX processing, AI agents). Allow only what the job needs.
Exit criteria
- All repos green in the two‑version CI matrix for 7 consecutive days.
- Canary traffic stable with equal or better p95 latency and error budget.
- Roll plan approved and scheduled; runtime pinned in infra as code.
Cloud runtime implications you should plan for
Vercel: Node 24 is available and commonly the default for new projects and sandboxes. If you don’t set engines.node, you may already be on 24 in new deployments. Validate your lockfiles and serverless function cold starts before promoting.
Heroku: The platform supports 22/24 and defaults to 24.x when you don’t specify engines. Add "engines": { "node": "24.x" } if you want explicitness and automatic security patches within 24.x.
AWS Lambda: Use nodejs22.x for the long runway. Node 20 hits community EOL on April 30, 2026 and then rides AWS’s deprecation schedule later in the year; plan that cutover now so you’re not compressing testing into their deadline window.
Tip: Bake runtime checks into health endpoints. Log process.version and the V8 version. It makes audits and incident triage saner.
Adopt the permission model without breaking everything
Node’s permission model lets you run with “default deny” for filesystem, env, and network. It’s powerful—and easy to over‑tighten. Roll it out in phases:
- Observe first: run a nightly job under
--permissionwith permissive allows, and log denials. Don’t fail the build yet. - Scope by job: enable strict policies for content processing, codegen, or anything that ingests untrusted input. Leave web servers permissive while you learn.
- Gradually lock down: start with
--allow-fs-readfor your repo/workspace and--allow-env=NODE_ENV. Then add network allow‑lists for known hosts (DB, cache, APIs). - Document exceptions: if a test runner needs child processes or a bundler writes outside
./dist, make that explicit with comments and a TTL on the exception.
For teams building AI features or plugin ecosystems, permissions are cheap defense‑in‑depth. If that’s you, our guide on runtime egress controls pairs well with this model—see Egress Firewalls for AI Agents.
People also ask
Is Node.js 20 secure after EOL?
No. You may run it, but you won’t receive upstream security patches. A routine dependency vuln plus an unpatched runtime is an avoidable risk. Move.
Can I stay on Node 20 in AWS Lambda a bit longer?
Temporarily, yes—but you’ll hit AWS’s deprecation window and lose updates and new region access. Migrate functions to nodejs22.x now and you avoid a forced sprint later.
Should greenfield projects start on 22 or 24?
24. New apps deserve the longest support runway. If a vendor SDK blocks you on 24 today, file the issue and pin 22 briefly.
What about odd versions like 25?
They’re “Current” and short‑lived; great for experimentation, not for production. Stick to even LTS lines in prod.
A pragmatic dependency and CI checklist
Before you flip the runtime, run this checklist in each repo:
- Engines: set
"engines.node"to22.xor24.x. Verify your PaaS picks it up. - Lockfiles: regenerate on the target Node, commit, and warm caches per‑version in CI.
- Native addons: pin known‑good versions or compile from source. Add a CI job that fails if prebuilds are missing.
- Testing: run your suite with
--testimprovements on 24; remove custom subtest awaits and retired polyfills. - Observability: emit
process.versionandprocess.versions.v8at startup. Add a metric tag for the Node major to compare latency and error rates pre/post. - Permissions: add an optional CI stage that executes under
--permissionand logs denials. Gate only the riskiest jobs at first. - Containers: move to a 22 or 24 base image. If you use multi‑arch, validate arm64 images as they often deliver better price/perf on modern clouds.
If you deploy on Vercel and are still carrying legacy config, review your project settings and pin a runtime. While you’re there, this is a good moment to retire old config files and follow a modern rollout pattern—our zero‑downtime Vercel config guide shows one that works well.
Version timelines at a glance (mark your calendar)
Today is March 1, 2026. The key dates you’re planning around:
- April 30, 2026: Node 20 reaches end of life.
- Through April 2027: Node 22 receives security fixes (Maintenance LTS).
- Through April 2028: Node 24 receives security fixes (LTS).
If your organization needs an interim, risk‑managed plan to cross April 30 without drama, we’ve published a concise, timesboxed method here: Node.js EOL 2026: Your 45‑Day Upgrade Playbook.

Let’s get practical: reference implementation notes
These are small, high‑leverage changes I recommend making during the upgrade:
- Standardize on
node --run <script>in 22/24 to invoke package scripts directly. It reduces shell weirdness across Windows/macOS/Linux runners. - Replace ad‑hoc HTTP clients with the built‑in
fetch/Undici where feasible. Fewer dependencies, fewer CVEs. - Use URLPattern for routing utilities and URL validation; cut a lightweight, thoroughly‑tested wrapper and share it across services.
- Re‑baseline performance budgets. New V8 + npm 11 can shift startup and memory—update p95 targets so you’re not chasing phantom regressions.
What to do next (this week)
- Pick a target: 22 for speed, 24 for runway. Write it down.
- Flip CI: run tests on 20 and your target today. Make it impossible to merge red.
- Schedule a canary for one production service next week. Set hard rollback and success criteria.
- Pin engines and your cloud runtime. Verify the version in staging logs.
- Plan permissions for one job that handles untrusted input; enable
--permissionin a non‑blocking stage.
If you want a partner who’s done this at scale, see what we build on the daily in our portfolio, skim how we approach upgrades on what we do, and reach out via contacts. We can take you from Node 20 to 22/24 without surprises.

Comments
Be the first to comment.