Quando uma aplicação Node.js apresenta lentidão, vazamento de memória, uso alto de CPU ou comportamento inesperado, logs nem sempre são suficientes. O módulo e o protocolo de Inspector no Node.js permitem conectar ferramentas de depuração ao processo, definir breakpoints, acompanhar variáveis, gerar perfis de CPU, capturar heap snapshots e executar comandos do Chrome DevTools Protocol.
O Inspector é poderoso, mas também sensível. Uma porta de depuração exposta pode permitir execução de código no processo. Por isso, o acesso deve permanecer restrito ao ambiente local, a redes administrativas ou a túneis autenticados.
Neste guia, você aprenderá a iniciar o Node.js com inspeção, usar Chrome DevTools, VS Code e o módulo node:inspector, coletar perfis, analisar memória, depurar processos em containers e proteger o endpoint de depuração.
O que é o Inspector?
O Node.js implementa o Chrome DevTools Protocol para expor recursos de depuração e profiling. A documentação oficial do módulo Inspector descreve a API programática, enquanto o guia oficial de debugging do Node.js apresenta formas de conexão.
Para investigar desempenho, veja também Performance Hooks no Node.js e Módulo V8 no Node.js.
Iniciando com –inspect
node --inspect server.jsO processo inicia normalmente e abre uma porta de depuração, geralmente em 127.0.0.1:9229. A aplicação não para automaticamente no começo.
Para alterar a porta:
node --inspect=127.0.0.1:9230 server.jsPrefira vincular ao loopback. Usar 0.0.0.0 expõe a porta em todas as interfaces.
Parando antes da primeira linha
node --inspect-brk server.js--inspect-brk pausa antes da execução do código do usuário. Isso é útil para investigar inicialização, carregamento de módulos e configuração.
Conectando com Chrome DevTools
No Chrome, abra chrome://inspect, configure o destino e selecione o processo Node.js. O DevTools oferece:
- breakpoints;
- step over, step into e step out;
- watch expressions;
- console de depuração;
- CPU profiler;
- heap snapshots;
- análise de chamadas assíncronas.
Em produção, não abra a porta diretamente na internet. Use túnel SSH ou uma plataforma de diagnóstico controlada.
Depuração no VS Code
Um arquivo launch.json pode iniciar a aplicação:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Iniciar API",
"program": "${workspaceFolder}/src/server.js",
"envFile": "${workspaceFolder}/.env"
}
]
}Para anexar a um processo existente:
{
"type": "node",
"request": "attach",
"name": "Anexar ao Node.js",
"port": 9229,
"restart": false
}Evite armazenar segredos diretamente no arquivo de configuração versionado.
Breakpoints no código
function calculateTotal(items) {
debugger;
return items.reduce((sum, item) => sum + item.price, 0);
}A palavra-chave debugger pausa somente quando um cliente de depuração está conectado. Remova breakpoints permanentes antes de liberar código ou controle seu uso por ambiente.
Depurando código assíncrono
O DevTools pode mostrar async stack traces que conectam Promises, timers e callbacks. Mesmo assim, stacks assíncronas podem ficar incompletas em bibliotecas nativas ou abstrações personalizadas.
AsyncLocalStorage ajuda a preservar contexto por requisição. Veja AsyncLocalStorage no Node.js para request IDs e traces.
Abrindo o Inspector em tempo de execução
const inspector = require('node:inspector');
if (process.env.ENABLE_INSPECTOR === 'true') {
inspector.open(9229, '127.0.0.1', false);
}O terceiro argumento define se o código deve aguardar um debugger. Ativar isso em produção sem controle pode interromper o serviço.
Obtendo a URL de inspeção
const url = inspector.url();
console.log(url);A URL contém um identificador de sessão. Trate-a como informação sensível. Não a publique em logs acessíveis a usuários.
Fechando o Inspector
inspector.close();Quando a investigação terminar, feche a porta. Em ambientes automatizados, aplique um tempo máximo de ativação.
Usando inspector.Session
A classe Session permite enviar comandos do protocolo:
const inspector = require('node:inspector');
const session = new inspector.Session();
session.connect();
session.post('Runtime.enable', error => {
if (error) console.error(error);
});Os nomes dos comandos seguem domínios do Chrome DevTools Protocol, como Runtime, Profiler e HeapProfiler.
Promisificando session.post
function post(session, method, params = {}) {
return new Promise((resolve, reject) => {
session.post(method, params, (error, result) => {
if (error) reject(error);
else resolve(result);
});
});
}Essa função simplifica sequências com async e await.
Coletando perfil de CPU
const fs = require('node:fs/promises');
async function captureCpuProfile(durationMs = 10000) {
const session = new inspector.Session();
session.connect();
try {
await post(session, 'Profiler.enable');
await post(session, 'Profiler.start');
await new Promise(resolve => {
setTimeout(resolve, durationMs);
});
const { profile } = await post(session, 'Profiler.stop');
await fs.writeFile(
'./cpu-profile.cpuprofile',
JSON.stringify(profile)
);
} finally {
session.disconnect();
}
}O arquivo pode ser aberto no DevTools. Capture durante uma carga representativa e por tempo limitado. Perfis longos geram arquivos maiores e overhead.
Interpretando CPU profiles
Observe funções com alto tempo próprio e total. Uma função pode aparecer muito porque chama outras rotinas caras. Compare:
- self time;
- total time;
- quantidade de amostras;
- caminhos de chamada;
- diferenças entre cenários.
Não otimize apenas a função mais visível sem confirmar impacto no throughput ou na latência.
Heap snapshots
Snapshots mostram objetos vivos e referências que os mantêm na memória. É possível gerar um snapshot pelo DevTools ou pelo protocolo:
async function captureHeapSnapshot(filePath) {
const session = new inspector.Session();
const fs = require('node:fs');
const output = fs.createWriteStream(filePath);
session.connect();
session.on('HeapProfiler.addHeapSnapshotChunk', message => {
output.write(message.params.chunk);
});
try {
await post(session, 'HeapProfiler.enable');
await post(session, 'HeapProfiler.takeHeapSnapshot', {
reportProgress: false
});
} finally {
output.end();
session.disconnect();
}
}Heap snapshots podem congelar o processo e duplicar temporariamente consumo de memória. Em uma instância próxima do limite, a captura pode causar encerramento.
Dados sensíveis em snapshots
Um snapshot pode conter:
- tokens;
- objetos de usuário;
- conteúdo de requisições;
- variáveis de ambiente;
- chaves e configurações;
- dados mantidos em caches.
Armazene o arquivo com acesso restrito, criptografe durante transporte e apague depois da análise.
Comparando snapshots
Para investigar vazamento, capture:
- um snapshot após aquecimento;
- execute a carga repetida;
- force um período de estabilização;
- capture outro snapshot;
- compare objetos e retained size.
Objetos crescentes podem ser caches legítimos. Confirme se continuam aumentando sob carga constante.
Sampling heap profiler
O sampling profiler possui overhead menor que snapshots completos e ajuda a descobrir onde alocações acontecem. Ele não mostra todas as referências, mas pode identificar caminhos de criação responsáveis por grande volume.
Inspector e containers
Para depuração local em Docker:
docker run \
-p 127.0.0.1:9229:9229 \
-p 3000:3000 \
app \
node --inspect=0.0.0.0:9229 server.jsDentro do container, o processo precisa ouvir em 0.0.0.0, mas a publicação no host deve permanecer em 127.0.0.1. Não publique a porta globalmente.
Port forwarding no Kubernetes
kubectl port-forward pod/api-123 9229:9229Essa abordagem reduz exposição. Ainda assim, controle permissões de acesso ao cluster e encerre o port-forward depois do diagnóstico.
Debug em Cluster
Cada worker é um processo e precisa de uma porta diferente. Ao iniciar múltiplos workers com a mesma porta de inspeção, podem ocorrer conflitos. É possível derivar a porta do worker ou depurar apenas uma instância.
Veja Cluster no Node.js para entender processos e workers.
Debug em Worker Threads
Worker Threads executam no mesmo processo, mas possuem contextos de execução próprios. Ferramentas modernas podem listar threads e permitir seleção. Para cargas de CPU, consulte Worker Threads no Node.js.
Signals para ativação
Em sistemas Unix, determinados sinais podem ativar o Inspector dependendo da versão e configuração do runtime. Verifique a documentação da versão usada e restrinja quem pode enviar sinais ao processo.
Profiling sem pausar usuários
Em produção, prefira:
- uma réplica retirada do balanceador;
- perfil curto;
- carga controlada;
- limites de armazenamento;
- monitoramento de CPU e memória durante a captura;
- plano de rollback.
Para métricas contínuas, use instrumentação de baixo overhead. O artigo de OpenTelemetry no Node.js apresenta observabilidade distribuída.
Source maps
Aplicações TypeScript ou empacotadas precisam de source maps para mostrar o código original. Configure o compilador e o debugger corretamente. Não publique mapas contendo código sensível em ambientes públicos sem necessidade.
Breakpoints condicionais
Um breakpoint condicional interrompe apenas quando uma expressão é verdadeira, por exemplo:
request.userId === 'test-user'Use condições simples. Expressões pesadas executadas em alta frequência podem alterar o comportamento observado.
Logpoints
Logpoints registram valores sem modificar o código. Eles são úteis para diagnósticos temporários, mas ainda adicionam custo e podem expor dados. Não registre credenciais ou payloads completos.
Erros comuns
- Expor 9229 na internet: o processo fica vulnerável a controle remoto.
- Capturar snapshot sem memória livre: a instância pode ser encerrada.
- Perfilar por tempo excessivo: overhead e arquivos crescem.
- Ignorar dados sensíveis: snapshots contêm conteúdo da aplicação.
- Usar breakpoint em produção ativa: requisições ficam paradas.
- Depurar todos os workers: portas e custo se multiplicam.
- Otimizar sem comparar métricas: a mudança pode não melhorar o sistema.
Boas práticas para produção
- Vincule o Inspector ao loopback.
- Use túnel autenticado ou port-forward.
- Ative por tempo limitado.
- Prefira uma réplica isolada.
- Monitore overhead durante a coleta.
- Proteja perfis e snapshots.
- Remova arquivos depois da análise.
- Use source maps corretos.
- Compare antes e depois da correção.
- Combine profiling com métricas e logs.
Conclusão
O Inspector no Node.js oferece uma visão profunda da execução: breakpoints, pilhas assíncronas, perfis de CPU, alocações e heap snapshots. Ele é uma ferramenta essencial quando logs e métricas mostram o sintoma, mas não revelam a causa.
Essa capacidade exige proteção. Portas restritas, sessões curtas, réplicas isoladas e tratamento seguro dos arquivos reduzem o risco. Com uma investigação controlada e comparação de métricas, o Inspector ajuda a corrigir gargalos e vazamentos com evidências, em vez de suposições.




