Architecture Patternshigh

Event Sourcing

Instead of storing the current state of an entity, event sourcing stores the full sequence of events that led to that state. Current state is derived by replaying the event log.

Memory anchor

Event sourcing = your bank statement. It doesn't store 'balance = $500' — it stores every deposit and withdrawal ever. Replay the list to get the balance.

Expected depth

The event store is append-only — events are immutable facts. The current aggregate state is reconstructed by folding events. Benefits: complete audit trail for free, ability to reconstruct state at any point in time (temporal queries), natural integration with CQRS projections, and event replay for debugging. Costs: increased storage, complex query patterns (you must build projections for any query beyond 'give me all events for aggregate X'), and schema evolution of past events is painful.

Deep — senior internals

Snapshot optimization: replaying thousands of events on every load is expensive. Periodically persist an aggregate snapshot alongside the event position, and on load, start from the latest snapshot then replay only subsequent events. Schema evolution of immutable events is the hardest problem in event sourcing. Strategies: upcasters (transform old event version to new version at read time), versioned event types (OrderPlacedV1, OrderPlacedV2), or weak schema (store JSON and handle missing fields gracefully). The event store must guarantee ordering and optimistic concurrency (reject a write if the expected aggregate version does not match current version) to prevent lost updates.

🎤Interview-ready answer

Event sourcing is justified when you have compliance requirements for a full audit log, need temporal query capability ('what was the state of account X at 3pm yesterday?'), or need to rebuild multiple different read projections from the same historical fact base. I pair it with snapshot every N events to bound replay time. For schema evolution I use upcasters in the event deserialization layer so consumers always receive the current schema version regardless of when the event was written.

Common trap

Using event sourcing as a general-purpose database pattern. It is a specialized tool. Exposing the raw event store directly as an API violates encapsulation — the event structure is an implementation detail of the aggregate, not a public API.

Related concepts