Os 4 frameworks: Express, NestJS, Fastify, Hono

TL;DR

Em 2026, a decisão pragmática em Node passa por quatro modelos: Express (middleware-based e ubíquo), NestJS (opinativo, DI e decorators), Fastify (schema-first e performance), Hono (edge-first e Fetch API). Não existe campeão universal. Existe matching problema ferramenta.

O que é

Express é o framework minimalista e “unopinionated” do ecossistema Node. A documentação oficial o descreve como uma camada fina de features web com uso forte de middleware; em 2026, Express 5.x é a linha corrente.

NestJS é um framework TypeScript opinativo para server-side apps escaláveis. O modelo central combina módulos, controllers, providers, decorators e um container de dependency injection.

Fastify é um framework HTTP focado em baixo overhead, plugin architecture e schemas. A própria documentação recomenda JSON Schema para validar rotas e serializar respostas.

Hono é um framework pequeno e multi-runtime baseado em Web Standards. Roda em Cloudflare Workers, Deno, Bun, AWS Lambda e Node, com API baseada em Request/Response.

Por que importa

Confundir os modelos leva a escolhas caras. Usar NestJS em um microserviço simples pode introduzir DI e decorators sem retorno. Usar Express por hábito em um domínio enterprise grande pode deixar estrutura demais na disciplina individual de cada dev. Usar Fastify sem schema desperdiça o diferencial do framework. Usar Hono em app que depende profundamente de fs, net ou bibliotecas Node-only pode bater em constraints de edge.

Como funciona

FrameworkModeloUse case típicoMaturidadeTrade-offs
ExpressMiddleware-based, minimalistaMicrosserviços simples, prototipagem, glue codeMaduro, v5.xPouca estrutura; precisa montar validation, DI e contracts manualmente
NestJSOpinativo, DI, decoratorsApps enterprise, time grande, domínio complexoMaduro, v10+Curva de aprendizado; overhead em apps simples
FastifySchema-first, performance-focusedAPIs com contrato claro e throughput altoMaduro, v5.xPlugin encapsulation exige mental model; ecossistema menor que Express
HonoUltralight, edge-first, Fetch APIEdge workers, serverless, multi-runtimeMais recente, v4+Ecossistema menor; edge limita APIs Node-specific
graph LR
    subgraph EX["Express — middleware chain"]
        E1[req] --> E2[mw1] --> E3[mw2] --> E4[handler] --> E5[res]
    end
    subgraph FS["Fastify — schema + hooks"]
        F1[req] --> F2[schema validation] --> F3[handler] --> F4[serialization] --> F5[res]
    end
    subgraph NS["NestJS — lifecycle hooks"]
        N1[req] --> N2[Guard] --> N3[Pipe] --> N4[handler] --> N5[res]
    end
    subgraph HO["Hono — Fetch API"]
        H1[Request] --> H2[middleware onion] --> H3[handler] --> H4[Response]
    end

    style E2 fill:#4A90D9,color:#fff
    style E3 fill:#4A90D9,color:#fff
    style F2 fill:#F5A623,color:#fff
    style F4 fill:#F5A623,color:#fff
    style N2 fill:#D0021B,color:#fff
    style N3 fill:#F5A623,color:#fff
    style H2 fill:#4A90D9,color:#fff
// Express 5
import express from "express";
 
const app = express();
app.get("/hello", (_req, res) => res.json({ greeting: "hello" }));
app.listen(3000);
// NestJS
@Controller()
export class AppController {
  @Get("/hello")
  hello() {
    return { greeting: "hello" };
  }
}
// Fastify
import Fastify from "fastify";
 
const app = Fastify();
app.get("/hello", async () => ({ greeting: "hello" }));
await app.listen({ port: 3000 });
// Hono
import { Hono } from "hono";
 
const app = new Hono();
app.get("/hello", (c) => c.json({ greeting: "hello" }));
export default app;

Casos práticos

  • Microsserviço I/O-bound simples, time pequeno: Express ou Fastify.
  • App enterprise, time grande, DI complexa: NestJS.
  • API com schema bem definido e throughput alto: Fastify.
  • Edge worker, serverless ou multi-runtime: Hono.
  • Comparação detalhada: 12 - Decision tree + cheatsheet.

Cenário 1 — Webhook receiver

Imagine uma API que recebe webhooks de Stripe/GitHub, valida assinatura, grava evento bruto e responde rápido. O domínio é pequeno, o throughput é moderado e o risco principal é latência/timeout do provedor. Express resolve bem se o time já conhece o ecossistema; Fastify ganha se schema e serialização forem parte central do contrato.

// Express: simples, explícito, bom para glue code.
app.post("/webhooks/github", verifyGithubSignature, async (req, res) => {
  await inbox.save({ source: "github", payload: req.body });
  res.status(202).json({ accepted: true });
});
// Fastify: contrato explícito na rota — schema valida e serializa.
app.post("/webhooks/github", {
  schema: {
    body: GithubWebhookSchema,
    response: { 202: AcceptedSchema },
  },
}, async (req, reply) => {
  await inbox.save({ source: "github", payload: req.body });
  return reply.code(202).send({ accepted: true });
});

