Le projet Bun a achevé en mai 2026 une migration majeure du code de Zig à Rust, avec plus de 1 million de lignes modifiées et 6 778 commits en 11 jours. La migration a utilisé 64 instances de Claude en parallèle, générant un coût API de 165 000 dollars. Après la migration, les fuites mémoire ont été résolues de manière fondamentale : la mémoire est passée de 6,7 Go à 609 Mo après 2 000 builds, avec une amélioration des performances de 2 % à 5 % et une réduction de la taille du binaire d’environ 20 %. Toutefois, le code contient environ 13 000 mots-clés unsafe, soit 178 fois plus que dans les projets similaires, présente 19 problèmes de régression connus, et les 1 million de lignes modifiées ne peuvent pas être revues ligne par ligne par un humain. Actuellement, Bun a été acquis par Anthropic.Auteur et source de l'article : InfoQ
En mai 2026, le projet Bun a effectué une migration de code à grande échelle, presque rare dans l'histoire du développement logiciel.
Cette migration a démarré le 3 mai et a été officiellement fusionnée dans la branche principale le 14 mai, soit en seulement 11 jours. Le code a été écrit en 6 jours, et tout le processus a été rendu public. Toutefois, Jarred Sumner a mis presque un mois pour rédiger son billet de blog de synthèse, soit bien plus long que le temps nécessaire pour écrire le code.
Ce runtime JavaScript contenait à l'origine 535 496 lignes de code Zig, hors commentaires ; environ 20 % du code était écrit en C++ et intégrait plusieurs bibliothèques C/C++. Ce réécriture en Rust, assistée par l'IA, a impliqué plus d'un million de modifications de code, 6 778 commits, et l'exécution d'environ 50 workflows dynamiques dans Claude Code.
Selon les données révélées par Sumner, cette réécriture a consommé 5,9 milliards de tokens d'entrée non mis en cache, 690 millions de tokens de sortie et 72 milliards de lectures de tokens d'entrée mis en cache, soit environ 165 000 USD selon les tarifs de l'API.
Sumner a déclaré qu'il s'agissait du niveau de pointe actuel de la technologie. Il estime que si trois ingénieurs parfaitement familiers avec la base de code Bun avaient effectué cette migration à la main, cela aurait pris environ un an, et pendant cette période, l'équipe aurait été presque incapable de continuer à développer de nouvelles fonctionnalités, à corriger des bogues ou à appliquer des correctifs de sécurité.
Après cette réécriture, Bun v1.3.14 sera la dernière version en Zig, et Bun v1.4.0 sera la première version en Rust.
1 Résultat : passage d'une fuite mémoire de 6,7 Go à une stabilité à 609 Mo
Bun a été initialement développé comme un projet Zig avec une portée très large : il s'agit à la fois d'un transpileur JavaScript et TypeScript, d'un emballeur, d'un gestionnaire de paquets, d'un exécuteur de tests, d'un résolveur de modules, ainsi que d'un client HTTP et WebSocket, et il implémente également la couche API Node.js. C'est cette large gamme de fonctionnalités qui a permis à l'interface CLI de Bun d'atteindre plus de 22 millions de téléchargements mensuels et d'obtenir le soutien de projets ou entreprises tels que Vercel, Railway, DigitalOcean, Claude Code et OpenCode.
Mais cette même largeur présente également certains défis pour Bun.
Dans Bun v1.3.14, un problème qui préoccupait les utilisateurs depuis longtemps : lors de l'exécution consécutive d'appels à Bun.build(), la mémoire s'accumule continuellement sans jamais être libérée. Chaque build entraîne une fuite d'environ 3 Mo, ce qui semble peu, mais si vous exécutez un serveur de développement où chaque requête déclenche un build, la mémoire est progressivement absorbée jusqu'à ce que le processus plante.
Lors des tests réels, l'utilisation de la mémoire s'élève à 1,9 Go après 500 builds, 3,5 Go après 1 000 builds, 5,1 Go après 1 500 builds et atteint 6,7 Go après 2 000 builds.

