I once saw a codebase where a plain CRUD application claimed “we implemented CQRS.” A single “create user” operation had a Command, a CommandHandler, a separate read model, and a projection. All that ceremony ended in one line of INSERT.

CQRS buys real clarity in some systems. In this application, the only thing it bought was twice the code.

What CQRS is, briefly

CQRS — Command Query Responsibility Segregation — rests on a single idea: separate the write model from the read model.

In the classic approach a single model is both written and read — the same Order class both creates an order and renders it on screen. CQRS splits this in two: a write side that is a normalized model enforcing the rules; a read side that is a denormalized model shaped to the screen.

Note: this does not necessarily mean two databases. Most of the time it means two models — they can live in the same database.

Don’t confuse it with a read replica

A common confusion: people think CQRS and a read replica are the same thing. They are not.

  • A read replica (read/write splitting) is an infrastructure decision: same model, different server. To scale read load.
  • CQRS is a modeling decision: different model, same or different location. Because the shape of reads and writes has diverged.

You can use either one without the other. You can have a read replica but a single model; or do CQRS but on a single server.

What CQRS buys you

CQRS adds value when the write model and the read model genuinely diverge. That happens in complex domains: the shape you write drifts away from the shape you read.

The write side is a normalized model that enforces invariants and carries business rules. The read side is a model flattened to the needs of the screens, precomputed, fast to query. Forcing them into a single model makes both mediocre.

Dead weight in plain CRUD

Here’s the problem: in a plain CRUD application the write model and the read model are already the same — both are that row itself. Applying CQRS there is modeling a distinction that doesn’t exist.

The result: two models, two structures that must be kept in sync, twice the code — and zero gain in return. This is speculative generality at the scale of a pattern: paying today for a complexity that doesn’t exist today.

Lightweight CQRS

To “do” CQRS you don’t need event sourcing, separate databases, or projection infrastructure. Those are the heaviest form of CQRS, not its mandatory form.

A lightweight start: leave the write side on plain Eloquent models, and for the read side write a separate query class that returns a DTO shaped to the screen. The write and read paths are separated in code — which is the essence of CQRS already. Move to the heavy infrastructure only when you actually need it.

When you really need it

To take CQRS seriously, you should see these signals:

  • High domain complexity — the write side carries serious business rules (the kind of domain where Clean Architecture adds value).
  • The shape and load of reads and writes are markedly different.
  • Most often alongside event-driven architecture — the read model is updated by events emitted from the write side.

Without these signals, a single model with a separate read query when needed is more than enough.


CQRS is not a maturity badge; it’s the solution to a specific problem — reads and writes genuinely diverging. If you don’t have that problem, the only thing it buys you is the burden of keeping a second model in sync.

Before you split the model, look at whether your reads and writes are truly separate.