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

Clean Architecture no Node.js: camadas e dependências

Atualizado em: 13 de outubro de 2026

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

Clean Architecture no Node.js organiza o sistema em camadas com dependências apontando para regras de negócio, não para frameworks, bancos ou protocolos. O objetivo é permitir que casos de uso continuem testáveis mesmo quando detalhes externos mudam.

A arquitetura não depende de uma estrutura de pastas específica. Ela depende de fronteiras claras, contratos pequenos e inversão de dependência.

Neste guia, você aprenderá entidades, casos de uso, adapters, infraestrutura, composição, testes e erros comuns.

Regra de dependência

Camadas externas podem conhecer camadas internas. Camadas internas não devem importar detalhes externos.

domain <- application <- adapters <- infrastructure

Entidades

Entidades representam regras e invariantes centrais:

export function criarUsuario({ id, email, active = true }) {
  if (!email.includes('@')) throw new InvalidEmailError(email);
  return { id, email, active };
}

Elas não precisam conhecer HTTP, SQL ou logger.

Casos de uso

export function criarCadastrarUsuario({ users, idGenerator, clock }) {
  return async function cadastrar(input) {
    if (await users.existeEmail(input.email)) {
      throw new EmailAlreadyUsedError(input.email);
    }

    const user = criarUsuario({
      id: idGenerator.next(),
      email: input.email,
      createdAt: clock.now()
    });

    await users.salvar(user);
    return user;
  };
}

O caso de uso depende de portas, não de implementações.

Portas

Portas são contratos exigidos pela aplicação:

  • repository de usuários;
  • gateway de pagamento;
  • publisher de eventos;
  • relógio;
  • gerador de IDs.

Em JavaScript, o contrato pode ser documentado e validado em testes.

Adapters

Adapters traduzem entre o mundo externo e a aplicação:

  • controller HTTP transforma request em input;
  • repository PostgreSQL implementa a porta de persistência;
  • consumer de fila transforma mensagem em chamada de caso de uso;
  • presenter transforma resultado em resposta.

Infraestrutura

Banco, framework, cache, fila e observabilidade ficam na borda. Eles podem ser substituídos sem alterar entidades e casos de uso.

Estrutura de pastas

src/
  domain/
    user.js
    errors.js
  application/
    register-user.js
    ports/
  adapters/
    http/
    persistence/
    messaging/
  infrastructure/
    database.js
    server.js
  main.js

A estrutura é uma sugestão. O mais importante é impedir imports da camada interna para a externa.

Composition root

const pool = criarPool(config.databaseUrl);
const repository = criarPostgresUserRepository(pool);
const registerUser = criarCadastrarUsuario({
  users: repository,
  idGenerator: uuidGenerator,
  clock: systemClock
});
const app = criarHttpApp({ registerUser });

Veja Dependency Injection no Node.js.

Controllers

Controllers validam protocolo, chamam casos de uso e mapeiam erros:

export function criarRegisterController(registerUser) {
  return async function controller(req, res) {
    const result = await registerUser({ email: req.body.email });
    res.status(201).json(result);
  };
}

Eles não devem conter regra de negócio.

Repositories

Repositories implementam portas de persistência. Veja Repository Pattern no Node.js.

Service Layer e casos de uso

A Service Layer pode representar a camada de aplicação quando seus métodos correspondem a ações de negócio. Consulte Service Layer no Node.js.

DTOs

Não exponha diretamente entidades internas como contrato externo quando isso acopla clientes à estrutura do domínio. Use DTOs e presenters para controlar formatos.

Validação

Validação estrutural pertence à fronteira. Invariantes de negócio pertencem ao domínio. A mesma regra não deve ser duplicada em todas as entradas.

Erros

Casos de uso lançam erros com códigos estáveis. Adapters decidem como traduzir para HTTP, fila ou CLI.

Transações

A camada de aplicação coordena transações sem importar o driver. Uma porta de unidade de trabalho pode fornecer repositories vinculados à mesma transação.

Eventos

Eventos de domínio descrevem fatos. A publicação confiável pode usar outbox na infraestrutura. Não faça entidade chamar broker diretamente.

Testes unitários

Entidades e casos de uso são testados com fakes pequenos:

const users = criarUserRepositoryFake();
const register = criarCadastrarUsuario({ users, idGenerator, clock });
const user = await register({ email: 'a@b.com' });
assert.equal(user.email, 'a@b.com');

Testes de adapters

Adapters de persistência precisam de integração real. Controllers precisam de testes de serialização e status.

Não transforme tudo em abstração

Clean Architecture não exige interface para cada função. Crie fronteiras onde existe dependência externa, variação ou regra importante.

Custo

Projetos pequenos podem começar com módulos simples e evoluir conforme crescem. Muitas camadas sem comportamento aumentam navegação e manutenção.

Erros comuns

  • organizar apenas por pastas;
  • entidade importando ORM;
  • caso de uso retornando response HTTP;
  • interfaces gigantes;
  • DTO duplicado sem necessidade;
  • container global;
  • abstrair framework sem motivo;
  • ignorar custo da arquitetura.

Checklist

  • regras internas independentes;
  • portas pequenas;
  • adapters explícitos;
  • composition root;
  • erros estáveis;
  • testes rápidos de casos de uso;
  • integração para infraestrutura;
  • sem imports invertidos.

Conclusão

Clean Architecture no Node.js protege regras de negócio de detalhes que mudam com frequência. Ela permite trocar framework, banco ou protocolo sem reescrever o núcleo da aplicação.

Use a regra de dependência como guia, não como dogma. Crie fronteiras onde elas reduzem acoplamento e mantenha o código simples onde não existe variação real.

Consulte o artigo original sobre Clean Architecture e a documentação de testes 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