Ceci n'est qu'une partie des nombreux problèmes de mémoire. Dans la liste de correctifs de la version v1.3.14, Sumner a répertorié une longue série de problèmes :
Lors de l'appel de .reset() dans le module zlib, si une écriture asynchrone est en cours d'exécution dans le pool de threads, le processus se bloque en raison d'une « utilisation après libération de la mémoire » ; dans le module http2, des rappels JavaScript imbriqués déclenchent une re-hachage de la table de hachage, ce qui rend les pointeurs internes de flux invalides ; lors de l'exécution de UDPSocket.sendMany(), si le code utilisateur modifie l'état de connexion du socket via des rappels valueOf ou toString, une écriture hors limites se produit ; lorsqu'une allocation du tampon de sortie échoue dans crypto.scrypt, le rappel et le tampon protégé contenant le mot de passe ne sont jamais libérés ; ......La nature commune de ces bugs est très claire — ils pointent presque tous vers la même source : la combinaison de GC et de gestion manuelle de la mémoire dans un même logiciel.
Les moteurs modernes comme JavaScriptCore (et V8) imposent des règles extrêmement strictes concernant la gestion des exceptions et le GC, tandis que Zig, comme C, ne gère pas automatiquement la mémoire. Lorsque ces deux paradigmes coexistent dans le même processus, chaque allocation mémoire doit être examinée ligne par ligne : où ces octets sont-ils libérés ? Comment s'assurer qu'ils ne sont libérés qu'une seule fois ? Les exceptions JavaScript sont-elles correctement vérifiées ? Ce pointeur géré par le GC est-il visible pour le scanneur de pile conservateur ? S'agit-il de mémoire gérée par le GC ou de mémoire gérée manuellement ?
Ce qui est encore plus préoccupant, c’est que l’équipe n’a pas manqué d’efforts. Ils ont modifié le compilateur Zig pour ajouter le support d’Address Sanitizer (ASAN), exécutent des tests ASAN dans CI à chaque commit, utilisent la construction ReleaseSafe sous Windows, effectuent des tests de fuzzing 24/7 avec Fuzzilli, et réalisent de nombreux tests end-to-end sur les fuites mémoire. Malgré tout, les rapports de plantage continuent d’affluer.
« Notre liste de correctifs de bugs nous donne une mauvaise impression ; je suis fatigué de m’endormir en craignant une panne de Bun », a écrit Sumner. Il ne blâme pas Zig — d’autres utilisateurs de Zig n’ont pas rencontré de problèmes similaires avec Bun, car combiner un GC avec une gestion manuelle de la mémoire est une exigence extrêmement rare, pour laquelle presque aucun langage n’a été conçu.
La version Rust a obtenu les résultats suivants : lors de l'exécution de 2000 fois Bun.build(), la mémoire reste stable à 609 Mo.
Outre la résolution fondamentale du problème de fuite de mémoire, la réécriture en Rust apporte d'autres améliorations sur plusieurs axes.
En termes de stabilité, la version v1.4.0 corrige 128 bugs reproductibles de la version v1.3.14, allant des fuites mémoire aux plantages en passant par les erreurs d'affichage des couleurs dans les textes d'aide.
En termes de taille, combiné à la réécriture en Rust, les modifications d'ICU et le même regroupement de code, la taille binaire de Bun a été réduite d'environ 20 % sur Linux et Windows.

En termes de performance, une amélioration générale de 2 % à 5 % a été observée. Bun.serve est passé de 169 600 req/s à 177 700 req/s, et node:http de 103 800 à 108 500. Dans des scénarios réels, next build est passé de 13,62 secondes à 13,03 secondes, et la compilation par lots tsc de 0,94 seconde à 0,89 seconde.
Après le déploiement de Claude Code sur Rust Bun, le temps de démarrage sous Linux est passé de 517 ms à 464 ms, soit une amélioration d'environ 10 %.

2 Méthode : 64 Claude, 11 jours, 50 flux de travail
Comment Sumner y est-il parvenu ? Cela pourrait bien être la partie la plus à surveiller — car la méthode qu'il a utilisée diffère de la traditionnelle « faire écrire du code à l'IA ».
Sumner a décomposé l'ensemble du processus en environ 50 flux de travail dynamiques, chacun étant une boucle. Il a décrit ce modèle sous forme de pseudo-code sur son blog :

