Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

sourcery provides building blocks for pragmatic event-sourced systems in Rust. It keeps your domain types pure while giving you tools to rebuild state, project read models, and persist events through a pluggable store interface.

When to Use Event Sourcing

Event sourcing shines when you need:

  • Complete audit trails — every state change is recorded
  • Time travel — reconstruct state at any point in history
  • Decoupled read models — optimize queries independently of writes
  • Complex domain logic — model behavior as a sequence of facts

It adds complexity, so consider simpler approaches for CRUD-heavy applications with minimal business logic.

What This Crate Provides

IncludedNot Included
Core traits for aggregates, events, projectionsCommand bus / message broker
Derive macro to reduce boilerplateOutbox pattern
Repository for command executionSnapshot scheduler
In-memory store for testingEvent streaming infrastructure
PostgreSQL store (optional)
Test framework (given-when-then)

The crate is intentionally minimal. You wire the repository into whichever pipeline you prefer—whether that’s a web framework, actor system, or CLI tool.

A Taste of the API

#[derive(Aggregate)]
#[aggregate(id = String, error = String, events(FundsDeposited, FundsWithdrawn))]
pub struct Account {
    balance: i64,
}

impl Handle<Deposit> for Account {
    fn handle(&self, cmd: &Deposit) -> Result<Vec<Self::Event>, Self::Error> {
        Ok(vec![FundsDeposited { amount: cmd.amount }.into()])
    }
}

The derive macro generates the event enum and serialization glue. You focus on domain behavior.

Next Steps