#cqrs #event-sourcing #event-handling #mysql #event-sourcing-cqrs #ddd #postgresql #event-processing #event-store #event-stream

evento

A collection of libraries and tools that help you build DDD, CQRS, and event sourcing

72 releases (14 stable)

new 1.8.0 Dec 15, 2025
1.7.2 Nov 11, 2025
1.5.1 Oct 25, 2025
1.0.4 Apr 18, 2022
0.0.2 Jun 19, 2022

#225 in Database interfaces


Used in timada-market

Apache-2.0

150KB
3.5K SLoC

Evento

Crates.io Documentation License

A collection of libraries and tools that help you build DDD, CQRS, and event sourcing applications in Rust.

More information about this crate can be found in the crate documentation.

Features

  • Event Sourcing: Store state changes as immutable events with complete audit trail
  • CQRS Pattern: Separate read and write models for scalable architectures
  • SQL Database Support: Built-in support for SQLite, PostgreSQL, and MySQL
  • Event Handlers: Async event processing with automatic retries
  • Event Subscriptions: Continuous event stream processing
  • Event Streaming: Real-time event streams (with stream feature)
  • Snapshots: Periodic state captures to optimize aggregate loading
  • Database Migrations: Automated schema management
  • Macro Free API: Clean, macro-free API (macros available optionally)
  • Type Safety: Fully typed events and aggregates with compile-time guarantees

Usage Example

use evento::{EventDetails, AggregatorName};
use serde::{Deserialize, Serialize};
use bincode::{Decode, Encode};

// Define events
#[derive(AggregatorName, Encode, Decode)]
struct UserCreated {
    name: String,
    email: String,
}

#[derive(AggregatorName, Encode, Decode)]
struct UserEmailChanged {
    email: String,
}

// Define aggregate
#[derive(Default, Serialize, Deserialize, Encode, Decode, Clone, Debug)]
struct User {
    name: String,
    email: String,
}

// Implement event handlers on the aggregate
#[evento::aggregator]
impl User {
    async fn user_created(&mut self, event: EventDetails<UserCreated>) -> anyhow::Result<()> {
        self.name = event.data.name;
        self.email = event.data.email;
        Ok(())
    }

    async fn user_email_changed(&mut self, event: EventDetails<UserEmailChanged>) -> anyhow::Result<()> {
        self.email = event.data.email;
        Ok(())
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Setup SQLite executor
    let pool = sqlx::SqlitePool::connect("sqlite:events.db").await?;
    let mut conn = pool.acquire().await?;

    // Run migrations
    evento::sql_migrator::new_migrator::<sqlx::Sqlite>()?
        .run(&mut *conn, &evento::migrator::Plan::apply_all())
        .await?;

    let executor: evento::Sqlite = pool.into();

    // Create and save events
    let user_id = evento::create::<User>()
        .data(&UserCreated {
            name: "John Doe".to_string(),
            email: "john@example.com".to_string(),
        })?
        .metadata(&true)?
        .commit(&executor)
        .await?;

    // Update user
    evento::save::<User>(&user_id)
        .data(&UserEmailChanged {
            email: "newemail@example.com".to_string(),
        })?
        .metadata(&true)?
        .commit(&executor)
        .await?;

    // Load aggregate from events
    let user = evento::load::<User, _>(&executor, &user_id).await?;
    println!("User: {:?}", user.item);

    Ok(())
}

Event Handlers and Subscriptions

use evento::{Context, EventDetails, Executor};

// Define a handler function
#[evento::handler(User)]
async fn on_user_created<E: Executor>(
    context: &Context<'_, E>,
    event: EventDetails<UserCreated>,
) -> anyhow::Result<()> {
    println!("User created: {} ({})", event.data.name, event.data.email);
    // Trigger side effects, send emails, update read models, etc.
    Ok(())
}

// Subscribe to events
evento::subscribe("user-handlers")
    .handler(on_user_created())
    .run(&executor)
    .await?;

Feature Flags

  • macro (enabled by default) Enable procedural macros for cleaner code
  • handler (enabled by default) Enable event handlers with retry support
  • stream Enable streaming support with tokio-stream
  • group Enable event grouping functionality
  • sql Enable all SQL database backends (SQLite, MySQL, PostgreSQL)
  • sqlite SQLite support via sqlx
  • mysql MySQL support via sqlx
  • postgres PostgreSQL support via sqlx

Minimum Supported Rust Version

Evento's MSRV is 1.75.

Safety

This crate uses #![forbid(unsafe_code)] to ensure everything is implemented in 100% safe Rust.

Examples

The examples directory contains sample applications demonstrating various features:

  • todos - A complete todo application with CQRS, demonstrating command/query separation and event handlers

Getting Help

If you have questions or need help, please:

License

This project is licensed under the Apache-2.0 license.

Dependencies

~3–22MB
~239K SLoC