Node.js Release & LTS Policy
Node.js ships on a predictable cadence - production services should run Active or Maintenance LTS releases, never short-lived Current odd majors.
Recipe
Quick-reference recipe card - copy-paste ready.
| Release line | Status (Jul 2026) | Production use |
|---|---|---|
| Node 24.x | Active LTS (24.18.0) | Yes - default for new work |
| Node 22.x | Maintenance LTS (22.23.1) | Yes - during migration window |
| Node 25.x | Current (odd) | No - bleeding edge only |
| Node 20.x | End-of-Life | No - upgrade immediately |
When to reach for this:
- Choosing a base image for a new microservice
- Writing an ADR for an LTS upgrade
- Auditing whether any fleet still runs End-of-Life Node
- Explaining to security why Current releases are blocked in prod
Working Example
// src/health.ts - expose LTS awareness in health checks
import { readFileSync } from 'node:fs';
const pkg = JSON.parse(readFileSync('package.json', 'utf8')) as {
engines?: { node?: string };
};
export function healthPayload() {
const major = Number(process.versions.node.split('.')[0]);
const allowedMajors = [22, 24]; // Maintenance + Active LTS
return {
status: allowedMajors.includes(major) ? 'ok' : 'degraded',
node: process.version,
enginesPolicy: pkg.engines?.node ?? 'not set',
ltsPolicy: major === 24 ? 'active-lts' : major === 22 ? 'maintenance-lts' : 'unsupported',
};
}// package.json
{
"engines": {
"node": ">=24.18.0 <25 || >=22.23.1 <23"
}
}What this demonstrates:
- Health endpoints can flag non-LTS runtimes before security scanners do
enginescan express an intentional migration window (22 and 24 concurrently)- Major version is derived from
process.versions.node, notprocess.versionstring parsing alone
Deep Dive
How It Works
- New majors release every April and October (roughly). Even numbers (22, 24, 26) enter LTS; odd numbers (23, 25) do not.
- Active LTS receives features, bug fixes, and security patches for ~18 months after promotion.
- Maintenance LTS receives critical fixes only for ~12 more months, then End-of-Life.
- Current (odd majors) is for early adopters and library authors testing compatibility.
Lifecycle Timeline (simplified)
| Phase | Duration | Patch types |
|---|---|---|
| Current | ~6 months | Features, fixes, security |
| Active LTS | ~18 months | Fixes, security, limited features |
| Maintenance LTS | ~12 months | Critical fixes, security |
| End-of-Life | Forever | None |
TypeScript Notes
// CI matrix during LTS migration - test both supported lines
const SUPPORTED_NODE_MAJORS = [22, 24] as const;
type SupportedMajor = (typeof SUPPORTED_NODE_MAJORS)[number];
function assertSupportedMajor(): SupportedMajor {
const major = Number(process.versions.node.split('.')[0]) as SupportedMajor;
if (!SUPPORTED_NODE_MAJORS.includes(major)) {
throw new Error(`Unsupported Node major: ${major}`);
}
return major;
}Gotchas
- Deploying
node:latestornode:current- you may land on an odd major without security SLAs. Fix: pinnode:24.18.0-bookworm-slim. - Staying on Maintenance LTS past EOL - Node 20 EOL means no CVE patches. Fix: calendar reminders 6 months before EOL.
- Skipping LTS versions (20 → 24 with no testing on 22) - breaking changes accumulate. Fix: upgrade to Active LTS at least one cycle before your current line EOLs.
- Treating semver-minor as risk-free - LTS minors can deprecate APIs. Fix: run CI on every LTS patch release.
- Ignoring npm compatibility - each Node LTS bundles a specific npm major. Fix: use bundled npm or document Corepack pins.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Stay on Maintenance LTS | Migration needs more time | Maintenance is within 6 months of EOL |
| Jump to Active LTS immediately | Greenfield or small fleet | Large brownfield with native addons untested on new major |
| Vendor-extended support (commercial) | Cannot migrate before EOL | Active LTS path is feasible with planning |
| Container digest pinning | Reproducible deploys | You also need a policy for when to bump the digest |
FAQs
What is Active LTS right now?
Node.js 24 (Active LTS), latest patch 24.18.0 as of this writing.
Can production run Node 22?
Yes during the Maintenance LTS window (through April 2027). Prefer Node 24 for new services.
Why avoid odd-numbered releases?
Odd majors (23, 25) are "Current" - shorter support, more churn, and not covered by typical enterprise LTS policies.
How often are LTS patches released?
Roughly every few weeks for security and bug fixes. Subscribe to nodejs-security announcements.
Does LTS include new JavaScript features?
Active LTS backports V8 updates with new language features. Maintenance LTS is conservative - mostly fixes.
What happened to Node 20?
Node 20 reached End-of-Life. Upgrade to Node 22 (temporary) or Node 24 (target).
How do I find EOL dates?
Check https://nodejs.org/en/about/previous-releases or the schedule.json in the Node.js GitHub repository.
Should Docker tags use 24 or 24.18.0?
Pin the full patch (24.18.0) or a digest for reproducibility. Floating 24 tags drift on every patch release.
Do serverless platforms hide LTS concerns?
Partially - but you still choose the runtime version in config. Verify it maps to Active or Maintenance LTS.
How does OpenSSL versioning relate to LTS?
Node bundles OpenSSL; LTS patches include OpenSSL security updates. Running EOL Node means stale TLS primitives.
Can I run different LTS lines in one monorepo?
Possible but costly. Standardize on one Active LTS per org; allow Maintenance only during a timed migration.
What is the upgrade cadence recommendation?
Adopt each new Active LTS within 6 months of promotion. Exit Maintenance LTS at least 3 months before EOL.
Related
- Installing & Version Management - fnm, nvm, and engines pinning
- Node.js vs Bun vs Deno - runtime ADR context
- Node.js Fundamentals Best Practices - LTS enforcement checklist
- Before/After Node 20-24 LTS Upgrade - migration case study
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.