Event Sourcing
Instead of storing only an entity’s current state (Order.status = "SHIPPED"), store every state change as an immutable event in an append-only store. The event store is the system of record; current state is derived from it. Martin Fowler’s formulation: “capture all changes to an application state as a sequence of events”. Often paired with cqrs, but independent of it.
How it works
- Application code raises events named in the past tense and in domain language, such as
OrderPlaced,PaymentReceived,OrderShipped. - Each entity has its own event stream, an ordered sequence of its events.
- To get current state, the system rehydrates the entity by replaying its stream (from the start or from a saved snapshot).
- Because replay is costly for reads, systems keep materialised views / projections, read-only stores updated by event handlers.
- Other handlers can react to the same events to integrate with external systems; producers do not know their consumers.
What it gives you
- Audit trail by construction: you can see how the state came about, not just where it is (Fowler’s “where it’s been”).
- Complete rebuild, temporal queries, retroactive correction (Fowler): discard derived state and re-run events; compute state at any past time; replay with corrected logic.
- Write throughput: append-only writes avoid the row-level lock contention of update-in-place (Microsoft).
- Concurrency: handlers rehydrate state before appending, and the event store uses optimistic concurrency control, rejecting an append if the stream changed since it was read; the handler reloads, re-evaluates and retries. (The “prevents conflicts” claim therefore means conflicts are detected and retried, not absent.)
- Compensating events keep a visible history of reversals instead of overwriting.
- Decoupling and analytics: events can feed other services, behaviour analysis and debugging.
Costs (Microsoft’s own warning)
Microsoft marks this “a complex pattern that introduces significant trade-offs”: it changes how data is stored, how concurrency and schema evolution work, and how state is queried; migrating to or from it is costly, and it constrains later design. “For most systems and most parts of a system, traditional data management is sufficient.” Typical costs:
- Eventual consistency between the event store and read models.
- More storage and snapshotting/replay machinery.
- Event schema evolution: old events live forever, so versioning matters.
- Low-level events may need translating into business-level ones for consumers.
- Harder ad-hoc querying of current state without projections.
With CQRS
The write side (command handlers) loads the stream, applies business rules and appends events; the read side serves queries from projections kept up to date asynchronously. Microsoft’s diagram shows exactly this flow, and its CQRS page adds that the combination is where complexity grows most. See cqrs.
Fit (opinion)
Choose it where history is itself a requirement (finance, ledgers, compliance, order lifecycles) and apply it to one bounded context, not the whole system. For AI agents the same idea shows up as an append-only log of actions and tool calls that can be replayed or audited; durable-execution engines such as temporal use event histories in a related way.
Related
Sources (read 2026-10-09)
- https://learn.microsoft.com/en-us/azure/architecture/patterns/event-sourcing
- https://martinfowler.com/eaaDev/EventSourcing.html (2005; Fowler notes it is draft material)
- https://martinfowler.com/bliki/CQRS.html