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
mkdir fastify-api && cd fastify-api
npm init -y
npm install fastify
npm install -D typescript @types/node tsx
npx tsc --initThis 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
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
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
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
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.