Express contre Fastify en 2026 : une comparaison pratique des frameworks Node.js
Ce guide compare Express et Fastify en termes de performance, de validation, d’écosystème et de gestion des erreurs, et aborde également les principales modifications significatives d’Express 5.
Imaginez une équipe qui lance un nouveau backend Node.js.
Ils commencent à rechercher des frameworks, et deux noms dominent presque immédiatement la discussion :
Express.js et Fastify.
Puis apparaissent les graphiques de benchmark.
Dans de nombreux tests synthétiques, Fastify affiche des valeurs de débit nettement plus élevées.
La réaction naturelle est la suivante :
"Si Fastify l’emporte en vitesse, pourquoi quelqu’un continuerait-il à utiliser Express ?"
C’est une question légitime en apparence.
Mais le choix d’un framework backend ne se résume rarement à un seul indicateur de ce type.
Le nombre brut de requêtes par seconde n’est qu’un élément du tableau. Il vous faut également prendre en compte l’écosystème environnant, le fonctionnement des middleware, la validation intégrée, le support de TypeScript, le coût potentiel d’une migration, l’expérience quotidienne des développeurs, tout code existant que vous maintenez, ainsi que les besoins spécifiques de votre application.
Il existe également une deuxième dimension à cette comparaison qui mérite d’être soulignée.
Express 5 est désormais officiellement disponible.
Après une longue utilisation d’Express 4, cette nouvelle version majeure introduit quelques modifications dont tout ceux qui gèrent un codebase Express plus ancien doivent être conscients.
Avec ce contexte établi, examinons ce qui distingue réellement Express de Fastify — et, plus utilement encore, les situations dans lesquelles chacun d’eux s’avère approprié.
Tout d’abord : qu’est-ce exactement que Express et Fastify ?
Ces deux frameworks existent pour vous aider à créer des serveurs web basés sur Node.js.
Leur fonction principale est de vous épargner l’écriture directe avec le module HTTP de bas niveau de Node, en vous fournissant une API plus simple pour définir des routes et gérer les requêtes.
Voici à quoi ressemble un serveur Express minimal :
const express = require("express");
const app = express();
app.get("/users", (req, res) => {
res.json([
{ id: 1, name: "Neha" },
{ id: 2, name: "Rahul" }
]);
});
app.listen(3000);
Le point de départ avec Fastify est assez similaire :
const fastify = require("fastify")({
logger: true
});
fastify.get("/users", async (request, reply) => {
return [
{ id: 1, name: "Neha" },
{ id: 2, name: "Rahul" }
];
});
fastify.listen({ port: 3000 });
Vous remarquez quelque chose ?
Aucun des exemples n’est particulièrement intimidant.
La véritable différence entre les deux ne devient évidente que lorsque votre application dépasse ce stade d’exemple simplifié.
Express vs Fastify : Le tableau général
Examinons pourquoi les différences entre ces deux frameworks sont en réalité importantes dans la pratique.
1. Performance : Fastify a l’avantage
C’est probablement la raison principale pour laquelle Fastify revient constamment dans ces discussions.
Dès le début, la performance et un coût d’exploitation minimal ont été les objectifs fondamentaux de la conception de Fastify.
Ses mécanismes internes s’appuient fortement sur des schémas, tant pour valider les données entrantes que pour serialiser les réponses sortantes, ce qui peut améliorer considérablement le débit pour des charges de travail lourdes en API. La documentation officielle de Fastify recommande spécifiquement d’utiliser JSON Schema pour la validation des routes et la serialisation des réponses.
Cela dit, il existe une mise en garde importante à ce sujet.
Ne vous basez pas sur un seul résultat de test pour en conclure immédiatement que :
Fastify signifie automatiquement une application trois fois plus rapide.
La plupart des tests de performance des frameworks mesurent le coût d’exploitation du framework lui-même, dans des conditions strictement contrôlées.
Les propres mainteneurs de Fastify reconnaissent que leur test de référence publié est un test synthétique de type « hello world », et ils suggèrent explicitement d’effectuer des tests de performance sur votre propre application réelle si la vitesse est une priorité pour vous.
Considérez un flux de requêtes qui ressemble à ceci :
Request
↓
Authentication
↓
Database query
↓
Redis
↓
External API
↓
Business logic
↓
Response
Si seule l’appel à la base de données prend 80 millisecondes, réduire légèrement la charge supplémentaire du framework n’aura aucun effet significatif sur la vitesse de cet endpoint.
La vraie question à se poser est donc :
Mon application est-elle réellement limitée par la puissance du CPU ou par les surcoûts du framework ?
En d’autres termes : le framework lui-même est-il la cause du ralentissement des requêtes ? Si c’est le cas, passer à Fastify est beaucoup plus justifié.
Si ce n’est pas le cas, alors les tests de performance génériques sur des frameworks ne devraient probablement pas être le facteur décisif pour vous.
2. Validation : c’est ici que Fastify devient intéressant
Imaginez que votre API soit conçue pour accepter un en-tête de données ayant cette forme :
{
"name": "Neha",
"age": 25
}
Naturellement, vous voudriez rejeter une version mal formatée de cet même en-tête de données, quelque chose comme :
{
"name": 123,
"age": "hello"
}
Dans le monde d’Express, les équipes ont généralement recours à une bibliothèque supplémentaire pour gérer ce type de validation des requêtes. Fastify adopte une approche différente : la validation basée sur des schémas est intégrée directement dans le framework lui-même.
Voici à quoi cela ressemble en pratique :
const schema = {
body: {
type: "object",
required: ["name", "age"],
properties: {
name: { type: "string" },
age: { type: "integer" }
}
}
};
fastify.post("/users", { schema }, async (request, reply) => {
return { message: "User created" };
});
Fastify vous permet de définir des définitions JSON Schema pour différentes parties du cycle de requête et de réponse, notamment :
- le corps de la requête
- les paramètres de recherche
- les paramètres de route
- les en-têtes
- la sérialisation de la réponse
Au niveau technique, Fastify s’appuie sur Ajv pour gérer cette couche de validation, et les mêmes définitions de schéma peuvent également être utilisées pour accélérer la sérialisation des réponses.
Ajv, abréviation de « Another JSON Schema Validator », est une bibliothèque rapide et conforme aux normes permettant de valider des objets de données JavaScript selon des définitions JSON Schema ; elle fonctionne aussi bien dans Node.js que dans le navigateur.
Cette approche axée sur les schémas devient particulièrement précieuse lorsque votre API intègre de nombreux entrées et sorties structurées.
3. Express possède quelque chose que Fastify ne peut pas remplacer facilement : son écosystème
Express existe depuis 2010, ce qui signifie qu’un vaste ensemble de connaissances, d’outils et d’expériences communautaires a été développé autour de lui.
- Besoin d’authentification ? Il existe un package pour cela.
- Besoin de journalisation ? Il existe également un package pour cela.
Cette profondeur d’écosystème est plus importante qu’il n’y paraît au premier abord.
Imaginez que vous rejoigniez une entreprise dont le backend fonctionne en production depuis six ans. Vous ne pouvez pas choisir le framework à partir de zéro ; vous devez utiliser ce qui est déjà en place, qui pourrait ressembler à ceci :
Express
├── 200+ routes
├── authentication middleware
├── custom middleware
├── logging
├── validation
├── monitoring
└── lots of business logic
Est-il vraiment judicieux de réécrire tout cela simplement parce que Fastify est plus rapide selon les benchmarks ? Probablement pas.
Migrer une base de code existante entraîne toujours des coûts, et toute décision d’ingénierie réelle doit évaluer ces coûts par rapport aux avantages attendus.
4. Middleware vs Plugins
Il existe également une distinction architecturale plus profonde entre ces deux frameworks.
Express est conçu autour du concept de middleware. Une configuration typique pourrait ressembler à ceci :
app.use(authMiddleware);
app.use(loggingMiddleware);
app.use(express.json());
Chaque requête entrante passe alors successivement par ces fonctions middleware.
Fastify, en revanche, utilise une architecture basée sur des plugins, construite autour d’hooks et d’encapsulation. Conceptuellement, le flux se présente plutôt comme ceci :
Request
↓
Fastify
↓
Hooks
↓
Plugins
↓
Route
↓
Response
Pour les applications conçues dès le départ selon le modèle de Fastify, cette structure permet d’organiser et de comprendre plus facilement des bases de code plus volumineuses.
Cela dit, il y a un compromis : si vous avez passé des années à développer des modèles mentaux autour du middleware de style Express, s’adapter au système de plugins et d’hooks de Fastify peut sembler inhabituel au début.
5. Gestion des erreurs
Dans Express 4, gérer les erreurs provenant des gestionnaires de routes asynchrones nécessitait généralement un redirigement manuel. Un schéma typique ressemblait à ceci :
app.get("/user/:id", async (req, res, next) => {
try {
const user = await getUserById(req.params.id);
res.json(user);
} catch (error) {
next(error);
}
});
Express 5 simplifie considérablement cela. Désormais, les rejets de promesse générés par les gestionnaires de routes ou le middleware sont automatiquement transmis au middleware de traitement des erreurs, ce qui vous permet d’écrire du code beaucoup plus concis :
app.get("/user/:id", async (req, res) => {
const user = await getUserById(req.params.id);
res.json(user);
});
Si getUserById() génère une erreur ou un rejet, Express 5 la capture automatiquement et l’envoie au gestionnaire d’erreurs, sans nécessiter de try/catch explicite ni d’appel à next(err).
En soi, cela semble être une simple facilité syntaxique. Mais dans un codebase comptant des centaines de routes, ce genre d’optimisation mineure contribue à un code nettement plus ordonné et moins sujet aux erreurs.
Express 5 : Qu’a vraiment changé ?
Express 5 est sorti en octobre 2024, donc à l’approche de 2026 il ne s’agit plus d’une version récente. Néanmoins, un grand nombre d’applications en production fonctionnent encore sur Express 4, ce qui signifie que comprendre les modifications entre les versions est essentiel pour quiconque envisage une mise à niveau.
Oui, il existe des changements pouvant causer des problèmes auxquels il faut être attentif.
1. Modification des paramètres de route optionnels
Avec Express 4, on pouvait écrire une route de cette manière :
app.get("/:file.:ext?", handler);
Express 5 remplace ce schéma par :
app.get("/:file{.:ext}", handler);
La vieille notation ? pour indiquer qu’un paramètre est optionnel ne fonctionne plus.
Pourquoi ce changement ?
La nouvelle syntaxe permet de voir d’un coup d’œil quelle partie du chemin est optionnelle.
C’est un changement subtil en apparence, mais il peut perturber silencieusement des dizaines de routes dans une application importante et bien établie.
2. Modification des routes avec des jokers
Auparavant, une route générique pouvait ressembler à ceci :
app.get("/*", handler);
Express 5 exige que les wildcards soient nommés :
app.get("/*splat", handler);
Si vous avez besoin que ce wildcard corresponde également au chemin racine /, l’entourez comme ceci :
app.get("/{*splat}", handler);
C’est encore un petit changement de syntaxe qui peut briser silencieusement la logique de routage existante lors d’une mise à niveau.
3. Les modèles de routes basés sur des expressions régulières ont changé
Express 5 cesse de prendre en charge plusieurs anciens modèles basés sur des chaînes de caractères utilisant des caractéristiques propres aux expressions régulières.
Par exemple, au lieu d’incorporer directement des segments alternatifs dans une seule chaîne de chemin, vous passez désormais généralement un tableau de chemins :
app.get(
["/discussion/:slug", "/page/:slug"],
handler
);
L’objectif de ce changement est de rendre la correspondance des routes explicite et prévisible, plutôt que de compter sur des raccourcis similaires aux expressions régulières.
4. req.body peut désormais être undefined
C’est un détail subtil qui passe facilement inaperçu.
Au sein d’Express 4, on supposait généralement que :
req.body
il reviendrait par défaut à un objet vide même avant toute analyse.
Avec Express 5, si rien n’analyse le corps de la requête, req.body peut simplement être undefined.
Cela signifie qu’une vérification de sécurité comme celle-ci devient pertinente en fonction de la route :
if (!req.body) {
return res.status(400).send("Request body required");
}
C’est un léger changement de comportement, mais c’est précisément ce genre de détail qui peut provoquer des bugs difficiles à tracer après une mise à niveau.
5. express.urlencoded() a changé
La valeur par défaut de l’option extended est désormais false.
Ainsi, plutôt que de compter sur la valeur par défaut implicite :
app.use(express.urlencoded());
il conviendra de la définir explicitement si votre application repose sur le comportement ancien :
app.use(
express.urlencoded({
extended: true
})
);
Un autre détail qui mérite une attention particulière lors de la migration d’une base de code existante.
6. Modifications du parseur du corps
Express 5 a également simplifié le fonctionnement interne du parseur du corps.
Vous pouvez maintenant écrire :
app.use(express.json());
app.use(
express.urlencoded({
extended: false
})
);
au lieu de combiner des packages middleware body-parser séparés comme avant.
7. Certaines anciennes API de réponse ont été supprimées
Imaginez une application Express plus ancienne contenant quelque chose comme :
res.send({
message: "Success"
}, 200);
Sous Express 5, la forme attendue est :
res
.status(200)
.send({
message: "Success"
});
De même, l’ancien raccourci :
res.redirect("back");
a été complètement supprimé.
Le guide officiel de migration suggère de lire manuellement l’en-tête referer et de recourir à un chemin par défaut en cas d’absence.
Aucun de ces changements individuels n’est particulièrement difficile à mettre en œuvre.
Mais imaginez une base de code ancienne contenant des milliers d’appels écrits à l’ancienne manière.
A cette échelle, la mise à niveau cesse d’être une simple augmentation de dépendances pour devenir un véritable effort d’ingénierie en soi.
Alors, Express ou Fastify : lequel l’emporte ?
À ce stade, vous disposez de suffisamment de contexte pour prendre une décision réelle.
Je ne me baserais pas uniquement sur :
« Lequel est le plus rapide selon les benchmarks ? »
Plutôt, commencez par examiner l’application elle-même.
Raisons de rester avec Express :
Raisons d’examiner Fastify :
- Vous commencez un nouveau service axé sur les API depuis zéro.
- Le débit et la minimisation de la charge du framework sont effectivement importants.
- Vous souhaitez que la validation soit gérée directement par des schémas.
- Vous voulez également que la sérialisation soit gérée via des schémas.
- Vous développez des microservices.
- Vous aimez travailler avec une architecture basée sur des plugins.
- Vous n’avez pas de problème à adopter un écosystème relativement plus récent.
Rien n’est intrinsèquement erroné à choisir Express même pour un système à grande échelle.
Le fait d’avoir une « application volumineuse » ne signifie pas automatiquement que Fastify est le choix approprié.
Ce qui entoure le framework – votre architecture globale – compte généralement bien plus que le choix du framework lui-même.
Une manière de raisonner à ce sujet
Voici un schéma mental approximatif pour prendre cette décision :
Start
│
▼
Is this an existing app?
/ \
Yes No
│ │
▼ ▼
Already using Need very high
Express? throughput?
/ \ / \
Yes No Yes No
│ │ │ │
▼ ▼ ▼ ▼
Keep Evaluate Fastify Evaluate
Express migration both
Avant de se fixer sur une réponse définitive, il y a encore une question à se poser :
Quel problème essaie-t-on vraiment de résoudre ?
Si votre application Express actuelle semble lente, résistez à l’envie de blâmer immédiatement le framework.
Analyssez-la d’abord en termes de performance.
Le véritable problème pourrait être :
Slow API
↓
Database query
↓
Missing index
ou bien :
Slow API
↓
External API
↓
3-second response time
ou encore :
Slow API
↓
Expensive business logic
↓
CPU bottleneck
Changer de framework ne résoudra pas seul aucun de ces problèmes sous-jacents.
Ma position à ce sujet
Si vous deviez lancer un petit projet Node.js aujourd’hui, il ne serait pas très judicieux d’écarter Express simplement parce que Fastify affiche de meilleurs résultats dans les benchmarks. Express dispose d’un écosystème immense, d’un modèle conceptuel simple et de nombreuses années de connaissances collectives développées autour de lui.
Néanmoins, Fastify ne doit pas non plus être négligé. Pour un nouveau service où le débit, la validation des schémas, la sérialisation et les coûts opérationnels minimes du framework sont vraiment importants, Fastify mérite une réflexion sérieuse.
Et si vous avez hérité d’une application Express 4 existante ? La réécrire uniquement parce que Fastify est plus rapide serait une erreur.
La meilleure approche consiste d’abord à comprendre l’application, à identifier les véritables goulots d’étranglement, à vérifier la compatibilité avec Express 5, à exécuter les tests de migration, et seulement ensuite à décider si le changement de framework apporte une valeur réelle suffisante pour justifier cet effort.
C’est probablement le point essentiel à retenir ici.
Le framework ayant les meilleures performances n’est pas automatiquement le bon choix pour votre situation.
Le bon framework est celui qui résout votre problème réel tout en ajoutant le moins de complexité inutile possible.
Lectures complémentaires
- Node.js, Deno et Bun comparés : essais de performance, compromis et stratégie de migration — Explique les véritables différences architecturales entre Node.js, Deno et Bun, ce que révèlent les essais de 2025, ainsi que la manière de décider s’il convient de migrer et quand le faire.
- Partager un seul schéma Zod entre votre frontend React et votre backend Node — Découvrez comment un seul schéma Zod peut valider les formulaires React, les réponses API, les corps de requête Express et les variables d’environnement tout en générant des types TypeScript correspondants.