O Module Compile Cache no Node.js permite armazenar em disco o código compilado pelo V8 para módulos CommonJS, ECMAScript Modules e TypeScript suportado pelo runtime. Quando a aplicação inicia novamente e os arquivos não mudaram, o Node.js pode reutilizar esse cache e reduzir parte do custo de compilação, melhorando o tempo de inicialização de CLIs, workers, testes e serviços com muitos módulos.
O recurso não substitui cache de dependências, bundling ou snapshots de container. Ele atua em uma etapa específica: a compilação do código-fonte carregado pelo Node.js. A primeira execução pode ficar um pouco mais lenta porque o cache é produzido; os ganhos aparecem nas execuções seguintes do mesmo grafo de módulos.
Neste guia, você aprenderá a ativar o cache por API e variável de ambiente, escolher diretório, trabalhar com processos filhos e workers, usar modo portátil, medir resultados, limpar arquivos antigos e evitar problemas com cobertura de testes.
O que o cache armazena?
Quando o V8 recebe JavaScript, ele analisa e compila o código antes da execução. O compile cache persiste uma representação de código compilado para que uma execução futura não precise repetir todo o trabalho. O conteúdo do cache é um detalhe interno e não deve ser lido, editado ou versionado pela aplicação.
O recurso é útil principalmente em projetos com:
- muitos módulos pequenos;
- CLIs executadas frequentemente;
- workers de vida curta;
- testes que iniciam muitos processos;
- funções serverless com inicializações repetidas;
- ferramentas de build ou lint escritas em Node.js.
Ativação por variável de ambiente
NODE_COMPILE_CACHE=/tmp/node-compile-cache node src/server.jsEssa é a forma mais simples porque o cache é ativado antes do carregamento do entry point. Para scripts npm:
{
"scripts": {
"start": "NODE_COMPILE_CACHE=.cache/node-compile node dist/server.js",
"cli": "NODE_COMPILE_CACHE=.cache/node-compile node dist/cli.js"
}
}Em projetos multiplataforma, use configuração de ambiente do sistema, cross-env ou um script JavaScript de bootstrap. Consulte npm Scripts no Node.js.
Ativação pela API
import { enableCompileCache } from 'node:module';
const result = enableCompileCache();
console.log({
status: result.status,
directory: result.directory,
message: result.message
});Sem diretório explícito, o Node.js usa NODE_COMPILE_CACHE quando definido ou cria uma pasta padrão dentro de os.tmpdir().
A API foi desenhada para tratar o cache como otimização não crítica. Falhas de permissão ou disco não devem derrubar a aplicação; o resultado retorna status e mensagem para diagnóstico.
Verificando o status
import {
constants,
enableCompileCache
} from 'node:module';
const result = enableCompileCache();
switch (result.status) {
case constants.compileCacheStatus.ENABLED:
console.log('Cache ativado', result.directory);
break;
case constants.compileCacheStatus.ALREADY_ENABLED:
console.log('Cache já estava ativado', result.directory);
break;
case constants.compileCacheStatus.DISABLED:
console.log('Cache desativado por configuração');
break;
case constants.compileCacheStatus.FAILED:
console.warn('Falha ao ativar cache', result.message);
break;
}Escolhendo o diretório
Use um caminho gravável, isolado por aplicação e adequado à política de limpeza:
import path from 'node:path';
import os from 'node:os';
import { enableCompileCache } from 'node:module';
const directory = path.join(
os.tmpdir(),
'minha-api-node-compile-cache'
);
enableCompileCache({ directory });Diretórios temporários são recomendados porque versões antigas e módulos removidos podem deixar entradas sem uso. Não coloque o cache dentro de uma pasta servida publicamente e não use um diretório compartilhado por usuários sem permissões adequadas.
Não versionar o cache
Adicione ao .gitignore quando o caminho estiver no projeto:
.cache/node-compile/
O cache depende da versão do Node.js, caminhos e conteúdo dos módulos. Ele não é um artefato-fonte e não deve entrar no repositório ou pacote npm.
Compatibilidade entre versões
O cache criado por uma versão do Node.js não deve ser considerado reutilizável por outra. O runtime separa entradas quando necessário, mas pipelines e containers devem tratar mudança de versão como uma nova linha de cache.
Inclua a versão do Node.js na chave de cache do CI:
node-compile-${{ runner.os }}-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }}Mesmo assim, confirme se restaurar o cache realmente economiza tempo. Upload e download podem custar mais que recompilar.
Modo portátil
Por padrão, mover o projeto para outro caminho pode invalidar entradas, porque caminhos absolutos fazem parte da identidade. Em versões atuais, o modo portátil tenta reutilizar o cache quando a estrutura relativa permanece igual:
enableCompileCache({
directory: '/cache/node',
portable: true
});Ou:
NODE_COMPILE_CACHE=/cache/node \
NODE_COMPILE_CACHE_PORTABLE=1 \
node dist/server.jsO comportamento é de melhor esforço. Módulos que não podem ser relacionados ao diretório do cache podem não ser armazenados.
Processos filhos
A chamada da API afeta apenas o processo atual. Para filhos, propague a variável:
import { spawn } from 'node:child_process';
import { enableCompileCache } from 'node:module';
const result = enableCompileCache();
const child = spawn(process.execPath, ['worker.js'], {
env: {
...process.env,
NODE_COMPILE_CACHE: result.directory
},
stdio: 'inherit'
});Veja child_process no Node.js para sinais, streams e segurança.
Worker Threads
Workers não recebem automaticamente uma chamada feita na thread principal. Propague a variável ou ative no código do worker:
import { Worker } from 'node:worker_threads';
import { enableCompileCache } from 'node:module';
const result = enableCompileCache();
process.env.NODE_COMPILE_CACHE = result.directory;
const worker = new Worker(new URL('./worker.js', import.meta.url));Para pools que criam workers repetidamente, o ganho pode ser maior. Consulte Worker Threads no Node.js.
Flush antecipado
O Node.js normalmente grava o cache acumulado quando o processo está terminando. Se um processo pai deseja compartilhar as entradas antes disso, use:
import {
enableCompileCache,
flushCompileCache
} from 'node:module';
const result = enableCompileCache();
await import('./carregar-modulos.js');
flushCompileCache();
Depois disso, processos filhos podem aproveitar os módulos já compilados. A função falha silenciosamente em problemas de gravação porque cache miss não deve quebrar a execução.
Descobrindo o diretório ativo
import { getCompileCacheDir } from 'node:module';
console.log(getCompileCacheDir());Retorna undefined quando o recurso não está ativo. Esse valor pode ser exposto em diagnóstico administrativo, mas não há necessidade de registrar todos os caminhos em logs públicos.
Desativação emergencial
NODE_DISABLE_COMPILE_CACHE=1 node dist/server.jsEssa variável é útil para comparação de desempenho, investigação de comportamento inesperado e execução de cobertura precisa.
Impacto na cobertura
A documentação do Node.js alerta que a cobertura de código do V8 pode ficar menos precisa para funções restauradas do cache. Portanto, desative o recurso em jobs de cobertura:
NODE_DISABLE_COMPILE_CACHE=1 \
node --test --experimental-test-coverageNão misture resultados coletados com e sem cache em uma mesma tendência. Para práticas de source maps e stacks, veja Source Maps no Node.js.
Medindo o ganho
Faça pelo menos três grupos:
- cache desativado;
- primeira execução com cache vazio;
- execuções subsequentes com cache quente.
rm -rf /tmp/app-compile-cache
time NODE_DISABLE_COMPILE_CACHE=1 node dist/cli.js
time NODE_COMPILE_CACHE=/tmp/app-compile-cache node dist/cli.js
time NODE_COMPILE_CACHE=/tmp/app-compile-cache node dist/cli.jsRepita várias vezes, descarte outliers e meça tempo até a aplicação estar realmente pronta, não apenas o fim do processo de bootstrap.
Métrica de startup
const startedAt = process.hrtime.bigint();
await startApplication();
const readyMs = Number(process.hrtime.bigint() - startedAt) / 1e6;
console.log({ event: 'application_ready', readyMs });Correlacione com versão, quantidade de módulos e ambiente. O artigo perf_hooks no Node.js mostra medições mais detalhadas.
Containers
Em containers efêmeros, gravar cache em camada temporária pode não ajudar entre reinícios. Estratégias possíveis:
- volume persistente por versão do runtime;
- cache compartilhado somente por réplicas confiáveis;
- aquecimento no entrypoint;
- não usar quando o container vive por muito tempo.
Não copie um cache produzido em máquina incompatível sem medir. Para imagens reproduzíveis, consulte Docker Multi-stage para Node.js.
Serverless
O cache só ajuda entre invocações quando o diretório temporário sobrevive no ambiente reutilizado. Cold starts em máquinas novas continuam sem cache. Avalie se bundling reduz mais o grafo de módulos e o custo de I/O.
CLIs
Ferramentas executadas centenas de vezes por dia são um caso forte. O bootstrap pode habilitar cache antes de importar o restante:
// bootstrap.mjs
import { enableCompileCache } from 'node:module';
enableCompileCache();
await import('./cli.mjs');Evite static import de ./cli.mjs no mesmo arquivo, porque dependências estáticas são carregadas antes da chamada.
Segurança
O diretório de cache contém artefatos derivados do código. Aplique:
- proprietário correto;
- permissões restritas;
- diretório separado por aplicação;
- limpeza periódica;
- não compartilhar entre usuários não confiáveis;
- não aceitar caminho vindo de requisição.
Um atacante com escrita no diretório pode causar negação de serviço, ocupar disco ou interferir em artefatos. O cache não deve ser considerado uma fronteira de segurança.
Limpeza
Para limpar, remova o diretório com a aplicação parada ou use política de expiração do sistema:
rm -rf /tmp/minha-api-node-compile-cacheNão dependa da estrutura interna para remover apenas arquivos específicos. Trate o diretório como descartável.
Monitoramento de disco
Se o cache fica em volume persistente, acompanhe tamanho e idade. Releases frequentes e múltiplas versões podem acumular dados. Use quotas ou limpeza por tempo, mantendo cuidado para não remover arquivos durante gravação ativa.
Erros comuns
- esperar ganho na primeira execução;
- versionar o diretório;
- reutilizar cache entre versões do Node.js;
- usar cobertura com cache ativo;
- ativar depois de todos os módulos já carregados;
- não propagar para workers e filhos;
- usar volume lento;
- compartilhar diretório sem permissões;
- não medir tempo de startup real.
Fluxo recomendado
- meça o startup atual;
- ative em diretório temporário;
- compare cache frio e quente;
- desative na cobertura;
- propague para processos curtos;
- monitore disco;
- inclua versão do Node.js na estratégia;
- mantenha fallback sem cache.
Conclusão
O Module Compile Cache no Node.js é uma otimização prática para aplicações que carregam muitos módulos repetidamente. Ele persiste o code cache do V8 e reduz trabalho em execuções seguintes, sem alterar a lógica da aplicação.
Ative cedo, use diretório descartável, meça cache frio e quente e desative em cobertura. Quando combinado com scripts previsíveis, containers bem configurados e monitoramento, o recurso melhora startup sem transformar o cache em dependência operacional.
Consulte a documentação oficial do compile cache e a explicação do V8 sobre code caching.


