Reescrevendo o Bun em Rust
(bun.com)- O Bun, que começou em Zig, cresceu até se tornar um runtime com mais de 22 milhões de downloads por mês, mas os problemas recorrentes de estabilidade causados pela combinação de um engine JavaScript baseado em GC com gerenciamento manual de memória motivaram a migração para Rust
- Em vez de uma pessoa passar 1 ano migrando 535.496 linhas de código Zig, cerca de 50 fluxos de trabalho dinâmicos do Claude Code e até 64 instâncias do Claude foram executados em paralelo por 11 dias
- O port foi validado com
PORTING.md,LIFETIMES.tsv, 1 implementador e pelo menos 2 revisores adversariais, além da suíte de testes existente em TypeScript, e obteve 100% de aprovação em CI em 6 plataformas - Após a migração para Rust, o Bun v1.4.0 corrigiu 128 bugs reproduzíveis no v1.3.14, eliminou todos os vazamentos de memória instrumentáveis e reduziu em cerca de 20% o tamanho dos binários para Linux e Windows
- O Bun v1.3.14 é a última versão em Zig, e o v1.4.0 é a primeira versão em Rust, disponibilizada em canary; a equipe usa borrow checker, Miri, LeakSanitizer e fuzzing baseado em cobertura 24/7 como ferramentas para melhorar a estabilidade
O Bun, que começou em Zig, e os problemas de estabilidade
- O Bun começou como um projeto que fez o port linha por linha do transpiler de JavaScript e TypeScript do esbuild de Go para Zig
- O primeiro código em Zig foi escrito em 16 de abril de 2021, e o controle de baixo nível e o design voltado a desempenho do Zig possibilitaram a implementação inicial do Bun
- O Bun inicial foi escrito em Zig por uma única pessoa ao longo de 1 ano e tinha um escopo muito amplo
- transpiler, minifier e bundler de JavaScript, TypeScript e CSS
- gerenciador de pacotes compatível com npm
- test runner semelhante ao Jest
- resolução de módulos compatível com Node.js e TypeScript
- clientes HTTP/1.1 e WebSocket
- implementação de APIs do Node.js como
fs,netetls
- Atualmente, o CLI do Bun tem mais de 22 milhões de downloads por mês, Claude Code e OpenCode o utilizam como runtime, e Vercel, Railway e DigitalOcean oferecem suporte de primeira parte
Bugs recorrentes de estabilidade de memória
- Entre os exemplos de bugs corrigidos no Bun v1.3.14 estão use-after-free, double-free, vazamentos de memória, acessos out-of-bounds e race conditions
- heap-use-after-free causado pela chamada de
.reset()durante um.write()assíncrono denode:zlib - use-after-free em
node:http2, em que um callback JS reentrante provocava rehash de hashmap e invalidava ponteiros internos de stream - problema em
UDPSocket.send()esendMany()em que callbacksvalueOf()outoString()faziam detach deArrayBuffer - crashes e leituras out-of-bounds em
Buffer#copyeBuffer#fillcausados por detach ou resize deArrayBufferdurante a coerção de argumentos - vazamentos de memória relacionados a
crypto.scrypt,tlsSocket.setSession()efs.watch() - double-free durante o tratamento de vendor prefix e multi-layer background no parser de CSS
- crash por race condition de
MessageEventdurante acesso simultâneo aBroadcastChannelouMessagePort
- heap-use-after-free causado pela chamada de
- Já eram usados vários mecanismos para reforçar a estabilidade
- foi aplicado um patch no compilador Zig para suportar Address Sanitizer, e a suíte de testes com ASAN era executada em todos os commits
- no Windows, eram distribuídas builds Zig ReleaseSafe com verificação de segurança
- a API de runtime do Bun era submetida a fuzzing 24/7 com Fuzzilli
- vários testes end-to-end de vazamento de memória eram mantidos em operação
- A posição não é de que o próprio Zig seja o problema, mas sim de que a exigência de lidar ao mesmo tempo com valores de GC e memória gerenciada manualmente era a principal fonte dos problemas de estabilidade
Por que escolher Rust
- JavaScript é uma linguagem com GC, e engines como JavaScriptCore e V8 têm regras rígidas para tratamento de exceções e GC
- Assim como C, Zig não faz gerenciamento automático de memória; não há construtores nem destrutores, e a limpeza normalmente precisa ser explicitada em cada call site com
defer - No Bun, lidar corretamente com o lifetime de valores de GC e valores gerenciados manualmente era uma grande fonte de problemas de estabilidade
- era preciso verificar onde os bytes alocados seriam liberados
- era preciso garantir que fossem liberados apenas uma vez
- era preciso verificar corretamente o tratamento de exceções JavaScript
- era preciso garantir que ponteiros de GC fossem visíveis ao conservative stack scanner
- O método de cleanup do Zig usa
defereerrdeferexplícitos; C++ usa destructor e move, e Rust usaDrop - No código Zig existente do Bun, havia uma mistura de lifetime de arena, reference counting e revisão cuidadosa
- É possível impor regras de ownership com guia de estilo e code review, mas em código seguro de Rust, use-after-free, double-free e
freeausente em caminhos de erro se tornam erros de compilação - Cerca de 20% do código do Bun é C++, e ele incorpora várias bibliotecas C/C++
- JavaScriptCore
- uWebSockets e usockets
- lshpack e lsquic
- BoringSSL
- SQLite
- C++ também poderia ter sido uma opção, mas ainda dependeria de guia de estilo e code review, e mesmo com ASAN ainda podem ocorrer corrupção de memória e vazamentos
Estratégia de reescrita: de uma vez, de forma mecânica
- O código Zig existente do Bun tinha 535.496 linhas, excluindo comentários, e uma reescrita tradicional foi estimada como um trabalho de cerca de 1 ano para uma pequena equipe de engenharia
- Como não era possível interromper por 1 ano as correções de bugs, correções de segurança e o desenvolvimento de funcionalidades, foi escolhido o port mecânico como a abordagem de menor risco para minimizar mudanças no comportamento observado pelos usuários
- A suíte de testes do Bun foi escrita em TypeScript e não dependia da linguagem de implementação do runtime
- Considerou-se que uma reescrita incremental seria dolorosa no curto e médio prazo por exigir código temporário que depois precisaria ser removido, então toda a base foi migrada de uma vez
- A direção adotada foi escrever o código Rust de forma que parecesse um transpile do código Zig e, após o Bun v1.4, reduzir gradualmente o
unsafee refatorar para um Rust mais idiomático
Fluxos de trabalho dinâmicos do Claude Code
- Na reescrita para Rust, cerca de 50 fluxos de trabalho dinâmicos foram executados continuamente no Claude Code durante 11 dias
- Os fluxos iam desde a criação do guia de port até a conversão de arquivos, correção de erros de compilação, restauração de subcommands, aprovação em toda a suíte de testes e grandes limpezas
- geração de um guia de port que mapeava padrões e tipos de Zig para padrões e tipos de Rust
- port mecânico de todos os arquivos
.zigpara arquivos.rsde acordo comPORTING.mdeLIFETIMES.tsv - correção de erros do compilador por crate
- restauração do funcionamento de subcommands como
bun testebun build - aprovação em toda a suíte de testes
- grandes refatorações e limpezas
- Durante a maior parte do período, uma pessoa lia a saída dos fluxos de trabalho, verificava problemas e bugs e ajustava os prompts para que o Claude corrigisse o loop
- Como preparação, passou-se cerca de 3 horas discutindo com o Claude como mapear os padrões da base de código Zig para Rust, e o resultado foi serializado em
PORTING.md - Para adicionar lifetimes de Rust ao código com gerenciamento manual de memória, foi executado um fluxo de trabalho que analisava o lifetime de todos os campos de struct
- encontrava campos com lifetimes complexos
- sugeria lifetimes
- 2 agentes de revisão adversarial analisavam o resultado
- o feedback era incorporado e salvo em
LIFETIMES.tsv
Método de revisão adversarial
- Cada implementação tinha um Claude revisor adversarial em uma janela de contexto separada do Claude implementador, e o revisor recebia apenas o diff e era instruído a procurar bugs assumindo que o código estava errado
- A estrutura básica era composta por 1 implementador, pelo menos 2 revisores adversariais e 1 fixer
- Todos os bugs que os revisores realmente encontraram compilavam sem problemas, mas tinham falhas de comportamento
uv_closeé assíncrono, masBox<uv::Pipe>era descartado no fim do match arm, fazendo com que o libuv ficasse com memória já liberada, causando use-after-free e double-free- Erro de
timespecem que usartrunc()em file time negativo não inteiro geravansecnegativo - Erro em que
unwrap_oravaliava o argumento eagermente e causava panic no caso de omissão de porcentagem emcolor-mix()
- Assim como na revisão humana, os contextos de autor e revisor foram separados para reduzir o viés que pode surgir quando o implementador quer fazer o merge
Execução do grande porte e paralelização
- Antes de migrar todos os 1.448 arquivos
.zig, o procedimento foi validado primeiro com 3 arquivos- 1 implementador escrevia o arquivo
.rs - 2 revisores verificavam se o comportamento batia com o
.zige se seguiaPORTING.mdeLIFETIMES.tsv - 1 fixer aplicava as sugestões
- 1 implementador escrevia o arquivo
- No início da migração completa dos arquivos, vários Claudes executavam
git stash,git stash popegit reset HEAD --hard, entrando em conflito entre si - Depois, foram adicionadas ao workflow regras proibindo
git stash,git reset, comandosgitque não fossem commits de arquivos específicos e comandos lentos comocargo - No fim, foram usados 4 shards de workflow e 4 worktrees, e em cada shard 16 Claudes faziam commit e push dos arquivos
- Graças à paralelização e à preparação prévia, no pico o Claude escreveu cerca de 1.300 linhas de código por minuto
- Os commits no branch do port, excluindo merges, foram 6.502, a hora de pico teve 695 commits, e o diff final landed foi de +1.009.272 linhas
- Também houve problema por não aumentar o IOPS padrão da instância EC2: um único
greplento podia travar as leituras e gravações em disco por vários minutos
Erros de compilação e separação em crates
- Depois que todo o código foi escrito, o workflow do Claude corrigiu os erros do compilador
- A base de código em Zig era, na prática, uma única compilation unit, e o código Rust seria dividido em cerca de 100 crates para compilar mais rápido
- A categoria de erro mais complicada era a de dependências circulares
- Só o PR de separação em crates feito logo antes da reescrita em Rust não foi suficiente
- Um workflow separado classificou e registrou onde o código com dependência circular deveria ficar
- Outro workflow executou esse refactoring
- Depois de resolver as dependências circulares, apareceram cerca de 16.000 erros de compilador
- Esses erros foram tratados em paralelo por crate
- Em cada crate, era executado
cargo check - A saída era agrupada e salva por arquivo
- Os erros de compilação daquela crate eram corrigidos
- 2 revisores adversariais analisavam as mudanças
- 1 fixer aplicava as correções
- Em cada crate, era executado
- Também houve um false start em que o Claude interpretou “fazer todos os crates compilarem” como gerar stubs de função
- Quando surgiu um padrão de tentar justificar workarounds com comentários explicativos longos, foi adicionada uma regra de revisão: “se precisa de um comentário do tamanho de um parágrafo, o código está errado e o código precisa ser corrigido”
O caminho até passar nos testes
- Depois que
cargo checkpassou, foram resolvidos em sequência erros de linkedição, panic logo na inicialização,bun --versione a execução debun test <file> - Foi usado um workflow que salvava em arquivo stacktraces de falhas por subcomando da CLI e corrigia em um loop de implementador, revisor e fixer
- O workflow dos arquivos de teste distribuía cerca de 100 arquivos de teste aleatórios em 4 worktrees, salvava stacktraces e erros por falha e fazia as correções
- A suíte de testes incluía testes de vazamento de memória e testes de integração que podiam dar timeout em builds de debug
- Teste que executava
next deve verificava se o hot module reloading detectava 100 mudanças - Stress test que esgotava o número máximo de sockets TCP
- Testes de leitura e gravação em disco na casa dos gigabytes
- Teste que fazia spawn de cerca de 10 mil processos
- Teste que executava
- Para isolamento,
systemd-rune cgroups foram usados para limitar uso de memória e CPU e separar o namespace de PID - Ainda assim, a máquina travou várias vezes por falta de espaço em disco
- Dois dias após a primeira execução do CI, os arquivos de teste com falha caíram de 972 para 23, e um dia e meio depois disso o Linux ficou completamente green
- No fim, toda a suíte de testes do CI passou em 6 plataformas
- macOS x64
- macOS arm64
- Linux x64
- Linux arm64
- Windows x64
- Windows arm64
- Depois de 100% dos testes passarem, humanos verificaram manualmente se os testes estavam realmente sendo executados e não pulados, e então fizeram o merge
- O momento em que foi feito o merge em
mainnão foi um release versionado; ainda não havia confiança suficiente para lançar, mas já havia confiança suficiente para se dedicar totalmente à reescrita
Escala dos testes e custo
- Ao longo de 11 dias, do dia 3 de maio até o merge em 14 de maio, foram gerados 6.778 commits
- Os testes não foram deletados nem pulados
- A escala dos testes por plataforma foi a seguinte
- Debian 13 x64:
expect()1.386.826 vezes, 60.624 testes, 4.174 arquivos - macOS 14 arm64:
expect()1.259.953 vezes, 58.850 testes, 4.175 arquivos - Windows 2019 x64:
expect()1.007.544 vezes, 57.337 testes, 4.173 arquivos
- Debian 13 x64:
- No trabalho pré-merge foram usados 5,9 bilhões de input tokens sem cache, 690 milhões de output tokens e 72 bilhões de cached input tokens read
- O custo com base no preço de API foi de cerca de US$ 165 mil
- A avaliação foi de que, se humanos tivessem feito isso diretamente, 3 engenheiros com contexto de toda a base de código levariam cerca de 1 ano
- O modelo usado foi o pre-release Claude Fable 5, e foi incluída a divulgação de que a Bun foi adquirida pela Anthropic em dezembro de 2025
Revisão de segurança, fuzzing e situação do unsafe
- Depois do merge do port em Rust, foram concluídas 11 rodadas de revisão de segurança com Claude Code Security e os findings foram tratados
- Foi adicionado fuzzing contínuo 24/7 com coverage para todos os parsers do Bun
- JavaScript
- TypeScript
- JSX
- CSS
- JSON5
- JSONC
- TOML
- YAML
- Markdown
- INI
- scripts do Bun Shell
- intervalos de semver
- arquivos
.patch - cores CSS
- O fuzzer envia os bugs encontrados ao Claude para que ele abra PRs com reprodução e correção, e humanos revisam os PRs
- Até agora, os parsers foram executados 100 bilhões de vezes, resultando em cerca de 15 PRs
- No momento da redação, cerca de 4% do código Rust estava dentro de blocos
unsafe- Cerca de 13.000 ocorrências da keyword
unsafe - Cerca de 27.000 linhas / cerca de 780.000 linhas no total
- 78% dos blocos
unsafetêm uma única linha e envolvem ponteiros vindos de C++ ou chamadas de bibliotecas C
- Cerca de 13.000 ocorrências da keyword
- Eles afirmam que, como continuam usando bibliotecas C/C++ como o JavaScriptCore, sempre haverá mais
unsafedo que em um projeto puramente Rust
Regressões encontradas após a migração para Rust
- A reescrita em Rust foi uma mudança de grande porte e criou 19 regressões conhecidas, todas corrigidas
- A maioria surgiu em código cuja sintaxe é parecida nas duas linguagens, mas cujo significado é diferente
-
Efeito colateral dentro de
debug_assert!- O
assertdo Zig é uma função, então os argumentos são executados em todas as builds - O
debug_assert!do Rust é uma macro, então em builds release a expressão inteira é removida - A chamada de
insert_staledesapareceu na build release e quebrou um caso específico de HMR em projetos de rota HTML que usam React - Issue relacionada: #30678
- O
-
Slice de tamanho ímpar
- O helper
reinterpretSlice(u16, bytes)do Bun em Zig usava@divTruncpara ignorar o byte ímpar no fim bytemuck::cast_slicedo Rust dá panic com comprimento ímpar- Houve uma regressão em que
Blob.text()com um byte ímpar após o BOM UTF-16 não retornava uma string e fazia o processo entrar em panic - A correção foi voltar a ignorar o byte ímpar com
&buf[..buf.len() & !1] - Issue relacionada: #31188
- O helper
-
Verificações de limites
- O código Zig no macOS e Linux era compilado com
ReleaseFast, removendo as verificações de limites, enquanto a build release em Rust as mantém - O tamanho do bloco de overflow do resolvedor de módulos do Bun ficou com o placeholder
64, reduzindo o teto de 8,4 milhões de nomes de arquivos internados para 270.272 - O erro de off-by-one portado em
ptrs[4095]passou a ser alcançável em projetos reais, e o Rust gerou panic em vez de fazer uma escrita fora dos limites - Issue relacionada: #31503
- O código Zig no macOS e Linux era compilado com
-
Strings de formatação
comptime- Em Zig,
fmtemOutput.prettyécomptime, então os marcadores de cor<r>e<d>são convertidos em escapes ANSI antes da substituição dos argumentos - A função em Rust não tem parâmetro comptime e processou os marcadores na string finalizada, reescrevendo incorretamente até os argumentos
- Em
bun update -i, a terminação de hyperlink OSC 8 e o marcador<r>no fim entravam em conflito, fazendorser exibido como texto - Em Rust, foi necessário usar a macro
bun_core::pretty!("<r>{}<r>", hyperlink) - Issue relacionada: #30693
- Em Zig,
Bugs corrigidos e vazamentos de memória
- O Bun v1.4.0 corrige 128 bugs reproduzíveis na v1.3.14
- O escopo vai de vazamentos de memória e crashes até texto de ajuda colorido incorretamente
- Em Rust,
Dropchama automaticamente a funçãodropquando um valor sai do escopo - Em Zig, era preciso adicionar
deferem cada call site, o que facilitava esquecer uma limpeza ou fazer limpeza duplicada Dropé uma escolha que reduz armadilhas comuns em troca de aceitar um fluxo de controle ocultoDropcorrigiu vários vazamentos de memória relacionados a caminhos de arquivo no código de tratamento de erros- A integração do Bun com o LeakSanitizer foi melhorada para rastrear todas as alocações de memória em código nativo
- Todos os vazamentos de memória instrumentáveis foram corrigidos
-
Melhorias no vazamento de
Bun.build()- No Bun v1.3.14, a cada chamada in-process de
Bun.build(), o texto-fonte analisado e a tabela de símbolos da AST sobreviviam além da vida útil da build, vazando vários MB por vez - Em um teste que empacotou o mesmo projeto de 60 módulos 2.000 vezes no mesmo processo, a v1.3.14 continuou vazando cerca de 3 MB por build
- No Bun v1.4.0, o uso de memória se estabilizou
- | Builds | Bun v1.3.14 | Bun v1.4.0 |
- | --- | ---: | ---: |
- | 500 | 1,914 MB | 526 MB |
- | 1,000 | 3,506 MB | 586 MB |
- | 1,500 | 5,097 MB | 608 MB |
- | 2,000 | 6,745 MB | 609 MB |
- No Bun v1.3.14, a cada chamada in-process de
Tamanho do binário, uso de stack e desempenho
- Só as mudanças iniciais da reescrita em Rust já reduziram o tamanho do binário
- Windows: redução de 3.8 MB
- macOS: redução de 5.5 MB
- Linux: redução de 6.8 MB
- O principal motivo foi o uso excessivo de
comptimeno código Zig - Depois, também foram aplicados o Identical Code Folding, a remoção de dados não usados do ICU e a descompressão tardia de parte da libicu com dicionário zstd
- Somando a reescrita em Rust, as mudanças no ICU e o identical code folding, o tamanho do binário do Bun caiu cerca de 20% em Linux e Windows
| Version | Platform | Size |
|---|---|---|
| Bun v1.4.0 canary | Windows | 76 MB |
| Bun v1.3.14 | Windows | 94 MB |
| Bun v1.4.0 canary | Linux | 70 MB |
| Bun v1.3.14 | Linux | 88 MB |
- O parser TOML e os parsers recursive-descent do Bun passaram a usar menos espaço de stack
- A geração de código LLVM IR do Rust emite os intrinsics
llvm.lifetime.startellvm.lifetime.endpara variáveis de stack, permitindo que o LLVM reutilize slots da stack - Antes, funções especialmente grandes eram refatoradas manualmente em várias funções menores para contornar uma issue aberta do Zig
- O Rust oferece suporte a cross-language link-time optimization entre C/C++ e Rust, permitindo inlining entre linguagens
-
Benchmark Linux x64
- Bun v1.3.14 e Bun v1.4.0 foram comparados em Linux x64 com EC2 Xeon Platinum 8488C
- O throughput HTTP foi medido com oha, e a carga de trabalho de apps com hyperfine
- | server | Bun v1.3.14 | Bun v1.4.0 | Δ |
- | --- | ---: | ---: | ---: |
- | Bun.serve | 169.6k req/s | 177.7k req/s | +4.8% |
- | node:http | 103.8k req/s | 108.5k req/s | +4.5% |
- | Elysia | 158.9k req/s | 163.3k req/s | +2.8% |
- | express | 64.5k req/s | 66.6k req/s | +3.2% |
- | fastify | 91.5k req/s | 95.9k req/s | +4.8% |
- | workload | Bun v1.3.14 | Bun v1.4.0 | Δ |
- | --- | ---: | ---: | ---: |
- | next build | 13.62 s | 13.03 s | +4.5% |
- | vite build | 1.69 s | 1.65 s | +2.2% |
- |
tsc -b --force| 0.94 s | 0.89 s | +4.7% |
Casos de uso reais e status de lançamento
- A Prisma lançou a beta pública do Prisma Compute sobre o rewrite em Rust do Bun
- Segundo a Prisma, eles testaram no rewrite em Rust o failure mode de pool de conexões que não se recupera após pause/resume da VM e de vazamento de memória, e afirmaram que esse failure mode foi bem tratado
- O Claude Code v2.1.181 e as versões lançadas após 17 de junho usam o Bun portado para Rust
- A inicialização do Claude Code no Linux ficou 10% mais rápida, e fora isso a maioria dos usuários quase não percebeu diferença
- O Bun v1.3.14 é a última versão do Bun escrita em Zig
- O Bun v1.4.0 é a primeira versão do Bun escrita em Rust e é fornecida como canary
Ferramentas que a equipe ganhou e trabalho restante
- A nova base de código em Rust mantém uma forma muito semelhante à base de código anterior em Zig
- Foi escrita de modo que quem entende o código original em Zig também consiga entender o código em Rust traduzido mecanicamente
- A revisão do PR de rewrite em Rust foi conduzida com um agente de revisão hostil verificando se ele conseguia detectar corretamente divergências entre Zig e Rust, o guia de portabilidade e o cumprimento do guide de lifetimes, enquanto pessoas liam muito código lado a lado
- O Bun v1.4 torna o Bun mais rápido e menor, reduz o uso de memória e fornece ferramentas para melhorar a estabilidade
- Rust borrow checker
- Miri
- LeakSanitizer
- fuzzing guiado por cobertura 24/7 para o parser
- Ainda restam partes a serem refatoradas, e o bun-unsafe-audit está vinculado
- Um engenheiro monitorou de perto o Fable e o Claude Code, e em apenas 11 dias chegou ao ponto em que toda a suíte de testes passava em todas as plataformas
2 comentários
Comentários do Hacker News
Este texto mostrou muito bem que houve disciplina e cuidado na reescrita automática, além de intervenção humana, e passou a impressão de que foi conduzido da forma mais diligente possível com IA
Separadamente, não entendo muito bem por que, em 2026, alguém não escolheria uma linguagem com segurança de memória e, se possível, também segura contra condições de corrida
Rust oferece isso com desempenho junto, então, mesmo que você não goste de coleta de lixo ou imutabilidade por causa de performance, ainda existe a opção de Rust
Entendo casos em que é preciso desempenho máximo absoluto e se desce para C++, ou simplesmente preferência pessoal, mas fora isso parece uma escolha quase óbvia
Além disso, em muitos problemas um coletor de lixo elimina sem grande atrito muitos defeitos, inclusive os defeitos mencionados no texto, enquanto Rust exige pensar pela ótica de ownership
Por exemplo, muitos desenvolvedores de jogos preferem iterar em linguagens com menos atrito. Código de jogo pode ser tão delicado quanto código de UI de frontend, e o processo de build também pode ser peculiar, além de muitas vezes depender de hot reloading para iterar
Pedir que usem um compilador lento significa aceitar mais latência nesse ciclo de iteração. Claro, não acho que todos esses motivos se apliquem a todo mundo
Rust não é perfeito, mas resolve muitas armadilhas do C++. Não só comportamento indefinido, mas também gerenciamento de pacotes, arquivos horríveis de CMake, erros de linker e coisas assim
Zig, Odin, C3, e até o velho C, pelo menos têm vantagens que nem Rust nem C++ oferecem. Mesmo que seja só velocidade de compilação
O importante é que essa abordagem é muito mais barata do que contratar uma equipe de engenharia de software. Mesmo que me contratassem por 200 mil dólares, acho que eu não teria conseguido fazer isso em um ano
Sem contexto e sem conhecer Zig ou Rust, eu até poderia aprender em um mês, mas seria muito lento
Mesmo deixando de lado previsões de singularidade, só a IA atual já deve dificultar justificar a contratação de um engenheiro de software de 200 mil dólares
Empresas centradas em software, como Google ou Anthropic, ainda continuarão contratando ótimos engenheiros para criar software novo, algo em que a IA ainda não é boa, mas em empresas como Walmart ou Target, onde software é apenas um centro de custo, ou em empresas que já terceirizavam desenvolvimento ou usavam mão de obra H1B barata, surge uma alternativa de IA muito melhor do que o engenheiro mediano
Os cerca de 1,6 milhão de desenvolvedores de software nos EUA provavelmente vão diminuir bastante. A elite de nível L6 da FAANG deve ficar bem, mas o desenvolvedor mediano de um banco sem nome ou quem faz o site do McDonalds vai precisar aprender outra coisa, ou pode perder o emprego em breve
Há um ano eu não teria feito essa previsão, mas agora parece claro que essa mudança vai acontecer
https://en.wikipedia.org/wiki/Jevons_paradox
Também é discutível se de fato houve criação de valor neste trabalho. Quem já usou Rust unsafe e também Zig sabe que Rust unsafe, em comparação, é muito mais perigoso
Isso também não substituiu nenhum emprego de verdade e, no fim, ainda foi preciso contratar engenheiros caros para concluir isso
Acho mais provável que isso gere mais mudanças de código, não menos contratações
Agora é bem possível que as empresas queiram contratar mais engenheiros seniores capazes de realmente executar esse tipo de mudança
Não só o tempo e o custo investidos foram menores do que muita gente esperava, como agora dá para prever que, em pouco tempo, essa interação humana, os erros, o tempo e o custo podem cair 2x, 5x ou até mais de 10x
Também é preciso considerar que o próprio post do blog funciona como peça de divulgação do Claude e dos LLMs em geral
Mesmo sem discutir o projeto Bun em si ou a natureza da reescrita, se apenas uma reescrita ingênua saindo de Zig corrigiu vazamentos de memória, melhorou a estabilidade, reduziu o tamanho do binário em 20% e aumentou o desempenho em 5%, isso não fica bem para o Zig
Se tivessem rodado US$ 165 mil de Fable na versão em Zig, provavelmente também teriam conseguido um ganho de 5% em desempenho
Já se fala há bastante tempo que Rust e LLMs combinam bem. Muito do atrito da linguagem fica mais suave com programação assistida por LLM
Não me importo que tenham usado IA para reescrever o Bun em Rust. Mesmo que o 1.4 ainda não esteja bom o bastante, há uma boa chance de melhorar com o tempo
O que me empurrou de volta para o Node foi que o processo de transição foi conduzido de forma amadora demais
Não há suporte LTS para a versão em Zig em relação a CVEs etc., bugs grandes como o vazamento de memória de 3 MB citado no blog foram deixados na versão em Zig, de modo que, na prática, para corrigir aplicativos em produção você acaba sendo levado para a versão em Rust, e não houve nenhum envolvimento da comunidade do Bun nessa decisão importante
Em um dia era “não façam drama, estou só brincando com isso”, e poucos dias depois virou “YOLO, merge na main”
Jarred na prática ainda toca isso como um hacker solo trabalhando no próprio projeto pessoal
Como, por exemplo, no caso do problema de memória mencionado no blog. Em termos de segurança, é melhor considerar que a versão em Zig não existe. Use por sua conta e risco
Quanto ao fato de Jarred tocar isso como um projeto pessoal, ainda assim eles têm esse direito. Especialmente se a empresa for dona disso, é algo esperado
Não vejo nada que pareça descuidado
Pelo contrário, ele colocou duas instâncias adversariais do Claude para revisar cada mudança de código, cada linha. Tirando talvez pessoas que escreveram software para o ônibus espacial, não conheço nenhuma equipe humana que faça duas revisões independentes de cada linha
O vazamento de memória também foi corrigido. Por que importa em que linguagem isso foi escrito? No fim, as pessoas usam o Bun para rodar código TypeScript e afins
O quanto os usuários do Bun realmente se importam com o fato de o Bun ter sido escrito em Zig? Eu, nem um pouco. Uso Bun há 2 anos e só fui olhar o Zig uma vez. Simplesmente não é relevante
Ficou mais estável? Sim. Ficou menor? Sim. Ficou mais rápido? Sim. Há evidência de que ficou menos seguro? Não. O código estava público havia dois meses e, a essa altura, quem é contra já deveria ter encontrado alguma prova definitiva, mas não encontrou
De quanta evidência a mais vocês precisam de que isso foi um grande sucesso?
Esta é a nova realidade. Os agentes ficaram bons o bastante para entrarmos numa área em que projetos assim são possíveis, e isso é algo interessante
“Essa reescrita em Rust seria algo que levaria 1 ano para uma equipe de engenheiros com contexto de toda a base de código. Com 1 engenheiro usando Fable e monitorando o Claude Code de perto, foram 11 dias do início até passar 100% da suíte de testes em todas as plataformas”
Tecnicamente é impressionante, mas passam meio por cima do fato de que, se a Bun não fizesse parte da Anthropic, isso teria custado US$ 165 mil em tokens
A comparação não é totalmente justa. Se você considera o custo adicional como US$ 0, isso significa que uma equipe pequena levaria 1 ano para portar
Eu queria comparar gastar US$ 165 mil no Claude por 11 dias com pegar esse dinheiro e dividir entre 50 pessoas para reescrever o código em Zig linha por linha. O Claude provavelmente seria mais rápido e, por isso, mais barato, mas talvez a diferença não fosse tão grande
Isso dá US$ 1.200 por dia
50 pessoas * 11 dias = US$ 660 mil, 4x o custo do Claude
E isso ainda assume que essas 50 pessoas trabalham sem travar, sem se atropelar e sem problemas de coordenação. Só a complexidade de coordenação já seria enorme
Não gosto disso, mas aqui o Claude ganha com folga. Nem é por pouco
Mesmo que essa não seja a resposta definitiva de hoje, não dá para ver isso ao menos como um sinal de um futuro possível?
Dica: essas 50 pessoas teriam que ser coordenadas
Aproximadamente, o custo seria: DeepSeek v4 Pro & Mimo v2.5 Pro US$ 3.426, Tencent HY3 US$ 3.892, GLM 5.2 US$ 30.016, Qwen 3.7 Max US$ 37.925, Claude Opus 4.8 & GPT 5.5 xhigh US$ 82.750
Isso com base em 5,9 bilhões de tokens de entrada sem cache, 690 milhões de tokens de saída e 72 bilhões de leituras de tokens de entrada em cache
Esse é o poder de uma suíte de testes forte. LLMs se destacam quando existe uma recompensa verificável
Acho que vamos ver muito mais projetos sendo reescritos em Rust. Rust também é um alvo ideal para esse tipo de reescrita, porque oferece muita verificação pelo sistema de tipos e baixo overhead sem garbage collection
Na era da codificação por agentes, há cada vez menos motivo para usar linguagens com garbage collection
Vejo Rust como um ótimo alvo de ótimo local para código gerado por LLM. No futuro pode surgir uma linguagem melhor, mas acho que Rust vai dominar por bastante tempo
Já migrei um projeto pessoal com mais de 300 mil linhas de Python para TypeScript, e o motivo de eu não ter usado Rust foi justamente o tempo de desenvolvimento iterativo
Fico curioso sobre como a Anthropic usa a Bun. Sei que ela é usada como “runtime” do Claude Code, mas em vez de portar 1 milhão de linhas de Zig para Rust, não daria para portar o Claude Code para Rust e simplesmente não embutir um runtime JS?
A Anthropic usa Bun para mais alguma coisa? Talvez para chamadas de ferramentas que executam JS dentro das respostas do Claude
Por que eles simplesmente não migraram o Claude Code?
Meu palpite é que talvez a suíte de testes não seja tão robusta
Isso pode deixá-los mais ousados depois do que aconteceu agora
A ideia de que “historicamente, reescritas são uma ideia terrível” mudou para mim nos últimos 5 anos
A primeira vez foi quando entrei numa empresa com um produto de software que mal funcionava. Fizemos a combinação tradicional de refatoração incremental e reescrita, mas no fim aprendi que o núcleo estava tão apodrecido que o melhor era reescrever a partir de primeiros princípios
A lição que tirei disso é que a sabedoria convencional provavelmente só se aplica a reescrever sistemas complexos, mas que funcionam
Depois disso, na era da codificação por agentes, passei por várias situações. Entre trabalho e projetos pessoais, recriamos grandes partes de softwares complexos como Salesforce, Gmail e Pioneer Rekordbox com equipes muito pequenas
Assim como no post do blog, a chave é criar excelentes loops de validação ao redor do comportamento central com compilador, linter, test harness e suíte de testes
Cada vez mais, projetar e implementar um test harness abrangente parece ser o trabalho de verdade. Depois que isso existe, é só deixar o LLM cozinhar
Nesse caso, coisas como test harness, linter e workflow seriam os nossos cães pastores
O ponto que achei interessante foi que a maior parte da discussão em torno deste tema partiu da suposição de que a reescrita foi feita não com o Fable, mas com um modelo como o Opus
Essa suposição foi usada, pelo menos em parte, como argumento de que a reescrita não seria possível ou não seria uma boa ideia
O modelo em si não muda completamente a narrativa, mas pessoalmente senti que preciso ser mais cauteloso ao estimar a capacidade dos modelos usados pela Anthropic e por organizações relacionadas internamente
O que ele não disse era que estava usando o Fable antes do lançamento. [1]
O próximo sinal pode ser se uma empresa da Anthropic desligar o trailer Claude Co-Authored-By. [2] Se for um ano com IPO, eles deveriam aproveitar toda oportunidade para promover o Claude, e a única exceção seria se naquela época, em maio, fosse algo como o Fable que ainda não podia ser divulgado
[1]: https://xcancel.com/jarredsumner/status/2060050586024743376#...
[2]: https://github.com/oven-sh/bun/commit/23427dbc12fdcff30c23a9...
Sempre que reescrevi um projeto grande, ele ficou menor e mais rápido, e todos os bugs grandes, além da maioria dos pequenos, foram corrigidos
A equipe atual também teve uma experiência parecida. Fico curioso sobre que impacto na qualidade teria havido se tivessem feito uma reescrita de Zig para Zig na mesma escala
Comentários no Lobste.rs
extern "C", mas ainda dependeriam de guias de estilo impostos por code review, e mesmo com ASAN ainda haveria corrupção de memória e vazamentosCuriosamente, o Node.js funciona bem em C++, mas nunca vi o Bun como um projeto sério. Agora ele parece mais um benchmark do departamento de marketing da Anthropic, então pretendo continuar mantendo distância
Spoiler: na prática, não tomam tanto cuidado assim e cometem erros
unsafe, e 78% deles têm uma linha só” parece uma formulação para tranquilizar, mas não importa se um blocounsafetem uma linha ou não. Se ele quebrar as garantias de segurança ali dentro, então todo o código fora do bloco também pode ter a soundness comprometidaA fusão inicial do port em Rust do Bun incluía um caso claro desse tipo de unsoundness: https://github.com/oven-sh/bun/issues/30719
Esse issue foi tratado quando os mantenedores ativaram a ferramenta Miri do Rust no CI, e em “What's Next” no artigo também aparece Miri (which runs for a growing chunk of code in CI), então parece bom que estejam trabalhando nisso
Para ser justo, mesmo Rust com violações de segurança ainda pode ser mais fácil de manter do que o código Zig que substituiu, dependendo da qualidade desse código. Ainda assim, linhas de código por bloco unsafe não são um indicador de qualidade, e menos ainda se esses blocos não vieram acompanhados de outras práticas de programação, especialização ou verificações automáticas
unsafenão surgem por causa da portabilidade, e sim por requisitos do projeto. Se você chama bibliotecas C, precisa de blocosunsafe, e não há como removê-los só com refatoraçãoClaro, isso seria possível se reescrevessem também essas bibliotecas C, mas isso talvez pudesse ser avaliado depois
No anúncio “Bun is joining Anthropic”, Jarred disse que contrataria mais engenheiros para trabalhar no Bun, mas olhando o GitHub o time do Bun parece até ter diminuído. Não sei bem que conclusão tirar disso, além de que “o Bun é um time pequeno”
O método em si é interessante, mas o texto soa como matéria de marketing. Faltou análise de quanto isso custou, não há discussão dos riscos de uma reescrita em Rust, e também é fraca a explicação concreta de por que a reescrita aconteceu. Meu palpite é que foi por causa da no ai policy do Zig, ou por alguma diretriz interna da Anthropic de focar em Rust
E sobre o motivo da reescrita, acho que o texto conta uma história bem consistente. O Bun continuava tendo crashes mesmo depois de adotarem medidas para encontrar os problemas, e os desenvolvedores queriam uma forma mais sistemática de evitar esse tipo de falha
O plano inicial era reforçar com mais rigor um certo estilo de código e introduzir smart pointers, mas Jared achou que smart pointers próprios seriam piores de usar do que Rust e não ofereceriam garantias. Então virou algo como “e se testássemos por uma semana se o novo modelo da Anthropic consegue reescrever o Bun em Rust?”, e quando a taxa de aprovação da suíte de testes subiu, o fluxo parece ter mudado de “vale tentar” para “vamos fazer o merge”
Ou seja, não parece que decidiram desde o início por uma reescrita em Rust, mas sim algo mais próximo de “Rust parece resolver o problema, mas o custo de reescrever impede. Só que, testando um port via LLM, parece viável. Então vamos de reescrita com LLM”
Parabéns ao Jarred, ao time do Bun e à Anthropic por terem conseguido fazer isso