CQRS (Command Query Responsibility Segregation)
Pattern architectural séparant les opérations de lecture et d'écriture pour optimiser performances, scalabilité et cohérence des systèmes complexes.
Mis à jour le 9 janvier 2026
CQRS (Command Query Responsibility Segregation) est un pattern architectural qui distingue clairement les opérations de modification (commandes) des opérations de consultation (requêtes) dans un système. Contrairement aux architectures traditionnelles où un même modèle gère lectures et écritures, CQRS propose d'utiliser des modèles distincts optimisés pour chaque type d'opération. Cette séparation permet d'adapter finement les stratégies de persistence, de mise en cache et de scalabilité selon les besoins spécifiques de chaque flux.
Fondements du pattern CQRS
- Séparation stricte entre Command Model (mutations) et Query Model (lectures), chacun avec sa propre logique métier
- Les commandes modifient l'état sans retourner de données, tandis que les requêtes retournent des données sans modifier l'état
- Possibilité d'utiliser des bases de données différentes pour lectures et écritures (write DB vs read DB optimisées)
- Synchronisation éventuelle entre les modèles via event sourcing, message queues ou mécanismes de réplication
Avantages métier et techniques
- Scalabilité indépendante : dimensionnement séparé des ressources de lecture (souvent majoritaires) et d'écriture
- Performances optimisées : bases dénormalisées pour lectures ultra-rapides, modèles normalisés pour cohérence en écriture
- Modèles métier simplifiés : chaque modèle se concentre sur un seul objectif, réduisant la complexité du domaine
- Sécurité renforcée : isolation des responsabilités facilitant l'application de permissions granulaires
- Évolutivité architecturale : ajout facile de nouvelles vues métier sans impacter le modèle d'écriture
Exemple d'implémentation avec NestJS
// Command : mutation d'état
export class CreateOrderCommand {
constructor(
public readonly userId: string,
public readonly items: OrderItem[],
public readonly shippingAddress: Address
) {}
}
@CommandHandler(CreateOrderCommand)
export class CreateOrderHandler implements ICommandHandler<CreateOrderCommand> {
constructor(
private readonly orderRepository: OrderRepository,
private readonly eventBus: EventBus
) {}
async execute(command: CreateOrderCommand): Promise<void> {
// Validation métier
const order = Order.create(command.userId, command.items, command.shippingAddress);
// Persistence dans le write model
await this.orderRepository.save(order);
// Publication d'événement pour synchronisation
this.eventBus.publish(new OrderCreatedEvent(order.id, order.totalAmount));
}
}// Query : lecture sans mutation
export class GetOrderSummaryQuery {
constructor(public readonly orderId: string) {}
}
@QueryHandler(GetOrderSummaryQuery)
export class GetOrderSummaryHandler implements IQueryHandler<GetOrderSummaryQuery> {
constructor(
private readonly orderReadRepository: OrderReadRepository // DB optimisée lecture
) {}
async execute(query: GetOrderSummaryQuery): Promise<OrderSummaryDTO> {
// Lecture depuis modèle dénormalisé
const summary = await this.orderReadRepository.findSummaryById(query.orderId);
if (!summary) {
throw new NotFoundException(`Order ${query.orderId} not found`);
}
return summary; // DTO pré-calculé, optimisé pour l'affichage
}
}Mise en œuvre dans un projet
- Identifier les bounded contexts où CQRS apporte une valeur (forte charge lecture/écriture asymétrique)
- Définir les commandes métier avec leurs validations et effets de bord (CreateOrder, UpdateInventory...)
- Concevoir les requêtes avec leurs DTOs optimisés pour les cas d'usage UI (OrderSummary, UserDashboard...)
- Implémenter le modèle d'écriture avec validation métier stricte et persistence transactionnelle
- Créer les projections pour le modèle de lecture (vues matérialisées, bases NoSQL dénormalisées)
- Mettre en place la synchronisation via événements (Event Sourcing ou CDC - Change Data Capture)
- Monitorer les délais de synchronisation pour garantir une cohérence éventuelle acceptable
Conseil architectural
N'appliquez pas CQRS systématiquement à toute l'application. Ce pattern brille dans les contextes avec forte asymétrie lecture/écriture (analytics, dashboards) ou besoins de scalabilité extrême. Pour des CRUD simples, la complexité ajoutée peut surpasser les bénéfices. Commencez par identifier 1-2 modules critiques et validez la pertinence avant généralisation.
Outils et frameworks associés
- NestJS CQRS Module : implémentation native avec @CommandHandler et @QueryHandler decorators
- MediatR (.NET) : bibliothèque de référence pour implémenter CQRS avec pattern Mediator
- Axon Framework (Java) : framework complet CQRS + Event Sourcing avec support distribué
- EventStoreDB : base de données optimisée pour Event Sourcing, souvent couplée avec CQRS
- PostgreSQL + Redis : stack classique (PostgreSQL write, Redis read cache/projections)
- Kafka / RabbitMQ : message brokers pour propager événements entre modèles write/read
CQRS transforme la manière de concevoir les systèmes en reconnaissant que lectures et écritures ont des contraintes fondamentalement différentes. En permettant une optimisation ciblée de chaque flux, ce pattern débloque des gains de performances mesurables (réduction latence lecture de 70-90%) et facilite la scalabilité horizontale. Pour les équipes gérant des systèmes à forte charge ou des domaines métier complexes, CQRS constitue un levier stratégique pour maintenir performance et maintenabilité à long terme.
