Event Sourcing in Python — Core Concepts

What event sourcing is

In traditional applications, you store the current state of an entity — a row in a database that gets updated in place. Event sourcing takes a different approach: you store every state change as an immutable event and derive the current state by replaying those events.

The event store is an append-only log. Events are never modified or deleted. This gives you a complete audit trail and the ability to reconstruct state at any point in time.

How it works

Writing: capture events instead of state

When a user places an order, instead of inserting an orders row with status = "placed", you append an OrderPlaced event. When payment arrives, you append PaymentReceived. When it ships, OrderShipped.

Reading: replay events to build state

To get the current state of an order, load all events for that order and apply them in sequence:

OrderPlaced    → status: placed, items: [book]
ItemAdded      → status: placed, items: [book, pen]
PaymentReceived → status: paid, items: [book, pen]
OrderShipped   → status: shipped, items: [book, pen]

The result is identical to what a traditional system would store — but you also have the complete history.

Key components

Events

Immutable records of things that happened. Each event has a type, a timestamp, and a payload. Events are named in past tense: OrderPlaced, not PlaceOrder.

Event store

A persistence layer optimized for append-only writes and ordered reads. It can be a specialized database (EventStoreDB), a regular PostgreSQL table with an append-only pattern, or even Kafka.

Aggregates

Business objects that produce and consume events. An aggregate loads its history from the event store, applies each event to rebuild its state, then processes new commands and emits new events.

Projections

Read models built by processing events. While the event store is the source of truth, projections create optimized views for querying. A “customer orders dashboard” projection might maintain a denormalized table updated whenever order events occur.

Snapshots

Performance optimization for aggregates with long event histories. Instead of replaying thousands of events, periodically save the aggregate’s current state as a snapshot. On load, start from the snapshot and replay only subsequent events.

Benefits

  • Complete audit trail — Every change is recorded. Critical for finance, healthcare, and compliance-heavy domains.
  • Temporal queries — “What was the inventory level on January 15th?” Replay events up to that date.
  • Debugging — Reproduce any bug by replaying the exact sequence of events that caused it.
  • Event-driven integration — Other services can subscribe to the event stream without coupling to your internal state.

Challenges

  • Complexity — More moving parts than a simple CRUD system. Projections, event versioning, and eventual consistency require careful design.
  • Schema evolution — When event structures change over time, you need migration strategies (upcasting, versioned events).
  • Eventual consistency — Projections are updated asynchronously, so reads may be slightly behind writes.
  • Storage growth — The event log grows forever. Snapshots and archiving strategies help manage this.

Common misconception

“Event sourcing means you never use a regular database.” Not true. Event sourcing defines how you persist state changes. You still use projections (often backed by SQL databases) for querying. The event store supplements rather than replaces traditional databases.

When to use event sourcing

It shines in domains where audit trails, temporal queries, or event-driven integration are requirements — not nice-to-haves. Financial systems, logistics platforms, and collaborative editing tools are classic candidates.

For simple CRUD applications where history does not matter, traditional state-based persistence is simpler and more appropriate.

The one thing to remember: Event sourcing replaces “save current state” with “record what happened” — giving you a complete, immutable history that can reconstruct any past state on demand.

pythonarchitectureevent-sourcing

See Also