Building blocks for pragmatic event-sourced systems in Rust.
- Domain-first API – events are plain structs that implement
DomainEvent; IDs and metadata live in an envelope rather than in your payloads. - Aggregate derive –
#[derive(Aggregate)]generates the event enum plus serialisation/deserialisation glue so command handlers stay focused on behaviour. - Repository orchestration –
Repositoryloads aggregates, executes commands viaHandle<C>, and persists the resulting events in a single transaction. - Metadata-aware projections – projections receive aggregate IDs, events, and metadata
via
ApplyProjection, enabling cross-aggregate correlation using causation, timestamps, or custom metadata. - Store agnostic – ships with an in-memory store for demos/tests; implement the
EventStoretrait to plug in your own persistence.
use sourcery::{Apply, DomainEvent, Handle};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FundsDeposited { pub amount_cents: i64 }
impl DomainEvent for FundsDeposited {
const KIND: &'static str = "bank.account.deposited";
}
#[derive(Debug, Default, sourcery::Aggregate)]
#[aggregate(id = String, error = String, events(FundsDeposited))]
pub struct Account { balance_cents: i64 }
impl Apply<FundsDeposited> for Account {
fn apply(&mut self, event: &FundsDeposited) {
self.balance_cents += event.amount_cents;
}
}
pub struct DepositFunds { pub amount_cents: i64 }
impl Handle<DepositFunds> for Account {
fn handle(&self, cmd: &DepositFunds) -> Result<Vec<Self::Event>, Self::Error> {
Ok(vec![FundsDeposited { amount_cents: cmd.amount_cents }.into()])
}
}| Concept | Description |
|---|---|
| Aggregates | Rebuild state from events and validate commands via Apply<E> and Handle<C>. |
| Projections | Read models that replay events via ApplyProjection<E>, potentially across multiple aggregates. |
| Repository | Orchestrates loading, command execution, and persistence in a single transaction. |
| EventStore | Trait defining the persistence boundary—implement for Postgres, DynamoDB, S3, etc. |
- Full documentation — Conceptual guides and tutorials
- API docs — Type and trait reference
- How sourcery compares — Design trade-offs vs other Rust event-sourcing crates
| Example | Description |
|---|---|
quickstart |
Minimal aggregate + projection |
inventory_report |
Cross-aggregate projection |
subscription_billing |
Real-world billing domain |
versioned_events |
Schema migration via serde |
optimistic_concurrency |
Conflict detection and retry |
snapshotting |
Aggregate snapshots for performance |
cargo run --example quickstartPre-1.0. APIs will evolve as real-world usage grows. Feedback and contributions welcome!
This project is publicly available under the GNU General Public License v3.0. It may optionally be distributed under the MIT license by commercial arrangement.
Was this useful? Buy me a coffee