Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Module Compile Cache no Node.js: startup mais rápido

Atualizado em: 9 de outubro de 2026

Rack de servidores processando fluxos de dados no Node.js

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.js

Essa é 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.js

O 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.js

Essa 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-coverage

Nã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:

  1. cache desativado;
  2. primeira execução com cache vazio;
  3. 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.js

Repita 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-cache

Nã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

  1. meça o startup atual;
  2. ative em diretório temporário;
  3. compare cache frio e quente;
  4. desative na cobertura;
  5. propague para processos curtos;
  6. monitore disco;
  7. inclua versão do Node.js na estratégia;
  8. 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.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita