Ce qui se passe
Bun 1.4.1 corrige 202 tickets. Derrière ce décompte de version mineure, trois changements méritent qu'on s'arrête.
La mémoire au repos
C'est le résultat le plus marquant de la version. JavaScriptCore supprime désormais le code produit par le compilateur à la volée après une période d'inactivité prolongée — ce qui change tout pour un processus de longue durée qui alterne charge et creux.
Mesures de l'équipe (RSS après 60 s de charge puis 3 minutes d'inactivité, Linux x64) :
| Application | Bun 1.4.1 | Bun 1.4.0 | Bun 1.3.14 | Node.js 26 |
|---|---|---|---|---|
| Next.js SSR | 142 Mo | 222 Mo | 1 303 Mo | 195 Mo |
vite dev |
111 Mo | 142 Mo | 292 Mo | 115 Mo |
| Express | 53 Mo | 65 Mo | 76 Mo | 83 Mo |
| Fastify | 55 Mo | 65 Mo | 78 Mo | 89 Mo |
| Elysia | 44 Mo | 46 Mo | 69 Mo | 96 Mo |
| Hono | 34 Mo | 35 Mo | 53 Mo | 92 Mo |
Deux lectures. La progression depuis 1.3.14 sur Next.js SSR — de 1 303 Mo à
142 Mo — corrige surtout une anomalie. Le point durable est ailleurs : Bun passe
sous Node.js 26 sur les six applications mesurées, alors qu'il était encore
au-dessus sur Next.js et vite dev en 1.3.14.
HTTP/2 dans Bun.serve
Bun.serve sert maintenant HTTP/2 sur le même port que HTTP/1.1, avec les
mêmes routes et le même handler fetch ; req.url et req.body se comportent
de façon identique sur les deux protocoles. Sur TLS, la négociation passe par
ALPN ; en clair, un client qui envoie le préambule HTTP/2 est servi en HTTP/2.
Pour refuser HTTP/1.x :
Bun.serve({ http1: false, fetch(req) { return new Response("ok"); } });Le débit annoncé, sur un GET « Hello World » (Linux x64, 64 cœurs, h2load) :
291 512 req/s pour Bun.serve, contre 55 619 pour node:http2 exécuté dans
Bun et 42 733 pour node:http2 sous Node.js 26 — soit 6,8× plus rapide.
La limite à connaître avant de basculer : les WebSockets et les trailers de réponse ne sont pas encore supportés en HTTP/2.
Ce que ça change ailleurs
Bun.write(path, response) écrit désormais le corps d'une Response, d'une
Request ou d'un ReadableStream en flux vers le fichier au lieu de le charger
en mémoire : un téléchargement de 128 Mio ajoutait 161 Mo au pic de RSS, il en
ajoute maintenant 13 Mo. Dans la même logique, fetch() et les
téléchargements S3 se mettent en pause quand 256 Kio de corps ne sont pas lus.
Côté installation, bun install accepte --offline et --prefer-offline, qui
résolvent depuis le cache local sans contacter le registre — utile en intégration
continue et dans une image de construction, où le réseau est le maillon lent.
Le client WebSocket gagne pause() et resume(), qui arrêtent et relancent
les lectures sur la socket TCP sous-jacente. C'est une extension propre à Bun,
absente des navigateurs : l'API WHATWG ne sait pas cesser de recevoir sans
fermer la connexion, si bien que les messages qui arrivent plus vite qu'ils ne
sont traités s'accumulent en mémoire. Socket en pause, Bun ne lit plus et le
pair reçoit la contre-pression TCP.
S'y ajoutent crypto.argon2, le tree-shaking à travers les import()
dynamiques, --compile --bytecode en compilation croisée, et des exécutables
compilés plus petits et plus rapides à démarrer.
À retenir
bun upgradesuffit ; le gain mémoire ne demande aucun changement de code.- Si un proxy était placé devant Bun uniquement pour parler HTTP/2, il peut disparaître — sauf si vous servez des WebSockets par ce chemin.
- La compatibilité Node.js progresse sans être achevée : un projet qui dépend d'un module natif se teste avant de basculer.
Source : Bun