Express vs Koa vs Fastify vs NestJS

intermediate express koa fastify nestjs comparison

This is one of the most common backend interview questions: “Why Express over Fastify?” or “When would you use NestJS?” Let’s break down what actually differs.

The 30-second version

  • Express — the default. Old, stable, huge ecosystem, unopinionated.
  • Koa — Express’s spiritual successor. Async/await first, no built-in router or body parser.
  • Fastify — Express-like API but ~2x faster. Schema-based validation built-in.
  • NestJS — Opinionated framework on top of Express (or Fastify). TypeScript, decorators, DI — basically Angular for the backend.
Feature Express Koa Fastify NestJS
Perf (req/s)~15k~17k~30k~15k
OpinionatedNoNoSlightlyVery
Async/await nativeNo*YesYesYes
TypeScript firstNoNoYesYes
Ecosystem sizeHugeSmallMediumLarge

*Express 5 has better async error propagation, but Express 4 (still dominant) needs try/catch or wrappers.

Express

The default choice. Used everywhere — old projects, tutorials, Stack Overflow answers. The ecosystem (middlewares, integrations, Stack Overflow answers) is unmatched.

const express = require('express');
const app = express();

app.get('/users/:id', (req, res) => {
  res.json({ id: req.params.id });
});

Pick when: building a typical REST API, team already knows it, need a specific middleware.

Koa

Built by the same team that made Express. Smaller, async-first, uses a ctx (context) object instead of req, res. No bundled router or body parser — you install separately.

const Koa = require('koa');
const app = new Koa();

app.use(async (ctx) => {
  ctx.body = { hello: 'world' };
});

Pick when: you want a clean async-first base and don’t mind assembling pieces yourself. Honestly, Koa is fading — Fastify ate its lunch.

Fastify

Express-like API but with serious engineering behind perf. Uses JSON Schema for validation AND fast serialization (it compiles a fast JSON.stringify from your schema). Built-in logger (Pino), plugins for everything.

const fastify = require('fastify')({ logger: true });

fastify.get('/users/:id', async (req) => {
  return { id: req.params.id };
});

fastify.listen({ port: 3000 });

Pick when: you need high throughput, want schema validation built-in, starting a new project without legacy Express middleware to keep.

NestJS

A full framework — controllers, services, modules, dependency injection. Heavy use of TypeScript decorators. Feels like Spring Boot or Angular.

@Controller('users')
export class UsersController {
  @Get(':id')
  findOne(@Param('id') id: string) {
    return { id };
  }
}

Pick when: large team, large codebase, want enforced structure, building something complex with many modules. Overkill for a 5-route service.

The interview answer

“Express is the safe default — huge ecosystem, easy hiring. We’d pick Fastify for high-throughput APIs where the 2x perf actually matters, since it has Express-like DX with schema validation built in. NestJS makes sense for large teams that benefit from enforced structure and DI — but it’s overhead for small services. Koa is mostly legacy at this point.”

That’s the call. The framework rarely matters as much as the team’s familiarity with it.