· fastify / express / nodejs

Fastify vs Express — the performance gap is real (2026)

Fastify handles 55% more requests per second than Express 5.x. For new TypeScript APIs, the DX win is as compelling as the speed. Here's what the numbers show.

By

2,118 words · 11 min read

Start a new Node.js API project today and pick Fastify. If you are maintaining a large Express codebase and your bottleneck is the database, stay where you are — migration cost will not pay off. That is the verdict. The rest of this article is the evidence.

Who this is for

Node.js engineers picking a framework for a new TypeScript service, or asking whether a migration from Express is worth the effort. If you are running Express 4.x and wondering whether to upgrade to 5.x or jump to Fastify, this comparison is for you.

If your app is already Fastify, you can skip to the DX comparison — you may find ammunition to push back on teammates who want to revert.

What we tested

We are citing primary-source benchmarks from the official fastify/benchmarks repository (github.com/fastify/benchmarks), last updated May 18, 2026. The test environment: Node.js v24.15.0, Linux x64, 4 vCPUs, 15.6 GB RAM. Method: autocannon -c 100 -d 40 -p 10 localhost:3000 (one warmup round, one measurement round).

Versions tested: Fastify 5.8.5 vs Express 5.2.1.

For real-world simulation numbers, we reference a third-party benchmark from Michael Guay (michaelguay.dev, October 2025) that adds authentication, request validation, and database inserts to the workload. Methodology is noted where cited.

Fastify vs Express benchmark results

The headline number: Fastify handles 55% more requests per second than Express 5.x, with 37% lower latency, on a bare hello-world endpoint.

FrameworkVersionReq/sLatency (avg)Throughput
Node (bare HTTP)v24.15.058,10816.71 ms10.36 MB/s
Fastify5.8.555,71617.43 ms9.99 MB/s
Express5.2.135,90927.37 ms6.40 MB/s

Source: github.com/fastify/benchmarks, May 18, 2026, Node.js v24.15.0.

Fastify runs at 96% of bare Node throughput. Express runs at 62%. That gap — ~34 percentage points — is framework overhead you are paying on every request.

What the official Fastify page shows (and why it differs)

The fastify.dev/benchmarks page shows a ~5× gap with Express delivering just 9,433 req/s. That number is real, but it reflects Express 4.x, not 5.x. Express 5.x became latest in March 2025 and is meaningfully faster than its predecessor. Do not cite the 5× figure against a modern Express setup.

The correct apples-to-apples comparison is 55,716 vs 35,909 — a 1.55× delta, not 5×.

Real-world workload: the gap stays meaningful

A synthetic hello-world benchmark isolates framework overhead. What happens when you add auth, validation, and database writes?

Michael Guay ran a POST endpoint with authentication, request validation (JSON Schema on Fastify, manual on Express), and database inserts against both frameworks:

FrameworkReq/sAvg latency
Express1,84753.2 ms
Fastify4,23123.1 ms

Source: michaelguay.dev, October 2025. Single-source; treat as directionally correct, not authoritative. Method: autocannon, same connection count.

Fastify is 2.3× faster under a real workload. Slower than the 5× synthetic myth, but faster than many people expect at this scale. Two factors drive the production gap:

  1. Schema compilation: Fastify compiles JSON Schema validation once at startup, per route. Express with manual validation (zod, joi, express-validator) re-parses and re-validates on every request.
  2. Serialization: Fastify uses fast-json-stringify — schema-based serialization that avoids the generic JSON.stringify path. Response serialization costs almost nothing in Fastify; it is non-trivial in Express.

The practical implication: 2× throughput at the same cost means you can double your traffic before adding a server instance. At indie/startup scale, that is real money. If your bottleneck is the database (and at early scale, it usually is), this gap is invisible — both frameworks spend 40 ms waiting on Postgres while adding at most 2 ms of their own. Choose the database query path first.

DX comparison

TypeScript

Fastify has first-party TypeScript support maintained by the core team since v2. The generic-based architecture (FastifyRequest<{Body: MyType}>) threads types through your entire route handler. Combine it with @fastify/type-provider-typebox and you get compile-time type checking and runtime JSON Schema validation from a single source of truth — write the schema once, get validation and types for free.

