Les coulisses de Bun Install
(bun.com)- L’installation de paquets de Bun fonctionne à une vitesse très élevée par rapport aux gestionnaires de paquets existants
- Le cœur de cette rapidité repose sur une approche relevant de la programmation système et sur la minimisation des appels système
- Les performances sont améliorées grâce à des stratégies fines, comme du code natif basé sur le langage Zig, l’utilisation d’un cache binaire et des optimisations selon l’OS
- Même dans les étapes de décompression des tarballs et de copie de fichiers, des méthodes hautes performances tirant parti des caractéristiques matérielles ont été adoptées
- L’optimisation des structures de données comme le graphe de dépendances et le lockfile améliore l’efficacité du cache CPU et l’accessibilité mémoire
Pourquoi Bun Install est rapide
- En moyenne,
bun installde Bun offre des performances d’installation de paquets 7 fois plus rapides que npm, 4 fois plus rapides que pnpm et 17 fois plus rapides que yarn - Ce n’est pas simplement le résultat d’un benchmark, mais d’une approche du problème de l’installation de paquets sous l’angle de la programmation système plutôt que de JavaScript
- Bun applique activement des optimisations à plusieurs niveaux : minimisation des appels système, cache binaire des manifests, optimisation de l’extraction des tarballs et copie de fichiers native selon l’OS
Les limites de Node.js et de l’architecture des gestionnaires de paquets
- Depuis la sortie de Node.js en 2009, le modèle d’IO asynchrone fondé sur une boucle d’événements et un pool de threads s’est propagé aux gestionnaires de paquets
- À l’époque, en raison des limites matérielles (disques lents, réseau lent), la stratégie fondée sur l’IO asynchrone et une forte fréquence d’appels système était rationnelle
- Mais sur les systèmes modernes, les SSD NVMe, les réseaux rapides et les CPU haute performance sont devenus courants, et le véritable goulet d’étranglement n’est plus l’IO mais le surcoût des appels système
Le coût des appels système et des changements de mode
- Lorsqu’un programme demande une opération comme la lecture d’un fichier, il doit passer du user mode au kernel mode, un processus qui consomme un nombre élevé de cycles CPU (1000 à 1500 cycles)
- L’installation de paquets nécessite fondamentalement des dizaines de milliers, voire des centaines de milliers d’appels système, si bien que le seul coût de ces transitions représente déjà plusieurs secondes de temps CPU
- Par exemple, lors de l’installation de React et de ses dépendances, npm utilise environ 1 million d’appels système, yarn 4 millions, pnpm 500 000, et bun 160 000
Différences d’approche entre les gestionnaires de paquets existants et Bun
- npm, pnpm et yarn sont tous basés sur Node.js, ce qui oblige à exécuter JavaScript à travers plusieurs couches d’abstraction (libuv, boucle d’événements, pool de threads, médiation des appels système)
- Cela accumule la conversion d’arguments, les files d’attente du pool de workers, la répartition des tâches dans la boucle d’événements et les appels système futex (synchronisation par verrou), au point que la gestion des appels système finit par être plus lente que l’IO elle-même
- À cause de cette limite structurelle, un gestionnaire de paquets construit avec Node.js a du mal à atteindre des performances réellement proches du natif
Bun : un moteur d’installation natif implémenté en Zig
- Bun appelle directement les appels système en langage Zig, en éliminant entièrement le moteur JavaScript et les couches d’abstraction
- Par exemple, la lecture de fichier exécute directement l’appel système
openat()dans le code Zig et renvoie immédiatement les données - Ainsi, la lecture de dizaines de milliers de fichiers fonctionne à très grande vitesse, sans pool de threads, boucle d’événements ni conversion de données
- Dans les benchmarks, Bun peut lire 146 057
package.jsonpar seconde, tandis que Node.js est plus de deux fois plus lent, autour de 60 000
Gestion des dépendances et optimisation DNS
- Lors de l’exécution de
bun install, Bun déclenche l’analyse des dépendances et le DNS prefetch de manière asynchrone en parallèle - Par exemple, sur macOS, il utilise l’API DNS asynchrone non officielle d’Apple (
getaddrinfo_async_start()), ce qui permet de traiter simultanément les opérations réseau sans bloquer de thread - Les gestionnaires de paquets existants reposent sur le pool de threads de libuv, où du code bloquant s’exécute en réalité en interne, ce qui gaspille des ressources
Cache binaire des manifests de paquets
- npm et d’autres mettent les manifests en cache au format JSON, mais Bun les parse une fois, puis stocke le résultat converti en binaire (fichier
.npm) - Cela réduit au minimum la duplication des chaînes et le coût du parsing, et en mémoire l’accès aux valeurs se fait immédiatement par simple calcul d’offset (sans création de nouveaux objets, parsing ou garbage collection)
- Les en-têtes ETag et If-None-Match permettent de vérifier uniquement les changements et de valider l’actualité des données sans parsing inutile
- D’après les benchmarks, une installation depuis le cache de Bun est plus rapide qu’une fresh install avec npm
Performances de traitement des tarballs
- Les gestionnaires de paquets classiques reçoivent généralement les tarballs en flux, ce qui entraîne une succession de réallocations, copies et redimensionnements dès que la mémoire tampon devient insuffisante
- Bun reçoit d’abord l’intégralité du tarball puis le décompresse ; il détermine à l’avance la taille décompressée grâce aux 4 derniers octets du gzip, puis n’alloue la mémoire qu’une seule fois
- En utilisant notamment libdeflate, Bun accélère la décompression tout en supprimant les copies redondantes et les redimensionnements inutiles
Optimisation du graphe de dépendances et des structures de données
- Les gestionnaires de paquets existants construisent des arbres de dépendances à base d’objets JavaScript et de pointeurs, ce qui disperse aléatoirement la mémoire et provoque fréquemment des défauts de cache CPU (problème de pointer chasing)
- Bun applique le modèle Structure of Arrays (SoA) et stocke tous les paquets, chaînes et dépendances dans de grands blocs de mémoire contigus
- Grâce à un accès fondé sur les offsets et longueurs, le CPU peut lire plusieurs paquets en une fois au niveau des lignes de cache (structure favorable au cache)
- Le lockfile aussi, au lieu d’utiliser JSON/YAML, est stocké suivant le modèle SoA, ce qui facilite l’élimination des doublons de chaînes et l’accès séquentiel en mémoire
- Un format binaire de lockfile (
bun.lockb) a également été introduit à titre expérimental, mais a été abandonné au profit d’un format texte plus lisible, car il dégradait la collaboration via Git
Optimisation de la copie de fichiers selon l’OS
macOS
- Utilisation de
clonefile: duplication d’un répertoire entier en Copy-On-Write via un seul appel système - Cela minimise l’usage redondant de l’espace disque et maximise la vitesse d’installation
- En cas d’échec de
clonefile, Bun applique un fallback progressif : clonage par répertoire, puiscopyfile
Linux
- Tentative prioritaire de hardlink : au lieu de créer un nouveau fichier, seul un nouveau pointeur vers le fichier existant est créé (sans déplacement des données sur le disque)
- Si le hardlink n’est pas possible, Bun applique le Copy-On-Write via
ioctl_ficlonesur Btrfs/XFS - Ensuite, il bascule si nécessaire vers
copy_file_range,sendfile, puis en dernier recours vers une copie classique aveccopyfile
Bilan
- Bun dépasse les limites traditionnelles de performance des gestionnaires de paquets grâce à la minimisation des appels système, aux structures binaires, aux optimisations spécifiques à l’OS et à l’amélioration des structures de données
- Cela apporte non seulement des installations ultra-rapides, mais améliore aussi l’efficacité mémoire et CPU
- Par rapport aux gestionnaires basés sur Node.js, il peut être adopté dans les projets sans remplacement de runtime distinct, tout en conservant la compatibilité
- Dans de grandes bases de code réelles, il offre une expérience où des installations qui prenaient plusieurs minutes sont réduites à quelques millisecondes à quelques secondes
- C’est un excellent exemple d’optimisation sur mesure adaptée au système, au matériel et à l’OS, avec une forte valeur d’étude et de référence
1 commentaires
Avis Hacker News
J’ai essayé de vérifier l’affirmation selon laquelle mon MacBook M4 Max ferait partie du top 50 des supercalculateurs du TOP500 de 2009
Pour entrer dans le TOP500 en 2009, il fallait plus de 75 TFlop/s de performance
Le M4 Max atteint 18,4 TFlop/s en FP32, mais le TOP500 utilise le FP64 (LINPACK)
D’après des benchmarks du M2, le FP64 représente environ un quart du FP32, donc on peut estimer environ 9 TFlop/s
À ce niveau, il n’entrerait pas dans le TOP500 de 2009
Voir la liste TOP500 de 2009
Si chaque connexion effectue plusieurs opérations d’E/S en parallèle, il faut alors multiplier par des milliers de connexions
J’ai entendu dire qu’un serveur passait environ 95 % de son temps à attendre les E/S, mais en réalité cela s’applique à chaque thread, pas au serveur entier
En pratique, un serveur monte souvent à 70–80 % d’utilisation CPU (au-delà, la tail latency se dégrade fortement)
Si le CPU n’est qu’à 5 % à pleine charge, c’est qu’il y a un manque de processus parallèles ou un problème de mémoire
C’est un petit détail technique, mais ce genre d’erreur peut nuire à la crédibilité du billet (je dis ça en tant que fan de Bun)
Cette conclusion donne un peu l’impression d’une hallucination produite par un LLM
La partie conclusion, en particulier, ressemble à quelque chose généré par un LLM
« Cela m’a fait comprendre que les gestionnaires de paquets benchmarkés n’étaient pas mauvais, mais constituaient des solutions adaptées à leur époque »
« Ce qui est mis en avant avec l’approche de Bun, ce n’est pas tant son caractère révolutionnaire que le fait qu’elle résulte d’un regard lucide sur les causes actuelles de la lenteur »
« Si l’installation des paquets est 25 fois plus rapide, ce n’est pas par magie, mais simplement parce que l’outil a été conçu pour le matériel moderne »
J’ai vraiment aimé la façon dont un sujet complexe était expliqué de manière simple et facile à lire
C’est impressionnant de voir qu’il existe encore des gens passionnés qui remettent en cause le statu quo et s’attaquent à des problèmes difficiles
Chaque mois, le matériel informatique progresse, mais les logiciels deviennent plus lents, et ça me semble anormal
J’aimerais que tout le monde code plus efficacement
Zig est un langage très récent, donc c’est intéressant de le voir utilisé sérieusement en pratique
J’ai essayé bun pour la première fois, et j’ai été très impressionné
Grâce au serveur intégré et à SQLite, il suffit d’installer bun et le développement devient bien plus pratique
J’utilise généralement seulement du vanilla js et je n’ai jamais beaucoup aimé l’écosystème node, donc je me dis que j’aurais dû essayer bun plus tôt
J’ai essayé Bun plusieurs fois et l’expérience d’utilisation m’a beaucoup plu
Je l’ai trouvé meilleur que Node
Mais je finis toujours par tomber sur un problème bloquant, donc je reviens à Node
Au début, le module crypto n’était pas compatible avec Nodejs (c’est corrigé maintenant), puis Playwright ne fonctionnait pas sur Bun
De nos jours, Node prend aussi en charge un serveur intégré et SQLite
Si tu as besoin de plus de fonctionnalités, Hono est aussi une bonne alternative
Je n’ai pas bien compris la partie de l’article qui explique que les hard links de Linux et
clonefilede MacOS seraient équivalentsAvec les hard links, si on modifie une copie, est-ce que cela ne change pas aussi de façon inattendue le fichier dans tous les projets ?
Malgré une explication techniquement assez complexe, c’est vraiment écrit de façon très lisible et agréable
J’ai vu la plupart de ses travaux et de ses vidéos, et on sent qu’elle prépare ses sujets en profondeur
Si vous avez le temps, je recommande vivement ses articles et ses contenus YouTube
Ces derniers temps, j’ai l’impression qu’elle est moins active, sans doute à cause de son travail actuel
Dans la section Binary Manifest Caching, il semble que le temps de benchmark de « npm (cached) » manque
Il n’y a que bun, bun (cached) et npm, et même les statistiques récapitulatives ne semblent pas tout à fait cohérentes
J’ai adoré le style d’écriture de ce billet
Ça ferait un très bon exemple réutilisable pour expliquer l’importance de
io_uringJe me demande si la récente mise à jour io de Zig v0.15 pourrait encore améliorer les performances de Bun
Ça fait plus d’un an que j’attends beaucoup de bun
Je pensais que 2025 serait l’année de sa démocratisation, mais contre toute attente, il n’est toujours pas si populaire
Parmi les 100 000 principaux dépôts GitHub, pour les nouveaux dépôts en 2025, npm est utilisé 35 fois plus souvent et pnpm 11 fois plus souvent
Même Deno n’est pas aussi populaire que je l’imaginais
Je me demande pourquoi
Est-ce parce qu’il est plus difficile d’assurer la compatibilité pour un runtime que pour un gestionnaire de paquets ?
J’aimerais entendre l’avis de ceux qui ont essayé bun sans l’adopter
Statistiques associées
Commentaire HN associé
J’ai essayé plusieurs fois d’aimer à la fois Bun et Deno, mais à chaque fois je suis tombé sur un défaut bloquant, donc j’ai fini par abandonner
Le plus gros problème récent que j’ai rencontré sur Bun, c’était un souci où les streams se fermaient prématurément
Lien vers l’issue correspondante
Sur Deno, j’ai rencontré un problème de fuite mémoire
Lien vers l’issue correspondante
Au final, j’ai l’impression que l’écosystème Node finira par intégrer d’abord les avantages de Bun et Deno
Bun est un nouveau venu financé par du capital-risque, en concurrence avec un produit open source dominant et éprouvé (Node)
Il y a une incitation au lock-in, et au fond ce n’est pas si différent de Node
Son avantage stratégique n’est pas évident, et il n’apporte rien de vraiment nouveau qu’on ne puisse pas faire avec Node
Je n’ai jamais vu de cas d’usage vraiment sérieux, seulement des usages légers
Quand on regarde l’issue tracker, on a l’impression que le langage Zig n’est pas très sûr, vu la fréquence des crashs
Pour ma part, je vais rester sur Node
Moi aussi, je suis curieux d’avoir l’avis des autres
À mon sens, Node est un projet mature, démocratique, et très porté par sa communauté
C’est aussi parce qu’il a bien surmonté l’épisode du fork io.js
En revanche, bun et deno sont tous deux des projets soutenus par des VC, donc je n’ai pas l’impression qu’ils soient vraiment pilotés de manière démocratique par leur communauté
Je suis un grand fan de Bun
J’utilise Bun dans tous les projets où c’est possible, et j’écris aussi toutes sortes de scripts one-off en Bun/TS
Cela dit, il existe quelques problèmes, peu nombreux mais préoccupants, qui me font encore hésiter à le déployer en production
Par exemple, j’ai déjà eu un cas où un simple serveur web Express lancé dans Docker se figeait lorsqu’il tournait avec bun
En remplaçant uniquement par node, tout fonctionnait normalement
Il y a un an, j’avais aussi eu un serveur qui plantait à cause d’une fuite mémoire avec la combinaison Bun + Prisma (j’imagine que c’est corrigé aujourd’hui)
Malgré tout, j’aime tellement Bun que j’accepte ces défauts, car au global il me fait gagner du temps de développement
Le confort apporté par le transpile, les modules, les workspaces, etc., est énorme
Je comprends tout à fait qu’il ne soit pas encore aussi largement adopté que npm
J’ai pris énormément de plaisir à lire cet article
C’est un bon exemple de l’importance concrète des principes d’informatique théorique dans le développement logiciel
Big O, localité temporelle et spatiale, complexité algorithmique, espace utilisateur/espace noyau, système de fichiers, copy-on-write, etc.
Dans ce genre de développement de paquets bas niveau, tous les concepts appris dans un cursus d’informatique sont réellement mis en pratique
Le CS étudie le calcul et la théorie (langages de programmation, algorithmes, cryptographie, machine learning, etc.)
Le SE applique des principes d’ingénierie pour construire des logiciels extensibles et fiables
Je ne comprends pas bien pourquoi il serait avantageux d’attendre d’avoir entièrement lu une archive compressée avant de la décompresser
J’imagine qu’il serait au contraire plus avantageux de commencer la décompression avant la fin du téléchargement, malgré l’inconvénient lié à l’augmentation du nombre de recopies mémoire