Event Sourcing with Kafka: Append-Only Truth, Snapshot Optimization & Schema Evolution
Event Sourcing stores the history of state changes — not current state — making the event log the single source of truth from which any projection can be derived. Master Kafka as the append-only event store, snapshot optimization against O(n) replay, and Avro schema evolution with the Confluent Schema Registry.
Distributed Architecture & System Design
Event Sourcing with Kafka: Append-Only Truth, Snapshot Optimization & Schema Evolution
Every boundary is a failure isolation decision — and one of the most profound boundaries in distributed system design is the boundary between the current state you store and the history of changes you discard. Traditional systems store rows in a users table and update them in place. When a bug corrupts 10,000 user records, you write a fix-up script, apply it, and hope nothing was missed. When a business analyst asks "what was the order status at 3PM on Tuesday?", the answer is "we don't have that data." Event Sourcing inverts this model: you store the full history of state changes — not current state — and current state is derived by replaying that history. This means you can answer any temporal query, reconstruct any point-in-time snapshot, and deploy a bug-fix by simply correcting the projection logic and replaying from the beginning.
Series positioning: This is Part 6 of the Distributed Architecture & System Design series. Building directly on the CQRS foundations established in Part 5: Separating Write Models from Read Projections, this article explores Event Sourcing, append-only domain event streams, snapshotting optimizations, and Avro schema evolution before examining projection engines in Part 7: Materialized Views & Event-Driven Projections.
1. The Event Store as Source of Truth

1.1 The Append-Only Event Log
In Event Sourcing, DELETE and UPDATE do not exist at the event level. Every business fact that happened is appended. To "undo" something, you append a compensating event: OrderCancelled after OrderPlaced. The history is preserved; the derived state reflects the compensation.
2. Implementing the Event Store with Kafka
2.1 Kafka as an Append-Only Event Store
2.2 Aggregate Reconstruction
3. Snapshot Optimization
As an aggregate accumulates events over time, O(n) replay becomes expensive. A snapshot captures current state at a version checkpoint, reducing reconstruction to O(snapshot_gap):
3.1 Snapshot Strategy
| Aggregate | Event Rate | Snapshot Threshold |
|---|---|---|
| Order (short lifecycle) | Low (5–10 events total) | Not required |
| User account (long-lived) | Medium (grows over years) | Every 100 events |
| Trading position (high-frequency) | Very high (thousands/day) | Every 500 events or 1 hour |

4. Schema Evolution & the Confluent Schema Registry
Domain events are permanent. Unlike database rows that you can migrate in place, published events that are stored in Kafka will be read by consumers weeks or months later. Schema evolution requires explicit versioning from day one.
4.1 Avro Schema Definition
4.2 Schema Compatibility Rules
| Change Type | Compatibility | Action |
|---|---|---|
| Add optional field with default | Backward + Forward ✅ | Safe to publish immediately |
| Add required field (no default) | Breaking ❌ | New schema version required |
| Remove existing field | Breaking ❌ | New schema version + migration period |
| Rename field | Breaking ❌ | Add new field, deprecate old with alias |
4.3 Schema Registry Integration
5. Event Sourcing Anti-Patterns
5.1 Mutable Events
5.2 Anemic Events
Summary
| Architectural Concern | Production Rule |
|---|---|
| Immutable Event Log | The source of truth is the ordered event history; current state is a derived artifact rehydrated on demand. |
| Self-Contained Events | Each event must carry all context required to reconstruct state; avoid forcing consumers to make re-queries. |
| Snapshot Optimization | Periodic snapshots cap $O(n)$ replay to $O(\text{snapshot_gap})$; mandatory for long-lived aggregates. |
| Schema Evolution | Add optional fields with defaults; enforce schema registry compatibility to prevent consumer deserialization failures. |
| Compensating Events | State corrections are appended as new domain events; the historical log is never mutated or deleted. |
What's Next
Now that we have explored event-sourced persistence and snapshot strategies, Part 7: Materialized Views & Event-Driven Projections examines how to maintain denormalized projection stores, execute blue-green rebuilds without downtime, and monitor projection lag.
This article was developed with AI-assisted deep search, specification cross-referencing, and technical research synthesis.