Skip to content
Learni
View all tutorials
Backend

How to Create a REST API with Fastify in 2026

14 minINTERMEDIATE
Lire en français

Introduction

Fastify is a Node.js web framework known for its exceptional speed and low memory footprint. It excels at creating REST APIs thanks to its plugin system, built-in validation, and native TypeScript support. In 2026, it remains the preferred choice for applications requiring high performance without sacrificing maintainability. This tutorial guides you step by step to build a complete and production-ready API.

Prerequisites

  • Node.js 20+
  • npm or pnpm
  • Basic knowledge of TypeScript
  • Understanding of REST concepts

Project Initialization

terminal
mkdir fastify-api && cd fastify-api
npm init -y
npm install fastify
npm install -D typescript @types/node tsx
npx tsc --init

This command initializes the project, installs Fastify, and configures TypeScript. tsx allows executing TypeScript code directly during development.

TypeScript Configuration

Update the tsconfig.json file to enable strict options and ES modules. This ensures safer and more modern code.

Basic Fastify Server

src/server.ts
import Fastify from 'fastify';

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

fastify.get('/', async (request, reply) => {
  return { message: 'API Fastify opérationnelle' };
});

const start = async () => {
  try {
    await fastify.listen({ port: 3000, host: '0.0.0.0' });
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

This minimal server exposes a GET endpoint and uses Fastify's built-in logger. The start function handles asynchronous startup and errors robustly.

Adding Routes with Validation

src/routes/users.ts
import { FastifyInstance } from 'fastify';

export default async function userRoutes(fastify: FastifyInstance) {
  fastify.get('/users', {
    schema: {
      response: { 200: { type: 'array', items: { type: 'object' } } }
    }
  }, async () => {
    return [{ id: 1, name: 'Alice' }];
  });

  fastify.post('/users', {
    schema: {
      body: {
        type: 'object',
        properties: { name: { type: 'string' } },
        required: ['name']
      }
    }
  }, async (request) => {
    return { id: 2, name: request.body.name };
  });
}

Fastify's built-in JSON schemas automatically validate requests and responses. This improves security and performance without external dependencies.

Registering Plugins

src/server.ts
import Fastify from 'fastify';
import userRoutes from './routes/users';

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

fastify.register(userRoutes, { prefix: '/api' });

const start = async () => {
  try {
    await fastify.listen({ port: 3000 });
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

Encapsulation via register allows organizing code into independent modules. The prefix avoids route conflicts and cleanly structures the API.

Error Handling and Hooks

src/server.ts
fastify.setErrorHandler((error, request, reply) => {
  fastify.log.error(error);
  reply.status(500).send({ error: 'Erreur interne' });
});

fastify.addHook('onRequest', async (request) => {
  request.log.info('Requête reçue');
});

The centralized error handler and hooks enable uniform logging and exception processing throughout the application.

Best Practices

  • Always use validation schemas
  • Organize code into reusable plugins
  • Enable the logger in production with appropriate levels
  • Separate configuration from business logic
  • Test each route with tools like Vitest

Common Mistakes to Avoid

  • Forgetting to use async/await with handlers
  • Defining incomplete schemas that allow invalid data
  • Ignoring asynchronous error handling
  • Not configuring CORS for frontend applications

Going Further

Deepen your Fastify knowledge with JWT authentication and automated testing. Check out our Learni courses to master advanced backend architectures.