Express 5.2.1 still depends on @types/express v5.0.6 — community-maintained type definitions, not bundled types. The Express team acknowledged TypeScript DX improvements as planned work in the v5.1.0 release post. It works, but you will write more glue code to get typed route handlers.

If you are starting a TypeScript project, this is arguably a stronger argument for Fastify than the raw benchmark numbers. You stop maintaining two representations of the same data shape. Once your framework is set, the next TypeScript decision is typically the data layer — our best TypeScript ORM roundup covers the main options.

Schema validation

Fastify is schema-first by design. You declare a JSON Schema (or TypeBox equivalent) per route. Fastify rejects invalid input before your handler runs — no manual validation wiring, no forgotten validation on one route. Invalid requests return a consistent error format automatically.

Express gives you a blank canvas. Validation is manual: install zod or joi, call .parse() at the top of each handler, handle the thrown error yourself. It is not hard, but it is wiring you write for every route, and a route you forgot to wire fails silently.

Plugin system vs middleware chain

Express uses Connect’s imperative middleware chain — app.use(middleware). Every senior Express developer knows this pattern. It is also the source of every “middleware ran twice” debugging session.

Fastify uses a scoped plugin system. Plugins are registered with fastify.register() and get their own isolated scope unless you explicitly expose to the parent. This is a steeper ramp to learn, but it pays back when you need modular APIs: plugins encapsulate configuration, decorators, and lifecycle hooks without polluting the global app instance.

If your team is new to Node.js, Express’s mental model is easier to start. If you are building a modular API that will grow, Fastify’s plugin scoping prevents the common Express anti-pattern of middleware bleeding across route groups.

Logging

Fastify ships Pino built-in. Pino is structured JSON logging with the lowest overhead of any Node.js logger. Log levels, serializers, redaction — all configured via Fastify’s logger option at startup.

Express has no built-in logging. Morgan is the de facto default and it is not structured — you get Apache Combined Log Format, not JSON. If you want structured logs in Express, you wire Pino yourself and lose the Fastify integration layer.

Built-in OpenAPI

@fastify/swagger + @fastify/swagger-ui generate OpenAPI documentation from the same JSON Schema you write for validation. Write the schema, get docs. No code-gen, no separate spec file, no drift between your code and your docs.

Express requires separate OpenAPI tooling (swagger-jsdoc, tsoa, etc.) that adds a documentation layer you have to keep in sync manually.

Ecosystem and adoption

Express is 13× more downloaded than Fastify: ~101M weekly npm downloads vs ~7.5M. That gap is real and it matters.

What it means in practice:

  • More StackOverflow answers, tutorials, and existing team knowledge
  • A wider selection of npm packages that ship Express-native middleware
  • More confidence that your obscure use case has been solved

What inflates the number: Express downloads include transitive dependencies — every package that depends on or optionally integrates with Express pulls it at npm install. Fastify’s download count is cleaner (fewer packages treat Fastify as an optional peer).

