O suporte ao Bun está sendo limitado e descontinuado em alguns lugares. O Deno acabou de lançar outra grande versão. Provedores de Edge seguem apertando e afrouxando limites de recursos. Se o seu backend presume que um único runtime JavaScript ficará estável por anos, você está fazendo lock-in de fornecedor do jeito mais difícil. Você precisa de um hedge de runtime — não porque você quer trocar, mas porque você quer o direito de trocar sem um trimestre inteiro de retrabalho.
Por que isso importa agora
Três manchetes nas últimas semanas deveriam recalibrar seu modelo de risco:
- A volatilidade de runtimes é real. O Deno 2.8 saiu; ótima velocidade e também um lembrete de que ecossistemas não-Node continuam avançando rápido e mudando padrões.
- O suporte pode desaparecer. O suporte ao Bun agora é limitado ou descontinuado em várias ferramentas, o que significa que seu CI ou host pode simplesmente deixar de prometer compatibilidade.
- Fornecedores mudam de rumo. A Microsoft cancelando certas licenças de ferramentas de IA é outro domínio, mas a mesma lição: quando você aluga capacidades, seu roadmap herda risco de políticas externas.
Você pode manter a velocidade do JavaScript moderno enquanto isola o core do negócio da volatilidade de runtimes. O truque é adotar uma estratégia de subconjunto portátil + adaptador, medir o imposto (ele existe) e comprar uma opção: a capacidade de fazer um pivô em semanas, não em trimestres.
A planilha de risco de runtimes para o CTO
Coloque números ao lado destes modos de falha antes de escolher um runtime (ou dobrar a aposta em um):
- Deriva de API: ESM vs. CommonJS, Web APIs padrão vs. módulos exclusivos do Node, diferenças sutis em streams, crypto e timers.
- Limites de execução: isolates de edge com limites de memória de 128–256 MB vs. contêineres Node com 512 MB–1 GB; cotas de tempo de CPU e relógios de parede por requisição variam por provedor.
- Addons nativos: Qualquer coisa que exija Node-API ou variantes específicas de libc (glibc vs. musl) é uma âncora. Migrar entre AWS Lambda, contêineres e isolates vira um exercício de rebuild.
- Lock-in de toolchain: Um test runner, bundler ou gerenciador de pacotes específico de um runtime pode transformar uma migração “pequena” em uma reescrita completa do pipeline.
- Armadilhas de licenciamento: Trazer deps transitivas AGPL para componentes de servidor pode compelir divulgação de código — uma superfície separada, porém adjacente, que você precisa observar ao experimentar novos runtimes e forks.
Atribua pontuações de probabilidade e raio de impacto para cada um nos seus principais workloads. Se o raio de impacto é “API de pagamentos fora” ou “não dá para publicar um fix de segurança”, faça hedge.
O framework de decisão: escolha pelo workload, não pelo hype
Um runtime não servirá para tudo. Mapeie seus tipos de workload para o modelo de execução certo e, então, aplique disciplina de portabilidade onde importa.
1) Requisição/resposta sem estado e crítica em latência
- Exemplos típicos: renderização no edge, roteamento A/B, personalização, emissão de tokens de auth, adaptadores simples.
- Alvo: isolates de edge ou serverless leve que implementem o conjunto de Web APIs do WinterCG (fetch, Request/Response, Web Crypto, URL, Web Streams).
- Disciplina: Apenas ESM, sem built-ins do Node (http, net, tls), evitar fs, sem addons nativos; mantenha o código puro e com poucas dependências.
- Por quê: Cold starts costumam ser de milissegundos de um dígito em isolates; menor latência para o usuário; maior eficiência de escala. Você sacrificará sockets e I/O de arquivos — aceite isso.
2) Processos com estado ou em lote com I/O
- Exemplos típicos: ETL, processamento de mídia, geração de PDF, workers de fila, webhooks longos, intermediação de modelos de IA.
- Alvo: Node.js LTS em contêineres ou serverless com compute generoso (e idealmente sidecars de GPU quando necessário).
- Disciplina: Mantenha todas as partes não portáteis (fs, addons nativos, headless Chrome) atrás de uma interface estreita para que possam virar um serviço depois.
- Por quê: Você precisa de semântica estável de arquivos/rede, memória previsível e debugging maduro. Aqui, vazão vence latência de cauda.
3) Ferramentas de desenvolvedor e CLIs
- Exemplos típicos: geradores de projeto, scaffolding interno, scripts de migração.
- Alvo: Deno ou Bun podem ser excelentes, especialmente pela facilidade de distribuição e velocidade.
- Disciplina: Não deixe escolhas de runtime de ferramentas vazarem para suas libs de produção. Mantenha as libs de produção agnósticas de runtime.
- Por quê: Você pode trocar o runtime de uma CLI com baixo impacto no cliente; é um lugar seguro para explorar ergonomias de ponta.
O subconjunto portátil: construa sobre padrões da Web primeiro
A maior parte do hedge vem de se apoiar nas APIs em que todo runtime moderno está convergindo. Priorize estes:
- fetch / Request / Response: Primitivas universais de cliente/servidor HTTP. No Node 18+, fetch é embutido; em outros lugares é de primeira classe. Evite os módulos http/https do Node.
- Web Crypto (SubtleCrypto): Use digest, sign, verify e geração de chaves padrão; evite polyfills de crypto atrelados a semânticas exclusivas do Node.
- URL e URLSearchParams: Não use parsers customizados.
- TextEncoder / TextDecoder e Web Streams: Prefira transform streams em vez dos tipos de stream exclusivos do Node; a interoperabilidade está melhorando entre runtimes.
- Apenas ESM: Nada de CommonJS. Exports condicionais quando necessário, mas não introduza require dinâmico.
Sempre que você sentir vontade de importar um builtin do Node, pare e pergunte: Existe uma forma compatível com o WinterCG? Se não, isso pode viver atrás de uma fronteira?
Antipadrões que matam a portabilidade
- Apoiar-se em fs para armazenamento temporário em código destinado a edge/serverless. Use object storage via fetch; ou um cache apenas em memória com tamanho limitado.
- Addons nativos para compressão, operações de imagem ou crypto quando existem alternativas WASM ou em JS puro de alta qualidade. Se precisar usar nativo, isole-o.
- Node Streams em todo lugar. Migre para Web Streams para pipelines de request/response.
- Fazer polyfill global de Buffer ou outros globais do Node. Prefira imports explícitos e utilitários portáteis.
- SSR que assume APIs do Node para leitura de arquivos, resolução de paths ou sockets de rede. Mantenha a renderização pura; alimente-a com dados via fetch.
Sua camada de adaptadores: a menor caixa com o maior retorno
Crie um único pacote interno que expresse suas necessidades estreitas específicas de runtime. Superfície típica:
- kv.get/set/delete: apoiado por Redis no Node, por um KV do provedor no edge ou por um store durável de objetos.
- secrets.get(name): mapeia para process.env no Node, bindings de ambiente no edge e store local criptografado no dev.
- scheduler.delay(fn, ms): usa setTimeout no Node, alarms do provedor em ambientes de edge e um fallback no-op em testes locais.
- storage.put/get: cliente fetch compatível com S3; nunca fs bruto para caminhos portáteis.
Depois escreva de duas a quatro implementações concretas: Node, Edge e qualquer host de caso especial de que você dependa. Seu código de aplicação importa a interface, não o host.
Testes de conformidade: torne a deriva visível
Portabilidade sem uma matriz de testes é teatro. Adicione um job que rode seus testes unitários e de integração nestes alvos:
- Node.js: LTS atual e anterior (para 2026, pense em 20.x e 22.x).
- Deno: estável atual (2.x). Use o modo de compatibilidade com Node apenas em testes do adaptador, não no código da aplicação.
- Bun: fixe uma versão comprovadamente boa para tooling de dev e adaptadores; falhe rápido se as semânticas diferirem.
- Emulador de edge: emulador local de isolate (por exemplo, estilo Miniflare) para validar suposições de Web APIs.
Bloqueie merges nessa matriz para as bibliotecas que precisam permanecer portáteis. Espere um imposto de 10–15% no tempo de build e refactors ocasionais. É mais barato do que uma migração forçada sob pressão de outage.
Checagem de realidade de performance
Os números variam por provedor e app, mas o formato do trade-off é confiável:
- Cold start: edge baseado em isolates costuma acordar em milissegundos de um dígito; funções Node genéricas em serverless tipicamente levam dezenas a centenas de milissegundos dependendo do runtime e do tamanho de memória.
- Memória: isolates de edge comumente limitam ~128–256 MB por requisição; contêineres/funções Node oferecem 512 MB ou mais.
- Tempo de CPU: edge impõe tetos apertados de compute por requisição; contêineres dão CPU estável e são mais amigáveis a transforms de streaming e tarefas CPU-bound.
Não escolha um runtime para “vencer benchmarks”. Escolha para cumprir um SLO claro: latência P95, vazão e custo por 1K requisições. Depois use seu adaptador para colocar cada função na camada de execução certa.
Segurança e compliance não param por causa de runtimes
Fazer hedge de runtime também é uma jogada de segurança:
- SBOMs prontos para SSA/CSA: gere e armazene SBOMs por build e por runtime. Se um CVE surgir em uma transitiva exclusiva do Node, você consegue cortar para uma variante segura para edge mais rápido.
- Varredura de licenças: adicione uma etapa que sinalize AGPL, SSPL ou licenças não validadas em código executado no servidor. Os casos públicos recentes em torno de violações de AGPL são alertas, não rodapés.
- Disciplina de segredos: nada de gambiarras apenas com dotenv; seu adaptador deve centralizar o acesso a segredos e tornar explícito o que é local vs. produção.
Pessoas e processo: mantenha a velocidade enquanto faz hedge
Brazil tem 750K+ desenvolvedores e uma base ampla de talentos em Node/TypeScript. A maioria ainda não colocou Deno ou Bun em produção — e tudo bem. As habilidades de portabilidade de que você precisa são ensináveis em semanas:
- Semana 1–2: Treine em Web APIs (fetch, Web Crypto, Web Streams) e práticas apenas ESM; elimine CommonJS em código novo.
- Semana 3–4: Introduza o padrão de adaptador; migre um serviço não crítico para usá-lo.
- Contínuo: Mantenha um perfil de lint “agnóstico de runtime” e faça cumprir em PRs para pacotes portáteis.
O custo: espere uma queda de 5–10% na velocidade bruta de features para times que possuem módulos portáteis. O benefício: quando você precisar de fato trocar de runtime, normalmente economiza 4–6 semanas de trabalho de migração pontual e evita um congelamento arriscado.
Seu plano de hedge de runtime em 90 dias
Dias 0–30: inventário e limites
- Faça inventário de todas as chamadas específicas de runtime (built-ins do Node, addons nativos, polyfills globais). Classifique por criticidade e capacidade de substituição.
- Defina seu subconjunto portátil e codifique-o em regras de lint. Apenas ESM para todo código novo.
- Coloque de pé um pequeno pacote de adaptador e implemente versões Node e Edge para kv, secrets, scheduler, storage.
- Adicione um job de teste de conformidade ao CI entre Node LTS e um runtime alternativo. Faça falhar módulos greenfield que desviem.
Dias 31–60: primeiro port e observabilidade
- Migre um endpoint sensível a latência para o subconjunto portátil e publique em um runtime de edge lado a lado com seu caminho em Node. Roteie 1–5% do tráfego e meça.
- Migre um worker em lote para isolar deps nativas atrás do adaptador. Se for impossível, registre isso como dívida técnica deliberada com um plano de saída.
- Instrumente tags de runtime/versão/região em cada linha de log e trace. Construa dashboards de SLO por runtime.
Dias 61–90: expandir e impor
- Portar 30–50% dos seus endpoints de requisição/resposta que caibam nas restrições de edge; deixe o resto em Node.
- Endureça o adaptador (testes de caos entre implementações, timeouts, backoffs). Documente-o como se fosse uma API pública.
- Torne a matriz de conformidade um gate de merge para qualquer biblioteca destinada a ser reutilizada entre serviços.
Trade-offs e quando dizer não
Hedging não é de graça. Diga não à portabilidade quando:
- Você realmente precisa de recursos exclusivos do Node ou nativos e não há alternativa realista (por exemplo, renderização de PDF de alta fidelidade com headless Chrome). Mantenha isso em um serviço delimitado.
- O código é descartável (um script de migração pontual). Prefira velocidade e apague-o após o uso.
- Seu time está sob pressão aguda de entrega. Coloque a portabilidade no timebox do adaptador e do lint; agende o resto para o próximo ciclo.
Caso contrário, compre a opção. Hoje é o suporte ao Bun ficando instável; amanhã pode ser uma mudança de faturamento ou uma capacidade de plataforma de que você de repente precisa e que seu runtime atual não entrega.
Como é o “bom” em seis meses
- Você consegue rodar bibliotecas críticas em Node LTS e em pelo menos um runtime alternativo sem mudanças de código além da ligação do adaptador.
- Seus SLOs são por runtime, e você tem gráficos provando onde o edge vence e onde o Node vence.
- Você tem zero código de cola de runtime indiferenciado fora do adaptador; todo o resto é lógica de aplicação.
- Desenvolvedores priorizam Web APIs primeiro. Code review intercepta imports exclusivos do Node instantaneamente.
Essa postura lhe dá poder de barganha com fornecedores, menos surpresas às 2 da manhã e um funil de contratação que aproveita o enorme mercado de TypeScript (incluindo 6–8 horas de sobreposição US/Brazil) sem treinar engenheiros em um beco sem saída.
Principais conclusões
- Não aposte seu backend na boa vontade de um único runtime JavaScript. Compre a opção de trocar com um subconjunto portátil e uma camada de adaptador.
- Escolha runtimes por workload: edge para caminhos sem estado e puros em latência, Node LTS para jobs com I/O pesado e de longa duração, runtimes de ponta para ferramentas/CLIs.
- Apoie-se nos padrões da Web (fetch, Web Crypto, Web Streams, URL) e em ESM-only; evite módulos exclusivos do Node em código portátil.
- Rode uma matriz de conformidade entre Node LTS e pelo menos um runtime alternativo; use-a como gate de merge para bibliotecas compartilhadas.
- Espere um imposto de 5–10% na velocidade por portabilidade; ele paga 4–6 semanas de tempo de migração quando um pivô é necessário.
- Centralize segredos, storage, kv e agendamento em um pequeno adaptador; trate-o como um produto com testes e documentação.
Autor: Diogo Hudson Dias