CQRS with NestJS: A Practical Guide (Without the Ceremony)
April 22, 20267 min read
NestJSCQRSBackendPostgreSQL
The 80/20 of CQRS
CQRS simply separates commands (writes) from queries (reads). In NestJS, @nestjs/cqrs gives you a CommandBus and a QueryBus — that's all you need to start.
The structure I use
modules/articles/
├── articles.module.ts
├── articles.controller.ts
├── dto.ts
├── commands.ts # command classes + handlers
└── queries.ts # query classes + handlers
Controllers stay thin: they validate input with DTOs and dispatch to the bus.
@Post()
create(@Body() dto: CreateArticleDto) {
return this.commandBus.execute(new CreateArticleCommand(dto));
}
Why bother?
- Testability — handlers are tiny classes with one job.
- Clarity — every state change in the system has a named command.
- Growth path — when you need events, sagas, or separate read models, the seams already exist.
When to skip it
A 3-endpoint CRUD service doesn't need CQRS. Adopt it when your domain logic starts to branch — not before.