Why architecture matters here
The architecture matters because reads and writes have fundamentally different requirements, and a shared model is a permanent compromise between them. Writes are about correctness: they must enforce invariants, avoid race conditions, and keep the data normalized so there is one authoritative place for each fact. Reads are about presentation and speed: they want data pre-joined and denormalized into exactly the shape a screen needs, so a query is a single fast lookup rather than a sprawling join. Forcing both onto one schema means every read pays for the write model's normalization and every write is complicated by the read model's denormalization. Splitting them lets each be optimal.
It matters because reads and writes scale independently and usually asymmetrically. Most systems read far more than they write — often by orders of magnitude — and the two loads want different resources: writes need a consistent, transactional store that is hard to scale horizontally, while reads can be served from replicas, caches, and search indexes that scale out cheaply. With one model you scale the whole thing to the harder of the two demands. With CQRS you scale the read side wide and independently, adding read models and replicas without touching the write path's consistency guarantees.
It matters because multiple read models unlock query patterns a single schema cannot serve well. The same order data might need to appear in a customer's order history (a document keyed by user), in an operations dashboard (aggregated by status and time), and in a full-text search (an inverted index). No single normalized schema serves all three efficiently. In CQRS each is a separate read model, each a projection of the same events, each independently optimized and independently rebuildable. Adding a fourth view later is a matter of writing a new projector and replaying history, not a schema migration on the write path.
Finally, it matters because CQRS forces you to confront consistency as an explicit design parameter rather than an accident. In a single-model system the read-after-write guarantee is implicit and total, and applications lean on it without thinking. CQRS makes the read side eventually consistent, which surfaces the question every distributed system must eventually answer: which operations truly need to see their own writes immediately, and which can tolerate a small lag? That question is uncomfortable but honest, and answering it deliberately produces a more robust system than pretending strong consistency is free. The discipline CQRS imposes is also its main cost, which is why it should be applied where the asymmetry is real and avoided where it is not.
The architecture: every piece explained
The client issues two fundamentally different kinds of request: commands that intend to change state and queries that intend to read it. Recognizing that split at the API boundary is the first move in CQRS — commands and queries travel down entirely separate paths from here on, and conflating them is what the pattern is designed to prevent.
The command side receives a command, validates it against business rules, and applies the change to the write store — a normalized, strongly consistent database that is the single source of truth. Here is where invariants live: an order cannot be paid twice, a balance cannot go negative, a username must be unique. Having committed the change, the command side emits events that describe what actually happened — OrderPlaced, PaymentCaptured — as immutable facts rather than instructions.
Those events travel over an event bus or log, an ordered, durable stream that both decouples the write side from the read side and provides the replayable history that makes read models rebuildable. Projectors subscribe to this stream and apply each event to the read models — a projector is a small, focused piece of logic that knows how one event should update one view. Because the log preserves order and history, a projector can be pointed at the beginning to rebuild its view from scratch.
The read models are the payoff: each is denormalized and tuned for a specific query. Read model A might be a document store shaped exactly like a screen, read model B a search index or a cache. They are derived data — never authoritative — so they can be dropped and rebuilt from the event log at any time. The query side serves reads exclusively from these views and never touches the write store, which keeps read load off the consistency-critical path and lets the read models scale independently.
The unavoidable consequence, called out in the diagram, is eventual consistency: a read model reflects a write only after the event has propagated and the projector has applied it, so the read side lags the write side by the projection latency. The ops strip names the disciplines that keep this manageable — accept the read lag as a design parameter, make projectors idempotent and replayable, version events so their schema can evolve, rebuild views from the log when they drift or corrupt, and monitor projection lag as a first-class metric.
End-to-end flow
Follow a command. A customer clicks 'place order,' and the client sends a PlaceOrder command to the command side. The command handler loads the relevant state from the write store, checks the business rules — is the item in stock, is the payment method valid, is this not a duplicate submission — and, if everything holds, writes the new order into the normalized write store within a transaction. The source of truth now reflects the order.
Having committed, the command side emits an OrderPlaced event capturing what happened: the order id, the customer, the items, the timestamp. This event is appended to the event log, durably and in order relative to other events. The command side's job is now done; it returns success to the client. Crucially, at this instant the read models do not yet know about the order — the event has been recorded but not yet projected.
Downstream, the projectors consume the OrderPlaced event asynchronously. The order-history projector inserts a denormalized record into the customer's order-history view; the dashboard projector increments the day's order count; the search projector indexes the order's contents. Each projector updates its own read model independently, and each does so idempotently, so that if the event is delivered twice the view is not double-counted. Within a short window — milliseconds to seconds — all the read models reflect the new order.
Now follow a query. The customer navigates to their order history, and the client sends a query to the query side, which reads directly from the order-history read model — a single fast lookup against a view already shaped like the page. No joins, no touching the write store, no contention with the write path. If the customer queries immediately after placing the order, they may briefly not see it, because the projector has not yet caught up; this is the eventual-consistency window in action, and well-designed clients either tolerate it or use a targeted read-your-writes technique for the narrow cases that cannot.
The replay flow shows why the log is central. Suppose you want a new analytics read model, or an existing view is found to be corrupted by a projector bug. You deploy a fixed or new projector, point it at the start of the event log, and let it replay the entire history of events into a freshly built view. Because the events are the authoritative record and the read models are merely derived, rebuilding is always possible — the read side has no unique state that could be lost. That property, more than anything, is what makes CQRS resilient: any read model can be regenerated from the one source of truth, the event log.