Node 26 goes long-term support
Even-numbered releases become LTS every October. What that actually promises, and what it does not.
Node.js promotes an even-numbered release to long-term support every October. That is the version most organisations will run for the next two and a half years, so it is worth being precise about what the designation means.
what LTS actually promises#
Active LTS, roughly 12 months. Backports of bug fixes, security patches, and occasionally non-breaking features.
Maintenance LTS, roughly 18 months after that. Critical fixes and security patches only.
Then nothing. No security patches at all. Running an end-of-life Node version is running unpatched software, and the CVEs do not stop arriving because you stopped upgrading.
The commonly-misread part: LTS does not mean "more stable than the current release." It means "supported for longer." A version that has been LTS for two years has accumulated more backported changes than a fresh one.
the practical policy#
Run the active LTS in production. Not the current release — its API surface is still moving and it is unsupported within months.
Upgrade every October, one LTS to the next. This is a twelve-month cadence you can put in the calendar permanently.
Test the current release in CI as a non-blocking job. That gives six months of warning about what the next LTS will break, at the cost of a few minutes per build.
Never run end-of-life. Check your version against the release schedule today; a surprising number of production services are past their date and nobody has looked.
what to check on the upgrade#
Base image compatibility. Node's minimum glibc and macOS versions move between majors. This is the most common cause of an upgrade failing at the container level rather than in tests.
Native modules. Anything with a compiled component needs a rebuild against the new ABI. If a dependency has no prebuilt binary for the new version, that is a blocker to find early.
Deprecated APIs that now throw. Node deprecates in stages: documentation only, then runtime warning, then removal. Run with --throw-deprecation in CI and you will find these before they find you.
Your observability agents. APM tools that hook into internals are, along with native modules, the most common upgrade breakage. They break at startup, loudly, which is at least a merciful failure mode.
what has accumulated in the runtime#
Worth restating because it changes what a new project needs. Over the last few major versions Node has absorbed into core: a test runner, watch mode, .env file loading, TypeScript type stripping, a SQLite module, fetch and WebSocket as globals, a permission model, and using for deterministic cleanup.
Every one of those replaced a dependency — which means one fewer package with a lifecycle script, one fewer upgrade treadmill, one fewer supply chain surface.
For a new service, the dependency count of a sensible starting point is dramatically lower than it was three years ago, and that is the most important thing about modern Node. It is not a feature anyone announces.
the no-build-step setup#
{
"compilerOptions": {
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true,
"module": "nodenext",
"strict": true,
"noEmit": true
}
}node --test # tests
node --watch app.ts # development
npx tsc # typecheck, in CI
node app.ts # productionNo bundler, no transpiler, no ts-node. The erasableSyntaxOnly flag is what makes it safe — it rejects any TypeScript syntax that cannot be removed by whitespace substitution, so your source is guaranteed to run under type stripping.
The one blocker that remains is decorators, which are not erasable. If your framework depends on them, you still need a build.
— Dom, October 12, 2026