Noções Básicas de Arquitetura e Design
8 exemplos para você começar com Arquitetura e Design para backends Node.js - 6 básicos e 2 intermediários.
Busque em todas as páginas da documentação
8 exemplos para você começar com Arquitetura e Design para backends Node.js - 6 básicos e 2 intermediários.
Estes exemplos assumem Node.js 24.18.0, TypeScript 5.6+ e uma pequena API Express 5 ou Fastify 5.
mkdir orders-api && cd orders-api
npm init -y
npm install express@5 zod
npm install -D typescript@5.6 @types/node @types/express tsx
npx tsc --initUma implantação, com limites claros de módulos dentro do repositório.
src/
├── modules/
│ ├── orders/
│ │ ├── domain/
│ │ ├── application/
│ │ └── infrastructure/
│ └── billing/
├── shared/
└── main.tsRelacionado: Monólito Modular - empacotamento por funcionalidade dentro de uma única implantação
Rotas traduzem HTTP; o código de domínio permanece agnóstico ao framework.
// src/modules/orders/application/create-order.ts
export type CreateOrderInput = { customerId: string; sku: string; qty: number };
export function createOrder(input: CreateOrderInput) {
if (input.qty <= 0) throw new Error("qty must be positive");
return { id: crypto.randomUUID(), ...input, status: "pending" as const };
}// src/modules/orders/infrastructure/http/routes.ts
import express from "express";
import { createOrder } from "../../application/create-order";
export const ordersRouter = express.Router();
ordersRouter.post("/", (req, res) => {
const order = createOrder(req.body);
res.status(201).json({ data: order });
});createOrder não possui importações de Request ou Response - testes unitários rodam sem HTTPRelacionado: Arquitetura Hexagonal em Node - layout de portas e adaptadores
Uma porta é uma interface da qual o domínio depende; adaptadores a implementam.
// src/modules/orders/domain/ports/order-repository.ts
export type Order = { id: string; customerId: string; sku: string; qty: number };
export interface OrderRepository {
save(order: Order): Promise<void>;
findById(id: string): Promise<Order | null>;
}// src/modules/orders/infrastructure/postgres-order-repository.ts
import type { Order, OrderRepository } from "../domain/ports/order-repository";
export class PostgresOrderRepository implements OrderRepository {
constructor(private readonly pool: { query: (sql: string, params: unknown[]) => Promise<unknown> }) {}
async save(order: Order): Promise<void> {
await this.pool.query(
"INSERT INTO orders (id, customer_id, sku, qty) VALUES ($1,$2,$3,$4)",
[order.id, order.customerId, order.sku, order.qty]
);
}
async findById(id: string): Promise<Order | null> {
const rows = await this.pool.query("SELECT * FROM orders WHERE id = $1", [id]);
return (rows as Order[])[0] ?? null;
}
}pg ou RedisAgrupe tudo para "pedidos" em conjunto, em vez de uma árvore global de controllers/.
src/modules/orders/
├── domain/
│ ├── order.ts
│ └── ports/
├── application/
│ ├── create-order.ts
│ └── list-orders.ts
└── infrastructure/
├── http/routes.ts
└── postgres-order-repository.tsimport/no-restricted-paths pode impor limites de móduloRelacionado: Monólito Modular - aplicando limites em um único repositório
Sistemas distribuídos compram independência ao custo de rede, operações e consistência.
| Sinal | Mantenha monólito | Considere serviços |
|---|---|---|
| Tamanho da equipe | 1-3 esquadrões em um produto | 4+ esquadrões pisando no mesmo deploy |
| Cadência de implantação | Lançamento compartilhado semanal ou diário | Necessidade de implantações horárias por domínio |
| Acoplamento de dados | Transações compartilhadas entre funcionalidades | Contextos delimitados claros com junções cruzadas raras |
| Maturidade de operações | Rotação de plantão única | Equipe de plataforma para malha, rastreamento, SLOs |
Relacionado: Microsserviços Quando Vale a Pena - trade-offs de equipe e custo
Registros de Decisão de Arquitetura sobrevivem a reestruturações e perda de memória.
# ADR-003: Permanecer Monólito Modular até 2026
## Status
Aceito
## Contexto
Três esquadrões, 40k RPS de pico, Postgres compartilhado. Nenhuma equipe de plataforma dedicada.
## Decisão
Permanecer um monólito modular. Revisitar quando o faturamento precisar de cadência de implantação independente.
## Consequências
+ Entrega de funcionalidades mais rápida, depuração mais simples
- Implantações de faturamento aguardam lançamentos de pedidosRelacionado: ADR: Monólito vs. Serviços - modelo específico para Node
A raiz de composição é o único lugar que conhece as implementações concretas.
// src/main.ts
import express from "express";
import { PostgresOrderRepository } from "./modules/orders/infrastructure/postgres-order-repository";
import { ordersRouter } from "./modules/orders/infrastructure/http/routes";
const pool = { query: async () => [] }; // substitua por um pg.Pool real
const orderRepo = new PostgresOrderRepository(pool);
const app = express();
app.use(express.json());
app.use("/orders", ordersRouter);
app.listen(3000);main.ts ou em um composition-root.ts dedicadoExecute uma lista de verificação estrutural antes de extrair um serviço.
// scripts/architecture-audit.ts - grep para importações entre módulos
import fs from "node:fs";
import path from "node:path";
const modulesDir = "src/modules";
for (const mod of fs.readdirSync(modulesDir)) {
const files = fs.readdirSync(path.join(modulesDir, mod), { recursive: true }) as string[];
const tsFiles = files.filter((f) => f.endsWith(".ts"));
console.log(`${mod}: ${tsFiles.length} arquivos`);
}index.ts reexportar tudo, corrija a modularidade dentro do monólito primeiroRelacionado: Lista de Verificação de Refatoração - auditorias de
index.tsmonolítico e proliferação de rotas
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (LTS Ativo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026