Sitemap

Express.js vs Fastify: Comparison for Building Node.js Applications

4 min readOct 31, 2024

--

When it comes to building fast, efficient, and scalable backend applications in Node.js, Express.js and Fastify are two of the most popular frameworks. This guide provides a comprehensive comparison, including key features, usage scenarios, performance aspects, and detailed code examples to help you choose the right tool for your project.

Press enter or click to view image in full size

Overview

  • Express.js: Known for its simplicity and flexibility, Express.js has been the go-to choice for Node.js applications for years. It provides an extensive middleware ecosystem, allowing for quick prototyping and production-ready solutions.
  • Fastify: Built with a focus on speed and low overhead, Fastify is highly optimized for performance and provides built-in support for JSON schema validation. It’s ideal for applications that need high scalability and robust data validation.

Setting Up Express and Fastify

Let’s start by setting up a simple server with both frameworks.

Express.js

// express-setup.js
const express = require('express');
const app = express();

app.use(express.json()); // Parse JSON data
app.get('/', (req, res) => {
res.send('Hello from Express!');
});

app.listen(3000, () => {
console.log('Express server running on http://localhost:3000');
});

Fastify

// fastify-setup.js
const fastify = require('fastify')();

fastify.get('/', async (request, reply) => {
return { message: 'Hello from Fastify!' };
});

fastify.listen(3000, (err) => {
if (err) {
console.error(err);
process.exit(1);
}
console.log('Fastify server running on http://localhost:3000');
});

Both setups are simple, but the Fastify example highlights its return of an object for JSON responses by default, aligning with its high-performance goals.

Request Validation

Validation in APIs is essential for data integrity. Fastify has built-in JSON schema validation, whereas Express requires external libraries for similar functionality.

Express.js (Validation with Joi)

// express-validation.js
const express = require('express');
const Joi = require('joi');
const app = express();
app.use(express.json());

const userSchema = Joi.object({
name: Joi.string().required(),
age: Joi.number().integer().min(0).required(),
});

app.post('/user', (req, res) => {
const { error } = userSchema.validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
res.send(`User ${req.body.name} validated successfully!`);
});

app.listen(3000, () => console.log('Express validation example running'));

Fastify (Built-in JSON Schema Validation)

// fastify-validation.js
const fastify = require('fastify')();

fastify.post('/user', {
schema: {
body: {
type: 'object',
required: ['name', 'age'],
properties: {
name: { type: 'string' },
age: { type: 'integer', minimum: 0 },
},
},
},
handler: async (request, reply) => {
const { name, age } = request.body;
return { message: `User ${name} is ${age} years old.` };
},
});

fastify.listen(3000, (err) => {
if (err) throw err;
console.log('Fastify validation example running');
});

Middleware and Plugins

Express.js leverages a middleware-based approach, while Fastify uses a plugin system. This plugin structure offers Fastify better performance and modularity.

Get Frontend Highlights’s stories in your inbox

Join Medium for free to get updates from this writer.

Express.js Middleware Example

// express-middleware.js
const express = require('express');
const app = express();

app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});

app.get('/', (req, res) => {
res.send('Middleware in Express!');
});

app.listen(3000, () => console.log('Express middleware example running'));

Fastify Plugin Example

Fastify’s plugins encapsulate functionality and provide lifecycle hooks, making them reusable and efficient.

// fastify-plugin.js
const fastify = require('fastify')();

fastify.register(async (instance) => {
instance.addHook('preHandler', async (request, reply) => {
console.log(`${request.method} ${request.url}`);
});
});

fastify.get('/', async (request, reply) => {
return { message: 'Plugins in Fastify!' };
});

fastify.listen(3000, (err) => {
if (err) throw err;
console.log('Fastify plugin example running');
});

Error Handling

Both frameworks allow centralized error handling. Fastify offers hooks that enhance performance and control.

Express.js Error Handling

// express-error-handling.js
const express = require('express');
const app = express();

app.get('/', (req, res) => {
throw new Error('Oops! Something went wrong.');
});

app.use((err, req, res, next) => {
console.error(err.message);
res.status(500).send('Internal Server Error');
});

app.listen(3000, () => console.log('Express error handling example running'));

Fastify Error Handling

Fastify’s setErrorHandler simplifies centralized error management across routes.

// fastify-error-handling.js
const fastify = require('fastify')();

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

fastify.get('/', async (request, reply) => {
throw new Error('Oops! Something went wrong in Fastify.');
});

fastify.listen(3000, (err) => {
if (err) throw err;
console.log('Fastify error handling example running');
});

Handling Complex Responses and Optimization

Fastify’s schema-based response validation improves performance in complex APIs by optimizing JSON serialization.

// fastify-optimized-response.js
const fastify = require('fastify')();

fastify.get('/data', {
schema: {
response: {
200: {
type: 'object',
properties: {
id: { type: 'number' },
name: { type: 'string' },
active: { type: 'boolean' },
},
},
},
},
handler: async (request, reply) => {
return { id: 1, name: 'John Doe', active: true };
},
});

fastify.listen(3000, (err) => {
if (err) throw err;
console.log('Fastify optimized response example running');
});

TypeScript Support

For larger applications, TypeScript ensures type safety. Fastify’s JSON schema approach aligns well with TypeScript.

Fastify with TypeScript

import Fastify, { FastifyInstance } from 'fastify';

const server: FastifyInstance = Fastify();

server.get('/ping', async (request, reply) => {
return { pong: 'it worked!' };
});

server.listen(3000, (err) => {
if (err) {
console.error(err);
process.exit(1);
}
console.log('Fastify with TypeScript example running');
});

Summary

Press enter or click to view image in full size

For projects that require high scalability, better performance, and built-in validation, Fastify may be the ideal choice. It’s particularly beneficial for data-intensive applications and TypeScript-based projects. Express.js, on the other hand, is a flexible, widely-adopted framework perfect for general-purpose applications or projects with existing middleware requirements.

--

--

Frontend Highlights
Frontend Highlights

This page is about simple frontend things which can be useful in real work Support us on buymeacoffee.com/guestdm or https://ko-fi.com/dm110416