Cenário 2 — Produto enterprise com módulos

Imagine um backend com billing, usuários, permissões, auditoria, integrações e jobs internos. O problema já não é só “servir HTTP”; é manter boundaries por feature, lifecycle, DI, testes e composição de concerns. NestJS fica mais atraente porque força uma gramática comum.

@Module({
  imports: [BillingModule, IdentityModule, AuditModule],
  controllers: [InvoicesController],
  providers: [CreateInvoiceUseCase, InvoicePolicy],
})
export class InvoicesModule {}

O custo é real: decorators, módulos, providers e scopes precisam ser aprendidos. Mas, em time maior, convenção compartilhada frequentemente vale mais do que liberdade local.

Cenário 3 — Edge API com KV store

Se o requisito é responder perto do usuário em Cloudflare Workers, Deno Deploy ou runtime similar, a pergunta muda. Express e NestJS assumem Node HTTP; Hono assume Web Standards.

const app = new Hono<{ Bindings: { KV: KVNamespace } }>();
 
app.get("/flags/:userId", async (c) => {
  // c.env.KV é binding do runtime — não existe em Node tradicional.
  const flags = await c.env.KV.get(`flags:${c.req.param("userId")}`, "json");
  return c.json(flags ?? {});
});

Essa decisão é menos sobre sintaxe e mais sobre deploy target. Edge runtime costuma limitar filesystem, sockets e tempo de CPU; escolher Hono evita carregar abstrações que não foram desenhadas para esse ambiente.

Heurística de decisão rápida

Faça quatro perguntas antes de escolher:

  1. Qual é o deploy target? Node tradicional, container, serverless, edge?
  2. O contrato HTTP é central? Se sim, schema-first pesa a favor de Fastify.
  3. O domínio é grande? Se sim, DI e módulos pesam a favor de NestJS ou Clean Architecture manual.
  4. O time já domina qual modelo? Familiaridade não decide sozinha, mas reduz risco.

Como revisar essa escolha em arquitetura

Procure sinais concretos, não preferências:

  • Se o projeto é Express e já tem 40 services com wiring espalhado, pergunte por composition root ou container.
  • Se o projeto é NestJS e só tem 4 endpoints CRUD, questione o overhead.
  • Se o projeto é Fastify sem schemas, o principal diferencial está subutilizado.
  • Se o projeto é Hono mas depende de libs Node-only, a portabilidade é ilusória.
  • Se a justificativa é “performance”, peça benchmark do caso real: payload, DB, rede, CPU, warm/cold start.

Benchmark não é arquitetura

Framework overhead raramente é o gargalo principal de um backend com banco, fila, rede externa e autenticação. Use benchmark para eliminar opções inviáveis, não para transformar escolha de framework em ranking universal.

Anti-decision tree

Alguns sinais indicam que a decisão está sendo tomada pelo critério errado:

"Vamos de NestJS porque é enterprise"
  -> Qual complexidade enterprise existe agora?
 
"Vamos de Fastify porque é mais rápido"
  -> O gargalo medido é framework overhead?
 
"Vamos de Express porque todo mundo conhece"
  -> Quem vai impor estrutura, validation e error handling?
 
"Vamos de Hono porque é moderno"
  -> O deploy target é edge ou multi-runtime de verdade?

O papel de senior é transformar preferência em hipótese verificável. Se a hipótese não menciona deploy, contrato, domínio, time e operação, ela ainda está incompleta.

Compatibilidade com os galhos anteriores

Framework não substitui fundamentos:

  • index continua decidindo impacto de CPU-heavy work, timers, microtasks e bloqueio.
  • index continua necessário quando o problema é CPU-bound ou isolamento de processo.
  • index continua aparecendo em upload, download, proxy, CSV, multipart e respostas longas.
// Framework nenhum torna isso barato:
app.get("/report", (_req, res) => {
  const result = generateHugeCpuBoundReport(); // bloqueia event loop
  res.json(result);
});

Se a API sofre por CPU, escolher Fastify não resolve. Se sofre por upload gigante sem backpressure, escolher NestJS não resolve. Framework é camada HTTP; fundamentos ainda mandam.

Critérios de maturidade de uma escolha

Uma escolha de framework está madura quando o time consegue responder:

  1. Como validamos input?
  2. Como formatamos erro?
  3. Como observamos latência e falhas?
  4. Como desligamos o app com graceful shutdown?
  5. Como testamos handlers sem subir infraestrutura real?
  6. Como isolamos regra de negócio da camada HTTP?
  7. Como versionamos contrato?
  8. Como lidamos com deploy target e limites operacionais?

Sem essas respostas, a escolha ainda é só scaffold.

Regra prática final

