Back to blog

Node.js 24 LTS: why and how to upgrade to Krypton

May 17, 2026 Dedimarco
nodejs javascript lts performance webdev
Node.js 24 LTS: why and how to upgrade to Krypton

Node.js 24 LTS: why and how to upgrade to Krypton

Node.js 24, codenamed “Krypton”, officially entered Long-Term Support (LTS) on October 28, 2025 with version 24.11.0. It will be supported through April 2028. If you’re still running Node 22 (or worse, Node 20 in maintenance), now is the time to plan your migration.

In this article, I’ll break down what Node 24 actually brings to the table, the concrete gains over Node 22, potential friction points, and most importantly — how to install it cleanly on your system. Because, spoiler alert: default Linux distribution repositories are rarely up to date.

Node.js 24 vs Node.js 22: what actually changed

Node 24 isn’t a cosmetic revamp. It’s a foundational update with a new V8 engine, a modernized ecosystem, and security decisions that impact your day-to-day work.

V8 13.6: the engine running faster

The JavaScript engine jumps from V8 12.9 (Node 23) to V8 13.6 in Node 24. This matters. Here’s what it brings to your code:

// Float16Array — half the memory for large tensors
const data = new Float16Array(1024 * 1024); // 2 MB instead of 4 MB

// RegExp.escape — no more manual escaping hacks
const safe = RegExp.escape("hello.world?+*"); // "hello\\.world\\?\\+\\*"

// Error.isError — reliable cross-realm error checking
if (Error.isError(thing)) {
  // thing is definitely an error, even from an iframe or vm context
}

// Explicit Resource Management — RAII finally comes to JS
function processFile(path) {
  using file = await fs.open(path, 'r');
  // File will be automatically closed, even on error
}

On the performance side, the new Maglev JIT compiler (introduced in V8 12.x, refined in 13.x) reduces compilation time while generating better-optimized code. The result: faster startup and tighter hot loops. Buffer operations, fs calls, ESM module loading, and URL parsing have all received measurable improvements.

npm 11: faster, more secure

Node 24 ships with npm 11, which delivers:

  • Faster installs thanks to an optimized resolver
  • Hardened security: npm no longer falls back to the old advisory endpoint if bulk requests fail
  • The --ignore-scripts flag now covers ALL lifecycle scripts
  • Compatible with ^20.17.0 || >=22.9.0

For projects with heavy dependency trees, the difference is tangible. On an Astro + Svelte project with 800 packages, I measure about 30% less time on npm ci compared to npm 10.

AsyncContextFrame: painless context tracking

The AsyncLocalStorage API now uses AsyncContextFrame by default, replacing the older async_hooks-based mechanism.

import { AsyncLocalStorage } from 'node:async_hooks';

const context = new AsyncLocalStorage();

// No more --experimental-async-context-frame flag needed
// It's the default now, and it's faster
context.run({ requestId: 'abc-123' }, async () => {
  await someAsyncWork();
  // Context survives through ALL async operations
  console.log(context.getStore().requestId); // 'abc-123'
});

For developers doing distributed tracing or request context propagation, this is a game-changer: roughly 40% less overhead compared to the old implementation, plus the confidence that context won’t get lost in complex call stacks.

Permission Model: security graduates from experimental

The Permission Model, introduced experimentally in Node 20, is now stable. The flag changes: --experimental-permission becomes simply --permission.

# Run a script with restrictive permissions
node --permission \
  --allow-fs-read=/app/data \
  --allow-fs-write=/app/logs \
  --allow-net=api.myservice.com \
  server.js

This is a feature I’ve been waiting for. In a world where malicious npm packages are a genuine threat, being able to limit what a Node process can do (filesystem, network, child processes) without needing a Docker container is a massive step forward for security.

URLPattern goes global

No more explicit imports:

// Node 24 — available everywhere
const pattern = new URLPattern({ pathname: '/blog/:slug' });
console.log(pattern.test('https://mysite.com/blog/node-24')); // true

