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

CommonJS no Node.js: require e module.exports

Atualizado em: 10 de outubro de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

CommonJS no Node.js é o sistema de módulos tradicional do runtime. Ele usa require() para carregar dependências e module.exports ou exports para disponibilizar valores a outros arquivos.

Mesmo com a adoção crescente de ECMAScript Modules, CommonJS continua presente em aplicações antigas, ferramentas, scripts e milhares de pacotes. Entender seu funcionamento é essencial para manter sistemas existentes, diagnosticar ciclos de dependência e planejar migrações seguras.

Neste guia, você aprenderá resolução de módulos, cache, exports, caminhos, interoperabilidade com ESM, testes, segurança e boas práticas para produção.

Como funciona o require

O require() recebe um identificador e retorna o valor exportado pelo módulo:

const fs = require('node:fs');
const { somar } = require('./math');

console.log(somar(20, 22));

O carregamento é síncrono. Por isso, ele funciona bem para módulos locais e dependências instaladas durante a inicialização, mas não deve ser usado para arquivos remotos ou tarefas lentas.

Criando um módulo

// math.js
function somar(a, b) {
  return a + b;
}

module.exports = { somar };

O consumidor recebe o objeto exportado:

const { somar } = require('./math');

module.exports e exports

exports começa como uma referência para module.exports. Adicionar propriedades funciona:

exports.buscar = async function buscar(id) {
  return { id };
};

Reatribuir exports não altera o valor exportado:

exports = function criar() {}; // não funciona como esperado

Para exportar uma função, classe ou objeto único, use:

module.exports = function criarAplicacao() {
  return { iniciar() {} };
};

Wrapper do módulo

O Node.js envolve cada arquivo CommonJS em uma função. Isso fornece variáveis locais como module, exports, require, __filename e __dirname.

console.log(__filename);
console.log(__dirname);

Essas variáveis facilitam caminhos relativos ao arquivo atual, mas não existem da mesma forma em ESM.

Resolução de módulos

O identificador pode apontar para módulo interno, arquivo relativo, diretório, pacote instalado ou subpath público. Prefira caminhos explícitos e APIs públicas. Importar arquivos internos de uma dependência cria acoplamento e pode quebrar em atualizações.

Cache do require

Após o primeiro carregamento, o módulo é armazenado em require.cache. Chamadas seguintes normalmente retornam a mesma instância:

const a = require('./config');
const b = require('./config');
console.log(a === b); // true

Isso significa que estado mutável exportado é compartilhado. Evite usar módulos como depósitos globais de dados sem ciclo de vida claro.

Efeitos colaterais no carregamento

O código no topo do arquivo executa durante o primeiro require(). Evite conectar banco, abrir porta ou iniciar timers durante o import.

module.exports = function criarRepositorio(client) {
  return {
    buscar(id) {
      return client.query('SELECT * FROM users WHERE id = $1', [id]);
    }
  };
};

Fábricas tornam testes, inicialização e shutdown mais previsíveis.

JSON com require

const config = require('./config.json');

O arquivo é lido e armazenado em cache. Para configuração dinâmica ou validação rigorosa, leia explicitamente e valide com schema. Veja JSON Schema no Node.js.

Carregamento condicional

let adapter;

if (process.env.STORAGE === 'memory') {
  adapter = require('./memory-storage');
} else {
  adapter = require('./postgres-storage');
}

Use com moderação. Dependências ocultas dificultam análise, testes e empacotamento.

require.resolve

require.resolve() retorna o caminho que seria carregado:

const caminho = require.resolve('meu-pacote');
console.log(caminho);

É útil para diagnóstico e ferramentas, mas não deve ser usado para acessar arquivos privados de pacotes.

Ciclos de dependência

Se A requer B e B requer A, um deles pode receber um objeto parcialmente inicializado. O problema costuma aparecer como propriedades indefinidas ou comportamento dependente da ordem.

