{
    "slug": "event_sourcing",
    "term": "Event Sourcing",
    "category": "architecture",
    "difficulty": "advanced",
    "short": "Storing state as an immutable sequence of domain events rather than the current snapshot — the current state is derived by replaying events.",
    "long": "Event Sourcing persists every state change as an immutable domain event (OrderPlaced, ItemAdded, PaymentProcessed) in an append-only event store. Current state is reconstructed by replaying the event stream. Benefits: complete audit trail, ability to reconstruct state at any point in time, temporal debugging, and natural fit with CQRS (events feed read model projections). Challenges: eventual consistency, snapshot strategies for long-lived aggregates, event schema evolution, and increased operational complexity. PHP implementations include EventSauce, Broadway, and Prooph.",
    "aliases": [
        "event store",
        "append-only log",
        "event-sourced architecture"
    ],
    "tags": [
        "architecture",
        "design-pattern",
        "cqrs",
        "ddd"
    ],
    "misconception": "Event sourcing and CQRS must always be used together. They complement each other well but are independent. You can use CQRS without event sourcing (separate read/write models backed by the same DB) and event sourcing without CQRS (single model rebuilt from events).",
    "why_it_matters": "Event sourcing stores every state change as an immutable event — the current state is derived by replaying events, providing a complete audit trail and enabling time-travel debugging.",
    "common_mistakes": [
        "Storing current state alongside events — the two will eventually diverge; current state must be derived from events.",
        "Modifying or deleting past events — events are immutable; use compensating events for corrections.",
        "No snapshot strategy for aggregates with thousands of events — replaying from the beginning becomes too slow.",
        "Using event sourcing for simple CRUD — the complexity is only justified when audit history, replay, or temporal queries add real value."
    ],
    "when_to_use": [
        "Audit-critical domains (finance, healthcare, legal) where every state change must be recorded and replayable.",
        "Systems that need time-travel debugging — replaying events to reproduce bugs at any point in history.",
        "Collaborative editing or conflict resolution where the sequence of changes matters.",
        "Decoupled read/write models (CQRS) where projections are built from the event stream."
    ],
    "avoid_when": [
        "Simple CRUD applications — event sourcing adds enormous complexity for no benefit when there is no need for history.",
        "Teams unfamiliar with the pattern — incorrect event schema design is very hard to reverse once events are stored.",
        "High-frequency write workloads where replaying thousands of events to rebuild state is too slow.",
        "When eventual consistency is unacceptable and reads must always reflect the latest write instantly."
    ],
    "related": [
        "cqrs",
        "domain_events",
        "domain_driven_design",
        "event_driven"
    ],
    "prerequisites": [
        "domain_events",
        "cqrs",
        "message_queue_patterns"
    ],
    "refs": [
        "https://martinfowler.com/eaaDev/EventSourcing.html"
    ],
    "bad_code": "// Mutable event store — breaks event sourcing guarantees:\nclass EventStore {\n    public function update(int $id, array $data): void {\n        $this->db->update('events', $data, ['id' => $id]); // Events must be immutable!\n    }\n}",
    "good_code": "// Events are the source of truth — state is derived by replaying them\nclass BankAccount {\n    private int $balance = 0;\n    private array $events = [];\n\n    public function deposit(int $amount): void {\n        $this->apply(new MoneyDeposited($amount));\n    }\n\n    private function apply(DomainEvent $event): void {\n        $this->events[] = $event;\n        match($event::class) {\n            MoneyDeposited::class  => $this->balance += $event->amount,\n            MoneyWithdrawn::class  => $this->balance -= $event->amount,\n        };\n    }\n\n    public function getEvents(): array { return $this->events; }\n    public function getBalance(): int  { return $this->balance; }\n}",
    "quick_fix": "Store every state change as an immutable event (OrderPlaced, PaymentReceived) — rebuild current state by replaying events, never update in place",
    "severity": "info",
    "effort": "high",
    "created": "2026-03-15",
    "updated": "2026-03-25",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/event_sourcing",
        "html_url": "https://codeclaritylab.com/glossary/event_sourcing",
        "json_url": "https://codeclaritylab.com/glossary/event_sourcing.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Event Sourcing](https://codeclaritylab.com/glossary/event_sourcing) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/event_sourcing"
            }
        }
    }
}