Book a 30-min callBook a call

Event sourcing and CQRS: storing what happened, not just the current state

How event sourcing and CQRS work: event streams and replay, projections, snapshots, upcasting, idempotent read models, GDPR deletion and when to avoid them.

A vertical stack of event blocks, an arrow into a box that replays them, and two arrows out to separate read-model tables.
Written by
BYD Tech
Published
Topic
Deep dives
Reading time
16 min read

Questions people ask

Is event sourcing the same as CQRS?

No. Event sourcing is about storage: the events are the record and state is derived from them. CQRS is about models: commands go to one, queries to another. CQRS works fine over an ordinary database, and an event-sourced system can use one model, but most event-sourced systems use CQRS because the event log cannot answer general queries.

Can Kafka be my event store?

It makes a good distribution layer, but Microsoft advises against using a broker such as Kafka as the event store itself, because brokers typically lack reads of one entity's stream and optimistic concurrency on append. A common setup keeps events in a store that has both and publishes them to a broker for consumers.

How do I fix a wrong event?

Append a compensating event that reverses or corrects it, and let projections pick it up or rebuild them. The original stays in the log, which preserves the audit trail. If the problem is the event's shape rather than its facts, handle it with an upcaster on read. Rewriting stored events is a last resort.

How often should I take snapshots?

Only when replay time is a measured problem, and then every N events, with N chosen by how long a load may take. Many aggregates never need one. Store the stream version with each snapshot, and treat snapshots as disposable: they can always be rebuilt from the events.

Do I need event sourcing just for an audit log?

Usually not. An append-only audit table written in the same transaction as each change, or change data capture from the database, records history without changing how the rest of the system reads and writes. Event sourcing earns its complexity when the history drives the domain itself: replay, temporal queries and new read models built from past events.

Building something like this?