Node 20 reaching end-of-life is not just a reminder to run nvm install 22. It is a visibility event for a bigger shift: JavaScript is now managed infrastructure, and the runtime upgrade path is increasingly controlled by cloud support windows, CI images, serverless contracts, and compliance dashboards instead of by application developers alone.
The date is not ambiguous. The Node.js release schedule lists v20 Iron with a start date of April 18, 2023, maintenance start on October 22, 2024, and end-of-life on April 30, 2026. Node 22 Jod runs until April 30, 2027. Node 24 Krypton runs until April 30, 2028. That looks tidy on a project calendar. In production, it is messier because Node is no longer just a binary on a developer laptop or a base image in a Dockerfile.
It is the language runtime baked into Lambda. It is the default installed version on a GitHub Actions image. It is the execution layer inside a managed WordPress platform. It is the JavaScript option exposed through Azure Functions. It is a policy object that cloud providers patch until they stop patching it. The old Node upgrade story was mostly about syntax, package compatibility, and maybe native module rebuilds. The new story is about who owns the execution environment after the upstream project walks away.
The security timing sharpens the point. On March 24, barely more than a month before the cutoff, the Node project shipped security releases for 25.x, 24.x, 22.x, and 20.x. The advisory covered high-severity remote denial-of-service issues like CVE-2026-21637 in TLS SNICallback handling and CVE-2026-21710 in req.headersDistinct when a request contains a __proto__ header. It also covered HTTP/2 resource exhaustion, an HMAC timing side-channel, permission model bypasses, URL assertion crashes, and V8 HashDoS behavior.
That list matters because it makes the EOL boundary less abstract. Node 20 did not become boring and safe before it died. It was still receiving fixes for bugs that can crash servers, leak timing information, or turn attacker-shaped inputs into process-level trouble. After April 30, the upstream answer changes from “upgrade to v20.20.2” to “you should not be on this line.” The risk is not that every Node 20 process becomes compromised on May 1. The risk is that the next one of these issues becomes a negotiation with your platform vendor, your extended support provider, or your own ability to fork and patch a runtime you probably do not want to maintain.
Cloud platforms turn that maintenance boundary into operational choreography. AWS Lambda’s runtime documentation describes the managed-runtime deprecation model plainly: when a runtime is deprecated, security updates cease and technical support ends; the console blocks creates and updates first, then later AWS blocks function creation and function updates through all methods. Invocations do not stop immediately. That is the dangerous comfort. A deprecated function can keep serving traffic while the layer underneath it leaves the patch stream.
AWS also shipped Node.js 24 support for Lambda, and the details are a useful antidote to lazy upgrade advice. Node 24 is not just “newer Node.” In Lambda it comes with a new runtime interface client, removes callback-based handlers, removes old context methods like context.succeed, context.fail, and context.done, and changes unresolved-promise behavior so Lambda no longer waits for background work after a handler returns or a response stream ends. It also sits on Amazon Linux 2023, which changes container-image habits for anyone still assuming yum-era base images.
That makes the obvious answer, “just move to 24,” less obvious for real systems. Node 24 is the longer-lived target, but it can force application semantics to change. Node 22 is shorter-lived, with end-of-life on April 30, 2027, but it is the more conservative landing zone for a lot of production Lambda code. This is what managed infrastructure does to language upgrades: it turns a runtime lifecycle into a product decision, an architecture decision, and a migration-risk decision at the same time.
WordPress VIP’s Node 20 EOL notice shows the same pattern from another angle. VIP told customers that Node v20 would no longer receive security patches after April 30 and that environments would be automatically moved to Node v22, with non-production environments updated on April 24 and production on April 30. The recommended work was not exotic: test locally, reinstall dependencies fresh, update non-production, then production. But the important word is “automatically.” The platform is not waiting for every app team to discover the release calendar. It is enforcing the lifecycle.
GitHub Actions has a parallel version of the problem. A runner-image issue filed against ubuntu-latest points out that Node 20 transitions to EOL on April 30, 2026, while ubuntu-latest, equivalent to ubuntu-24.04, still had Node 20.20.x as the default installed version. macOS and Windows latest images were already on Node 22. The issue is mundane, which is exactly why it matters. A CI image default is infrastructure. If the default runtime is EOL, every workflow that quietly relies on that default inherits the lifecycle problem without declaring it.
This is the part that keeps repeating across modern developer infrastructure. The runtime boundary used to be visible. You installed Node on a host. You chose a Docker tag. You ran a version manager. Now the runtime can be implicit in a managed function, implicit in a buildpack, implicit in a hosted runner, implicit in a platform UI. That saves time until the calendar moves. Then the hidden dependency becomes a platform migration.
The cultural mistake is treating EOL as housekeeping. Housekeeping is deleting a stale branch. Runtime EOL is different. It is a withdrawal of upstream responsibility from a layer that parses attacker input, terminates TLS, handles HTTP, links native modules, executes package-manager hooks, and hosts application code. If the layer is managed by somebody else, EOL is also a transfer of responsibility. The cloud provider may patch it for a while. An extended-support vendor may sell fixes. A platform may force an upgrade. A CI image maintainer may change a default. None of those are the same as your application team actually owning the dependency.
The Node 20 cutoff also lands in a JavaScript ecosystem that has spent years pretending the runtime is the stable part and the package graph is the chaos. That distinction is weaker now. Native modules like sharp, bcrypt, and better-sqlite3 still care about ABI changes. ESM details still matter. Import assertion syntax changed. Lambda handler contracts change. CA certificate loading and base operating systems matter. The runtime is not the quiet floor under npm. It is another moving dependency with security advisories, compatibility traps, and platform-specific behavior.
The right response is boring, but it has to be explicit. Put runtime versions in source control instead of inheriting platform defaults. Pin CI setup steps with actions/setup-node or equivalent rather than trusting whatever ubuntu-latest happens to contain. Inventory managed functions by runtime, not just by repository. Rebuild native modules under the target Node version. Run dependency installs from a clean state because lockfiles do not prove native artifacts were built against the right ABI. For Lambda, choose Node 22 or 24 deliberately, then test handler style, unresolved async work, certificates, layers, and container base-image assumptions. For Azure, GitHub Actions, WordPress VIP, and other managed platforms, read the platform lifecycle policy as part of the application dependency graph.
There is an older web lesson hiding in this. CGI, PHP hosts, Rails deploy targets, Heroku buildpacks, and browser engines all taught the same thing in different costumes: when a runtime becomes a platform service, the upgrade schedule becomes governance. JavaScript got big enough that Node is no longer merely a developer tool. It is an operating layer for other people’s computers.
Node 20 died exactly when the calendar said it would. The real story is that so many systems had to move because of that line on the calendar. That is not a minor version bump. That is infrastructure showing its ownership map.