2 pontos por GN⁺ 2025-09-12 | 1 comentários | Compartilhar no WhatsApp
  • 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 install do 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.json por 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 libdeflate e 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 clonefile falhar, há fallback gradual para clonagem por diretório e depois para copyfile

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, sendfile e, por fim, para o método comum de copyfile

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

 
GN⁺ 2025-09-12
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

    • Eu não sabia que o bun era escrito em Zig
      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

    • A Lydia é muito boa em transmitir conceitos complexos de forma simples
      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

    • Na verdade, isso está mais próximo de engenharia de software (SE) do que de ciência da computação (CS)
      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