hapi vs express vs fastify vs koa
Building High-Performance Node.js APIs
hapiexpressfastifykoaSimilar Packages:

Building High-Performance Node.js APIs

express, fastify, hapi, and koa are the four major server frameworks for Node.js, each solving the problem of handling HTTP requests with different architectural philosophies. express is the unopinionated industry standard with a massive middleware ecosystem. fastify focuses on speed and low overhead, using a schema-based approach for validation and serialization. hapi emphasizes configuration over code, offering robust built-in features for enterprise needs without relying on third-party middleware. koa, created by the Express team, modernizes the stack with async/await and a lightweight context object, leaving middleware choices entirely to the developer.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
hapi56,17614,768-597 years agoBSD-3-Clause
express068,86475.4 kB1893 months agoMIT
fastify035,7352.73 MB119a month agoMIT
koa035,73765 kB267 days agoMIT

Express vs Fastify vs Hapi vs Koa: Architecture, Performance, and DX

When building a backend in Node.js, the framework you pick shapes how you handle requests, validate data, and structure your code. express, fastify, hapi, and koa are the main contenders. They all route HTTP traffic, but they solve it in very different ways. Let's look at how they handle the daily work of an API developer.

🏗️ Core Architecture: Middleware vs Configuration

express relies on a middleware chain. You add functions that run one after another. It is flexible but can get messy if you don't organize files well.

// express: Middleware chain
const express = require('express');
const app = express();

app.use((req, res, next) => {
  console.log('Time:', Date.now());
  next();
});

app.get('/user', (req, res) => {
  res.send('User Data');
});

fastify uses a plugin architecture and hooks. It is designed for speed and encapsulates logic to avoid global state pollution.

// fastify: Plugin and Hooks
const fastify = require('fastify')();

fastify.addHook('onRequest', async (request, reply) => {
  console.log('Incoming request');
});

fastify.get('/user', async (request, reply) => {
  return { hello: 'world' };
});

hapi avoids middleware entirely. Instead, you configure extensions and routes with detailed options. It forces a structured approach.

// hapi: Configuration and Extensions
const Hapi = require('@hapi/hapi');
const server = Hapi.server({ port: 3000 });

server.ext('onRequest', (request, h) => {
  console.log('Request started');
  return h.continue;
});

server.route({
  method: 'GET',
  path: '/user',
  handler: (request, h) => 'User Data'
});

koa uses a stack-like middleware system but with async/await. It gives you a clean ctx object instead of separate req and res.

// koa: Async Middleware Stack
const Koa = require('koa');
const app = new Koa();

app.use(async (ctx, next) => {
  console.log('Time:', Date.now());
  await next();
});

app.use(async (ctx) => {
  ctx.body = 'User Data';
});

📝 Validation and Serialization

express has no built-in validation. You must install libraries like joi, zod, or express-validator and wire them up manually.

// express: Manual validation setup
const { body, validationResult } = require('express-validator');

app.post('/user', 
  body('email').isEmail(), 
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) return res.status(400).json({ errors });
    res.send('Created');
  }
);

fastify has validation built-in using JSON Schema. It also serializes responses quickly based on the schema.

// fastify: Schema-based validation
fastify.post('/user', {
  schema: {
    body: {
      type: 'object',
      properties: { email: { type: 'string' } },
      required: ['email']
    }
  }
}, async (request, reply) => {
  return { id: 1, email: request.body.email };
});

hapi uses joi (often bundled or integrated) for rigorous validation rules defined in the route config.

// hapi: Joi validation in route options
const Joi = require('joi');

server.route({
  method: 'POST',
  path: '/user',
  options: {
    validate: {
      payload: Joi.object({ email: Joi.string().required() })
    }
  },
  handler: (request, h) => ({ id: 1, email: request.payload.email })
});

koa like Express, leaves validation to you. You pick your own library and middleware.

// koa: External validation middleware
const validator = require('koa-validator');

app.use(validator());

app.post('/user', async (ctx) => {
  ctx.assert(ctx.request.body.email, 400, 'Email required');
  ctx.body = { id: 1 };
});

🚨 Error Handling

express uses a special middleware function with four arguments. If you forget the next(err), the app hangs.

// express: Error middleware
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

fastify lets you set a global error handler or handle errors inside routes using try/catch.

// fastify: Global error handler
fastify.setErrorHandler((error, request, reply) => {
  console.error(error);
  reply.status(500).send({ error: 'Internal Server Error' });
});

hapi handles errors via the response toolkit. You return an error object or throw one, and the framework formats it.

// hapi: Error handling in handler
server.route({
  method: 'GET',
  path: '/error',
  handler: (request, h) => {
    throw new Error('Something broke');
    // Or: return h.response().code(500);
  }
});

koa uses a central error handler middleware. Since it uses promises, unhandled rejections are caught here.

// koa: Central error handler
app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    ctx.status = err.status || 500;
    ctx.body = err.message;
  }
});

🚀 Performance and Overhead