Handy for routing, URL validation, or server-side matching. Combined with the standard URL API, it covers 90% of URL manipulation needs without external dependencies.

Undici 7: the modern HTTP client

Node 24 ships Undici 7, the next-generation HTTP client. Better performance, improved keep-alive handling, and native HTTP/2 and HTTP/3 support.

// Just use fetch() — Undici is the engine under the hood
const res = await fetch('https://api.example.com/data');
// Faster and more reliable than Undici 6 (Node 22)

Test runner: more intuitive

The native test runner now automatically waits for subtests:

import { describe, it } from 'node:test';

describe('Users API', () => {
  // Before Node 24: you had to manually await
  // Now: auto-waiting, just like Jest or Vitest
  it('should create a user', async () => {
    const res = await fetch('/api/users', { method: 'POST' });
    assert.strictEqual(res.status, 201);
  });
});

Native SQLite: an embedded database with zero dependencies

Node 24 includes node:sqlite, a native binding to SQLite. No more better-sqlite3 needed for 80% of use cases:

import { DatabaseSync } from 'node:sqlite';

const db = new DatabaseSync(':memory:');
db.exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)');
db.prepare('INSERT INTO users (name) VALUES (?)').run('Dedimarco');
const users = db.prepare('SELECT * FROM users').all();
console.log(users); // [{ id: 1, name: 'Dedimarco' }]

Node 22 vs Node 24 comparison table

FeatureNode 22 (Jod)Node 24 (Krypton)
V8 Engine12.713.6
npm10.x11.x
Undici6.x7.x
Float16ArrayNoYes
RegExp.escapeNoYes
Error.isErrorNoYes
Resource ManagementNoYes (explicit)
Global URLPatternNoYes
AsyncContextFrameExperimentalDefault
Permission ModelExperimentalStable (--permission)
Native SQLiteNoYes (node:sqlite)
OpenSSL3.0.x (sec. level 1)3.5.x (sec. level 2)
32-bit supportWindows x86Dropped
End of supportApril 2027April 2028

Friction points to watch out for

OpenSSL 3.5 and security level 2

This is the change most likely to bite you. Node 24 moves to OpenSSL 3.5 with security level 2 by default. This means:

  • RSA, DSA, DH keys shorter than 2048 bits: rejected
  • ECC keys shorter than 224 bits: rejected
  • Any cipher suite using RC4: rejected

If your application uses self-signed certificates with old keys, JWT tokens signed with RSA-1024, or connections to legacy APIs, test thoroughly before migrating.

32-bit support dropped

Prebuilt binaries for 32-bit Windows (x86) and ARMv7 Linux (32-bit) are no longer provided. If you’re deploying on a Raspberry Pi 2 or aging 32-bit server, you’ll either need to compile from source or stay on Node 22 until its end of life.

url.parse() deprecated

// ❌ Deprecated in Node 24
const parsed = url.parse('https://example.com/path?q=1');

// ✅ Use the WHATWG API
const parsed = new URL('https://example.com/path?q=1');

Codemods to ease the migration

The Node.js team provides ready-to-use codemods to automate part of the migration:

# Update deprecated RSA-PSS options
npx codemod run @nodejs/crypto-rsa-pss-update

# Replace dirent.path with dirent.parentPath
npx codemod run @nodejs/dirent-path-to-parent-path

# Migrate fs.F_OK constants to fs.constants.F_OK
npx codemod run @nodejs/fs-access-mode-constants

# Replace process.assert with node:assert
npx codemod run @nodejs/process-assert-to-node-assert

Run these on your codebase before migrating — they’ll save you valuable time.

Installing Node.js 24

Contrary to what you might hope, default Linux distribution repositories don’t offer Node 24. Ubuntu 24.04 ships Node 22, Debian 13 is on Node 22, Fedora 43 too. Here’s how to install Node 24 cleanly on each platform.

On Windows

Head to nodejs.org, download the LTS installer (.msi), and run it. Check the box “Automatically install the necessary tools” if you compile native modules. That’s it.

