NestJS est le framework backend que j'utilise sur tous mes projets qui nécessitent une API robuste. C'est Node.js avec une vraie architecture, pas un fichier index.js de 2000 lignes.
Ce qui fait la différence : l'injection de dépendances, l'architecture modulaire, et le TypeScript natif. Chaque service, chaque controller, chaque guard a sa place. Le code est testable, maintenable, et un nouveau développeur peut comprendre la structure en quelques minutes.
Express est un excellent point de départ. Mais quand un projet grandit, sans structure imposée, le code devient ingérable. NestJS résout ce problème dès le premier commit.
Express donne une liberté totale. C'est sa force et sa faiblesse. Sur un petit projet, ça fonctionne. Sur une application métier avec 50 endpoints, de la logique business complexe et 3 développeurs, l'absence de conventions devient un problème.
Architecture modulaire. NestJS organise le code en modules. Chaque module regroupe ses controllers, services et providers. Un module users, un module billing, un module notifications. Chacun est indépendant, testable, remplaçable.
Injection de dépendances. Les services sont injectés automatiquement là où ils sont nécessaires. Pas de require() en cascade, pas de singletons manuels. Le framework gère le cycle de vie des instances.
Décorateurs TypeScript. Les routes, les validations, les guards, la documentation se déclarent via des décorateurs. @Get(), @Body(), @UseGuards(). Le code est déclaratif et lisible.
Pipes de validation. Les données entrantes sont validées automatiquement avec class-validator. Un DTO mal formé retourne une erreur 400 avant même d'atteindre le controller. Fini les validations manuelles éparpillées.
Modules par domaine métier. Je découpe chaque application par domaine, pas par couche technique. Un module orders contient son controller, son service, ses DTOs et ses tests. Pas de dossier controllers/ global avec 30 fichiers.
DTOs typés pour chaque opération. CreateUserDto, UpdateUserDto, UserResponseDto. Chaque opération a son propre DTO avec validation intégrée. Le frontend sait exactement ce qu'il peut envoyer et ce qu'il va recevoir.
Guards pour la sécurité. Authentification JWT via Passport, guards de rôles (@Roles('admin')), guards custom pour la logique métier. La sécurité est déclarative, pas dispersée dans le code.
Interceptors pour les patterns transversaux. Logging, transformation de réponse, cache, timing. Les interceptors encapsulent la logique qui s'applique à tous les endpoints sans polluer les controllers.
Tests unitaires et e2e. Chaque service est testé unitairement avec des mocks injectés. Les endpoints critiques ont des tests e2e qui vérifient le flux complet, de la requête HTTP à la réponse.
Voici comment je structure une API NestJS en production :
Auth module. JWT + refresh tokens, stratégies Passport (local, Google OAuth), middleware de rate limiting. Gestion des sessions et des permissions centralisée.
Database module. TypeORM ou Prisma avec PostgreSQL. Migrations versionnées, seeds pour le développement, transactions pour les opérations critiques.
Queue module. BullMQ avec Redis pour les tâches asynchrones : envoi d'emails, génération de PDF, synchronisation de données tierces. Les jobs sont typés, retry-ables et monitorables.
Config module. Variables d'environnement validées au démarrage avec @nestjs/config + Joi. Si une variable critique manque, l'application ne démarre pas plutôt que de crasher en production.
Health module. Endpoint /health qui vérifie la base de données, Redis, les services tiers. Utilisé par le monitoring et les load balancers.