Learn when event sourcing and CQRS are worth their extra complexity in Clojure microservices, how write and read models diverge, and where teams usually overapply them.
Event sourcing: A pattern where the source of truth is a sequence of domain events rather than only the latest stored state.
CQRS: A pattern that separates the write model from the read model so commands and queries can evolve differently.
These patterns can be extremely valuable, but they also add real cost. They are strongest when the domain benefits from an event log, auditability, projections, or independently optimized read models. They are weaker when the team mainly wants trendy architecture language for a straightforward CRUD system.
In a typical CRUD system, the database row is the source of truth. In an event-sourced system, the durable event stream becomes the source of truth, and current state is reconstructed by applying those events in order.
That gives you:
It also gives you:
CQRS is often paired with event sourcing, but it does not require it. The important idea is that the model used to validate and process writes may not be the same model used to answer reads efficiently.
That is useful when:
It is less useful when one straightforward model already serves both sides well.
The real benefit is not ceremony. It is clarity:
That pipeline can be powerful in domains with audit requirements, workflow history, or heavy read-model variation.
1(defn apply-event [state event]
2 (case (:event/type event)
3 :account-opened (assoc state :account/id (:account/id event)
4 :balance 0)
5 :money-deposited (update state :balance + (:amount event))
6 :money-withdrawn (update state :balance - (:amount event))
7 state))
8
9(defn replay [events]
10 (reduce apply-event {} events))
That code is intentionally small. The key idea is that state is derived from events rather than updated in place without a durable history.
As event streams grow, replaying from the beginning for every load becomes impractical. That is where snapshots help. They shorten rebuild time by storing a derived state checkpoint.
Projections serve a different purpose: they build read models tailored to consumer needs. A projection is not the source of truth. It is a derived view optimized for a query shape or downstream use case.
If the system does not truly need event history or multiple derived views, the added machinery may not pay for itself.
Events should reflect meaningful domain facts, not every incidental code step.
Event schema changes, replay behavior, and projection versioning become major concerns once the system lives long enough.
Choose event sourcing when history and replay are core to the domain. Choose CQRS when write behavior and read shape genuinely diverge. Use projections as derived views, not as hidden alternate sources of truth. If a simpler CRUD model already meets the business need, simplicity usually wins.