Node.js 22 became the current LTS in October 2025, and it's a significant release. Let's go through what actually changed and what it means for your projects.
Native TypeScript Support (Type Stripping)
This is the headline feature. You can now run .ts files directly:
node --experimental-strip-types server.ts
Node strips the type annotations before executing; it doesn't type-check. Think of it as a lightweight alternative to ts-node for running scripts without a build step.
[!IMPORTANT] This is type stripping only, not full TypeScript compilation. Features like
enum,namespace, and decorators (pre-standard) are not supported. For production TypeScript compilation, you still wanttscor a bundler.
For most utility scripts and quick prototypes, it's exactly what you need.
require(esm) Is Now Stable
The long-standing headache of importing ES modules in CommonJS code is resolved:
// In a CommonJS file (.cjs or "type": "commonjs")
const { something } = require('./esm-module.mjs'); // Now works!
const chalk = require('chalk'); // ESM-only package - now works!
This eliminates the ERR_REQUIRE_ESM error that forced either converting your entire project to ESM or maintaining awkward dynamic import workarounds.
Built-in WebSocket Client
Node.js now ships a native WebSocket client, matching the browser's WebSocket API:
const ws = new WebSocket('wss://api.example.com/realtime');
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'subscribe', channel: 'updates' }));
};
ws.onmessage = ({ data }) => {
console.log('Received:', JSON.parse(data));
};
No more ws package for simple client-side WebSocket connections.
Improved Test Runner
Node's built-in node:test module gets meaningful upgrades:
import { test, describe, beforeEach } from 'node:test';
import assert from 'node:assert/strict';
describe('User service', () => {
let userService;
beforeEach(() => {
userService = new UserService({ db: mockDb });
});
test('returns user by ID', async () => {
const user = await userService.findById('user-1');
assert.equal(user.name, 'Alice');
});
test('throws when user not found', async () => {
await assert.rejects(
() => userService.findById('nonexistent'),
{ name: 'NotFoundError' }
);
});
});
Run with node --test. No additional tools needed for basic test suites.
AbortSignal.timeout() Improvements
Cleaner timeout handling without manual cleanup:
const controller = new AbortController();
// Automatically aborts after 5 seconds
const response = await fetch('https://api.example.com/data', {
signal: AbortSignal.timeout(5000),
});
Performance Improvements
| Operation | Node.js 20 | Node.js 22 | Improvement |
|---|---|---|---|
| URL parsing | 100% | 174% | +74% |
| Buffer operations | 100% | 143% | +43% |
fs.readFile | 100% | 128% | +28% |
| HTTP/1.1 throughput | 100% | 115% | +15% |
Upgrade Path
# With nvm
nvm install 22
nvm use 22
# With fnm (faster alternative to nvm)
fnm install 22
fnm use 22
# Verify
node --version # v22.x.x
Breaking changes to watch for:
--experimental-fetchflag removed (Fetch is now stable and always on)punycodemodule deprecated (usewhatwg-urlinstead)- Minimum OpenSSL version bumped to 3.0
Should You Upgrade?
If you're on Node.js 18 LTS: Yes, plan the upgrade. Node.js 18 goes EOL in April 2025.
If you're on Node.js 20 LTS: Eventually yes, but Node.js 20 is supported until April 2026.
For new projects starting today: Start on 22.
Tagged with
Written by
DebuggerMe TeamThe DebuggerMe team builds developer tools, writes technical content, and helps teams ship better software.
Related Articles
All articles →package.json vs package-lock.json – What's the Difference?
Understanding why both package.json and package-lock.json exist in your Node.js project, and when each file matters.
TypeScript 5.8 Major Speed Up
TypeScript 5.8 introduces return type check optimizations and compile time improvements, making local development faster.
React 19 Stable Is Finally Here
React 19 has entered stable release, introducing the React Compiler, server actions, and cleaner async form handling hooks.