Node.js 24 LTS : Toutes les Nouvelles Features du V8 13.6, npm 11 et Améliorations de Performance
Salut HaWkers, Node.js 24 est officiellement arrivé en mai 2025 et est programmé pour entrer en LTS (Long-Term Support) en octobre. Cette version apporte une quantité impressionnante de nouvelles features JavaScript, améliorations de performance et APIs modernisées.
Si vous travaillez avec JavaScript côté backend, ce guide va vous montrer tout ce que vous devez savoir sur la nouvelle version.
Overview de Node.js 24
Node.js 24 représente un saut significatif en capacités.
Principales mises à jour :
| Composant | Version Précédente | Node.js 24 |
|---|---|---|
| V8 Engine | 12.x | 13.6 |
| npm | 10.x | 11 |
| Undici | 6.x | 7 |
| libuv | 1.48 | 1.50 |
Timeline de support :
- Lancement : Mai 2025
- LTS Actif : Octobre 2025 - Avril 2027
- Maintenance : Avril 2027 - Avril 2028
Nouvelles Features JavaScript
Le V8 13.6 débloque plusieurs features ECMAScript modernes.
RegExp.escape
Nous avons enfin une façon native d'échapper les strings pour utilisation dans les expressions régulières.
// Avant - fonction manuelle (sujette aux bugs)
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
// Maintenant - méthode native
const userInput = "Hello [World]! Price: $100";
const escaped = RegExp.escape(userInput);
// Résultat : "Hello \\[World\\]! Price: \\$100"
// Usage pratique en recherche
function highlightText(text, searchTerm) {
const safeSearchTerm = RegExp.escape(searchTerm);
const regex = new RegExp(`(${safeSearchTerm})`, 'gi');
return text.replace(regex, '<mark>$1</mark>');
}
const result = highlightText(
"Prix : 50,00€ (promotion)",
"50,00€"
);
// "<mark>50,00€</mark>" correctement mis en évidenceFloat16Array
Nouveau typed array pour floats 16 bits, idéal pour ML et graphiques.
// Float16Array - moitié de la taille de Float32Array
const float16Data = new Float16Array(4);
float16Data[0] = 1.5;
float16Data[1] = -2.25;
float16Data[2] = 3.14159; // Tronqué pour précision 16 bits
float16Data[3] = 0.0001;
console.log(float16Data.byteLength); // 8 bytes (vs 16 pour Float32Array)
// Conversion entre types
const float32 = new Float32Array([1.5, 2.5, 3.5, 4.5]);
const float16 = new Float16Array(float32); // Conversion automatique
// Utile pour WebGL et Machine Learning
class NeuralNetworkLayer {
constructor(inputSize, outputSize) {
// Poids en Float16 économisent la mémoire
this.weights = new Float16Array(inputSize * outputSize);
this.biases = new Float16Array(outputSize);
}
forward(input) {
// Calcul avec précision réduite mais suffisante
const output = new Float16Array(this.biases.length);
// ... implémentation
return output;
}
}Error.isError
Vérification native si une valeur est vraiment un objet Error.
// Avant - vérification manuelle (échoue avec objets d'autres realms)
function isErrorOld(value) {
return value instanceof Error;
}
// Maintenant - méthode native (fonctionne entre realms)
console.log(Error.isError(new Error('test'))); // true
console.log(Error.isError(new TypeError('test'))); // true
console.log(Error.isError(new RangeError('test'))); // true
console.log(Error.isError({ message: 'fake error' })); // false
console.log(Error.isError(null)); // false
// Usage pratique en error handling
function handleResponse(result) {
if (Error.isError(result)) {
logger.error('Operation failed:', result.message);
return { success: false, error: result.message };
}
return { success: true, data: result };
}
// Fonctionne avec erreurs d'iframes/workers
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const IframeError = iframe.contentWindow.Error;
const iframeError = new IframeError('from iframe');
console.log(iframeError instanceof Error); // false (différents realms)
console.log(Error.isError(iframeError)); // true (fonctionne !)
Atomics.pause
Nouvelle primitive pour synchronisation de bas niveau dans les Workers.
// Atomics.pause - utile pour spin-waiting efficace
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Worker attendant une valeur
function waitForValue(expected) {
while (Atomics.load(sharedArray, 0) !== expected) {
// Pause permet au CPU d'optimiser le spin-wait
Atomics.pause();
}
return sharedArray[0];
}
// Main thread signalant
function signalWorker(value) {
Atomics.store(sharedArray, 0, value);
Atomics.notify(sharedArray, 0);
}
// Implémentation de spinlock
class SpinLock {
constructor(buffer, index) {
this.array = new Int32Array(buffer);
this.index = index;
}
acquire() {
while (Atomics.compareExchange(this.array, this.index, 0, 1) !== 0) {
Atomics.pause(); // CPU hint pour attendre
}
}
release() {
Atomics.store(this.array, this.index, 0);
}
}WebAssembly Memory64
Support mémoire 64 bits pour WebAssembly.
// WebAssembly avec mémoire 64 bits
const memory64 = new WebAssembly.Memory({
initial: 1,
maximum: 65536, // Jusqu'à 4TB de mémoire
index: 'i64', // Indexation 64-bit
});
// Permet d'adresser plus de 4GB de mémoire
// Utile pour applications big data et ML
// Exemple d'usage avec module WASM
const wasmCode = await fetch('/module.wasm');
const wasmBuffer = await wasmCode.arrayBuffer();
const wasmModule = await WebAssembly.instantiate(wasmBuffer, {
env: {
memory: memory64,
},
});
// Traiter datasets plus grands que 4GB directement en WASM
const exports = wasmModule.instance.exports;
const result = exports.processLargeDataset(dataPointer, dataSize);
AsyncLocalStorage Amélioré
AsyncLocalStorage utilise maintenant AsyncContextFrame par défaut.
import { AsyncLocalStorage } from 'node:async_hooks';
const requestContext = new AsyncLocalStorage();
// Middleware Express/Fastify
function contextMiddleware(req, res, next) {
const context = {
requestId: crypto.randomUUID(),
userId: req.user?.id,
startTime: Date.now(),
};
requestContext.run(context, () => {
next();
});
}
// Logger qui inclut automatiquement le contexte
class ContextLogger {
log(message, data = {}) {
const ctx = requestContext.getStore();
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
requestId: ctx?.requestId,
userId: ctx?.userId,
message,
...data,
}));
}
// Nouveau : Performance améliorée avec AsyncContextFrame
async logAsync(message) {
// Contexte préservé même dans opérations async complexes
await someAsyncOperation();
this.log(message);
}
}
// Usage n'importe où dans le code
const logger = new ContextLogger();
async function processOrder(orderId) {
logger.log('Processing order', { orderId });
// Même dans callbacks imbriqués, le contexte est préservé
await db.transaction(async (trx) => {
logger.log('Starting transaction');
await trx.insert('orders', { id: orderId });
logger.log('Order inserted');
});
logger.log('Order processed');
}Améliorations de performance :
| Opération | Node.js 22 | Node.js 24 |
|---|---|---|
| getStore() | ~150ns | ~50ns |
| run() overhead | ~500ns | ~200ns |
| Nested contexts | Linéaire | Constant |
URLPattern Global
L'API URLPattern est maintenant disponible globalement.
// Avant - nécessitait import
// import { URLPattern } from 'urlpattern-polyfill';
// Maintenant - disponible globalement
const pattern = new URLPattern({
pathname: '/users/:userId/posts/:postId',
});
// Matching d'URLs
const url1 = 'https://api.example.com/users/123/posts/456';
const match = pattern.exec(url1);
console.log(match.pathname.groups);
// { userId: '123', postId: '456' }
// Patterns plus complexes
const apiPattern = new URLPattern({
protocol: 'https',
hostname: '*.example.com',
pathname: '/api/v:version/:resource{/:id}?',
});
const testUrls = [
'https://api.example.com/api/v2/users',
'https://api.example.com/api/v2/users/123',
'https://cdn.example.com/api/v1/files/abc',
];
testUrls.forEach(url => {
const result = apiPattern.exec(url);
if (result) {
console.log('Match:', {
subdomain: result.hostname.groups[0],
version: result.pathname.groups.version,
resource: result.pathname.groups.resource,
id: result.pathname.groups.id,
});
}
});
// Router simple utilisant URLPattern
class PatternRouter {
constructor() {
this.routes = [];
}
add(method, patternString, handler) {
this.routes.push({
method,
pattern: new URLPattern({ pathname: patternString }),
handler,
});
}
match(method, url) {
for (const route of this.routes) {
if (route.method !== method) continue;
const match = route.pattern.exec(url);
if (match) {
return { handler: route.handler, params: match.pathname.groups };
}
}
return null;
}
}
const router = new PatternRouter();
router.add('GET', '/users/:id', getUserHandler);
router.add('POST', '/users', createUserHandler);
router.add('GET', '/posts/:postId/comments/:commentId?', getCommentsHandler);
npm 11
npm 11 apporte des améliorations significatives.
Performance d'Installation
# Installation plus rapide avec cache optimisé
npm install
# Benchmark comparatif (projet moyen ~500 deps)
# npm 10 : 45 secondes
# npm 11 : 28 secondes (-38%)
# Nouvel algorithme de résolution de dépendances
# Moins de duplication, arbre plus flatNouvelles Commandes et Flags
# Query améliorée de dépendances
npm query ":root > :has([name^=@types/])"
# Liste toutes les dépendances de types directes
# Audit avec plus de détails
npm audit --format=json --detail
# Pack avec preview
npm pack --dry-run --json
# Montre exactement ce qui serait inclus
# Installation sélective
npm install --omit=dev --omit=optional --omit=peer
# Vérification d'intégrité améliorée
npm doctor --fix
# Corrige les problèmes automatiquement quand possibleWorkspaces Améliorés
# Exécution parallèle dans workspaces
npm run build --workspaces --parallel
# Filtrage par workspace
npm run test --workspace=packages/core --workspace=packages/utils
# Publication coordonnée
npm publish --workspaces --tag latest
# Dépendances entre workspaces
npm install @myorg/utils --workspace=packages/core
Test Runner Natif Amélioré
Le test runner de Node.js a reçu des améliorations significatives.
import { describe, it, before, after, mock } from 'node:test';
import assert from 'node:assert';
describe('UserService', () => {
let db;
let service;
before(async () => {
db = await createTestDatabase();
service = new UserService(db);
});
after(async () => {
await db.close();
});
// Nouveau : Subtests n'ont plus besoin d'await explicite
it('should create user', async (t) => {
const user = await service.create({
name: 'Test User',
email: 'test@example.com',
});
// Subtests gérés automatiquement
t.test('should have valid id', () => {
assert.ok(user.id);
assert.match(user.id, /^[a-f0-9-]{36}$/);
});
t.test('should have timestamps', () => {
assert.ok(user.createdAt instanceof Date);
assert.ok(user.updatedAt instanceof Date);
});
});
// Nouveau : Mocking amélioré
it('should send welcome email', async (t) => {
const sendEmail = t.mock.fn(async () => ({ sent: true }));
// Mock de module
t.mock.module('../email-service.js', {
namedExports: { sendEmail },
});
await service.create({ name: 'Test', email: 'test@test.com' });
assert.strictEqual(sendEmail.mock.calls.length, 1);
assert.strictEqual(
sendEmail.mock.calls[0].arguments[0],
'test@test.com'
);
});
// Nouveau : Snapshot testing
it('should format user correctly', async (t) => {
const user = await service.getById('user-123');
t.assert.snapshot(user);
});
});Exécution des tests :
# Exécuter tous les tests
node --test
# Avec coverage
node --test --experimental-test-coverage
# Watch mode
node --test --watch
# Filtrer par nom
node --test --test-name-pattern="UserService"
# Reporter personnalisé
node --test --test-reporter=spec
Undici 7
Le client HTTP par défaut a été mis à jour vers Undici 7.
import { request, fetch, Agent, Pool } from 'undici';
// Fetch avec plus de contrôle
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: 'test' }),
// Nouveau : Contrôle de timeout granulaire
signal: AbortSignal.timeout(5000),
});
// Pool de connexions optimisé
const pool = new Pool('https://api.example.com', {
connections: 10,
pipelining: 6,
keepAliveTimeout: 30000,
keepAliveMaxTimeout: 60000,
});
// Requests utilisant pool
const { statusCode, body } = await pool.request({
path: '/users',
method: 'GET',
});
const data = await body.json();
// Agent customisé pour retry
const retryAgent = new Agent({
connect: {
timeout: 10000,
},
// Nouveau : Retry automatique
retry: {
maxRetries: 3,
minTimeout: 100,
maxTimeout: 1000,
},
});
// Streaming amélioré
const streamResponse = await fetch('https://api.example.com/stream', {
dispatcher: retryAgent,
});
for await (const chunk of streamResponse.body) {
process.stdout.write(chunk);
}
Dépréciations et Suppressions
Certaines APIs ont été dépréciées ou supprimées.
url.parse() Déprécié
// Déprécié
import { parse } from 'node:url';
const parsed = parse('https://example.com/path?query=1');
// Recommandé : WHATWG URL API
const url = new URL('https://example.com/path?query=1');
console.log(url.hostname); // 'example.com'
console.log(url.pathname); // '/path'
console.log(url.searchParams.get('query')); // '1'
// Migration de code legacy
// Avant
const oldUrl = parse('https://user:pass@example.com:8080/path?q=1#hash');
console.log(oldUrl.auth); // 'user:pass'
// Après
const newUrl = new URL('https://user:pass@example.com:8080/path?q=1#hash');
console.log(newUrl.username); // 'user'
console.log(newUrl.password); // 'pass'tls.createSecurePair Supprimé
// Supprimé : tls.createSecurePair()
// Utilisez tls.TLSSocket directement
import tls from 'node:tls';
import net from 'node:net';
const socket = net.connect(443, 'example.com');
const tlsSocket = new tls.TLSSocket(socket, {
// options
});
Migration depuis Node.js 22
Guide pratique pour la mise à jour.
Checklist de Migration
# 1. Vérifier version actuelle des dépendances
npm outdated
# 2. Mettre à jour dépendances qui peuvent avoir des problèmes
npm update
# 3. Vérifier usage d'APIs dépréciées
npx depcheck
# 4. Tester avec Node.js 24
nvm install 24
nvm use 24
npm test
# 5. Vérifier compatibilité des native modules
npm rebuild
# 6. Mettre à jour engines dans package.json{
"engines": {
"node": ">=24.0.0"
}
}Breaking Changes Importants
Changements qui peuvent affecter votre code :
url.parse()émet maintenant un warning de dépréciationtls.createSecurePaira été supprimé- Certains flags expérimentaux ont été supprimés
--experimental-specifier-resolutionsupprimé (utilisez import maps)
Conclusion
Node.js 24 représente une évolution significative de la plateforme. Avec V8 13.6, nous gagnons des features JavaScript modernes comme RegExp.escape et Float16Array. npm 11 apporte des installations plus rapides et des workspaces améliorés. Le test runner natif est de plus en plus complet.
Pour ceux qui sont en production avec Node.js 20 ou 22, la migration vers 24 LTS (quand disponible en octobre) sera tranquille pour la plupart des projets. Les dépréciations sont peu nombreuses et bien documentées.
Si vous voulez explorer davantage l'écosystème JavaScript moderne, consultez notre article sur ECMAScript 2025 et Nouvelles Features JavaScript.
C'est parti ! 🦅
📚 Vous Voulez Maîtriser Node.js du Zéro à l'Avancé ?
Cet article a montré les nouveautés de Node.js 24, mais pour profiter de tout le potentiel de la plateforme, vous avez besoin de fondements solides.
Matériel d'Étude Complet
Si vous voulez construire une base solide en JavaScript pour maîtriser Node.js :
Options d'investissement :
- 1x de 9,90€ par carte
- ou 9,90€ comptant
👉 Découvrir le Guide JavaScript
💡 JavaScript solide = Node.js maîtrisé

