Abubakr404
Back to blog

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.

CQRS with NestJS: A Practical Guide (Without the Ceremony) | Abubakr Hisham — Full-Stack Developer