Imagina abrir o seu editor, digitar uma linha de código e esperar mais de 5 segundos até o Copilot acordar. Agora imagina a mesma ação levando 292 milissegundos. Essa é a diferença entre o runtime antigo do GitHub Copilot, escrito em TypeScript rodando sobre Node.js e V8, e o novo, inteiramente reescrito em Rust.
A parte mais irônica? Quem fez a maior parte do trabalho foi o próprio Copilot.
O problema: 430 mil linhas de TypeScript que pesavam demais
O runtime do Copilot é o motor por trás de tudo que acontece quando você usa a ferramenta: completar código, sessões de chat, interação com ferramentas, comunicação com os SDKs das seis linguagens suportadas (TypeScript, Python, Go, C#, Java e Rust). Até setembro de 2026, toda essa lógica vivia em aproximadamente 430 mil linhas de TypeScript.
O problema não era o TypeScript em si. Era a arquitetura. Cada cliente do Copilot spawnava um processo Node.js separado, com todo o overhead de inicialização do V8: parsing, bytecode generation, garbage collection. O resultado? Cerca de 100 MB de memória por cliente e aquele startup de 5,25 segundos que qualquer dev que usava o Copilot conhecia bem.
Para uma ferramenta que precisa responder em tempo real enquanto você digita, isso era inaceitável. O time do GitHub queria embedding in-process, algo que o Node.js simplesmente não permitia de forma prática. Eles precisavam de uma linguagem com controle fino de memória, C ABI estável e overhead mínimo.
Rust era a escolha óbvia.
Um dev, 14 semanas, 800 mil linhas
Aqui é onde a história fica absurda. A migração inteira foi liderada por um único engenheiro. De 12 de maio a 21 de agosto de 2026, essa pessoa, com assistência pesada de agentes de IA, portou 430 mil linhas de TypeScript para 832.378 linhas de Rust em produção, mais 468.689 linhas de testes unitários.
Vou repetir: um dev. 14 semanas e meia. Mais de 1,3 milhão de linhas de código (contando produção e testes).
A estimativa original do time era de 1 a 2 anos usando uma abordagem tradicional. A IA comprimiu isso para um trimestre.
| Métrica | Valor | |
|---|---|---|
| ——— | ——- | |
| Linhas TypeScript portadas | ~430.000 | |
| Linhas Rust em produção | 832.378 | |
| Testes unitários Rust | 468.689 | |
| Testes E2E TypeScript | ~174.000 | |
| Pull Requests | 128 | |
| Releases durante a migração | 135 | |
| Tokens consumidos | 136,3 bilhões | |
| Custo em IA | ~US$ 120.000 |
Pra contextualizar: US$ 120 mil em tokens de IA versus o salário anual de um time de 5 a 8 engenheiros por 1 a 2 anos. A conta nem precisa de calculadora.
A estratégia: substituição atômica, sem big bang
O GitHub não parou o mundo para reescrever o Copilot. O runtime continuou recebendo features e correções normalmente durante toda a migração. Isso só foi possível por causa da estratégia escolhida: substituição incremental in-place.
Em vez de criar um branch paralelo e manter duas bases de código divergindo por meses, cada componente era substituído atomicamente. Um PR removia a implementação TypeScript e adicionava a equivalente em Rust. O main branch permanecia shippable o tempo todo.
A sequência seguiu uma lógica de dependência: das folhas para o tronco.
- Primitivas puras (lógica sem estado): maio, primeira quinzena
- Utilitários de sistema: filesystem, shell, exclusão de conteúdo (maio a junho)
- Subsistemas com estado: gerenciamento de sessão, caching (junho a julho)
- Camada de ferramentas: tools, hooks, clientes de modelo, MCP (julho a agosto)
- Orquestração de sessão: o coração do runtime (agosto, finalização)
Cada camada dependia apenas das camadas já portadas. Quando o PR de orquestração de sessão foi mergeado, o TypeScript tinha sido completamente eliminado.
A cola entre dois mundos: N-API e interop temporário
O truque que permitiu a coexistência de Rust e TypeScript foi um modelo de interop em duas camadas. Sem isso, a migração teria exigido uma parada total do desenvolvimento, algo impensável para um produto com milhões de usuários ativos.
A primeira camada era temporária: bindings N-API usando o crate napi-rs. Isso permitia que código TypeScript chamasse funções Rust (e vice-versa) enquanto a migração avançava. No pico, em 3 de agosto, existiam 2.019 funções N-API exportadas e 3.356 call sites em TypeScript apontando para Rust.
Na prática, funcionava assim: quando um componente TypeScript era portado para Rust, ele expunha as mesmas interfaces via N-API. O código TypeScript que dependia dele nem sabia que estava chamando Rust por baixo. Cada PR movia a fronteira um pouco mais, até que todo o TypeScript estivesse do lado Rust.
Na conclusão da migração, o número de exports N-API caiu para zero. O interop temporário foi completamente removido, sem deixar rastro.
A segunda camada é permanente: a superfície de SDK usa JSON-RPC bidirecional sobre dois transportes. In-process via FFI (para embedding direto no processo do editor), e out-of-process via subprocess/socket (para clientes que preferem isolamento). Essa decisão foi deliberada: em vez de criar bindings nativos para seis linguagens diferentes (o que multiplicaria a superfície de manutenção), o time optou por um protocolo universal que qualquer linguagem pode consumir.
O resultado final? 364 rotas de API (340 chamáveis pelo consumidor, 24 callbacks do runtime para o SDK) e 19 funções C ABI exportadas para ciclo de vida do servidor, registro de sessão e conexões.
// Exemplo simplificado da interface C ABI exportada
#[no_mangle]
pub extern "C" fn copilot_server_start(config: *const c_char) -> i32 { ... }
#[no_mangle]
pub extern "C" fn copilot_session_create(server: *mut Server) -> *mut Session { ... }
#[no_mangle]
pub extern "C" fn copilot_connection_open(session: *mut Session) -> i32 { ... }
Qualquer SDK (Python, Go, Java, C#) carrega esse binário e chama essas funções via FFI nativo da linguagem: ctypes em Python, cgo em Go, JNA em Java, P/Invoke em C#.
Performance: os números que importam
Eu já mencionei o headline: 5,25 segundos para 292 milissegundos no cenário de startup + criação de sessão + primeiro turno. Isso é uma melhoria de 18x.
Mas o impacto vai além do startup:
Memória: cada cliente do Copilot consumia ~100 MB de working set por causa do processo Node.js dedicado. Com Rust rodando in-process via C ABI, esse overhead simplesmente desaparece. O runtime compartilha o espaço de memória do host.
Previsibilidade: sem garbage collector, sem picos de latência. Rust dá controle total sobre alocações e lifetimes. Para uma ferramenta de code completion que precisa responder em milissegundos, isso muda o jogo.
Distribuição: o binário Rust é linkável estaticamente. Não precisa de Node.js instalado, não precisa de V8, não precisa de npm. Um único binário nativo que qualquer SDK pode carregar via FFI. Compare isso com a situação anterior, onde cada SDK precisava gerenciar a instalação do Node.js, a resolução de dependências npm e a compatibilidade de versões do V8. Era um pesadelo de packaging que afetava todas as seis plataformas suportadas.
136 bilhões de tokens: a IA escreveu, humanos revisaram
O número mais impressionante da migração talvez seja esse: 136,3 bilhões de tokens consumidos, dos quais 130,6 bilhões eram tokens de input cacheados. O custo total ficou em aproximadamente US$ 120 mil.
O sistema registrou 12,7 milhões de eventos durante o trabalho. Desses, 31.247 eram mensagens do usuário (incluindo ~2.600 digitadas manualmente), 1,38 milhão eram respostas do assistente, e 1,85 milhão eram invocações de ferramentas.
Olha esses números: 2.600 mensagens manuais versus 1,38 milhão de respostas do assistente. O humano funcionava mais como supervisor e corretor de rumo do que como autor do código.
Isso não significa que a IA fez tudo sozinha. Os revisores humanos identificaram problemas que iam além da compilação: semântica comportamental, gerenciamento de estado, manipulação de lifetimes e escolhas de bibliotecas. O cargo check rodou 4.478 vezes durante a migração, com 87,1% passando sem erros. Mas os 12,9% que falharam precisaram de intervenção humana para corrigir.
O que deu certo (e o que ainda falta)
A abordagem incremental eliminou o risco mais temido de rewrites: o momento “big bang” onde você joga fora o código antigo e reza para o novo funcionar. Durante 14 semanas, o Copilot continuou sendo lançado normalmente. Foram 100 pre-releases e 35 releases estáveis. Os usuários finais provavelmente nem perceberam a transição.
O time também manteve uma janela de testes pré-release expondo cerca de 10,5% dos downloads do npm à versão Rust. Problemas eram identificados em produção gradualmente, não de uma vez.
Dito isso, a migração não está 100% completa. O CLI do Copilot ainda tem acesso direto ao runtime interno, algo que está sendo separado gradualmente. E a funcionalidade de hosting in-process (onde o runtime Rust roda dentro do próprio editor sem processo separado) ainda está em fase de validação.
Copilot reescrevendo Copilot: meta ou padrão?
O caso do Copilot se junta a outras migrações massivas assistidas por IA em 2026. O Bun reescreveu 960 mil linhas de Zig para Rust em 6 dias usando Claude. A Shopify portou 300 telas de React Native em 12 semanas. A Microsoft elevou Rust a Tier-1 para Windows e Azure. Até o compilador Rust foi traduzido para C em 46 milhões de linhas.
Existe um padrão emergindo aqui. Migrações de linguagem, que historicamente eram projetos de anos com taxas altas de fracasso, estão se tornando operações de semanas. A IA não eliminou a complexidade, mas mudou drasticamente quem carrega o peso do trabalho mecânico.
E o ingrediente secreto não é nenhum modelo específico. É a combinação de três coisas: testes automatizados extensivos (que validam cada PR), migração incremental (que reduz risco) e um engenheiro sênior que sabe exatamente o que revisar. Sem qualquer uma dessas três peças, a migração teria descarrilhado.
O caso do GitHub é especialmente simbólico porque a ferramenta de IA reescreveu a si mesma. O Copilot agora roda sobre código que o próprio Copilot escreveu. É a definição de dogfooding levada ao extremo.
Mas antes de sair reescrevendo tudo em Rust, vale a ressalva que o próprio GitHub faz no post: a escolha por Rust foi específica para os requisitos do Copilot (embedding, C ABI, overhead mínimo, recursos previsíveis). Não é uma prescrição universal para trocar TypeScript por Rust.
Então se o seu servidor Express está funcionando bem, respira fundo e fecha o cargo init.
O custo real da migração
US$ 120 mil em tokens parece muito olhando isoladamente. Mas coloca na perspectiva de uma empresa do tamanho do GitHub (Microsoft):
| Cenário | Custo estimado | Tempo | |
|---|---|---|---|
| ——— | ————— | ——- | |
| Time tradicional (5 a 8 devs) | US$ 1 a 3 milhões (salários + overhead) | 1 a 2 anos | |
| Migração assistida por IA (1 dev + agentes) | ~US$ 120 mil (tokens) + salário de 1 dev por 3,5 meses | 14,5 semanas |
Economia de pelo menos 80% no custo e 75% no tempo. E com menos risco, já que o código ia para produção continuamente.
Claro, nem todo projeto tem a infraestrutura de CI/CD, os testes E2E e o expertise em Rust que o GitHub tem. Replicar isso em uma startup de 5 pessoas é outra história. Porém o modelo (1 dev senior + agentes de IA + testes automatizados extensivos + migração incremental) é replicável com ajustes.
Pra onde isso vai
Se 2025 foi o ano em que IA começou a escrever código, 2026 é o ano em que IA começou a reescrever sistemas inteiros. O Copilot é apenas o exemplo mais visível porque é, literalmente, uma ferramenta de IA reescrevendo a si mesma.
A pergunta que fica: se um dev sozinho com IA consegue portar 800 mil linhas em 3 meses, qual é o argumento para manter um time de 10 pessoas fazendo a mesma coisa por 2 anos? A resposta provavelmente envolve revisão, qualidade e ownership, mas a janela de negociação ficou muito mais estreita.
Seu TypeScript não precisa virar Rust. Mas se precisar, agora dá pra fazer enquanto o café ainda está quente.
—
Fonte de inspiração: Migrating the GitHub Copilot runtime to Rust, using Copilot (GitHub Blog)













