Express vs Fastify: Which One Should You Use in 2026?
Fastify is 3–5x faster. Express has 16x more downloads. Performance and adoption are telling very different stories — and you need to understand both before picking a side.
When Node.js emerged as a serious backend runtime in the early 2010s, Express became its de facto framework almost by accident. Released in 2010, it was minimal, unopinionated, and easy enough to learn in an afternoon. A decade later, it powers a substantial portion of the Node.js applications running in production worldwide.
Then came Fastify.
Born in 2017 from the minds of Matteo Collina and Tomas Della Vedova — both contributors to Node.js core — Fastify was designed with one explicit goal: go faster, without sacrificing developer experience. It borrowed Express's familiar routing API but rebuilt everything underneath: the router, the serializer, the validation layer, and the plugin system.
In 2026, the question isn't really "which one is better?" — it's "which one is better for you, right now, for this project?" Let's break it down with real numbers and real trade-offs.
The Performance Gap Is Real — And Architectural
Let's get the headline out of the way.
Fastify handles around 80,000 requests per second. Express handles around 25,000. That's a consistent 3x performance gap across every major benchmark — and it's architectural, not the result of a single clever optimization.
Here's a representative benchmark comparison under controlled conditions:
Framework
Req/sec
Latency (p99)
Memory (MB)
CPU Usage
Fastify
~76,835
18ms
45 MB
68%
Express
~38,510
42ms
62 MB
84%
Benchmarked on Node.js 20 LTS with hello-world endpoints on Ubuntu 22.04.
In practice, most applications never approach these limits — database calls, external API requests, and business logic dominate latency, not the framework. The performance gap matters for highly concurrent APIs, real-time services, or cases where you're running on low-memory infrastructure.
Where the Speed Comes From
Fastify's lead isn't magic — it's engineering. Three specific decisions account for most of the gap:
1. Routing via find-my-way
Express uses a linear middleware chain for routing. Fastify uses a radix-tree router (find-my-way) that resolves routes in O(log n) rather than O(n). At scale, the difference compounds significantly.
Share this article:
2. fast-json-stringify for serialization
Standard JSON.stringify() has no schema awareness — it inspects every value at runtime. Fastify's serializer compiles JSON schemas ahead of time into optimized serialization functions. This provides nearly twice the speed by optimizing JSON serialization, reducing CPU load and enhancing overall performance.
3. Encapsulated plugin system
Express middleware runs in a linear chain for every request; Fastify's encapsulated plugins reduce the overhead per request for plugins not registered globally. If a plugin is scoped to /api/v2, it simply doesn't run for requests to /health.
Code Comparison: The Basics
Both frameworks share a familiar API. Here's how a basic route looks in each:
Express
import express from 'express'
const app = express()
app.use(express.json())
app.get('/users/:id', async (req, res) => {
const user = await getUserById(req.params.id)
if (!user) return res.status(404).json({ error: 'Not found' })
res.json(user)
})
app.listen(3000, () => console.log('Listening on port 3000'))
The Fastify version is slightly more verbose upfront — but that verbosity pays dividends: the schema drives validation, serialization, and can auto-generate OpenAPI documentation.
Feature-by-Feature Breakdown
Validation
This is one of the most consequential differences between the two frameworks.
Express ships with no built-in validation. You add express-validator, joi, zod, or whatever library your team prefers. This is flexible, but it means validation is an afterthought bolted onto the request lifecycle.
Fastify's schema-based validation is built-in, reducing boilerplate and improving performance by leveraging compiled schemas for faster execution. Fastify's tight integration with JSON Schema and built-in validation engine makes it the better choice for applications that require structured, high-performance validation.
In practice: define your schema once in Fastify, get validation, serialization, and documentation for free. In Express, you wire these up separately, which works — but it's more surface area for inconsistency.
TypeScript Support
Fastify provides first-class TypeScript support, generics-based request validation, and built-in schema integrations, making it the better choice for type safety and maintainability.
Express has historically shipped types as a separate @types/express package. Express 5, released in 2024, introduced officially generated and tested types — narrowing this gap considerably. But Fastify's generics-based approach, where route-level schemas flow through to request and reply types automatically, remains more ergonomic for TypeScript-first teams.
Logging
Express ships with no built-in logger. You choose and configure Morgan, Winston, Pino, or another library yourself.
Fastify ships with Pino integrated by default — one of the fastest JSON loggers available for Node.js. Pass { logger: true } to the constructor and you have structured, performant logging out of the box, including automatic request/response logging.
HTTP/2 and Modern Protocols
Express does not natively support HTTP/2, so external libraries like spdy are required to enable it. Fastify supports HTTP/2 natively with a single configuration option.
For teams building APIs that will be consumed by modern clients — or running behind load balancers that leverage HTTP/2 multiplexing — this is a meaningful difference.
Plugin System vs Middleware
Express's middleware system is simple and familiar: functions that take (req, res, next) and run sequentially. It's easy to understand but runs every registered middleware globally unless you manually scope it.
Fastify's plugin system is built around encapsulation — plugins registered inside a scope don't leak outside it. This makes it easier to build large applications with isolated concerns without accidentally exposing internal plugins to the entire application.
// Fastify: auth plugin only applies to /api routes
fastify.register(async function apiRoutes(api) {
api.addHook('preHandler', authMiddleware)
api.get('/profile', profileHandler)
api.get('/settings', settingsHandler)
})
// This route has NO auth
fastify.get('/public', publicHandler)
Replicating this pattern cleanly in Express requires careful middleware ordering and explicit router.use() scoping.
The Ecosystem Gap: Still Large, Slowly Closing
Here's where Express maintains a commanding lead.
Express dominates in raw adoption with over 92 million weekly downloads — that's 16x more than Fastify's 5.8 million. This gap reflects years of ecosystem maturity and widespread production use.
What this means in practice:
More third-party middleware packages with Express adapters
More tutorials, Stack Overflow answers, and community resources
More junior developers who already know it
Better documentation for NestJS, which uses Express as its default adapter
More examples in official SDKs (AWS, Stripe, Twilio, etc.)
Fastify's ecosystem has grown substantially since 2020, with an official @fastify organization maintaining plugins for everything from CORS to JWT to WebSockets. But if you need a very specific, niche middleware package, there's a real chance it exists for Express and not for Fastify.
The @fastify/express compatibility layer helps here — it allows you to mount Express middleware in Fastify during migration. It adds some overhead, but it means you're not blocked from day one.
Express 5: The Sleeping Giant Wakes
Express 5 was a long time coming. After years of stagnation, the framework received a major update that addressed several longstanding criticisms:
Async error handling: Route handlers can now throw errors and they'll be caught automatically — no more forgotten next(err) calls
Official TypeScript types: Generated and tested alongside the source
Improved routing: Better handling of regex routes and path parameters
A clearer roadmap: For the first time in years, Express has maintainers with an explicit plan
Express 5 is here, and the framework now has a clear roadmap for the future, including official TypeScript support and a more modular, API-first design.
Express 5 doesn't close the performance gap — that's structural and won't change without a complete rewrite. But it does close the ergonomics gap meaningfully. If your objection to Express was "it feels dated," Express 5 is worth a second look.
Decision Framework: Which One Should You Choose?
Choose Express if:
Your team already knows it — familiarity eliminates an entire class of bugs
You're building a prototype or MVP — get to production faster without schema overhead
You need a specific middleware that only exists for Express — ecosystem breadth still matters
You're using NestJS — Express remains the default adapter with the best documentation
Your app isn't performance-constrained — most applications don't need 80K req/sec
Choose Fastify if:
Performance matters — high-throughput APIs, real-time services, microservices under load
You're building a TypeScript-first project — the DX advantage is real
You want built-in validation — JSON Schema validation reduces boilerplate and bugs
You're building a greenfield API in 2026 — Fastify is increasingly the default for new projects
Memory footprint matters — relevant for serverless environments with cold-start costs
The Honest Answer
The pragmatic approach: start new services in Fastify and migrate high-traffic existing routes gradually using the @fastify/express compatibility layer.
For the vast majority of applications — internal tools, small APIs, prototypes — the performance difference will never be the bottleneck. Postgres query time will dwarf framework overhead by an order of magnitude.
Where the choice genuinely matters is at the architectural edges: very high-traffic public APIs, serverless functions where cold start and memory matter, or teams that want to enforce consistent validation and serialization patterns across a large codebase.
Migration Path: Express → Fastify
If you're running Express in production and want to migrate, you don't have to do it all at once.
npm install fastify @fastify/express
import Fastify from 'fastify'
import expressPlugin from '@fastify/express'
import legacyExpressApp from './legacy-express-app.js'
const fastify = Fastify()
// Mount your entire legacy Express app inside Fastify
await fastify.register(expressPlugin)
fastify.use(legacyExpressApp)
// Start migrating routes to native Fastify one by one
fastify.get('/new-route', { schema }, newHandler)
fastify.listen({ port: 3000 })
This lets you run both frameworks simultaneously, migrating route by route. Start with your highest-traffic endpoints where Fastify's performance gains will have the most impact, and work down from there.
Quick Reference
Feature
Express
Fastify
Initial release
2010
2017
Weekly downloads
~92M
~5.8M
Throughput
~25K req/sec
~80K req/sec
Latency (p99)
~42ms
~18ms
Built-in validation
❌
✅ (JSON Schema + AJV)
Built-in logging
❌
✅ (Pino)
TypeScript support
Good (v5+)
Excellent (native)
HTTP/2
❌ (via spdy)
✅ (native)
Plugin encapsulation
❌
✅
Learning curve
Low
Moderate
Ecosystem size
Very large
Growing
Express middleware compat
Native
Via @fastify/express
Conclusion
Express is not dead. With 92 million weekly downloads, Express 5's arrival, and a decade of production-hardened ecosystem around it, the framework will remain a perfectly valid choice for years to come.
But the momentum has shifted.
Fastify is the modern, performance-first choice. For new projects in 2026, it gives you better throughput, built-in validation, superior TypeScript support, and structured logging — all without sacrificing developer experience. The trend is clear: Fastify's download growth rate is outpacing Express's, and new projects increasingly adopt it as the default.
The right answer in 2026 isn't "always Fastify" — it's "Fastify for new APIs where performance and structure matter, Express where ecosystem breadth and team familiarity win."
Know what you're optimizing for, and let that guide the choice.