Node.js Is Killing Odd-Numbered Releases and Your CI Matrix Is Already Wrong
Starting October 2026, Node.js drops to one major release per year, every version becomes LTS, and version numbers track the calendar. A new six-month alpha channel opens next month. Here is what changes in your CI matrix, your engines field, and your Docker tags, plus why the alpha window is the part most teams will ignore until it bites them in April 2027.
Nobody wrote this rule down, but everyone followed it: even numbers go to production, odd numbers are for playing. Node 21 shipped, six months passed, approximately zero people ran it anywhere that mattered, and we all waited for 22 in October.
From October 2026 that rule stops being true, because there are no odd releases to skip anymore.
The new calendar
One major per year. Every one of them becomes LTS. Node 26, which went Current in May and picks up its LTS badge on 28 October, is the last release under the old model.
The shape of a release is boring now, in a good way. A version goes Current in April, gets promoted to LTS in October, stays Active LTS for a year, drops to maintenance for eighteen months, and dies about 36 months after it first appeared as an alpha.
Version numbers now track the calendar year. Node 27 ships in 2027, 28 in 2028, and so on. I like this more than I expected to. "Are we on a supported runtime?" becomes arithmetic you can do in your head instead of a trip to the release repo to squint at a colored bar chart.
Concretely: Node 27 alphas start next month, it goes Current in April 2027, LTS in October 2027, EOL April 2030. Node 26 runs until April 2029. Node 24 dies April 2028. Node 22 is already on the clock for April 2027.
Your CI matrix is lying to you
Go open your workflow file. I would bet money it contains some version of this:
strategy:
matrix:
node: [20, 22, 24]Node 20 hit end of life on 30 April 2026. You are spending minutes testing a runtime that stopped receiving security patches five months ago, and that green check is worse than no check at all, because somebody downstream reads it as a support commitment.
Bumping the numbers buys you six months. What you actually want is a matrix that goes stale loudly and has a slot for what is coming:
jobs:
test:
strategy:
fail-fast: false
matrix:
node: [22, 24, 26]
include:
- node: 27-nightly
experimental: true
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci && npm test
continue-on-error: ${{ matrix.experimental || false }}The experimental row is the whole point of the rest of this post.
The alpha channel is the part people will ignore
Between October and March, Node 27 gets alpha builds numbered like 27.0.0-alpha.1, and semver-major breakage is allowed to land in them. That is a six-month window to find out that your native addon, your node-gyp build, or that one dependency doing unspeakable things to internal bindings is about to stop working.
Under the old cadence you found out in April when the Current release dropped. If the change rode an odd release, you often found out the following October instead, twelve months of drift later, by which point the behavior had shipped twice and reverting it was somebody else's political problem.
Here is what gets me though. This only works if library authors actually run the alphas. Node core can publish the channel, but if the top few hundred packages on npm do not have a nightly job pointed at it, April 2027 will feel exactly like every previous April, except now there is no odd-numbered release absorbing the first wave of damage. The alpha channel is free breakage insurance that nobody has to pay for and most people will still forget to claim.
Things worth an hour this week
Your engines field probably encodes the old assumption out loud:
{
"engines": {
"node": "^20.0.0 || ^22.0.0 || ^24.0.0"
}
}That range means "even majors only." Under the new model every major is even in spirit, so enumerating them is busywork that will lock your consumers out of Node 27 for no reason at all. A floor is almost always what you meant:
{
"engines": {
"node": ">=22.12.0"
}
}Docker tags deserve a look too. node:lts used to resolve to the most recent even release that got promoted, which meant it moved roughly every twelve months but felt jumpy because of the odd releases in between. After October it resolves to last April's release, every year. Slower and more predictable, but if you have FROM node:lts-alpine in a Dockerfile and any compliance answer that depends on knowing the exact minor, pin it properly.
Then grep your internal platform docs for the phrase "odd version." Somewhere in there is a wiki page saying you do not support odd-numbered Node releases. Delete it now, before somebody quotes it back at you in 2029 as a reason to stay off Node 29.
The part I'm skeptical about
The version numbering is the headline and the alpha channel is the actual change. Dropping to one major a year mostly means fewer upgrade tickets and a support window you can explain to a non-engineer, which is nice but not interesting.
The alpha window is what decides whether the ecosystem shows up in October to test breaking changes or shows up in April to complain about them. My money is on April. I would like to be wrong, and the cheapest way to make me wrong is one nightly CI job that nobody has to think about again after they write it.