Skip to content

Node.js revisited its 2015 release plan. The change was the easy part.

The work of revisiting an old policy is recovering why it was made.

What the 2015 plan said

James M Snell wrote the first Node.js LTS plan in July 2015, months before Node 4 “Argon” shipped as the first LTS. The shape, verbatim from the 2015-07-23 README:

“new LTS releases will occur once every 12 months… Every LTS release will be actively maintained for a period of 18 months… until the current LTS release moves into Maintenance 12 months later. (That is 18 months of active LTS + 12 months Maintenance only). There will be no more than two active LTS releases at any given time, overlapping for a maximum period of six months.”

Three numbers from that paragraph survived ten years: one new LTS line per year. Thirty months of total support per line. A six-month overlap so a team always has a supported version to move to.

What the document does not contain is also worth noticing. It never uses the words corporate, enterprise, adoption, or cycle. It describes mechanics without naming the audience the mechanics were designed for. That audience became explicit only ten years later — when the same author looked back on his own work.

Why the policy was revisited

On July 14, 2025, RafaelGSS opened nodejs/Release#1113 proposing annual majors and a 24-month LTS. Within an hour, Matteo Collina (TSC) replied “+1”. Twelve minutes later, the original plan’s author replied to his own ten-year-old work.

@jasnell View on GitHub →

When I first proposed the current plan a decade ago it was based entirely on corporate adoption cycles that were relevant at that time and we really haven’t revisited the plan since.

This is the comment everything else happened against. The original author named, on the public record, the assumption his plan had been built on top of: corporate adoption cycles. The 2015 README never said that. The 2025 retrospective did. In the same comment, the author asked the project to keep the six-month overlap — the part of his plan that lets large organizations move between LTS lines without ever running an unsupported version.

The author was willing to drop the cadence he chose in 2015 — but the migration window the cadence opened up, he asked the project to keep.

A second voice the same day put the maintainer-cost case plainly:

@marco-ippolito View on GitHub →

Backporting to old release lines is HARD so having a shorter lifespan makes releasers life easier.

Annual majors had instant agreement. LTS duration did not.

The proposal that didn’t ship

The 24-month LTS lasted nine days. On July 23, richardlau — IBM’s engineer on the Release WG — posted feedback gathered from internal teams at IBM and Red Hat.

@richardlau View on GitHub →

the consistent feedback is that they would prefer the support timeframes of Long Term Support releases to remain at 30 months… Our enterprise clients don’t want to/can’t move up to newer releases on a yearly basis. Current releases are ignored (since they are not LTS).

The comment is short on rhetoric and long on real numbers. A Release WG member is surfacing the real-world limits of the teams that ship audited, patched Node.js to enterprise customers — teams whose compliance audits and rollout schedules move slowly on purpose.

A second strand of pushback came from inside the project:

@panva View on GitHub →

I’m also -1 on shortening the LTS, the extra 6 months is what allows users to plan for a “skip one LTS” upgrade.

The “skip one LTS” pattern — Node 18 straight to Node 22, skipping 20 — only works if the LTS being skipped is supported long enough for the next-but-one to land. Twenty-four months doesn’t leave room. Thirty does.

By September 1, the proposer had pulled back: “what if we don’t have a ‘Current’ release and have a major starting with LTS since April? This way we’ll have 30 months of LTS period and a short release cycle.” The shape that shipped is close to that, with one adjustment: the six months before LTS promotion stay as a stabilization window, still called Current. The proposer’s original 24-month figure does not appear in the final policy.

What users were doing

The case for changing the cadence had two distinct arguments. One was about maintainer load. The other was about user confusion. They did not require the same change.

The clearest evidence on the second came late in the discussion, from outside the project’s maintainer pool:

@Matheus-RR View on GitHub →

Teams don’t know odd releases aren’t LTS. We regularly see Node 21/23/25 in production environments where the team assumed they were on a supported release. Annual majors where every release is LTS would eliminate this entire class of confusion.

The author works on endoflife.date, which tracks end-of-life data for hundreds of products. The comment is data, not opinion. It is a report that production teams are misreading the odd/even signal, often. Documentation that says “production applications should only use Active LTS or Maintenance LTS” didn’t make it into the heads of teams running npm install -g node@latest.

The new policy answers this directly. Every annual major becomes LTS. There is no longer a stable release line that production users have to learn not to use. The early-testing job that odd-numbered Currents were meant to do moves to a separate Alpha channel — marked clearly as a prerelease (27.0.0-alpha.1), explicitly not for production.

What survived, and why

Place the new schedule next to the old one and the resemblance is hard to miss. Two numbers from the 2015 plan came back unchanged in the 2026 announcement: thirty months of LTS, and six months of overlap. Each kept its place because someone with a specific dependency on it spoke up.

The 30-month window stayed because richardlau reported IBM and Red Hat downstream rebuilders preferred it unchanged, and panva named the “skip one LTS” upgrade pattern that needs the extra six months. Two named dependencies. After seven weeks of debate, four explicit -1 votes from named maintainers (richardlau, panva, mhdawson, Qard), and the proposer himself rewriting the shape — “30 months of LTS period and a short release cycle” — the 24-month figure was pulled.

The 6-month overlap stayed because jasnell, the original author, asked the project to keep it. He was willing to drop the biannual cadence he’d chosen in 2015. The migration window the cadence had opened up, he asked the project to keep.

The three changes that did ship — annual cadence, odd/even removal, the Alpha channel — had no equivalent defenders in the thread for the existing behavior. The biannual cadence had no one calling it load-bearing. The odd/even split had Matheus-RR’s endoflife.date data showing production teams misreading it.

The 30 months stayed because their reason, once recovered, still held. The odd/even split changed because its reason, once recovered, didn’t.

The work was the recovery.

Further reading