Skip to content
Event Sourcing — Explained with Examples

Event Sourcing — Explained with Examples

DodaTech Updated Jun 15, 2026 2 min read

Event Sourcing stores state changes as an append-only sequence of events rather than overwriting the current state, preserving full audit history.

Event Sourcing is a pattern where every change to an application’s state is captured as an immutable event. The current state is derived by replaying all events. This contrasts with traditional CRUD where the latest state overwrites the previous one.

Why Event Sourcing Matters

Traditional systems lose historical data every time a record is updated. You can’t answer “what did the user see at that moment?” or “what changed between Tuesday and Wednesday?” Event Sourcing provides a complete audit trail, temporal queries, and the ability to reconstruct past states for debugging or compliance.

Real-World Analogy

A bank statement versus a ledger. A traditional CRUD system is like looking at your current balance — you know how much you have but not how you got there. Event Sourcing is like the full transaction history — every deposit, withdrawal, and fee is recorded, and your balance is computed by replaying all transactions.

Example: Event Sourcing

from dataclasses import dataclass, field
from typing import List

@dataclass
class Event:
    type: str
    data: dict

class BankAccount:
    def __init__(self):
        self.events: List[Event] = []
        self.balance = 0

    def deposit(self, amount: int):
        event = Event("deposited", {"amount": amount})
        self.events.append(event)
        self._apply(event)

    def withdraw(self, amount: int):
        if self.balance >= amount:
            event = Event("withdrew", {"amount": amount})
            self.events.append(event)
            self._apply(event)
        else:
            raise ValueError("Insufficient funds")

    def _apply(self, event: Event):
        if event.type == "deposited":
            self.balance += event.data["amount"]
        elif event.type == "withdrew":
            self.balance -= event.data["amount"]

    def replay(self):
        """Rebuild state from events only"""
        self.balance = 0
        for event in self.events:
            self._apply(event)

# Usage
acct = BankAccount()
acct.deposit(100)
acct.withdraw(30)
print(f"Balance: ${acct.balance}")  # Output: Balance: $70

# Full history
for e in acct.events:
    print(f"{e.type}: {e.data}")
# Output:
# deposited: {'amount': 100}
# withdrew: {'amount': 30}

Related Terms

CQRS, CRUD, Repository Pattern

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro