Resend migra API de e-mail de Node.js para Go e reduz latência e uso de memória
Aprofundamento CEVIU
Aprofundamento
A Resend reescreveu em Go a API que recebe os pedidos de envio de e-mail, o fluxo que a própria equipe chama de mais crítico. Foram sete semanas e cerca de 140 pull requests, do projeto vazio ao tráfego de produção. Em outubro, o Go já atendia todo o tráfego da API de e-mail.
O motivo veio de falhas do serviço em Node.js. Em rajadas de requisições grandes, uma task inteira podia travar. Uma investigação apontou o parsing e a serialização de corpos grandes, operações síncronas e pesadas de CPU que bloqueiam o event loop, inclusive em requisições que o rate limiter já estava rejeitando. Havia ainda timeouts do S3 que apareciam para o cliente como erros 408 e 524.
Para provar equivalência, a equipe montou um harness que envia as mesmas requisições a Node e Go e compara respostas, erros, linhas no banco, objetos no S3, idempotência e rate limits. Checar só o HTTP deixaria passar casos em que ambos respondem com sucesso, mas gravam metadados ou geram conteúdo diferentes. Algumas esquisitices do Node foram preservadas de propósito, porque uma integração pode depender delas.
Dois exemplos mostram o tamanho do trabalho. A conversão de HTML para texto: a biblioteca Go escolhida de início ignorava o atributo data-skip-in-text="true" e acrescentava texto de URL nos links, então a equipe fez um port do comportamento específico, que bateu com 60 fixtures geradas pelo Node. E os anexos: o SDK Node aceita Buffer, que o JSON.stringify vira em {"type":"Buffer","data":[...]}, e o Go precisou reconstruir essa conversão à mão, incluindo as regras de coerção do JavaScript.
Os números vêm do rollout de 50%, com as duas implementações na mesma task size. O Go usou cerca de 62% menos CPU por request. A latência mediana do POST em /emails caiu cerca de 50% (de 58 ms para 31 ms) e o p99 caiu cerca de 16%. A memória por task foi de cerca de 1,3 GB para 180 MB. O p99 melhora menos porque boa parte da cauda é espera por S3 e banco de dados.
Nem tudo foi tranquilo. Mesmo com menos recursos por request, as tasks tiveram o tamanho dobrado duas vezes durante o rollout, e foi preciso limitar operações de storage e contar as conexões com Redis. A equipe também removeu um truque do Node para evitar varredura byte a byte na checagem de tamanho do e-mail, já que o Go não tem esse problema.
O que mudou
A cobertura anterior do CEVIU traz casos parecidos de troca de stack, mas de outras empresas. Em 11 de setembro de 2026, o CEVIU noticiou "Migração de serviço Node.js para Go com IA: ganhos de performance e lições aprendidas", sobre a Checkly. A Resend é outro caso, com método próprio, sem IA citada na fonte e com foco em comparar os dois serviços em produção.
Por que isso importa
Para quem opera uma API pública, o recado é que o ganho de latência e memória só vale se o comportamento ficar idêntico. A leitura aqui é que o harness de comparação e o widget com a distribuição de status codes dão mais segurança do que testes unitários isolados. E quem pensa em sair do Node deve contar com tempo de tuning de capacidade e timeouts, porque a economia média de recursos não dispensa dimensionar para picos.
Linha do tempo
CEVIU noticia a migração de um serviço Node.js para Go na Checkly, com ajuda de IA.
Resend divulga a migração da API de e-mail de Node.js para Go, com latência mediana de 58 ms para 31 ms.
Perguntas frequentes
Quanto a Resend ganhou ao migrar de Node.js para Go?
No rollout de 50%, a latência mediana do POST em /emails caiu cerca de 50%, de 58 ms para 31 ms. O p99 caiu cerca de 16% e o uso de CPU por request foi cerca de 62% menor. A memória por task passou de cerca de 1,3 GB para 180 MB.
Como a Resend garantiu que o Go se comportasse como o Node?
A equipe criou um harness que envia as mesmas requisições aos dois serviços e compara respostas, erros, linhas no banco, objetos no S3, idempotência e rate limits. Também usou fixtures geradas pelo Node, como as 60 do conversor de HTML para texto.
Por que o Node.js estava dando problemas na API?
Em rajadas de requisições grandes, parsing e serialização de corpos bloqueavam o event loop, e uma task inteira podia ficar sem responder. Isso valia até para requisições já rejeitadas pelo rate limiter. Havia também timeouts do S3 que viravam erros 408 e 524 para o cliente.
A migração exigiu ajustes em produção?
Sim. As tasks tiveram o tamanho dobrado duas vezes durante o rollout, e a equipe revisou timeouts de storage e conexões com Redis. Consumo médio baixo não indicava a capacidade necessária em picos.
Fontes
- resend.comfonte original
- Categoria
- CEVIU Web Dev
- Publicado
- 13 de novembro de 2026
- Editoria
- CEVIU Web Dev