Se duas opções parecem equivalentes, escolha a que reduz o risco dominante:

  • risco de desorganização NestJS ou Clean Architecture explícita;
  • risco de contrato fraco Fastify ou schema-first disciplinado;
  • risco de runtime incompatível Hono/Web Standards;
  • risco de complexidade acidental Express com poucas abstrações;
  • risco de time travar na curva de aprendizado ferramenta que o time opera bem.

Essa regra evita discutir framework como identidade. Framework é mitigação de risco.

Sinal de resposta madura

Uma resposta madura não termina em “eu escolheria X”. Ela termina em uma consequência operacional:

Escolheria Fastify porque o contrato é schema-first,
então eu espero ver schemas em todas as rotas críticas,
OpenAPI derivado deles e testes de payload inválido.

Se não há consequência verificável no repositório, a decisão ainda é retórica.

O que vem a seguir

Com o panorama dos quatro modelos mapeado, o próximo passo é mergulhar em cada framework individualmente. As notas seguintes detalham padrões idiomáticos, armadilhas específicas e code review checklists para cada escolha:

Armadilhas comuns

Escolher por hype, não por fit

O que acontece: Time adota NestJS em projeto pequeno porque “todo mundo usa”. Por quê: Sem domínio complexo, DI e módulos viram cerimônia sem retorno. Como evitar: Pergunte qual complexidade enterprise existe agora, não no futuro hipotético.

Migrar framework no meio do projeto

O que acontece: Reescrita de adapter HTTP durante desenvolvimento ativo gera regressões. Por quê: Mudança de framework exige adaptar testes, middleware, error handling e estrutura de pastas simultaneamente. Como evitar: Decida antes de escrever a primeira rota. Se precisar migrar, faça por feature e com strangler fig pattern.

Comparar performance por benchmark sintético

O que acontece: Decision é tomada por “Fastify é X% mais rápido que Express em hello-world”. Por quê: Benchmark sintético não inclui DB, rede, payload real, auth, cache e observability. Como evitar: Peça benchmark do caso real antes de usar performance como argumento principal.

Achar que NestJS é só "Express com decorators"

O que acontece: Dev usa NestJS mas contorna módulos e DI, criando acoplamento pior que Express puro. Por quê: O modelo de módulos e lifecycle é diferente de Express; ignorar isso cria dois frameworks em um. Como evitar: Ou use NestJS pelo modelo completo, ou use Express/Fastify sem DI container.

Confundir framework com arquitetura

O que acontece: Express vira massa acoplada; NestJS não garante Clean Architecture. Por quê: Framework entrega estrutura HTTP, não fronteiras de domínio. Como evitar: Defina explicitamente onde fica regra de negócio, independente do framework escolhido.

Ignorar deploy target

O que acontece: Código Express/NestJS é implantado em Cloudflare Workers e falha por falta de APIs Node. Por quê: Edge, container e Lambda têm constraints diferentes de filesystem, memória e CPU. Como evitar: Defina o runtime antes do framework. Hono e Web Standards para edge; Express/NestJS/Fastify para Node container.

Escolher Fastify por performance e validar manualmente no controller

O que acontece: Rota Fastify sem schema — o principal diferencial do framework fica inutilizado. Por quê: Fastify só otimiza serialização quando há response schema declarado; sem ele vira Express com API diferente. Como evitar: Schema obrigatório em todas as rotas que recebem ou retornam dados estruturados.

Escolher Hono por hype sem verificar bibliotecas do runtime alvo

O que acontece: App usa Hono mas depende de libs de auth, storage ou crypto que não existem no edge target. Por quê: Multi-runtime não é automático — cada biblioteca precisa ser auditada por compatibilidade. Como evitar: Antes de adotar Hono, liste as dependências críticas e verifique se rodam no runtime alvo.

Perguntas de entrevista

Como você escolheria entre Express e Fastify? Se o time precisa de simplicidade e ecossistema máximo, Express é baseline. Se contrato, validation e serialization são centrais, Fastify entrega mais estrutura sem virar framework enterprise.

Quando NestJS é overkill? Quando o app é pequeno, tem poucas dependências, domínio raso e time pequeno. Nessa situação, DI manual e Express/Fastify podem ser mais claros.

Quando Hono entra na conversa? Quando o deploy é edge ou multi-runtime. Hono não é “Express menor”; é um modelo baseado em Web Standards.

Qual erro você espera de um candidato junior? Responder “NestJS é melhor” ou “Fastify é mais rápido” sem falar de problema, time, domínio e deploy target.

Em entrevista

“Node has four main framework models in 2026. Express is middleware-based and ubiquitous; NestJS is opinionated, decorator-based, and built around dependency injection; Fastify is schema-first and performance-focused; Hono is ultralight, multi-runtime, and edge-first. The decision is matching, not ranking: pick based on deploy target, domain complexity, team size, and API contract needs.”

Vocabulário-chave:

  • middleware-based baseado em middleware
  • opinionated opinativo
  • schema-first orientado por schema
  • edge-first pensado para edge
  • decision matching matching entre problema e ferramenta

Fontes

Veja também