All posts

Node.js Goes Annual: What One Major Release a Year Means for Your Upgrade Strategy

Starting with Node.js 27 in October 2026, the project drops the odd/even model and ships one major release per year — every one an LTS. Here's what actually changes for how you plan upgrades, and the new Alpha channel library authors need to wire into CI.

Node.js Goes Annual: What One Major Release a Year Means for Your Upgrade Strategy

Node.js is retiring a versioning model that has shaped its release strategy for over a decade. Starting with Node.js 27, the project moves from two major releases a year to one, and eliminates the odd/even distinction entirely — every future major becomes a Long-Term Support line. The change takes effect in October 2026, and the official announcement leads with a reassuring line: if you already upgrade only to LTS versions, little changes beyond the version numbering. That's true, and it's also the part most teams get wrong. The details around the new Alpha channel and the shifted calendar are worth understanding now, while Node.js 26 is still the last release under the old rules.

What's actually changing

Since the io.js merger, Node.js has cut a new major every six months, alternating between odd-numbered lines that saw minimal adoption and even-numbered lines that graduated to LTS. That ends with version 26. Here is the new model, as of October 2026:

  • One major release per year, landing each April, with promotion to LTS the following October.
  • Every release becomes LTS. No more odd/even split — Node.js 27 will become an LTS line, and so will every version after it.
  • A new six-month Alpha channel for early testing, where semver-major (breaking) changes are allowed.
  • Alpha versions use standard semver prerelease tags like 27.0.0-alpha.1.
  • Version numbers align to the calendar year of a release's initial Current phase: 27.0.0 in 2027, 28.0.0 in 2028, and so on.

The support window itself barely moves. LTS remains roughly 30 months, and each release gets a total of 36 months from its first Current release to end of life. The overlap between consecutive LTS lines — the migration window you rely on to move off an aging version without a fire drill — is preserved.

The new phase schedule

Each release now flows through four clearly bounded phases:

Phase Duration Window Purpose
Alpha 6 months Oct – Mar Early testing; semver-major changes allowed
Current 6 months Apr – Oct Stabilization
LTS 30 months from Oct Long-term support with security fixes
EOL after ~36 mo No further support

Concretely, Node.js 27 begins its Alpha phase in October 2026, ships as 27.0.0 in April 2027, enters LTS in October 2027, and reaches end of life in April 2030. Node.js 28 shifts the whole pattern forward exactly one year. If you want to plan several cycles ahead, the project publishes the authoritative dates in schedule.json, and the announcement sketches the cadence out to Node.js 36 in the mid-2030s.

Why the project made the change

The current schedule is ten years old, and Node.js now has a decade of data on how people actually adopt it. Three findings drove the decision, per the proposal thread opened by TSC member Rafael Gonzaga: odd-numbered releases saw minimal real-world adoption, the odd/even convention confused newcomers, and many organizations skipped odd releases entirely and upgraded only to LTS.

Underneath the adoption numbers is a sustainability problem. Node.js is maintained primarily by volunteers, and each concurrent release line multiplies the work of backporting fixes and shipping coordinated security releases. Managing security across four or five active lines had become hard to sustain. Fewer lines means the release team can focus effort on the versions people actually run.

James Snell, a longtime core contributor who helped design the existing cycle, supported revisiting it:

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. It's always good to periodically revisit to see if the needs of ecosystem and the project have changed.

The change wasn't unanimous on every detail. As InfoQ reported, the discussion surfaced a real tension between enterprises that want long, stable support windows and fast-moving teams that upgrade aggressively and don't want to wait a full year for new features to reach an LTS line. That trade-off is the honest cost of an annual cadence, and it's worth weighing against your own release habits.

What it means for how you upgrade

For most teams, the practical impact is small — provided a couple of habits are already in place.

If your policy is "run the current LTS," the change is almost invisible. You'll see a new LTS every October instead of choosing between an even-year release and skipping the odd one, and the version numbers now line up with calendar years. Pin the major you support in your tooling and let the annual rhythm carry you forward. The engines field documents your intent for anyone installing your package, and a .nvmrc keeps local environments and CI in sync:

// package.json
{
  "engines": {
    "node": ">=27.0.0"
  }
}
# .nvmrc
27

If your team upgrades fast and wants new capabilities early, the annual major is where the tension shows up — a feature that misses one April release now waits a year for the next major, rather than six months. Two things soften that. First, minor and patch releases continue to land on the active line throughout the year, so non-breaking improvements still reach you without waiting for the next major. Second, the new Alpha channel gives you a supported way to exercise breaking changes long before they ship.

The Alpha channel is the part not to skip

The most consequential piece for library and framework authors isn't the annual cadence — it's the Alpha channel that replaces the early-testing role odd releases used to play. Alpha builds are signed and tagged (unlike untested nightly builds from main) and run through CITGM, the project's tool for detecting ecosystem breakage against major open-source packages. Crucially, Alpha is the phase where semver-major changes land, which makes it your earliest reliable signal that an upcoming Node.js major will break your code.

The announcement is blunt about the risk of ignoring it: if you only test against LTS releases, you won't be able to report bugs before they reach your users. So if you maintain a package, add an Alpha job to CI. On GitHub Actions, setup-node understands semver prerelease ranges, so you can pull the latest Alpha and run it as a non-blocking matrix entry:

# .github/workflows/test.yml
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        node: ["24", "26"]           # current LTS lines
        include:
          - node: "27.0.0-alpha"      # early warning for breaking changes
            experimental: true
    continue-on-error: ${{ matrix.experimental || false }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci
      - run: npm test

Marking the Alpha row continue-on-error keeps a breaking upstream change from turning your pipeline red while still giving you a visible, early heads-up. The cadence of Alpha releases is deliberately flexible — the release team decides timing based on the volume of changes — so treat the job as a rolling check rather than something tied to a fixed date. Note that Alpha is explicitly not for production; it's a compatibility-testing tool for CI and maintainers.

A short planning checklist

The move is a good prompt to tighten a few practices that pay off regardless of the schedule:

  1. Confirm your support policy in code. Set engines.node and .nvmrc to the LTS majors you actually support, and make CI enforce them. Ambiguity here is what turns a routine upgrade into a scramble.
  2. Map your runway off Node.js 26. It's the final release under the old model — it enters LTS in October 2026 and reaches end of life in April 2029. Put that EOL date on the roadmap now so the migration is planned, not reactive.
  3. Library authors: wire in Alpha. A non-blocking Alpha job in CI is the cheapest insurance against shipping a break to your users when the next major lands.
  4. Track dates from the source. schedule.json is the canonical calendar. Feed the October LTS promotions into wherever your team plans upgrades.

Takeaways

Node.js moving to one annual, always-LTS release is a structural simplification, not a disruption. For teams that already track LTS, it removes a confusing convention and makes version numbers legible against the calendar, while keeping the ~30-month support window and the overlap you rely on to migrate. The real action item lives with library and framework maintainers: the Alpha channel is now the earliest place breaking changes appear, and testing only against LTS means finding those breaks after your users do. Pin the majors you support, note Node.js 26's April 2029 end of life, add an Alpha job to CI if you publish packages, and let the annual October rhythm do the rest. Handled that way, the first release under the new model in April 2027 should be a non-event — which is exactly the point.

Sources: Node.js: Evolving the Node.js Release Schedule · InfoQ: Node.js Moves to One Major Release Per Year, Starting with Node 27 · nodejs/Release#1113: the proposal and discussion

Back to all posts
Next step

Need help shipping software?

Tell us what you're trying to build. A discovery call, a one-page summary within 48 hours, a proposal within a week.

Response · 48h·NDA on request·US contracts only