New Relic com Bun e Next.js 16: corrigindo ERR_REQUIRE_ESM no Turbopack
Ao instalar o New Relic Node.js Agent em uma aplicação Next.js 16 gerenciada com Bun, o servidor de desenvolvimento pode iniciar e, segundos depois, encerrar com ERR_REQUIRE_ESM. No caso analisado, a falha apareceu quando o Turbopack carregou o transformer do New Relic e resolveu o parser meriyah no formato errado.
O erro completo continha referências semelhantes a:
New Relic for Node.js was unable to bootstrap itself due to an error:
Error [ERR_REQUIRE_ESM]:
require() of ES Module .../meriyah/dist/meriyah.mjs not supported
at @apm-js-collab/code-transformer/lib/transformer.js
at next/dist/server/require-hook.js
Este artigo registra a causa e a solução para tornar o diagnóstico encontrável por quem pesquisar por termos como:
New Relic ERR_REQUIRE_ESM;Bun New Relic Next.js;meriyah.mjs not supported;@apm-js-collab/code-transformer meriyah;Next.js 16 Turbopack require ESM.
Outros usuários tiveram problemas semelhantes?
Sim, existem relatos públicos de incompatibilidades da mesma classe envolvendo Next.js 16, Turbopack, aplicações ou monorepos ESM e resolução de dependências com Bun.
Isso não significa que todos os relatos tenham exatamente a mesma cadeia New Relic → code-transformer → meriyah. Significa que ERR_REQUIRE_ESM, externalização de pacotes e diferenças entre o grafo do Bun e o runtime Node.js são problemas reais observados por outros usuários.
Por exemplo:
- o Next.js possui um issue confirmado sobre ERR_REQUIRE_ESM em runtime com Next.js 16 e monorepo ESM;
- há outro relato envolvendo Turbopack, pacotes externos e o layout isolado de dependências do Bun;
- a própria documentação informa que, desde o Next.js 16, o Turbopack é usado por padrão em desenvolvimento e build;
- o New Relic recomenda o Hybrid Agent baseado nos spans OpenTelemetry nativos do Next.js 16.
O caso documentado aqui é uma manifestação específica dessa família de problemas de resolução entre CommonJS e ESM.
Ambiente em que o erro foi reproduzido
A combinação relevante era:
Next.js 16
Turbopack
Bun como package manager
New Relic Node.js Agent 14.x
Node.js 22+
@apm-js-collab/code-transformer
meriyah 6.1.4
O Bun não estava executando a aplicação como runtime em produção. Ele era o gerenciador de pacotes e produzia o layout isolado em node_modules/.bun. O servidor Next.js continuava sendo executado pelo Node.js.
Essa diferença importa: dizer apenas “aplicação Bun” pode esconder se Bun é o runtime, o package manager ou ambos.
O sintoma
O servidor começava normalmente:
▲ Next.js 16 (Turbopack)
✓ Ready
✓ Running next.config.ts
Logo depois, o hook instrumentation.ts tentava importar newrelic. O agente carregava @apm-js-collab/code-transformer, que usa CommonJS:
const { parse } = require("meriyah");
Apesar do uso de require(), o hook de resolução do Next.js selecionava:
meriyah/dist/meriyah.mjs
O componente CommonJS tentava então carregar um módulo ESM de forma síncrona, produzindo:
Error [ERR_REQUIRE_ESM]: require() of ES Module not supported
Sem NEW_RELIC_LICENSE_KEY e NEW_RELIC_APP_NAME, o caminho de bootstrap não era executado e o servidor parecia funcionar. Por isso, testar sem as variáveis reais poderia esconder o defeito.
A causa
O pacote meriyah@6.1.4 publica builds para CommonJS e ESM por meio de exports condicionais:
{
"exports": {
"types": "./dist/types/meriyah.d.ts",
"module-sync": "./dist/meriyah.mjs",
"require": "./dist/meriyah.cjs",
"default": "./dist/meriyah.mjs"
}
}
No fluxo iniciado pelo Turbopack e pelo require-hook do Next.js, a condição module-sync tinha precedência. Como ela apontava para meriyah.mjs, o require("meriyah") feito pelo transformer do New Relic recebia ESM.
O erro citava meriyah, mas dependia da interação entre:
New Relic
↓
@apm-js-collab/code-transformer
↓ require("meriyah")
Next.js/Turbopack require hook
↓ escolhe module-sync
meriyah.mjs
↓
ERR_REQUIRE_ESM
Por que apenas serverExternalPackages não resolveu
O primeiro ajuste foi manter o New Relic fora do bundle do servidor:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
serverExternalPackages: ["newrelic"],
};
export default nextConfig;
Isso é apropriado porque o New Relic é um agente do runtime Node.js e precisa observar a aplicação em execução.
Mesmo externalizado, porém, o pacote ainda era carregado por um módulo externo gerado pelo Next.js. O require-hook global continuava participando da resolução das dependências transitivas. Consequentemente, meriyah.mjs ainda era selecionado.
A externalização continuou na solução final, mas não bastava sozinha.
A solução usada com Bun
A correção ficou dividida em duas partes:
- declarar
newrelicemserverExternalPackages; - aplicar um patch reproduzível pelo Bun em
meriyah@6.1.4.
O patch altera apenas a condição de carregamento síncrono:
"exports": {
"types": "./dist/types/meriyah.d.ts",
- "module-sync": "./dist/meriyah.mjs",
+ "module-sync": "./dist/meriyah.cjs",
"require": "./dist/meriyah.cjs",
"default": "./dist/meriyah.mjs"
}
Com isso:
require("meriyah")recebe o build CommonJS;- imports ESM normais continuam usando o arquivo
.mjs; - o transformer do New Relic consegue iniciar;
- o Turbopack continua habilitado;
- o Bun continua sendo usado como package manager.
Gerando o patch com Bun
A forma reproduzível é usar o fluxo nativo do Bun:
bun patch meriyah@6.1.4
Depois de editar o package.json preparado dentro de node_modules/meriyah:
bun patch --commit node_modules/meriyah
O Bun cria um arquivo semelhante a:
patches/meriyah@6.1.4.patch
E registra o patch no projeto:
{
"patchedDependencies": {
"meriyah@6.1.4": "patches/meriyah@6.1.4.patch"
}
}
Assim a correção é reaplicada em instalações limpas, no CI e no deploy. Editar node_modules sem executar bun patch --commit não seria suficiente, porque a alteração desapareceria na próxima instalação.
Exemplo genérico
Imagine uma loja virtual em Next.js que carrega o New Relic no hook oficial de instrumentação:
export async function register() {
if (process.env.NEXT_RUNTIME !== "nodejs") return;
await import("newrelic");
}
Ao executar:
bun install
bun run dev
o agente inicia e carrega um transformer CommonJS. Esse transformer precisa de um parser:
const { parse } = require("meriyah");
Antes do patch:
require("meriyah")
→ meriyah.mjs
→ ERR_REQUIRE_ESM
→ servidor encerrado
Depois do patch:
require("meriyah")
→ meriyah.cjs
→ New Relic inicializado
→ servidor responde normalmente
Não é necessário converter toda a aplicação para CommonJS nem desabilitar o Turbopack. A correção limita-se ao caminho síncrono incompatível.
Como confirmar que o New Relic realmente funciona
A ausência do erro não comprova que a telemetria chegou ao New Relic. A validação usada incluiu:
- configurar
NEW_RELIC_LICENSE_KEYeNEW_RELIC_APP_NAME; - iniciar o servidor com
bun run dev; - aguardar além da janela de conexão do agente;
- acessar uma rota e confirmar resposta HTTP 200;
- executar typecheck, testes e build;
- enviar um evento de log com identificador único;
- fazer o flush dos dados pendentes;
- localizar o identificador no painel do New Relic.
Exemplo de evento:
newrelic.recordLogEvent({
message: "New Relic local smoke test",
level: "INFO",
environment: "local",
marker: "unique-smoke-test-id"
});
O teste só deve ser considerado completo quando o evento aparecer no New Relic.
Cuidados
O patch é específico de versão
O patch deve indicar meriyah@6.1.4. Ao atualizar o New Relic ou @apm-js-collab/code-transformer, verifique se a dependência foi atualizada e se a correção ainda é necessária.
Teste uma instalação limpa
Antes de enviar para produção:
bun install --frozen-lockfile
bun run test
bun run build
O objetivo é confirmar que o patch vem do repositório e não de uma edição residual em node_modules.
Não confunda API key com o erro de módulos
Uma license key ausente ou inválida produz problemas de configuração ou conexão. Ela não explica um stack trace apontando para require(), .mjs, meriyah e ERR_REQUIRE_ESM.
Acompanhe as atualizações upstream
Essa solução é uma camada de compatibilidade. O ideal é removê-la quando o mapa de exports da dependência ou o resolvedor do Next.js deixar de produzir a combinação incompatível.
Resumo
Se o New Relic não inicia em um projeto Next.js 16 com Turbopack instalado pelo Bun e o erro menciona:
ERR_REQUIRE_ESM
@apm-js-collab/code-transformer
meriyah/dist/meriyah.mjs
next/dist/server/require-hook
a causa provável é que o carregamento CommonJS está recebendo a exportação ESM de meriyah.
A solução que funcionou foi:
- externalizar
newreliccomserverExternalPackages; - mudar a condição
module-syncdemeriyah@6.1.4para o build.cjs; - versionar a mudança com
bun patch; - validar o servidor e o envio real de telemetria ao New Relic.