Os bastidores do Bun Install
(bun.com)- A instalação de pacotes do Bun funciona de forma extremamente rápida em comparação com gerenciadores de pacotes existentes
- O ponto central dessa velocidade está em uma abordagem sob a ótica de programação de sistemas e na minimização de chamadas de sistema
- O ganho de desempenho vem da aplicação de estratégias detalhadas, como código nativo baseado em Zig, uso de cache binário e otimizações específicas por sistema operacional
- Até no processo de descompactação de tarballs e cópia de arquivos, ele adota métodos de alto desempenho que aproveitam as características do hardware
- Também aumenta a eficiência do cache da CPU e a acessibilidade à memória por meio de otimizações em estruturas de dados, como grafo de dependências e lockfile
Por que o Bun Install é rápido
- O
bun installdo Bun oferece, em média, uma instalação de pacotes 7 vezes mais rápida que npm, 4 vezes mais rápida que pnpm e 17 vezes mais rápida que yarn - Isso não se deve apenas a benchmark, mas ao fato de que o problema de instalação de pacotes foi abordado sob a ótica de programação de sistemas, e não de JavaScript
- Otimizações de desempenho foram aplicadas ativamente em várias camadas, como minimização de chamadas de sistema, cache binário de manifests, otimização da extração de tarballs e cópia de arquivos nativa do sistema operacional
Limitações do Node.js e da arquitetura dos gerenciadores de pacotes
- Desde o lançamento do Node.js em 2009, o modelo de IO assíncrono baseado em event loop e thread pool também se espalhou para os gerenciadores de pacotes
- Na época, por causa das limitações de hardware, como discos lentos e redes lentas, a estratégia de IO assíncrono com alta frequência de chamadas de sistema fazia sentido
- Porém, nos sistemas modernos, SSDs NVMe, redes rápidas e CPUs de alto desempenho já são comuns, e o gargalo real não é o IO, mas o overhead das chamadas de sistema
O custo de chamadas de sistema e troca de modo
- Quando um programa solicita uma operação como leitura de arquivo, é preciso alternar de user mode para kernel mode, e esse processo consome ciclos valiosos da CPU (1000 a 1500 ciclos)
- A instalação de pacotes exige, por natureza, dezenas ou centenas de milhares de chamadas de sistema, o que pode consumir vários segundos de tempo de CPU apenas com o custo de alternância entre operações
- Por exemplo, ao instalar o React e suas dependências, o npm usa cerca de 1 milhão de chamadas de sistema, o yarn 4 milhões, o pnpm 500 mil e o bun 160 mil
Diferença de abordagem entre gerenciadores tradicionais e o Bun
- npm, pnpm e yarn são todos baseados em Node.js, então o JavaScript precisa ser executado por várias camadas de abstração, como libuv, event loop, thread pool e intermediação de chamadas de sistema
- Nesse processo, acabam se acumulando conversão de argumentos, filas do worker pool, ramificações de tarefas no event loop e chamadas de sistema
futex(sincronização por lock), fazendo com que o gerenciamento dessas chamadas fique mais lento do que o próprio IO - Gerenciadores de pacotes feitos em Node.js têm dificuldade para alcançar desempenho próximo ao nativo por causa dessa limitação estrutural
Bun: motor de instalação nativo implementado em Zig
- O Bun, escrito em Zig, chama diretamente as chamadas de sistema, pulando totalmente o motor JavaScript e as camadas de abstração
- Por exemplo, a leitura de arquivo executa diretamente a chamada de sistema
openat()no código Zig e retorna os dados imediatamente - Assim, a leitura de dezenas de milhares de arquivos acontece em altíssima velocidade, sem thread pool, event loop ou conversão de dados no meio do caminho
- Em benchmark, o Bun consegue ler 146.057 arquivos
package.jsonpor segundo, enquanto o Node.js fica na casa dos 60 mil e é mais de 2 vezes mais lento
Gerenciamento de dependências e otimização de DNS
- Ao executar
bun install, o Bun aciona de forma assíncrona o prefetch de DNS ao mesmo tempo em que analisa as dependências - No macOS, por exemplo, ele usa a API assíncrona de DNS não oficial da Apple (
getaddrinfo_async_start()), permitindo processar tarefas de rede em paralelo sem bloquear threads - Já os gerenciadores tradicionais, baseados no thread pool do libuv, acabam executando internamente código bloqueante, desperdiçando recursos
Cache binário de manifests de pacotes
- npm e outros armazenam manifests em cache como JSON, mas o Bun faz o parse uma vez e depois salva o resultado em formato binário (arquivo
.npm) - Isso minimiza duplicação de strings e overhead de parse, e na memória real os valores podem ser acessados diretamente apenas por cálculo de offset, sem criar novos objetos, sem novo parse e sem garbage collection
- Com cabeçalhos ETag e If-None-Match, ele verifica apenas mudanças, validando atualizações sem parse desnecessário de dados
- Em benchmark, a instalação via cache do Bun é mais rápida até do que uma instalação fresh do npm
Desempenho no processamento de tarballs
- Gerenciadores de pacotes comuns recebem o tarball em stream, e sempre que falta espaço no buffer ocorrem realocações, cópias e redimensionamentos em sequência
- O Bun recebe o tarball inteiro antes de desempacotar e usa os últimos 4 bytes do gzip para descobrir previamente o tamanho descomprimido, o que permite alocar memória apenas uma vez
- Com uso de
libdeflatee afins, ele descompacta mais rápido e elimina cópias redundantes e redimensionamentos desnecessários
Grafo de dependências e otimização de estruturas de dados
- Gerenciadores tradicionais criam árvores de dependência com objetos JavaScript e ponteiros, o que espalha os dados aleatoriamente na memória e aumenta os cache misses da CPU com frequência (problema de pointer chasing)
- O Bun aplica o padrão Structure of Arrays (SoA), armazenando todos os pacotes, strings e dependências em grandes blocos contínuos de memória
- Com acesso baseado em offset/comprimento, a CPU consegue ler vários pacotes de uma vez por linha de cache, em uma estrutura amigável ao cache
- O lockfile também, em vez de JSON/YAML, é armazenado de forma alinhada ao padrão SoA, facilitando deduplicação de strings e acesso sequencial à memória
- O formato binário de lockfile (
bun.lockb) também foi introduzido de forma experimental, mas foi trocado por um formato de texto mais legível por reduzir problemas de colaboração com Git
Otimização de cópia de arquivos por sistema operacional
macOS
- Uso de
clonefile: clona o diretório inteiro com um único system call em modo Copy-On-Write - Reduz o uso duplicado de espaço em disco e maximiza a velocidade de instalação
- Se
clonefilefalhar, há fallback gradual para clonagem por diretório e depois paracopyfile
Linux
- Tenta hard link primeiro: em vez de criar um novo arquivo, cria apenas uma nova referência ao arquivo existente, sem mover dados no disco
- Se hard link não for possível, em Btrfs/XFS aplica Copy-On-Write com
ioctl_ficlone - Depois disso, faz fallback para
copy_file_range,sendfilee, por fim, para o método comum decopyfile
Resumo geral
- O Bun supera os limites tradicionais de desempenho de gerenciadores de pacotes por meio de minimização de chamadas de sistema, estruturas binárias, otimizações por sistema operacional e melhorias em estruturas de dados
- Com isso, além de instalação ultrarrápida, também oferece ganhos de eficiência em memória e CPU
- Em comparação com gerenciadores baseados em Node.js, ele pode ser aplicado a projetos sem necessidade de trocar o runtime separadamente, mantendo a compatibilidade
- Ele proporciona a experiência de reduzir processos de instalação que levavam minutos em codebases grandes para algo entre milissegundos e poucos segundos
- É um excelente caso de estudo e referência de otimização sob medida para o nível de sistema, hardware e sistema operacional
1 comentários
Comentários no Hacker News
Tentei verificar a afirmação de que meu MacBook M4 Max estaria entre os 50 primeiros supercomputadores do TOP500 de 2009
Para entrar no TOP500 de 2009, era preciso ter mais de 75 TFlop/s de desempenho
O M4 Max faz 18,4 TFlop/s em FP32, mas o TOP500 usa FP64 (LINPACK)
Com base em benchmarks do M2, FP64 fica em cerca de 1/4 do FP32, então a estimativa seria algo em torno de 9 TFlop/s
Com isso, ele não entraria no TOP500 de 2009
Veja a lista do TOP500 de 2009
Se cada conexão faz várias operações de I/O ao mesmo tempo, então isso precisa ser multiplicado por milhares de conexões
Já ouvi dizer que servidores passam cerca de 95% do tempo esperando por I/O, mas isso vale para threads individuais, não para o servidor inteiro
Na prática, servidores muitas vezes chegam a 70~80% de uso de CPU (acima disso, a tail latency piora rapidamente)
Se em carga total a CPU estiver em 5%, então o problema é falta de processos paralelos ou falta de memória
É um detalhe técnico pequeno, mas esse tipo de erro pode prejudicar a credibilidade do post (digo isso como fã do Bun)
Essa conclusão me parece meio como uma alucinação gerada por LLM
A parte da conclusão, em especial, parece saída de um LLM
"Entendi que os gerenciadores de pacote benchmarkados não estavam errados, mas eram soluções adequadas para aquela época"
"O ponto da abordagem do Bun não é tanto ser revolucionária, mas sim resultar de uma análise fria das causas da lentidão atual"
"O fato de a instalação de pacotes ter ficado 25 vezes mais rápida não é mágica, mas um efeito natural de construir ferramentas adequadas ao hardware moderno"
Mesmo sendo um tema complexo, gostei muito de como foi explicado de forma simples e fácil de ler
Continua sendo impressionante ver pessoas apaixonadas quebrando o status quo e encarando problemas difíceis
Todo mês o hardware evolui, mas o software fica mais lento, e isso parece anormal
Queria que todo mundo programasse com mais eficiência
Zig é uma linguagem bem nova, então é interessante vê-la sendo usada de forma séria na prática
Usei bun pela primeira vez e fiquei muito impressionado
O servidor embutido e o SQLite fazem com que baste instalar só o bun, então desenvolver fica muito mais conveniente
Eu normalmente só uso vanilla js e nunca gostei muito do ecossistema do node, então sinto que deveria ter experimentado bun antes
Já tentei usar Bun várias vezes e a experiência sempre foi muito boa
Achei melhor que Node
Mas sempre acabo batendo em algum problema decisivo e volto para Node
No começo, o módulo crypto não era compatível com Nodejs (agora isso foi corrigido), e depois foi o Playwright que não funcionou no Bun
Hoje em dia o Node também tem servidor embutido e suporte a SQLite
Se você precisar de mais recursos, o Hono também é uma boa alternativa
Não entendi muito bem a parte do artigo que explica hard links no Linux e clonefile no MacOS como se fossem equivalentes
No caso de hard links, se uma cópia for modificada, os arquivos de todos os projetos não mudariam inesperadamente?
Fiquei impressionado com como um conteúdo tecnicamente bastante complexo foi escrito de forma tão clara e agradável de ler
Vi a maior parte do trabalho e dos vídeos dela, e dá para perceber o quanto ela se prepara a fundo
Se tiver tempo, recomendo muito os artigos e o conteúdo dela no YouTube
Recentemente, parece que ela ficou menos ativa, provavelmente por causa do trabalho atual
Na seção Binary Manifest Caching, parece que está faltando o tempo de benchmark de "npm (cached)"
Só aparecem bun, bun (cached) e npm, e as estatísticas resumidas também parecem não bater direito
Gostei demais do estilo de escrita deste post
Acho que ele poderia ser reaproveitado como um ótimo exemplo para explicar a importância do io_uring
Fico curioso se a atualização recente de io no Zig v0.15 poderia trazer ganhos adicionais de desempenho para o Bun
Estou esperando pelo bun há mais de um ano
Achei que 2025 seria o primeiro ano da popularização do bun, mas surpreendentemente ele ainda não é tão popular assim
Entre os 100 mil principais repositórios no GitHub, em novos repositórios de 2025, o npm é usado 35 vezes mais e o pnpm 11 vezes mais
Até o Deno não é tão popular quanto eu imaginava
Fico me perguntando por quê
Será que é porque é mais difícil atingir compatibilidade em runtime do que em gerenciador de pacotes?
Gostaria de ouvir a opinião de quem tentou usar bun e acabou não adotando
Estatísticas relacionadas
Comentário relacionado no HN
Quis gostar tanto do Bun quanto do Deno e tentei usá-los várias vezes, mas sempre acabava encontrando algum defeito crítico e não conseguia continuar
O problema mais sério que tive recentemente no Bun foi um bug em que streams eram fechados cedo demais
Link da issue relacionada
No Deno, encontrei um problema de vazamento de memória
Link da issue relacionada
No fim, acho que o ecossistema Node vai acabar incorporando primeiro as vantagens do Bun/Deno
O Bun é um novato competindo, com novo dinheiro de venture capital, contra um produto open source dominante e comprovado (Node)
Há incentivos de lock-in e, no fim das contas, ele não é tão diferente assim do Node em termos fundamentais
Não tem uma vantagem estratégica tão clara, nem oferece algo realmente novo que não dê para fazer com Node
Na prática, nunca vi um caso de uso realmente sério; só vi usos mais casuais
Pelo issue tracker, parece que a linguagem Zig é bastante insegura, porque crashes acontecem com frequência
Eu vou continuar no Node
Também tenho curiosidade sobre a opinião dos outros
Na minha visão, o Node é um projeto maduro, democrático e fortemente guiado pela comunidade
Até porque conseguiu superar bem o episódio do fork io.js
Já bun e deno, por outro lado, são os dois projetos apoiados por VC, então não passam a mesma sensação de comunidade democrática e conduzida pelos usuários
Sou um grande fã do Bun
Uso Bun em praticamente todos os projetos possíveis e também escrevo vários scripts one-off em Bun/TS
Ainda assim, existem alguns problemas, poucos mas preocupantes, que me fazem hesitar antes de colocar em produção
Por exemplo, já vi um servidor web simples em Express rodando em Docker travar quando executado com bun
Se eu trocar apenas para node, ele funciona normalmente
Um ano atrás, também tive um servidor cair por vazamento de memória com a combinação Bun + Prisma (imagino que isso já tenha sido corrigido)
Mesmo assim, gosto tanto do Bun que, apesar dessas desvantagens, no geral ele reduz meu tempo de desenvolvimento
A conveniência com transpile, módulos, workspaces etc. é enorme
Também entendo perfeitamente por que ele ainda não se popularizou no nível do npm
Foi muito prazeroso ler este texto
É um ótimo exemplo de como princípios de ciência da computação são realmente importantes no desenvolvimento de software
Big O, localidade temporal/espacial, complexidade algorítmica, user/kernel space, sistema de arquivos, copy-on-write etc.
Em desenvolvimento de pacotes de baixo nível assim, todos os conceitos aprendidos em um curso de CS acabam sendo usados na prática
CS estuda computação e teoria (linguagens de programação, algoritmos, criptografia, machine learning etc.)
Já SE aplica princípios de engenharia para construir software escalável e confiável
Não entendi bem por que seria vantajoso esperar para descompactar só depois de ler todo o arquivo compactado
Imagino que começar a descompressão antes do fim do download possa ser mais vantajoso do que a desvantagem de aumentar o número de recópias em memória