NestJS est un framework Node.js créé par Kamil Myśliwiec en 2017. Son idée de départ : prendre ce qui fonctionne dans Angular — modules, décorateurs, injection de dépendances — et l'appliquer côté serveur. Le résultat est un framework qui impose une architecture claire dès le premier fichier, tout en restant compatible avec l'écosystème Express (ou Fastify).
Cet article explore ce qui rend NestJS différent des autres frameworks Node.js, pourquoi il séduit de plus en plus d'équipes, et dans quels cas il est le bon choix. On illustrera avec des exemples tirés d'un vrai projet de production : une API de réservation en ligne construite avec NestJS, TypeORM et PostgreSQL.
Prérequis : connaissances de base en JavaScript/TypeScript. Aucune expérience NestJS requise — c'est justement le but de cet article.
Le problème que résout NestJS
Express.js est le framework Node.js le plus utilisé, et pour cause : il est léger, flexible et facile à prendre en main. Mais cette flexibilité devient un piège quand le projet grandit :
- Pas de structure imposée — chaque développeur organise le code différemment
- Pas d'injection de dépendances native — les dépendances sont souvent importées directement
- Pas de système de modules — tout finit dans un gros fichier
app.jsou un arbre de dossiers improvisé - TypeScript en option — il faut le configurer soi-même
NestJS répond à chacun de ces points en imposant une architecture modulaire et déclarative, inspirée des frameworks backend matures comme Spring (Java) ou Symfony (PHP).
L'architecture en trois briques
Toute application NestJS repose sur trois concepts fondamentaux : les modules, les controllers et les services. Prenons un exemple concret.
Le Module : regrouper les fonctionnalités
Un module est un conteneur qui regroupe un ensemble cohérent de fonctionnalités. Voici le module principal d'un projet de production :
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ThrottlerModule } from '@nestjs/throttler';
import { DatabaseModule } from './database/database.module';
import { AuthModule } from './modules/auth/auth.module';
import { BookingModule } from './modules/booking/booking.module';
import { ServicesModule } from './modules/services/services.module';
import { PaymentModule } from './modules/payment/payment.module';
import { ContactModule } from './modules/contact/contact.module';
import configuration from './config/configuration';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [configuration],
}),
ThrottlerModule.forRoot([{
ttl: 60000, // 1 minute
limit: 100, // 100 requêtes max
}]),
DatabaseModule,
AuthModule,
ServicesModule,
BookingModule,
PaymentModule,
ContactModule,
// ... 12 autres modules
],
})
export class AppModule {}
Le décorateur @Module déclare les dépendances du module : quels autres modules il importe, quels controllers il expose, quels services il fournit. C'est la carte d'identité de chaque fonctionnalité.
Le Controller : gérer les requêtes HTTP
Un controller reçoit les requêtes HTTP et délègue le travail au service. Il ne contient aucune logique métier — juste du routage et de la validation :
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get('health')
getHealth(): string {
return this.appService.getHealth();
}
}
Les décorateurs @Get, @Post, @Put, @Delete remplacent les app.get(), app.post() d'Express. C'est plus lisible et ça se documente automatiquement avec Swagger.
Le Service : la logique métier
Le service contient la vraie logique. Il est marqué @Injectable() pour que NestJS puisse l'injecter automatiquement dans les controllers (ou d'autres services) :
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHealth(): string {
return 'API is running';
}
}
Cette séparation controller/service est le Single Responsibility Principle appliqué : le controller s'occupe du HTTP, le service s'occupe du métier. Quand vous testez, vous pouvez mocker le service sans toucher au HTTP.
L'injection de dépendances : le cœur du système
L'injection de dépendances (DI) est ce qui distingue NestJS d'Express. Au lieu d'importer directement vos dépendances :
// ❌ Express : import direct, couplage fort
import { UserRepository } from '../repositories/user.repository';
export function getUser(id: string) {
const repo = new UserRepository(); // impossible à mocker
return repo.findById(id);
}
NestJS injecte les dépendances via le constructeur :
// ✅ NestJS : injection, découplage, testabilité
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
) {}
async findById(id: string): Promise<User> {
return this.userRepository.findOneBy({ id });
}
}
Le conteneur IoC (Inversion of Control) de NestJS résout automatiquement les dépendances. Quand vous déclarez UserService comme provider d'un module, NestJS sait créer l'instance avec toutes ses dépendances résolues.
NestJS vs Express : ce que NestJS apporte
Voici une comparaison concrète sur un projet de taille moyenne (10+ routes, base de données, auth) :
- Structure : NestJS impose modules/controllers/services dès le départ. Express vous laisse libre — ce qui signifie que chaque projet a une structure différente.
- TypeScript natif : NestJS est écrit en TypeScript. Vous avez le typage, l'autocomplétion et la vérification à la compilation sans configuration supplémentaire.
- Testabilité : grâce à la DI, mocker une dépendance dans un test se fait en une ligne. En Express, il faut souvent contourner les imports.
- Écosystème intégré :
@nestjs/typeormpour la base de données,@nestjs/jwtpour l'auth,@nestjs/swaggerpour la doc — tout s'intègre de manière cohérente. - Documentation auto : Swagger génère une documentation interactive à partir de vos décorateurs. Elle est typiquement accessible à
/api/docs.
Les cas d'usage idéaux
NestJS est particulièrement adapté pour :
- APIs REST — c'est son terrain de jeu principal. La structure modulaire et les décorateurs rendent le code lisible et maintenable.
- Microservices — NestJS supporte nativement les transports TCP, Redis, NATS, gRPC via
@nestjs/microservices. - Applications temps réel — le support natif de WebSockets (via
@nestjs/websockets) permet de construire des applications interactives. - Applications fullstack — couplé à un frontend React/Next.js (comme Next.js ou React), NestJS fournit un backend solide et typé.
En revanche, pour un simple script, une CLI ou un prototype rapide, Express ou Fastify seul reste plus léger.
L'écosystème NestJS
Un projet de production typique utilise une bonne partie de l'écosystème officiel. Voici les packages clés et leur rôle :
{
"@nestjs/core": "11.0.1", // Le cœur du framework
"@nestjs/config": "4.0.2", // Gestion des variables d'environnement
"@nestjs/typeorm": "11.0.0", // Intégration TypeORM (PostgreSQL)
"@nestjs/jwt": "11.0.1", // Authentification JWT
"@nestjs/swagger": "11.2.3", // Documentation API auto-générée
"@nestjs/throttler": "6.4.0", // Rate limiting (anti-DDoS)
"@nestjs/serve-static": "5.0.1", // Servir les fichiers uploadés
"@nestjs-modules/mailer": "2.0.2" // Envoi d'emails
}
Ce qui frappe, c'est la cohérence : tous ces packages suivent les mêmes conventions, s'intègrent via le même système de modules, et se configurent de la même manière. Pas de surprise.
La CLI : productivité dès le premier jour
La CLI NestJS génère automatiquement les fichiers avec la bonne structure :
# Installer la CLI
npm install -g @nestjs/cli
# Créer un nouveau projet
nest new mon-projet
# Générer un module complet (controller + service + module + DTO)
nest generate resource booking
# Générer un composant isolé
nest generate controller users
nest generate service users
nest generate module users
La commande nest generate resource est particulièrement puissante : elle crée un module fonctionnel avec toutes les opérations CRUD prêtes à être complétées.
Pourquoi les entreprises adoptent NestJS
La vraie force de NestJS apparaît quand l'équipe grandit ou que le projet vieillit :
- Onboarding rapide : un nouveau développeur comprend la structure en 5 minutes. Chaque module a le même layout.
- Maintenabilité : modifier un module n'impacte pas les autres. Les dépendances sont explicites.
- Scalabilité : ajouter une fonctionnalité = créer un nouveau module. Un projet typique peut en avoir 18 et reste organisé.
- Tests : l'architecture facilite les tests unitaires et E2E. Le framework fournit
@nestjs/testingavec des utilitaires dédiés.
Conclusion
NestJS n'est pas juste "Express avec des décorateurs". C'est un changement de paradigme : au lieu de construire une structure ad-hoc qui finira par s'effondrer sous son propre poids, vous démarrez avec une architecture modulaire, typée et testable dès le premier fichier.
Un projet de production — avec ses 18 modules, son auth JWT, ses paiements Stripe, et sa doc Swagger — illustre ce que NestJS permet de construire de manière organisée. Dans les prochains articles, nous verrons comment créer un projet NestJS de zéro, puis comment implémenter chacune de ces briques.
Pour approfondir : documentation officielle NestJS.

Commentaires