SpikeMe
← Comparisons
Backend

Fastify vs Express

updated on July 14, 2026

Fastify vs Express

Fastify and Express compared on performance, JSON-schema validation and serialization, async/await, and the size of the middleware ecosystem, with real npm data.

FactFastifyExpress
Current version5.10.05.2.1
Downloads/week (npm)9,508,396113,709,424
LicenseMITMIT
Bundle (gzip)131.8 kB236.1 kB
CriterionFastifyExpress
Performancehigh throughput, low per-request overheadgood, with more overhead in the core
Validation and serializationbuilt-in JSON schema (validates input, serializes output fast)manual or via middleware
Async/await and errorsasync-first, async handler errors handled by the frameworkExpress 5 forwards async rejections (4.x needed a wrapper)
Ecosystem and middlewareplugins with encapsulation and scopinghuge, mature middleware ecosystem
TypeScript typesfirst-class support (schema-to-type via a type provider)types via @types/express
Maturity and adoptionnewer, ~9.5M/weekincumbent, ~114M/week
Current versionv5, async-first from the startv5, shipped after years on 4.x

Context

Fastify and Express are both web frameworks for Node, but they start from different priorities. Express is the incumbent: a tiny core built around middleware, where practically everything (body parsing, authentication, CORS, validation) is a function you slot into the (req, res, next) chain. That radical simplicity and over a decade on the road made Express the de facto standard of Node, with a middleware ecosystem that likely already has a ready answer for any need. The trade-off is that Express itself validates nothing, serializes nothing in an optimized way, and, until v5, didn't catch errors from async handlers for you.

Fastify starts from a different thesis: performance and an explicit data contract as part of the framework, not something bolted on top. It was designed for high throughput and low per-request overhead, ships with built-in JSON Schema validation, and uses that same schema to serialize the response far faster than the default JSON.stringify. It's been async-first from the start and has first-class TypeScript support. Extensibility comes from a plugin system with encapsulation (each plugin has its own scope of decorators, hooks, and routes), instead of Express's linear middleware chain. Worth noting that both are now on v5: Express 5 shipped after years stalled on 4.x and brought, among other things, automatic forwarding of rejected promises from async handlers to the error handler.

The deciding variable is what you value: ubiquity and a huge ecosystem, or performance and a built-in typed contract.

When to choose Fastify

Fastify makes the most sense when performance and an explicit data contract matter from the start. The JSON schema isn't decoration: it validates the request body, query, and params before the handler runs, and it's reused to serialize the response, a path that in practice beats generic JSON.stringify on high-volume routes. Add the async-first model and first-class TypeScript support (with schema-to-type inference via a type provider like typebox or json-schema-to-ts), and you get a framework that treats validation, serialization, and types as part of the core.

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 });

In the example, the schema declares that name and price are required and typed: a request without name or with a non-numeric price gets a structured 400 before the handler is ever called, without a line of manual validation. The handler is async, and Fastify handles the response lifecycle and error capture for you. The plugin system keeps this organized as the application grows: each plugin encapsulates its routes, hooks, and decorators in its own scope, which avoids the global coupling typical of a long middleware chain. The entry cost is learning the model of schemas, hooks, and plugins, but in services where throughput and a typed API contract are requirements, that investment pays off. At around 9.5 million downloads per week, Fastify is much smaller than Express in adoption, but established as the performance alternative.

When to choose Express

Express remains the right choice when ubiquity and ecosystem weigh more than raw throughput. The core is minimal and the mental model is one of the simplest in Node: a request comes in, passes through a queue of middleware, and a response goes out. That, combined with over ten years as the de facto standard, means practically every problem (sessions, uploads, rate limiting, authentication with any provider) already has a mature middleware, a tutorial, and a Stack Overflow answer. At around 114 million downloads per week, it's the base the most people know and the easiest to hire for.

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);

The same endpoint makes the difference clear: in Express validation is your responsibility (done by hand here, in practice via a library like zod or express-validator), and there's no optimized serialization or built-in schema. In exchange, you get full transparency over the request chain and access to the largest middleware catalog in the ecosystem. v5, released recently after a long stretch on 4.x, modernizes important points: rejected promises from async handlers are now forwarded automatically to the error handler (on 4.x you needed a wrapper or try/catch in every route), plus adjustments to routing and route syntax. For many services, moderate-traffic APIs, and teams that already know the model, Express remains the most predictable and best-documented base.

Verdict

Reduced to its essentials, the choice comes down to one question: do you need performance and a built-in typed data contract, or ubiquity and Node's largest ecosystem? If throughput under load, schema validation, and fast serialization are requirements, and you want them in the framework's core instead of assembled from middleware, Fastify was designed for exactly that case and delivers types, validation, and schema docs as part of the package. It's the natural bet for new APIs where performance and contract matter from the first endpoint.

If what weighs more is finding ready-made middleware for everything, hiring people who already know the model, and having the ecosystem's richest documentation, Express rarely disappoints, and v5 closed the most annoying gap by handling async errors by default. Don't rewrite a healthy Express app to Fastify just for the promise of a benchmark: the throughput gain only pays off when throughput is actually the bottleneck. Choose Fastify for performance and the built-in schema, Express for ubiquity and the ecosystem, and let the service's profile decide.

Fastify

Choose Fastify if…

Choose Fastify when performance, built-in JSON-schema validation, and fast serialization matter, and you want first-class TypeScript support on an async-first core.

Express

Choose Express if…

Choose Express when you want the incumbent with Node's largest middleware ecosystem, a minimal core, and massive adoption, now on v5 with routing and async-error improvements.

The numbers above came from the registry, with source and date. Still, this comparison is generic: the right answer depends on versions, your team and what already exists in your project.

Generate the spike for YOUR stack

Share

XLinkedIn