Node.js 22 became the "Current" release in April 2024 and moved to Active LTS in October that year, and it's the version I've had running in production the longest of the 22.x-and-up line. Most of what changed is unglamorous in the best way: fewer workarounds, fewer dependencies you needed only to patch over a gap in core. Four things stand out — require(esm), the built-in WebSocket client, watch mode going stable, and the V8 12.4 bump underneath it.
require(esm): loading ESM from CommonJS
For years, a CommonJS module calling require() on an ES module was a hard error — you had to fall back to a dynamic import(), which is async and awkward to bolt onto a synchronous codebase. Node 22 unflagged require(esm) for the common case: a CommonJS file can now require() a synchronous ES module directly, as long as that module doesn't use top-level await. It doesn't cover every case — a module with top-level await still needs `import()` — but it quietly fixes the single most annoying interop wall in the dual-package-hazard mess that's plagued the ecosystem since ESM landed.
// esm-utils.mjs
export function slugify(input) {
return input.trim().toLowerCase().replace(/\s+/g, '-');
}
// legacy-cjs-service.js
const { slugify } = require('./esm-utils.mjs'); // works in Node 22+, no flag needed
console.log(slugify('Node 22 Release Notes'));
A built-in WebSocket client
Node 22 stabilizes the global WebSocket client that had been experimental since Node 21 (it's the same client API undici already implemented for fetch's sibling APIs). You can open a client-side WebSocket connection with no dependency at all now — no ws package for the simple case of a service that just needs to consume a websocket feed. It's a client, not a server: if you're building a WebSocket server, you still reach for ws or the platform's native support, but for outbound connections it removes a dependency that used to be nearly universal.
The built-in WebSocket global in Node 22 lets a script connect out to a WebSocket endpoint with zero dependencies. It does not give you a way to accept inbound WebSocket connections — for that you still need ws, socket.io, or a framework's built-in support.
Watch mode leaves experimental status
node --watch has existed since Node 18 behind an experimental warning, restarting your process on file changes without nodemon. In Node 22 it's stable — no more warning printed to stderr on every restart, and it's reliable enough that I've dropped nodemon from new projects entirely. There's also --watch-path now, so you can scope what triggers a restart instead of watching the whole working directory, which matters once a repo has a build output folder or node_modules sitting next to the source.
node --watch --watch-path=./src server.js
# restarts only when files under ./src change,
# ignores writes to ./dist and ./node_modules
V8 12.4 and what it buys you
Node 22 ships V8 12.4, which brings the Array.fromAsync method, the Set methods (union, intersection, difference, and friends), and WebAssembly improvements including resizable ArrayBuffers exposed to Wasm memory. None of these are things you'll rewrite an app around, but Set operations in particular are a small, real quality-of-life win — I've replaced a handful of manual filter/includes patterns with a one-line `symmetricDifference` call since upgrading.
require(esm) and the stable built-in WebSocket client are Node 22+ features. If your package.json engines field or your deployment target is still on Node 18 or 20 LTS, using these will break for a chunk of your users — bump your minimum supported version deliberately, don't let it happen by accident because your local machine upgraded.
Wrapping up
Node 22's real theme is friction removal rather than new capability: less need for a WebSocket dependency, less need for nodemon, one less wall in the CommonJS/ESM interop mess. If you've been putting off the upgrade because you assumed it was mostly internal plumbing, it's worth doing for the `require(esm)` fix alone if you maintain any CommonJS code that consumes ESM-only packages.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.