express is stable but older. It does not serialize JSON as fast as newer frameworks and has higher overhead per request.

// express: Standard JSON send
res.json({ message: 'Hello' }); 
// Uses JSON.stringify internally

fastify is built for speed. It uses fast-json-stringify to serialize responses up to 2x faster than standard JSON.

// fastify: Optimized serialization
reply.send({ message: 'Hello' }); 
// Uses schema-based serialization if defined

hapi prioritizes security and structure over raw speed. It is generally slower than Fastify but consistent.

// hapi: Standard response
return h.response({ message: 'Hello' });
// Robust but heavier processing

koa is lightweight and modern. It is faster than Express because it doesn't bundle legacy features, but it lacks Fastify's serialization tricks.

// koa: Body assignment
ctx.body = { message: 'Hello' };
// Standard JSON.stringify

🧩 Ecosystem and Plugins

express has the largest ecosystem. If a tool exists for Node, it likely has an Express middleware.

// express: Huge middleware variety
const cors = require('cors');
const helmet = require('helmet');
app.use(cors());
app.use(helmet());

fastify has a growing plugin ecosystem. Plugins are encapsulated, which prevents conflicts but requires learning the specific API.

// fastify: Encapsulated plugins
fastify.register(require('@fastify/cors'));
fastify.register(require('@fastify/helmet'));

hapi has a curated set of plugins. Quality is high, but variety is lower than Express.

// hapi: Official and community plugins
await server.register(require('@hapi/inert')); // Static assets
await server.register(require('@hapi/vision')); // Templates

koa shares much of the Express middleware ecosystem but requires wrappers for some older callback-based middleware.

// koa: Middleware compatibility
const cors = require('@koa/cors');
app.use(cors());
// Some express middleware needs 'koa-connect' wrapper

📊 Summary Table

Featureexpressfastifyhapikoa
StyleMiddlewarePlugin + SchemaConfigurationAsync Middleware
ValidationExternal (Manual)Built-in (JSON Schema)Built-in (Joi)External (Manual)
Error Handling4-arg MiddlewareHandler / Try-CatchToolkit / ThrowTry-Catch Middleware
PerformanceStandardHigh (Optimized)StandardLightweight
Learning CurveLowMediumHighMedium
Best ForGeneral PurposeHigh ThroughputEnterpriseModern Custom Stacks

💡 The Big Picture

express is the reliable workhorse 🐴. It is everywhere, easy to learn, and gets the job done for 90% of projects. Use it when you want to spend time on business logic, not framework configuration.

fastify is the speed demon 🏎️. If you are building microservices that need to handle thousands of requests per second, or if you love schema-driven development, this is the modern choice.

hapi is the enterprise vault 🏦. It is strict and secure by default. Choose it if you are in a regulated industry or need a framework that enforces good patterns across a large team.

koa is the minimalist's canvas 🎨. It gives you the modern async features of Express without the legacy weight. Pick it if you want to build your own architecture from the ground up.

Final Thought: All four frameworks can build production-ready APIs. The decision comes down to whether you value ecosystem size (express), raw performance (fastify), strict governance (hapi), or modern minimalism (koa).

How to Choose: hapi vs express vs fastify vs koa

  • hapi:

    Choose hapi if you are building large-scale enterprise applications where security, input validation, and strict configuration are more important than flexibility. It suits teams that want a 'batteries-included' framework with strong governance and less reliance on the quality of external middleware.

  • express:

    Choose express if you need the widest possible selection of third-party middleware, tutorials, and community support. It is the safest bet for standard REST APIs, prototypes, and teams that value convention and ease of hiring. Stick with it if you don't have strict performance requirements that demand micro-optimization.

  • fastify:

    Choose fastify if performance is a top priority or if you want built-in validation and serialization without adding extra libraries. It is ideal for high-throughput microservices and teams that prefer schema-driven development to catch errors early in the request lifecycle.

  • koa:

    Choose koa if you want a modern, lightweight foundation that uses async/await natively and gives you full control over middleware composition. It is best for developers who find Express callbacks cumbersome and want to build a custom stack without the baggage of legacy Express design decisions.

README for hapi

Web and services application framework

Lead Maintainer: Eran Hammer

hapi is a simple to use configuration-centric framework with built-in support for input validation, caching, authentication, and other essential facilities for building web and services applications. hapi enables developers to focus on writing reusable application logic in a highly modular and prescriptive approach.

Version 18.x only supports node v8.12.0 and over. For older version of node please use hapi version 16.x.

Development version: 18.1.x (release notes) Linux Build Status Windows Build Status

For the latest updates, change log, and release information visit hapijs.com and follow @hapijs on twitter. If you have questions, please open an issue in the discussion forum.

Sponsorship

Development of the hapi core module generously supported by contributions from individuals and corporations. If you are benefiting from hapi and would like to help keep the project financially sustainable, please visit Eran Hammer's Patreon page or contact him via email.

Featured Sponsors

Auth0

Active Supporters

Legacy Supporters

Past major financial support for the project was provided by: