Express e Fastify são os dois frameworks Node.js mais discutidos quando o assunto é construção de APIs. Express tem mais de uma década de história, um ecossistema imenso e está instalado em mais projetos do que qualquer outro framework da plataforma. Fastify é mais recente, mais opinionado e, em praticamente todo benchmark público disponível, significativamente mais rápido.
A Grokseat usa Fastify como framework padrão para backends Node.js. Este artigo explica por quê, com dados reais, exemplos de código e uma análise honesta de quando Express ainda faz sentido.
Uma breve história dos dois frameworks
Express foi lançado em 2010 por TJ Holowaychuk e se tornou rapidamente o framework dominante do ecossistema Node.js. Sua filosofia minimalista e não opinada atraiu desenvolvedores que queriam liberdade para estruturar as aplicações do jeito que quisessem. Em 2020, porém, o projeto entrou em modo de manutenção. Wesley Todd, membro do comitê técnico, foi direto: "o projeto ficou em modo de manutenção por muito tempo. Ninguém é pago para trabalhar nisso e todos estamos muito ocupados."
O Express 5.0 foi lançado apenas em 2024, dez anos depois da primeira pull request para essa versão. O próprio time descreveu o lançamento como algo "projetado para ser entediante", com objetivo de "desbloqueio do ecossistema" mais do que introdução de novidades. O Express ainda tem 76 milhões de downloads semanais no npm, mas o desenvolvimento ativo está estagnado há anos.
Fastify foi lançado em 2017 por Matteo Collina e Tomas Della Vedova, dois dos maiores contribuidores do núcleo do Node.js, com um objetivo claro: construir o framework mais rápido possível sem abrir mão de uma boa experiência de desenvolvimento. A versão 4 foi lançada em 2022, a versão 5 em 2024. O projeto é mantido ativamente sob a OpenJS Foundation, com uma equipe de mais de 10 mantenedores e patrocínio corporativo de empresas como NearForm. Tem hoje 5,4 milhões de downloads semanais no npm, número que cresce 15% por trimestre segundo dados da comunidade.
Os números de performance
A diferença de performance entre Fastify e Express é documentada, consistente e arquitetural, não o resultado de uma otimização pontual.
Em benchmarks sintéticos de "Hello World", Fastify processa cerca de 80.000 requisições por segundo contra 25.000 do Express, uma diferença de 3 vezes que se mantém consistente desde o lançamento do Fastify.
Em cenários mais próximos de produção, com payloads JSON reais e múltiplos middlewares, o Fastify entrega consistentemente entre 45.000 e 50.000 requisições por segundo, enquanto o Express fica entre 10.000 e 20.000 RPS no mesmo hardware. A latência média cai de 15,84 ms no Express para 6,48 ms no Fastify, e o consumo de memória para 10.000 conexões simultâneas é de aproximadamente 100 MB no Fastify contra 150 MB no Express.
Em benchmarks independentes com middlewares de produção como CORS, compressão, helmet e cookies habilitados, o Fastify processou 45.140 requisições por segundo contra 10.702 do Express, uma diferença de 4,5 vezes no mesmo ambiente.
Para a maioria das aplicações que recebem centenas de requisições por segundo, essa diferença é irrelevante na prática. Mas para APIs que precisam lidar com picos de tráfego, microserviços com latência sensível ou qualquer sistema onde custo de infraestrutura importa, a diferença de throughput se traduz diretamente em menos instâncias necessárias para suportar a mesma carga, o que representa economia real em escala.
Por que Fastify é mais rápido: a arquitetura por baixo
A diferença de performance não vem de mágica. Vem de decisões arquiteturais específicas que o Express não tomou.
Roteamento com Radix Tree
No Express, quando uma requisição chega, o framework itera por uma lista de rotas até encontrar a correspondência correta. Para poucas dezenas de rotas, isso funciona bem. Para centenas, o custo se acumula.
O Fastify usa uma estrutura de dados chamada Radix Tree para roteamento, que transforma a correspondência de rotas em uma busca hierárquica altamente eficiente. Isso reduz significativamente o tempo de busca à medida que o número de rotas cresce, tornando o roteamento do Fastify mais eficiente tanto em tempo quanto em memória.
O router utilizado internamente é o find-my-way, que a própria Fastify mantém e que supera o roteamento do Express em 3 vezes isoladamente nos benchmarks do projeto.
Validação e serialização com JSON Schema
Essa é a diferença mais significativa na prática do dia a dia.
No Express, a validação é normalmente um afterthought, uma peça de middleware como express-validator que roda de forma imperativa. No Fastify, a validação é declarativa e acontece antes mesmo de o handler ser tocado.
O Fastify usa o AJV (Ajv v8), o validador de JSON Schema mais rápido disponível para Node.js, integrado nativamente ao framework. Os schemas são compilados uma vez durante o startup da aplicação e transformados em funções de validação otimizadas que executam muito mais rápido do que qualquer validação imperativa escrita manualmente.
Para a serialização das respostas, o Fastify usa o fast-json-stringify em vez do JSON.stringify nativo. A diferença é fundamental: enquanto JSON.stringify inspeciona cada propriedade do objeto em tempo de execução sem saber nada sobre sua estrutura, o fast-json-stringify usa o schema da resposta para pré-compilar uma função de serialização especializada. O resultado é serialização JSON até 2 vezes mais rápida.
Na prática, isso significa que uma rota Fastify com schema definido tem validação automática de entrada, serialização otimizada de saída e documentação OpenAPI gerada automaticamente, tudo a partir de uma única definição. Veja a diferença:
// Express: validação manual, serialização genérica
app.post('/users', async (req, res) => {
if (!req.body.email || typeof req.body.email !== 'string') {
return res.status(400).json({ error: 'Email inválido' })
}
if (!req.body.name || req.body.name.length < 2) {
return res.status(400).json({ error: 'Nome inválido' })
}
const user = await createUser(req.body)
res.json(user) // JSON.stringify genérico
})
// Fastify: validação declarativa, serialização otimizada
fastify.post('/users', {
schema: {
body: {
type: 'object',
required: ['email', 'name'],
properties: {
email: { type: 'string', format: 'email' },
name: { type: 'string', minLength: 2 }
}
},
response: {
201: {
type: 'object',
properties: {
id: { type: 'string' },
email: { type: 'string' },
name: { type: 'string' }
}
}
}
}
}, async (request, reply) => {
const user = await createUser(request.body)
return reply.status(201).send(user) // fast-json-stringify otimizado
})No exemplo Fastify, se o email ou o name estiverem ausentes ou no formato errado, o Fastify rejeita a requisição automaticamente com um erro 400 estruturado antes mesmo de chamar o handler. Nenhuma linha de validação imperativa necessária.
Sistema de plugins com encapsulamento
Uma das maiores críticas ao Express em escala é a natureza global do middleware. É fácil demais aplicar acidentalmente um middleware pesado de logging a um endpoint de health-check com alto tráfego. O Fastify usa um sistema de plugins encapsulado. Cada plugin pode ter seu próprio escopo, o que significa que você pode decorar a instância do Fastify ou adicionar hooks a um conjunto específico de rotas sem vazar essa lógica para o resto da aplicação.
Isso tem implicações profundas na organização de projetos maiores. Em vez de uma cadeia linear de middlewares globais que executam para toda requisição, o Fastify constrói um grafo acíclico direcionado (DAG) de plugins com escopos bem definidos. Autenticação, rate limiting e logging de auditoria podem ser aplicados apenas às rotas que realmente precisam deles, sem overhead desnecessário para as outras.
// Fastify: plugins com escopo encapsulado
fastify.register(async (publicRoutes) => {
// Rotas públicas: sem autenticação
publicRoutes.get('/health', async () => ({ status: 'ok' }))
publicRoutes.post('/auth/login', loginHandler)
})
fastify.register(async (privateRoutes) => {
// Apenas as rotas privadas têm o plugin de autenticação
privateRoutes.addHook('onRequest', verifyJWT)
privateRoutes.get('/users/me', getMeHandler)
privateRoutes.put('/users/me', updateMeHandler)
})No Express, alcançar o mesmo efeito exigiria aplicar o middleware manualmente em cada rota privada ou usar prefixos de rota com express.Router(), o que não oferece o mesmo nível de isolamento.
TypeScript de primeira classe
O Express foi criado antes do TypeScript existir e, embora tipos tenham sido adicionados via @types/express, o suporte não é nativo. O Fastify foi escrito com suporte de primeira classe a TypeScript, com tipos genéricos para requisições, respostas e schemas.
Na prática, isso significa que as propriedades de request.body, request.params e request.query são conhecidas pelo compilador quando um schema é definido. Não é necessário fazer cast manual de tipos nem confiar em any para acessar os dados da requisição.
// Fastify com TypeScript: tipos inferidos automaticamente
interface CreateUserBody {
email: string
name: string
}
interface CreateUserReply {
id: string
email: string
name: string
}
fastify.post<{
Body: CreateUserBody
Reply: CreateUserReply
}>('/users', {
schema: { /* ... */ }
}, async (request, reply) => {
// request.body.email e request.body.name são tipados corretamente
const user = await createUser(request.body)
return reply.status(201).send(user)
})O que o Express ainda faz melhor
Seria desonesto não reconhecer os casos em que Express ainda é a escolha mais sensata.
Projetos legados e equipes já familiarizadas. Se um projeto já existe em Express, com uma base de middleware bem estabelecida e uma equipe que conhece o framework por dentro, migrar para Fastify tem um custo real que raramente se justifica sem um gargalo de performance concreto. O Express funciona, e sistemas que funcionam raramente precisam ser reescritos.
Ecossistema de middleware. Express tem 15 anos de histórico e um ecossistema de middleware incomparavelmente maior. Para protótipos ou projetos que dependem de middleware específico que ainda não foi portado para Fastify, Express ainda é a escolha mais prática. O próprio Fastify oferece um plugin de compatibilidade @fastify/express que permite usar middleware Express dentro de rotas Fastify, o que facilita migrações incrementais.
Simplicidade para projetos pequenos. Para uma API com 5 rotas, um CRUD simples ou um servidor interno de uso limitado, a diferença de performance é irrelevante e a familiaridade do Express reduz o tempo de desenvolvimento.
NestJS. Se o projeto usa NestJS, o adapter padrão é Express. Embora o NestJS suporte Fastify como adapter alternativo, a documentação, os exemplos e o ecossistema de plugins do NestJS são mais maduros com Express.
Quando Fastify claramente vence
A diferença de performance se torna significativa em APIs com alto número de conexões simultâneas, como aplicações em tempo real e backends de IoT; em microserviços onde cada serviço precisa ser enxuto e rápido; em APIs com sensibilidade a latência, como serviços financeiros e backends de jogos; e em otimização de custos de nuvem, onde tempos de resposta mais rápidos significam menos instâncias necessárias.
A Grokseat desenvolve APIs que precisam escalar de forma previsível e que precisam ser mantidas por equipes técnicas que valorizam tipagem forte e validação declarativa. Para esse perfil, Fastify entrega vantagens reais que justificam a curva de aprendizado inicial.
Como estruturamos projetos Fastify na Grokseat
Na prática, a estrutura de um projeto Fastify na Grokseat segue um padrão consistente que aproveita o sistema de plugins para organizar o código em módulos com responsabilidades bem definidas.
src/
app.ts # instância Fastify e registro de plugins globais
plugins/
database.ts # conexão com PostgreSQL via plugin encapsulado
auth.ts # verificação JWT como hook de ciclo de vida
swagger.ts # documentação OpenAPI automática
routes/
users/
index.ts # registro das rotas do domínio users
schema.ts # JSON Schemas de entrada e saída
handler.ts # lógica do handler
products/
...
services/ # regras de negócio desacopladas dos handlers
repositories/ # acesso ao banco de dados
Cada domínio de negócio é registrado como um plugin separado com seu próprio prefixo de rota. Os schemas ficam em arquivos dedicados e são importados tanto pelo handler do Fastify quanto pelos tipos TypeScript, garantindo que a fonte de verdade seja única para validação, serialização e tipagem.
Migrar de Express para Fastify
Para projetos que precisam migrar de Express para Fastify, a abordagem pragmática é começar novos serviços em Fastify sem reescrever código Express que já funciona, e migrar rotas de alto tráfego primeiro para maximizar o impacto.
O plugin @fastify/express permite montar middleware Express diretamente em uma instância Fastify, o que significa que a migração pode ser incremental: as novas rotas são escritas em Fastify nativo, as antigas continuam funcionando via compatibilidade, e a migração acontece gradualmente ao longo do tempo sem uma grande reescrita de uma vez só.
Conclusão
A escolha entre Fastify e Express raramente é sobre performance isolada. É sobre qual conjunto de trade-offs faz mais sentido para o projeto, a equipe e os requisitos de longo prazo.
Para novos projetos backend Node.js na Grokseat, Fastify é o padrão porque entrega performance real, validação declarativa que reduz código repetitivo, suporte nativo a TypeScript que nos importa muito, e um sistema de plugins que favorece a organização de bases de código que precisam crescer. Para projetos legados em Express que funcionam bem, o Express continua funcionando bem.
A regra prática é simples: se você está começando um novo serviço em 2025 ou 2026 e não tem razão específica para usar Express, use Fastify. A diferença de curva de aprendizado é pequena e os benefícios se acumulam com o tempo.
Referências:
- Fastify - Documentação oficial: fastify.dev
- PkgPulse - Express vs Fastify: dados de npm e benchmarks (2026)
- Strapi Blog - Build Production-Ready APIs with Fastify (2025)
- Medium / Chetan Jain - Express vs Fastify: A Performance Comparison (2024)
- Medium / Lucas Wade - Express or Fastify in 2025: What's the Right Framework for You?
- DevClass - Express.js team explain purpose of version 5.0 (outubro de 2024)
- Nearform - Upgrading Fastify's input validation to Ajv version 8
- Medium / Webstack - Why Fastify consistently outperforms Express.js (janeiro de 2026)