Contexto
Fastify e Express são frameworks web para Node, mas partem de prioridades diferentes. Express é o incumbente: um core minúsculo construído em torno de middleware, onde praticamente tudo (parsing de corpo, autenticação, CORS, validação) é uma função que você encaixa na cadeia (req, res, next). Essa simplicidade radical e mais de uma década de estrada fizeram do Express o padrão de fato do Node, com um ecossistema de middleware que provavelmente já tem uma resposta pronta para qualquer necessidade. O trade-off é que o próprio Express não valida nada, não serializa nada de forma otimizada e, até a v5, não capturava erros de handlers async por você.
Fastify parte de outra tese: performance e um contrato de dados explícito como parte do framework, não como algo colado por cima. Ele foi desenhado para throughput alto e baixo overhead por requisição, traz validação por JSON Schema embutida e usa esse mesmo schema para serializar a resposta de forma muito mais rápida que o JSON.stringify padrão. É async-first desde o início e tem tipagem TypeScript de primeira classe. A extensibilidade vem de um sistema de plugins com encapsulamento (cada plugin tem seu próprio escopo de decorators, hooks e rotas), em vez da cadeia linear de middleware do Express. Vale notar que os dois estão hoje no v5: o Express 5 saiu depois de anos parado no 4.x e trouxe, entre outras coisas, o encaminhamento automático de rejeições de promises em handlers async para o error handler.
A variável decisiva é o que você valoriza: ubiquidade e um ecossistema imenso, ou performance e um contrato tipado embutido.
Quando escolher Fastify
Fastify faz mais sentido quando performance e um contrato de dados explícito importam desde o começo. O schema JSON não é decoração: ele valida o corpo, a query e os params da requisição antes de o handler rodar e ainda é reaproveitado para serializar a resposta, um caminho que na prática supera o JSON.stringify genérico em rotas de alto volume. Some a isso o modelo async-first e o suporte TypeScript de primeira classe (com inferência de schema para tipo via um type provider como typebox ou json-schema-to-ts), e você tem um framework que trata validação, serialização e tipos como parte do núcleo.
import Fastify from "fastify";
const app = Fastify();
app.post("/items", {
schema: {
body: {
type: "object",
required: ["name", "price"],
properties: {
name: { type: "string" },
price: { type: "number" },
},
},
},
}, async (request) => {
const { name, price } = request.body;
return { name, total: Math.round(price * 1.1 * 100) / 100 };
});
await app.listen({ port: 3000 });
No exemplo, o schema declara que name e price são obrigatórios e tipados: uma requisição sem name ou com price não numérico recebe um 400 estruturado antes de o handler ser chamado, sem uma linha de validação manual. O handler é async e o Fastify cuida do ciclo de vida da resposta e da captura de erros por você. O sistema de plugins mantém isso organizado à medida que a aplicação cresce: cada plugin encapsula suas rotas, hooks e decorators num escopo próprio, o que evita o acoplamento global típico de uma cadeia longa de middleware. O custo de entrada é aprender o modelo de schemas, hooks e plugins, mas em serviços onde vazão e um contrato de API tipado são requisitos, esse investimento se paga. Com cerca de 9,5 milhões de downloads por semana, o Fastify é bem menor que o Express em adoção, mas consolidado como a alternativa de performance.
Quando escolher Express
Express continua sendo a escolha certa quando ubiquidade e ecossistema pesam mais que throughput bruto. O core é mínimo e o modelo mental é dos mais simples do Node: uma requisição entra, passa por uma fila de middleware e sai uma resposta. Isso, somado a mais de dez anos como padrão de fato, significa que praticamente todo problema (sessão, upload, rate limit, autenticação com qualquer provedor) já tem um middleware maduro, um tutorial e uma resposta no Stack Overflow. Com cerca de 114 milhões de downloads por semana, é a base que mais gente conhece e a mais fácil de contratar.
import express from "express";
const app = express();
app.use(express.json());
app.post("/items", (req, res) => {
const { name, price } = req.body;
if (!name || typeof price !== "number") {
return res.status(400).json({ error: "name and price are required" });
}
res.json({ name, total: Math.round(price * 1.1 * 100) / 100 });
});
app.listen(3000);
O mesmo endpoint deixa a diferença clara: em Express a validação é responsabilidade sua (aqui feita à mão, na prática via uma biblioteca como zod ou express-validator), e não há serialização otimizada nem schema embutido. Em troca, você tem transparência total sobre a cadeia da requisição e acesso ao maior catálogo de middleware do ecossistema. A v5, lançada recentemente após um longo período no 4.x, moderniza pontos importantes: agora rejeições de promises em handlers async são encaminhadas automaticamente ao error handler (no 4.x era preciso um wrapper ou try/catch em cada rota), além de ajustes em roteamento e na sintaxe de rotas. Para muitos serviços, APIs de tráfego moderado e times que já dominam o modelo, Express continua sendo a base mais previsível e bem documentada.
Veredito
Reduzida ao essencial, a escolha gira em torno de uma pergunta: você precisa de performance e de um contrato de dados tipado embutido, ou de ubiquidade e do maior ecossistema do Node? Se vazão sob carga, validação por schema e serialização rápida são requisitos, e você quer isso no núcleo do framework em vez de montado com middleware, Fastify foi desenhado exatamente para esse caso e entrega tipos, validação e docs de schema como parte do pacote. É a aposta natural para APIs novas onde performance e contrato importam desde o primeiro endpoint.
Se o que pesa é encontrar middleware pronto para tudo, contratar gente que já conhece o modelo e ter a documentação mais farta do ecossistema, Express raramente decepciona, e a v5 fechou a lacuna mais irritante ao tratar erros async por padrão. Não reescreva um Express saudável para Fastify só pela promessa de benchmark: o ganho de throughput só se paga quando a vazão é de fato o gargalo. Escolha Fastify pela performance e pelo schema embutido, Express pela ubiquidade e pelo ecossistema, e deixe o perfil do serviço decidir.