Extraia interfaces, constantes e utilitários para um terceiro módulo. Outra alternativa é passar dependências por parâmetro em vez de importá-las diretamente.

Interoperabilidade com ESM

Um módulo CommonJS pode usar import dinâmico:

async function executar() {
  const { processar } = await import('./processador.mjs');
  return processar();
}

module.exports = { executar };

O resultado de import() é uma Promise. Consulte Dynamic Import no Node.js para estratégias de lazy loading.

Importando CommonJS a partir de ESM

import pacote from './legacy.cjs';

O valor de module.exports normalmente aparece como export default. Não presuma que exports nomeados sintetizados estarão disponíveis em todos os pacotes.

Estrutura de aplicação

src/
  app.js
  server.js
  config.js
  modules/
    users/
      controller.js
      service.js
      repository.js
  shared/
    errors.js
    logger.js

Mantenha o arquivo server.js responsável por recursos externos e o app.js por montar a aplicação. Assim, testes podem importar a aplicação sem abrir portas.

Testando CommonJS

const test = require('node:test');
const assert = require('node:assert/strict');
const { somar } = require('../src/math');

test('soma dois números', () => {
  assert.equal(somar(2, 3), 5);
});

Para substituir dependências, prefira injeção explícita:

function criarService({ repository, clock }) {
  return {
    async executar(id) {
      return repository.salvar({ id, createdAt: clock.now() });
    }
  };
}

module.exports = { criarService };

Segurança ao carregar módulos

Nunca use entrada do usuário diretamente em require():

// perigoso
const plugin = require(req.query.module);

Use uma allowlist fechada:

const plugins = {
  pdf: './plugins/pdf',
  csv: './plugins/csv'
};

const escolhido = plugins[tipo];
if (!escolhido) throw new Error('Plugin inválido');
const plugin = require(escolhido);

Limpeza de cache em testes

Excluir itens de require.cache pode forçar nova execução, mas gera testes frágeis. Prefira fábricas e dependências injetáveis.

CommonJS em bibliotecas

Pacotes podem publicar uma entrada CommonJS e outra ESM com conditional exports. É importante garantir que ambas representem a mesma API e não criem duas instâncias independentes de estado.

Veja Conditional Exports no Node.js e Package Exports no Node.js.

Migrando para ESM

  1. adicione testes;
  2. remova efeitos colaterais dos imports;
  3. substitua padrões globais por fábricas;
  4. mapeie usos de __dirname e require.resolve;
  5. converta um pacote por vez;
  6. adicione extensões a caminhos relativos;
  7. avalie dependências CommonJS;
  8. execute testes e benchmarks.

O guia ESM no Node.js detalha a configuração moderna.

Erros comuns

  • reatribuir exports e esperar alterar module.exports;
  • guardar estado global mutável no cache;
  • abrir conexões durante o carregamento;
  • depender da ordem de ciclos;
  • carregar módulos a partir de entrada externa;
  • importar arquivos internos de pacotes;
  • limpar require.cache como estratégia principal de testes;
  • misturar sintaxes sem uma fronteira clara.

Checklist para produção

  • use node: para módulos internos;
  • mantenha exports pequenos;
  • evite efeitos colaterais;
  • injete recursos externos;
  • documente o formato do pacote;
  • teste ciclos e inicialização;
  • valide configuração;
  • planeje interoperabilidade;
  • monitore tempo de startup.

Conclusão

CommonJS no Node.js continua relevante para manutenção, interoperabilidade e publicação de bibliotecas. Seu modelo síncrono e o cache de módulos são simples, mas exigem cuidado com estado compartilhado, efeitos colaterais e ciclos.

Projetos bem estruturados podem continuar usando CommonJS com segurança ou migrar gradualmente para ESM. O ponto principal é tornar dependências explícitas, reduzir lógica executada durante o carregamento e proteger a API pública.

Consulte a documentação oficial de módulos CommonJS do Node.js e a documentação de pacotes do Node.js.

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