Node.jsAPIsExpressFastify

From Express to Fastify: Modern Node.js APIs at Scale

When to use Express, when to reach for Fastify, and patterns for building resilient, observable Node APIs — routing, validation, and performance considerations.

6 min read
From Express to Fastify: Modern Node.js APIs at Scale

Node.js powers the backend of countless web services, and Express has been the default choice for building REST APIs for over a decade. Fastify is the up‑and‑coming alternative that squeezes more performance out of the same Node runtime. This post helps you choose between them and introduces a few beginner‑friendly patterns every API should follow.

Express vs. Fastify: which kitchen to use?

Express – the familiar classic

Express is the “well‑worn kitchen”: everyone knows where the pots and pans are, and there’s middleware for almost anything you can imagine. It’s a great default for small or medium apps, prototypes, and teams that already rely on the ecosystem.

Use Express when

  • your app is simple,
  • you depend on existing middleware, or
  • the team is already comfortable with it.

Fastify – the modern high‑throughput kitchen

Fastify was designed for speed. It comes with built‑in schema validation and fast JSON serialization, and the core framework is extremely lightweight. When requests start scaling into the thousands per second, Fastify often outperforms Express by a wide margin.

Use Fastify when

  • you need maximum throughput,
  • you want automatic request/response validation, and
  • you’re willing to adopt a slightly newer API.

Three core API patterns (applies to both frameworks)

  1. Validate everything – never trust incoming data. Use JSON Schema, Zod, or a similar library to enforce a contract. This prevents invalid requests from reaching your business logic.

  2. Centralize error handling – create a single middleware or hook that catches thrown errors and sends a consistent response. It’s like having a dedicated clean‑up crew: the rest of the code can assume happy paths.

  3. Instrument early – add logging, metrics, and tracing from day one. When problems occur in production, you want to be able to replay what happened. Think of this as installing security cameras in the kitchen.

Example: Fastify with schema validation

The snippet below illustrates a minimal Fastify setup with a JSON schema that validates request bodies. Express can do the same with a middleware like ajv or zod.

import Fastify from "fastify";

const fastify = Fastify({ logger: true });

// schema definition using JSON Schema
const postOptions = {
  schema: {
    body: {
      type: "object",
      required: ["title", "content"],
      properties: {
        title: { type: "string", minLength: 5 },
        content: { type: "string" },
      },
    },
  },
};

// route declaration – Fastify automatically validates and serializes
fastify.post("/blog", postOptions, async (request, reply) => {
  // if validation fails, Fastify will send a 400 error before this handler runs
  return { status: "Blog post created!", data: request.body };
});

fastify.listen({ port: 3000 });

Wrapping up

Express and Fastify each have their strengths; both can be used to build solid APIs. Express gives you maximum familiarity, while Fastify offers better performance and built‑in validation. Whatever you choose, apply the three patterns above – validation, centralized errors, and observability – and your API will be easier to maintain and debug.

Happy coding!