Node.js 26 goes LTS: when to upgrade from Node 22 or 24
Node.js 26 becomes the new long-term support release on 28 October 2026. A week earlier, on 20 October, Node.js 24 drops to maintenance, and Node.js 22 reaches end of life on 30 April 2027. If your business runs a Node.js backend, one question lands on someone's desk this month: do we upgrade, and when?
Our short answer: if you are on Node.js 22 or older, plan the move now and go straight to 26. If you are on 24, you are covered until April 2028, so schedule the upgrade calmly for the first half of 2027. New projects should start on 26 once it reaches LTS.
Below are the dates, what actually changes in Node.js 26, where the built-in TypeScript support helps and where it does not, how the release schedule changes from 2027, and the checklist we use for these upgrades.
The dates that matter
Node.js versions move through phases. Current is the newest line, where changes still land. Active LTS (long-term support) is the stable phase that gets audited fixes and improvements. Maintenance means critical bug fixes and security updates only. After end of life there are no more fixes from the project at all.
The Node.js project is direct about which phases belong in production: its releases page says "Production applications should only use Active LTS or Maintenance LTS releases." The dates below come from the project's official schedule.json, and the phase definitions from the Release working group.
| Version | Status from 28 Oct 2026 | Maintenance from | End of life |
|---|---|---|---|
| Node.js 20 | End of life | 22 Oct 2024 | 30 Apr 2026 |
| Node.js 22 | Maintenance LTS | 21 Oct 2025 | 30 Apr 2027 |
| Node.js 24 | Maintenance LTS | 20 Oct 2026 | 30 Apr 2028 |
| Node.js 26 | Active LTS | 20 Oct 2027 | 30 Apr 2029 |
Two things stand out. Anything still on Node.js 20 has been without upstream security fixes since April. And Node.js 22 has roughly six months left, which is not much once you count testing, staging and a quiet deployment window.
For a team on 22, moving to 24 buys one extra year of support. Moving to 26 buys two. In our experience the extra work of skipping a major is usually small compared with doing two upgrades in two years, which is why we recommend going straight to 26 in that case.
What changes in Node.js 26
The Node.js 26.0.0 release notes list the full set. These are the changes we think matter for typical business applications.
Temporal is on by default
Temporal is the new built-in date and time API for JavaScript, designed to replace the error-prone Date object. In Node.js 26 it is available without any flag. For business software this matters more than it sounds: invoices, bookings, opening hours and event calendars are full of time zone and month-length bugs that Date makes easy to write.
Here is a small example, using the Temporal.PlainDate API, that tells you how long each Node.js line has left:
// eol.mjs - run with: node eol.mjs (Node.js 26 or later)
const today = Temporal.Now.plainDateISO();
const endOfLife = {
'Node.js 22': Temporal.PlainDate.from('2027-04-30'),
'Node.js 24': Temporal.PlainDate.from('2028-04-30'),
'Node.js 26': Temporal.PlainDate.from('2029-04-30'),
};
for (const [line, date] of Object.entries(endOfLife)) {
const left = today.until(date, { largestUnit: 'month' });
console.log(`${line}: ${left.months} months and ${left.days} days left`);
}
Our advice: use Temporal in new code on Node.js 26, but do not rewrite working date logic just because you can. If your code also runs in browsers or on older Node.js versions, check Temporal support there separately.
Removals and deprecations
http.Server.prototype.writeHeader()is removed. UsewriteHead().- The legacy internal stream modules (
_stream_readable,_stream_writableand friends) are removed. Your own code rarely imports these, but old dependencies sometimes do. - The
--experimental-transform-typesflag is removed. More on that in the TypeScript section. module.register(), the asynchronous module customization hook, is now runtime-deprecated (DEP0205) in favor of the synchronousmodule.registerHooks(). This mostly affects test runners, loaders and dev tooling, so expect warnings from tools before they update.
Engine, HTTP client and native addons
The V8 JavaScript engine moves to 14.6. Undici moves to 8.0.2. Undici is the library behind Node's built-in fetch(), according to the globals documentation. If you use fetch() heavily for integrations, run those tests first.
The internal module version also changes, so native addons compiled for an older Node.js major must be rebuilt. Addons written against Node-API are the exception, because Node-API is designed to stay binary-compatible across versions. In practice this is why we always do a clean install on the new version rather than copying an old node_modules folder.
TypeScript without a build step: useful, with limits
Node.js can run .ts files directly by stripping out the type annotations. According to the Node.js TypeScript documentation, this type stripping has been stable since Node.js 24.12.0 and 25.2.0, so it is fully supported on 26 as well.
There are important limits. Node.js does not type-check and ignores tsconfig.json. It also fails on TypeScript features that need code generation: enums, namespaces with runtime code, parameter properties and import aliases. Decorators are not supported either.
That last point matters to us. The NestJS APIs we build depend on decorators and on constructor parameter properties like constructor(private readonly users: UsersService). So our NestJS projects still need a compile step with tsc or a similar tool, on Node.js 26 as before.
Type stripping does pay off for scripts, build tooling, seed and migration scripts, and small services written in plain, "erasable" TypeScript. The docs recommend TypeScript 5.8 or newer with erasableSyntaxOnly and verbatimModuleSyntax turned on, so the compiler flags anything Node.js cannot run.
If you adopted --experimental-transform-types to get enums working, note that Node.js 26 removes it. Replace those enums with plain objects or union types, or go back to a compiler-based runner such as tsx, which the documentation itself suggests for full TypeScript support.
The release schedule is changing after Node.js 26
Node.js 26 is the last line under the old odd/even model. The project has announced a new schedule starting with Node.js 27:
- One major release per year, in April, promoted to LTS in October.
- Every release becomes LTS. No more odd-numbered short-lived versions.
- A six-month Alpha phase for early testing. Alphas are meant for library authors and CI, not production.
- Version numbers follow the calendar year: 27 in 2027, 28 in 2028.
- 36 months in total from the first Current release in April to end of life.
Part of the project's stated reasoning is the cost of backporting security fixes across many release lines, work it describes as done mostly by volunteers.
For businesses this is good news, because upgrades become a predictable yearly event. Our recommendation is to put a recurring upgrade window in the calendar, for example each winter after the October LTS promotion, instead of waiting for an end-of-life deadline to force it.
Our upgrade checklist
This is the order we work in when moving a TypeScript backend to a new Node.js LTS line.
- Find every place the version is set. Check local tooling, CI pipelines, Dockerfiles, hosting or serverless settings, and the
enginesfield inpackage.json. Mismatches here cause more trouble than the upgrade itself. - Check your framework and key dependencies. Read the release notes of your framework, ORM and database drivers for Node.js 26 support before you start.
- Do a clean install and run the tests with deprecations as errors. This surfaces removed APIs and new runtime deprecations early.
- Test the integrations. Anything that uses
fetch(), streams or crypto deserves a manual run against staging. - Deploy to staging, then production, with a quick rollback path to the old image.
Step three in practice:
node --version
rm -rf node_modules && npm ci
NODE_OPTIONS=--throw-deprecation npm test
If a deprecation comes from a dependency rather than your code, swap --throw-deprecation for --trace-deprecation to see where it comes from without failing the run. Then record the supported version in package.json, and set the same version in CI, Dockerfiles and hosting (the engines field documents it, but npm only warns on a mismatch by default):
{
"engines": {
"node": "26.x"
}
}
What to do next
Check which Node.js version your production systems run today. If the answer is 22 or older, put the move to 26 on the roadmap before spring 2027. If it is 24, add it to next year's plan and use the time to clear deprecation warnings. Starting something new? Start on 26.
If you would like a second pair of eyes on an upgrade, or a backend that needs to get off an unsupported version, tell us about it and we will help you plan the move.