Fastify’s growth trajectory is steeper. It has 36,265 GitHub stars and 292 officially listed plugins — 61 core @fastify/* packages and 231 community plugins. The core plugins cover the full backend surface: JWT, OAuth2, CSRF, WebSocket, PostgreSQL, MongoDB, Redis, multipart uploads, rate limiting, CORS, and more. Fastify is an OpenJS Foundation At Large project. Express is an OpenJS Impact project — the highest tier — earned from its install base. Both have institutional backing; neither is at risk of abandonment.

Express 5.x targets MAINTENANCE LTS no sooner than April 2026 and EOL no sooner than April 2027, per the v5.1.0 release post. The project is not abandoned, but the pace of innovation is slow. No built-in TypeScript, no built-in validation, no structured logging — design decisions made a decade ago and not revisited.

Where Fastify’s ecosystem still lags: very niche middleware categories where someone shipped express-[thing] and never made a Fastify equivalent. If you are in that situation, @fastify/express (below) or manual porting is your path. Check fastify.dev/ecosystem for coverage first. If you want a lighter, Express-like DX with modern performance, Hono vs Express covers that comparison.

Migration path

You do not need a flag day. @fastify/express runs Express middleware inside a Fastify app, which lets you migrate one route at a time.

npm install @fastify/express
import Fastify from 'fastify'
import ExpressPlugin from '@fastify/express'

const fastify = Fastify()
await fastify.register(ExpressPlugin)

// Run your existing Express middleware during transition
fastify.use(yourExpressMiddleware)

// New routes go native Fastify
fastify.get('/new-route', { schema: { ... } }, async (req, reply) => {
  return { ok: true }
})

The incremental path works. The key conceptual shifts that will slow your team down:

  • Middleware → plugins: not a one-liner swap. Think about encapsulation scopes.
  • Imperative validation → JSON Schema first: the hardest mindset shift for teams used to inline zod calls.
  • req.app → Fastify decorators: anything you stored on the Express app object needs to be a Fastify decorator instead.

Official reference: fastify.dev/docs/latest/Guides/Migration-Guide-V5. BetterStack has a practical step-by-step guide: betterstack.com/community/guides/scaling-nodejs/migrating-from-express-to-fastify.

Honest effort estimate: a medium-size Express app (20–40 routes, standard middleware stack) takes one to two sprints to migrate properly — mostly schema writing and plugin architecture decisions, not line-by-line translation.

Verdict

Pick Fastify if:

  • You are starting a new TypeScript API project. The first-party types + TypeBox DX advantage compounds from day one.
  • You want built-in OpenAPI documentation without a separate spec file.
  • You are building a performance-sensitive service: a public-facing API, a high-throughput microservice, or a multi-tenant backend where every latency percentile matters.
  • Your team can commit to schema-first validation. If you can, you stop writing the same validation wiring for every route.
  • You are on Node.js 20+. Fastify 5.x requires it.

Stay on Express if:

  • You have a large existing codebase. Rewriting validation schemas for 200 routes does not pay back in performance if your p99 is dominated by database calls.
  • Your team is junior-heavy or the framework needs to be learnable by new engineers in a week. Express’s imperative model is harder to misuse badly and easier to Google.
  • You depend on Express-only middleware with no Fastify equivalent and no bandwidth to port it.
  • Your bottleneck is clearly not framework overhead. Profile first. If your slowest traces are database queries, switching frameworks is the wrong lever.

The benchmark in context: a 2× throughput improvement at real workloads is meaningful at any scale — it is the difference between a $200/mo instance and a $400/mo pair of instances under the same load. But it is not a magic fix. If your app is spending 80 ms per request in Postgres, Fastify saves you 4 ms of serialization overhead while your users still wait 76 ms. Fix the query.

The TypeScript DX and schema-first architecture are arguably more compelling reasons to adopt Fastify than the raw numbers — especially for teams that keep writing the same validation wiring across every new project.

Caveats

  • Benchmark results run on virtual hardware. Numbers can vary by 10–20% depending on cloud provider, host instance type, and concurrency settings. Use these as directional data, not commitments.
  • The real-world 2.3× figure comes from a single third-party benchmark (Michael Guay, October 2025). Methodology is reasonable but not independently replicated.
  • Fastify’s plugin ecosystem, while growing, has gaps in niche areas. Check fastify.dev/ecosystem for your specific use case before committing.
  • If you are deploying on Bun, the Fastify vs Express gap may widen — Fastify runs on Bun, and Bun’s faster I/O can amplify Fastify’s serialization advantages. We did not benchmark this combination. See Bun vs Node.js for Bun’s runtime performance profile.
  • No affiliate links in this article. All tool links go to official documentation or primary sources.

References

SourceURL
fastify/benchmarks (primary, current)github.com/fastify/benchmarks
fastify.dev benchmarks pagefastify.dev/benchmarks
Fastify TypeScript docsfastify.dev/docs/latest/Reference/TypeScript
Express v5.1.0 release postexpressjs.com/en/blog/2025-03-31-v5-1-latest-release.html
Fastify ecosystem / pluginsfastify.dev/ecosystem
OpenJS Foundation — project listopenjsf.org/projects
BetterStack — Express → Fastify migrationbetterstack.com/community/guides/scaling-nodejs/migrating-from-express-to-fastify
Real-world benchmark (Michael Guay)michaelguay.dev/express-vs-fastify-a-performance-benchmark-comparison
Fastify Migration Guide V5fastify.dev/docs/latest/Guides/Migration-Guide-V5