Chaque tâche dispose d’un contexte (par exemple, un ticket Jira ou une issue GitHub), Claude rédige le code en se basant sur ce contexte, puis deux relecteurs (également Claude) examinent le code, avant d’intégrer les retours. Une fois terminé, la tâche suivante est prise en charge.
Ce modèle traverse tout le processus de réécriture. Chaque flux de travail est chargé d'un objectif spécifique :
- Générer un guide de portage pour mapper les motifs et types de Zig aux motifs et types de Rust ;
- Mécaniquement porter chaque fichier .zig en un fichier .rs, en correspondance avec PORTING.md et LIFETIMES.tsv ;
- Corriger les erreurs de compilation de chaque crate ;
- Faites fonctionner des sous-commandes comme bun test ou bun build ;
- Faites passer tous les tests du jeu de tests Bun ; effectuez plusieurs rounds de refonte et de nettoyage majeurs.
Pendant la période de pointe, Sumner a exécuté simultanément 4 flux de travail, chacun contenant 16 Claude, soit un total de 64 Claude travaillant en parallèle sur 4 arbres de travail, soumettant et poussant des fichiers individuellement. Au pic maximum, Claude a écrit environ 1 300 lignes de code par minute.
Cette séparation entre « implémenteur » et « réviseur » est cruciale. Claude, qui écrit le code, a un biais, tout comme un ingénieur humain, en voulant que son code soit accepté. Ainsi, le réviseur et l’implémenteur sont complètement séparés — le réviseur ne voit que les différences de code, pas le raisonnement de l’implémenteur, et il est explicitement informé : « supposez que le code est erroné ». Chaque implémenteur est confronté à plus de deux réviseurs adversariaux, dont le seul objectif est de trouver des bogues.

Écrire le code n’est qu’une première étape. Le code Zig est un seul unité de compilation, tandis que Rust doit être divisé en environ 100 crates pour accélérer la compilation ; les dépendances circulaires ont provoqué l’affichage simultané d’environ 16 000 erreurs de compilation lors de l’exécution de cargo check. Pour une personne, c’est une catastrophe, mais pour 64 Claude travaillant en parallèle, c’est une file d’attente gérable. Le flux de travail regroupe les erreurs par crate, exécute cargo check pour chaque crate, un Claude corrige, deux revues, et un applique les modifications.
Ensuite, exécutez bun --version, puis bun test. Le flux de tests exécute aléatoirement 100 fichiers de test répartis sur 4 arbres de travail. La suite de tests comprend également plusieurs types : certains tests s'exécutent pendant plus d'une minute, d'autres épuisent le nombre maximal de connexions TCP du système, et d'autres encore forkent environ 10 000 processus. Sumner a utilisé systemd-run pour créer des cgroups afin de limiter les ressources, mais la machine a tout de même planté plusieurs fois en raison d'un manque d'espace disque.
Deux jours plus tard, les échecs des tests sur la plateforme Linux sont passés de 972 à 23. Un jour et demi plus tard, Linux était entièrement vert. Cinq jours plus tard, les six plateformes — Linux x64, Linux arm64, macOS x64, macOS arm64, Windows x64, Windows arm64 — ont toutes réussi.
Le 14 mai, la PR #30412 a été fusionnée officiellement, et tous les tests du jeu de tests ont été réussis sans aucun test ignoré ou supprimé.

3 Préoccupations : 13 000 lignes de code unsafe et non vérifiables ligne par ligne
Cependant, Sumner reconnaît également que ce travail n'est pas encore véritablement terminé.
À ce jour, environ 4 % du code Rust de Bun se trouve dans des blocs unsafe, soit environ 13 000 mots-clés unsafe répartis sur environ 27 000 lignes de code, contre un total de 780 000 lignes de code Rust. 78 % des blocs unsafe ne contiennent qu'une seule ligne, généralement un pointeur provenant de C++ ou un appel à une bibliothèque C.
Il prévoit que les futures重构 réduiront ce ratio. Mais quelqu'un a fait le calcul : environ 350 000 lignes de code pour uv, avec seulement 73 appels unsafe. Le nombre d'appels unsafe dans Bun est 178 fois supérieur à celui de uv. Ce écart est difficile à expliquer par le besoin d'appeler des bibliothèques C.
Et cela a ensuite exposé un comportement indéfini dans du code Rust sécurisé. C'est plus difficile à déboguer que C++, car vous supposez que le code sécurisé ne peut pas causer de problèmes.

L'équipe Bun a ensuite modifié PathString::init dans ce problème en unsafe fn.
Sumner admet lui-même que cette réécriture a introduit 19 problèmes de régression connus et indique que la plupart de ces régressions proviennent de code ayant la même syntaxe mais une sémantique différente.