fnm (Fast Node Manager) is written in Rust — fast, cross-platform:

# Install via winget
winget install Schniz.fnm

# Then install Node 24
fnm install 24
fnm use 24
fnm default 24

Method 3: Volta

winget install Volta.Volta
volta install node@24

Method 4: nvm-windows

nvm install 24
nvm use 24

On macOS

# fnm (my recommendation)
brew install fnm
fnm install 24
fnm default 24

# Or via nvm
nvm install 24
nvm alias default 24

# Or directly via Homebrew
brew install node@24

On Linux

This is where things get tricky. Default repos lag behind. Here are the battle-tested methods.

NodeSource provides officially maintained APT/RPM repositories. This is what I use in production.

Ubuntu / Debian:

# Download and run the NodeSource setup script
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -

# Install Node.js 24
sudo apt install -y nodejs

# Verify
node -v  # v24.15.0
npm -v   # 11.x

Fedora / RHEL / Rocky Linux:

# NodeSource also provides RPMs
curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo -E bash -
sudo dnf install -y nodejs

Arch Linux:

# Arch usually has recent versions in its repos
sudo pacman -S nodejs npm

NVM installs Node in your home directory. Ideal when you juggle multiple projects with different versions.

# Install NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash

# Reload your shell or open a new terminal, then:
nvm install 24
nvm alias default 24

# Pin the version per project
echo "24" > .nvmrc
nvm use

Warning: NVM installs Node to ~/.nvm/versions/. If you need to run Node via a systemd service or under a different user, NVM is not suitable. Use NodeSource in that case.

Method 3: fnm (my personal favorite)

Faster than NVM, supports .node-version and .nvmrc, and handles multiple versions without slowing down shell startup:

# Install fnm
curl -fsSL https://fnm.vercel.app/install | bash

# Install Node 24
fnm install 24
fnm default 24

# Projects with .node-version or .nvmrc auto-switch
fnm use

Method 4: official binaries (tarball)

For air-gapped environments or custom setups:

cd /usr/local
sudo curl -fsSL https://nodejs.org/dist/v24.15.0/node-v24.15.0-linux-x64.tar.xz | sudo tar -xJ --strip-components=1
node -v  # v24.15.0

Method 5: Docker / Podman

If you containerize your applications, simply update the base image:

# Dockerfile
FROM node:24-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
CMD ["node", "server.js"]

Official images node:24, node:24-alpine, node:24-slim are available on Docker Hub.

My migration experience

I migrated my personal projects and two client projects from Node 22 to Node 24 between January and March 2026. Here’s my field report.

What went smoothly:

  • Most “classic” applications (Express, Astro, scripts) worked without any changes
  • The native test runner became significantly nicer with automatic subtest waiting
  • npm install startup times dropped roughly 30% with npm 11
  • node:sqlite let me remove better-sqlite3 from 3 projects, reducing dependencies and build times

What hit snags:

  • An old JWT token signed with RSA-1024 refused to verify under Node 24 (OpenSSL 3.5 security level 2). I had to regenerate keys to RSA-2048.
  • A native package compiled with node-gyp required recompilation (normal for a major version bump)
  • The url.parse() to WHATWG API migration took me 10 minutes of grep + replace on a legacy codebase

My advice: If you’re on Node 22, don’t wait until April 2027 (its end of life). Plan the migration now, while you have time and the window isn’t under pressure. Run the Node.js codemods, test your suite, audit your crypto keys, and the rest should be smooth sailing.

Verdict

Node 24 LTS is a solid release. No flashy revolution, but a steady accumulation of improvements that make the runtime faster, more secure, and more modern. Native APIs keep getting richer (SQLite, test runner, URLPattern), reducing reliance on external dependencies. The stable Permission Model is a genuine security asset.

If you’re starting a new project today, go with Node 24 without hesitation. If you’re maintaining a Node 22 project, the migration is gentle enough to plan calmly.

Node.js keeps doing what it does best: evolving without breaking.