# Microservices NestJS en 2026 : Architecture gRPC, Streaming et Questions d'Entretien Technique > Guide pratique sur l'architecture microservices NestJS avec gRPC : couches de transport, Protocol Buffers, patterns de streaming et questions d'entretien pour développeurs backend en 2026. - Published: 2026-05-26 - Updated: 2026-05-26 - Author: SharpSkill - Tags: nestjs, microservices, grpc, nodejs, typescript, architecture - Reading time: 9 min --- Les microservices NestJS se sont imposés comme l'approche de référence pour construire des backends Node.js distribués en 2026. Avec la couche de transport améliorée de NestJS 11, le support natif de gRPC et la propagation automatique des identifiants de trace, le framework fournit tout le nécessaire pour découper un monolithe en services bien délimités sans sacrifier l'expérience développeur. > **gRPC ou REST pour les services internes ?** > > gRPC utilise les Protocol Buffers et HTTP/2, offrant une sérialisation jusqu'à 10 fois plus rapide et du streaming bidirectionnel natif par rapport à JSON sur REST. Pour la communication inter-services au sein d'un cluster, gRPC réduit la latence et impose des contrats stricts via les fichiers `.proto`. REST reste le meilleur choix pour les API publiques consommées par les navigateurs et les tiers. ## Architecture de la couche de transport des microservices NestJS Le package `@nestjs/microservices` remplace les contrôleurs HTTP par des handlers orientés messages. Au lieu du routage par chemin d'URL, chaque handler répond à un **pattern de message** — une clé de type chaîne ou objet qui identifie l'opération. Cette abstraction permet au même code de fonctionner avec TCP, Redis, NATS, Kafka, RabbitMQ ou gRPC sans modification. NestJS 11 a introduit la méthode `unwrap()` sur tous les transporteurs, donnant un accès direct à l'instance client sous-jacente. Cela résout un problème récurrent : inspecter l'état de connexion, ajuster les intervalles de keepalive ou accéder à des fonctionnalités spécifiques au broker que l'abstraction NestJS n'expose pas. Deux patterns de communication structurent les microservices NestJS : - **Requête-réponse** (`@MessagePattern`) : le client envoie un message et attend une réponse. Adapté aux requêtes synchrones comme la récupération d'un profil utilisateur ou la validation d'un token. - **Événementiel** (`@EventPattern`) : le client émet un événement et poursuit son exécution — aucune réponse attendue. Idéal pour les journaux d'audit, les notifications ou le déclenchement de workflows en aval. ```typescript // orders.controller.ts import { Controller } from '@nestjs/common'; import { MessagePattern, EventPattern, Payload } from '@nestjs/microservices'; import { OrdersService } from './orders.service'; import { CreateOrderDto } from './dto/create-order.dto'; @Controller() export class OrdersController { constructor(private readonly ordersService: OrdersService) {} // Requête-réponse : l'appelant attend la commande créée @MessagePattern('order.create') async createOrder(@Payload() data: CreateOrderDto) { return this.ordersService.create(data); } // Événementiel : fire and forget, aucune réponse retournée @EventPattern('order.shipped') async handleOrderShipped(@Payload() data: { orderId: string }) { await this.ordersService.markAsShipped(data.orderId); } } ``` Le handler `@MessagePattern` sérialise automatiquement la valeur de retour et la renvoie via le transport. Le handler `@EventPattern` ne renvoie rien — NestJS ignore toute valeur de retour. ## Configuration de gRPC comme transport microservices NestJS L'intégration gRPC dans NestJS commence par un fichier `.proto` qui définit le contrat de service. Les Protocol Buffers imposent la sécurité de type au niveau du fil — le client et le serveur doivent s'accorder sur la forme exacte de chaque message avant qu'un seul octet ne transite sur le réseau. ```protobuf // proto/users.proto syntax = "proto3"; package users; service UsersService { rpc FindOne (UserById) returns (User); rpc FindMany (UserFilter) returns (stream User); } message UserById { string id = 1; } message UserFilter { string role = 1; int32 limit = 2; } message User { string id = 1; string email = 2; string name = 3; string role = 4; } ``` Côté serveur, l'application NestJS démarre un microservice gRPC en pointant vers le fichier proto et en liant une adresse réseau : ```typescript // main.ts import { NestFactory } from '@nestjs/core'; import { MicroserviceOptions, Transport } from '@nestjs/microservices'; import { join } from 'path'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.createMicroservice( AppModule, { transport: Transport.GRPC, options: { package: 'users', protoPath: join(__dirname, 'proto/users.proto'), url: '0.0.0.0:5000', }, }, ); await app.listen(); } bootstrap(); ``` Le contrôleur utilise `@GrpcMethod` au lieu de `@MessagePattern`. Le décorateur prend le nom du service et le nom de la méthode RPC comme arguments, se mappant directement à la définition proto : ```typescript // users.controller.ts import { Controller } from '@nestjs/common'; import { GrpcMethod } from '@nestjs/microservices'; import { UsersService } from './users.service'; @Controller() export class UsersController { constructor(private readonly usersService: UsersService) {} @GrpcMethod('UsersService', 'FindOne') async findOne(data: { id: string }) { return this.usersService.findById(data.id); } } ``` NestJS gère automatiquement le chargement des proto, la sérialisation et la gestion des connexions HTTP/2. La méthode du contrôleur reçoit des objets TypeScript classiques — aucun décodage proto manuel nécessaire. ## Patterns de streaming gRPC dans NestJS Le streaming serveur convient aux scénarios où une seule requête produit plusieurs résultats dans le temps — flux de prix en temps réel, curseurs de base de données paginés ou mises à jour de progression pendant une tâche longue. Le handler retourne un `Observable` RxJS, et NestJS transmet chaque valeur émise au client sous forme de message gRPC distinct : ```typescript // users.controller.ts — streaming serveur import { Observable, from } from 'rxjs'; import { map } from 'rxjs/operators'; import { GrpcMethod } from '@nestjs/microservices'; @GrpcMethod('UsersService', 'FindMany') findMany(data: { role: string; limit: number }): Observable { // Diffuse les utilisateurs correspondant au filtre un par un const users$ = from(this.usersService.findByRole(data.role, data.limit)); return users$.pipe( map((user) => ({ id: user.id, email: user.email, name: user.name, role: user.role, })), ); } ``` Le streaming bidirectionnel utilise `@GrpcStreamCall()`. Le client et le serveur envoient des flux indépendants — utile pour les systèmes de chat, l'édition collaborative ou l'ingestion de télémétrie multiplexée. Le handler reçoit une instance `grpc.ServerDuplexStream` et gère manuellement le cycle lecture/écriture. > **Gestion des erreurs en streaming** > > Un Observable qui plante à l'intérieur d'un flux gRPC termine l'appel entier avec un statut `CANCELLED`. Il est nécessaire d'encapsuler la logique de streaming dans des opérateurs `catchError` et d'émettre des métadonnées d'erreur adaptées à gRPC. Les erreurs de flux non gérées sont la cause première des coupures de connexion inexpliquées dans les services gRPC NestJS en production. ## Applications hybrides : HTTP et gRPC sur le même service De nombreux services NestJS en production nécessitent à la fois une API REST publique et des endpoints gRPC internes. Le [pattern d'application hybride](https://docs.nestjs.com/faq/hybrid-application) connecte plusieurs transports à une seule instance NestJS : ```typescript // main.ts — application hybride import { NestFactory } from '@nestjs/core'; import { MicroserviceOptions, Transport } from '@nestjs/microservices'; import { join } from 'path'; import { AppModule } from './app.module'; async function bootstrap() { // Serveur HTTP sur le port 3000 const app = await NestFactory.create(AppModule); // Microservice gRPC sur le port 5000 app.connectMicroservice({ transport: Transport.GRPC, options: { package: 'users', protoPath: join(__dirname, 'proto/users.proto'), url: '0.0.0.0:5000', }, }); await app.startAllMicroservices(); await app.listen(3000); } bootstrap(); ``` Cette approche évite de déployer des services séparés lorsqu'un seul contexte délimité nécessite des interfaces externes et internes. Le même conteneur d'injection de dépendances, les mêmes guards, intercepteurs et pipes s'appliquent aux deux transports — réduisant la duplication et maintenant un comportement cohérent. ## Limites de services et conception pilotée par le domaine avec NestJS Découper un monolithe en microservices sans limites claires crée un monolithe distribué — le pire des deux architectures. Chaque microservice NestJS doit posséder un seul [contexte délimité](https://martinfowler.com/bliki/BoundedContext.html) : sa propre base de données, ses propres modèles de domaine et son propre cycle de déploiement. Principes pratiques pour définir les limites de services dans NestJS : - **Un module NestJS par racine d'agrégat.** Si `Order` et `OrderLine` changent toujours ensemble, ils appartiennent au même service. Si `User` et `Order` changent indépendamment, ils méritent des services séparés. - **Des événements asynchrones pour les effets de bord inter-domaines.** Lorsqu'une commande est passée, un événement `order.created` est émis via Kafka ou RabbitMQ. Le service d'inventaire réagit sans que le service de commandes ne connaisse son existence. - **Des packages proto partagés pour les contrats.** Les fichiers `.proto` sont stockés dans un dépôt partagé. Le producteur et le consommateur génèrent les types depuis la même source de vérité — la dérive devient un échec CI, pas un incident en production. Les options microservices de NestJS 11 depuis le conteneur DI rendent la configuration des services testable. Au lieu de coder en dur les URLs des brokers dans `main.ts`, il suffit d'injecter un `ConfigService` et de changer les chaînes de connexion par environnement sans reconstruire. ## Patterns de fiabilité : Timeouts, Retries et Circuit Breakers Les appels gRPC internes sans deadline transforment une seule dépendance lente en panne système généralisée. Chaque appel `ClientProxy.send()` doit inclure un timeout : ```typescript // orders.service.ts import { Inject, Injectable } from '@nestjs/common'; import { ClientGrpc } from '@nestjs/microservices'; import { firstValueFrom, timeout, retry } from 'rxjs'; @Injectable() export class OrdersService { private usersService: any; constructor(@Inject('USERS_PACKAGE') private client: ClientGrpc) {} onModuleInit() { this.usersService = this.client.getService('UsersService'); } async getOrderWithUser(orderId: string, userId: string) { // Deadline de 3 secondes, 2 retries avec backoff exponentiel const user = await firstValueFrom( this.usersService.findOne({ id: userId }).pipe( timeout(3000), retry({ count: 2, delay: (err, retryCount) => { const jitter = Math.random() * 100; return new Promise(r => setTimeout(r, 1000 * retryCount + jitter)); }}), ), ); return { orderId, user }; } } ``` Les retries ne doivent s'appliquer qu'aux opérations idempotentes. Rejouer un appel `CreateOrder` risque de créer des commandes en double. Rejouer une requête `FindOne` est sans danger car elle n'a aucun effet de bord. Pour la fonctionnalité de circuit breaker, la bibliothèque [opossum](https://github.com/nodeshift/opossum) s'intègre bien avec NestJS. Il suffit d'encapsuler les appels `ClientGrpc` dans un circuit breaker qui s'ouvre après N échecs consécutifs et se referme après un timeout de réinitialisation configurable. > **Propagation de traces dans NestJS 11** > > NestJS 11 propage automatiquement les identifiants de trace à travers les transports Kafka, RabbitMQ et gRPC. Combiné avec [OpenTelemetry](https://opentelemetry.io/docs/languages/js/), cela permet un traçage distribué complet sans intercepteurs personnalisés — une amélioration significative par rapport à NestJS 10 où la propagation manuelle du contexte était nécessaire. ## Questions d'entretien technique sur les microservices NestJS Les entretiens techniques pour les postes backend testent de plus en plus les connaissances en microservices aux côtés des patterns spécifiques au framework. Ces questions couvrent les concepts les plus fréquemment posés lors des entretiens orientés NestJS. **Quelle est la différence entre `@MessagePattern` et `@EventPattern` ?** `@MessagePattern` implémente le pattern requête-réponse : le client envoie un message et bloque jusqu'à recevoir une réponse. `@EventPattern` implémente le pattern fire-and-forget : le client émet un événement et poursuit immédiatement son exécution. En interne, `@MessagePattern` retourne le résultat du handler via le transport, tandis que `@EventPattern` ignore les valeurs de retour. **Comment NestJS charge-t-il et lie-t-il les fichiers `.proto` pour gRPC ?** NestJS utilise le package `@grpc/proto-loader` pour parser les fichiers `.proto` au démarrage et générer les descripteurs de service. La configuration `GrpcOptions` spécifie le chemin du proto et le nom du package. Les contrôleurs annotés avec `@GrpcMethod('ServiceName', 'MethodName')` sont associés aux descripteurs parsés. Si une méthode déclarée dans le proto n'a pas de handler correspondant, NestJS lève une erreur au démarrage. **Quand gRPC doit-il remplacer REST entre microservices ?** gRPC est adapté aux appels internes entre services où la sécurité de type, la performance et le streaming importent. Les Protocol Buffers produisent des payloads plus compacts et une sérialisation plus rapide que JSON. Le multiplexage HTTP/2 réduit la surcharge de connexion. REST reste préférable pour les API publiques, les clients navigateur et les intégrations tierces où la lisibilité humaine et le large support d'outillage l'emportent sur les performances brutes. **Comment fonctionne le pattern d'application hybride ?** `NestFactory.create()` démarre un serveur HTTP. L'appel à `app.connectMicroservice()` attache des transports supplémentaires — gRPC, Kafka, Redis ou tout transporteur supporté — à la même instance NestJS. Tous les transports partagent le même arbre de modules, le même conteneur DI et le même pipeline de middleware. `app.startAllMicroservices()` démarre tous les transporteurs connectés, et `app.listen()` démarre la couche HTTP. **Quels patterns de fiabilité préviennent les pannes en cascade ?** Trois patterns sont essentiels : les **timeouts** (chaque appel RPC nécessite une deadline), les **retries avec jitter** (uniquement pour les opérations idempotentes, avec backoff exponentiel plus jitter aléatoire pour éviter les effets de troupeau), et les **circuit breakers** (ouverts après N échecs, semi-ouverts après un délai de refroidissement, fermés une fois les vérifications de santé réussies). L'intégration RxJS de NestJS rend les timeouts et retries composables via les opérateurs pipe. Pour approfondir les patterns d'architecture NestJS, le module [modules et injection de dépendances NestJS](/technologies/node-nestjs/interview-questions/nestjs-modules-di) couvre les fondamentaux DI qui sous-tendent la composition des microservices. Le module [middleware et intercepteurs](/technologies/node-nestjs/interview-questions/middleware-interceptors) aborde les préoccupations transversales partagées entre les transports. ## Conclusion - L'abstraction de transport de NestJS 11 permet aux services de basculer entre TCP, gRPC, Kafka et NATS sans réécrire la logique des handlers — les décorateurs `@MessagePattern` et `@EventPattern` fonctionnent de manière identique sur tous les transports - gRPC avec les Protocol Buffers impose des contrats stricts entre services via les fichiers `.proto`, détectant les erreurs d'intégration à la compilation plutôt qu'en production - Les applications hybrides combinent HTTP et gRPC sur la même instance NestJS, éliminant le besoin de déployer des services séparés pour les interfaces publiques et internes - Le streaming serveur via les Observables RxJS permet des flux de données en temps réel sans la complexité des WebSockets — NestJS mappe chaque émission Observable vers un message de flux gRPC - Chaque appel RPC interne nécessite une deadline, les retries ne s'appliquent qu'aux opérations idempotentes, et les circuit breakers empêchent un seul service lent de provoquer une panne en cascade - Les limites de services suivent la conception pilotée par le domaine : un contexte délimité par service, des événements asynchrones pour la communication inter-domaines, des packages proto partagés pour l'application des contrats --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/fr/blog/node-nestjs/nestjs-microservices-grpc-architecture