Par exemple, ces deux extraits de code semblent similaires, mais se comportent différemment. L'assertion Zig est une fonction, donc ses paramètres s'exécutent à chaque build. L'assertion Rust debug_assert! est une macro, donc dans les versions de publication, l'expression entière (y compris l'appel de fonction) est supprimée insert_stale.
Bien que tous les problèmes aient été corrigés, cela ne signifie pas que les millions de lignes de code AI n'ont pas d'autres problèmes.

Qui, en son sain esprit, migrerait immédiatement son application de production vers une version dont l'exécution a été entièrement réécrite ? Croire que la version 1.4 n'a pas introduit de nouveaux bugs ou de changements de comportement est bien naïf.Un autre élément à ne pas ignorer est la revue de code. Il est impossible pour un humain de parcourir 1 million de lignes de modifications une à une — même à raison d'une ligne par minute, cela prendrait 11,7 jours continus ; à la vitesse réelle de revue de code (200 lignes par heure), il faudrait plus de deux ans pour les terminer.
Les examinateurs de cette PR sont principalement claude[bot] et coderabbitai[bot]. Sumner admet lui-même que sa méthode d'examen consiste à « vérifier si l'agent d'examen adversarial a correctement capturé les différences, s'assurer que les directives de conversion sont respectées, tout en lisant manuellement un bon nombre de lignes de code ». Mais il n'a pas précisé combien exactement.
Il reste encore un problème incontournable : Bun a été acquis par Anthropic en décembre 2025, et l’outil capable de maintenir efficacement ce dépôt de code est essentiellement Claude lui-même. Certains membres de la communauté affirment que cela ne correspond plus vraiment à la définition traditionnelle d’un projet open source — pour soumettre une PR à Bun, il faut d’abord souscrire à Anthropic, ou compter sur quelques membres clés qui ont déjà compris le code généré par l’IA.
165 000 dollars américains pour un an de travail, ça vaut le coup ?
Sumner a également révélé dans son blog que le coût de cette réécriture de l'API s'élève à environ 165 000 dollars, équivalent au travail d'un an de trois ingénieurs. Ce chiffre a suscité un débat animé sur Hacker News.
Certains estiment que cette dépense est en réalité très avantageuse. À Silicon Valley, 165 000 dollars ne permettent pas d'embaucher plusieurs ingénieurs à temps plein, encore moins des ingénieurs d'une entreprise du niveau d'Anthropic. Selon les données salariales de levels.fyi, la rémunération totale d'un ingénieur chez Anthropic est probablement de 500 000 dollars ou plus. Même en estimant grossièrement un salaire annuel moyen de 336 000 dollars pour 50 ingénieurs, cela équivaut à environ 1 292 dollars par jour. Pour 50 personnes travaillant continuellement pendant 11 jours, les coûts salariaux seuls approchent déjà 710 000 dollars, sans compter les avantages sociaux, les locaux, l'équipement et les autres frais de gestion.

Cependant, Sumner utilise une version préliminaire de Claude Fable 5, un modèle avancé non encore disponible au public et susceptible d'être soumis à des restrictions d'exportation. Ainsi, le prix de l'API n'est que le chiffre visible par l'utilisateur final, cachant des coûts de recherche et développement considérables engagés par Anthropic. Certains soulignent que réduire les coûts au seul prix de l'API revient à minimiser délibérément les investissements réels. Si l'on prend en compte les coûts de développement du modèle, d'entraînement, de puissance de calcul et de main-d'œuvre technique, le coût total final est certainement très élevé, probablement dépassant 1,5 million de dollars.

Et pour l'instant, bien que 165 000 dollars américains pour un an de travail semblent avantageux sur le papier.
Mais le vrai coût ne figure pas sur cette facture. Ce dépôt de code compte 6 778 commits, et personne n'a jamais lu l'intégralité du code depuis le début. Bien que tout fonctionne actuellement, que se passera-t-il dans six mois ? Lorsqu'un problème de concurrence étrange surgit soudainement à 3 heures du matin, l'ingénieur de garde doit faire face à un système dont même lui ne comprend pas bien la logique interne. À long terme, il faudra que l'IA le maintienne — mais comment évaluer ce coût de maintenance ? C'est en réalité très difficile.

