Skip to content

YodaHTAP for Rust, lightweight and serverless

Pair SQLite for OLTP with DuckDB or DataFusion for OLAP. Trigger-based CDC keeps them in sync. Zero servers, zero clusters, embedded.

30-second example

rust
use yoda::{HtapConfig, HtapEngine, OlapBackendType, TableSchema};
use arrow::datatypes::{DataType, Field, Schema};
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut engine = HtapEngine::new(HtapConfig {
        oltp_path: "./yoda.db".into(),
        olap_in_memory: true,
        olap_backend: OlapBackendType::DataFusion,
        ..Default::default()
    }).await?;

    // Register a table — schema replicates to OLAP, CDC triggers wire up automatically.
    let schema = Arc::new(Schema::new(vec![
        Field::new("id", DataType::Int64, false),
        Field::new("name", DataType::Utf8, true),
    ]));
    engine.register_table(TableSchema::new("users", schema, vec!["id".into()])).await?;

    // Writes go to OLTP.
    engine.execute("INSERT INTO users VALUES (1, 'Ada'), (2, 'Grace')", &[]).await?;

    // Analytical queries route to OLAP automatically.
    let batches = engine.query("SELECT COUNT(*) FROM users").await?;
    println!("{} batch(es) returned", batches.len());

    engine.shutdown().await;
    Ok(())
}

Same idea in Python, or yd query from the command line.

Operating modes

ModeWhat it doesUse when
Standard HTAPLocal SQLite + local OLAP, kept in sync by triggersEmbedded apps that need analytics over their own writes
SidecarPull data from external SQLite/Postgres by updated_at, no source changesYou don't own (or can't modify) the upstream DB
Temporal (SCD Type 2)Append-only OLAP with _yoda_valid_from / _yoda_valid_toAudit history, point-in-time queries, slowly changing dimensions
FlightSQL serverExpose OLAP over gRPC for clients (DBeaver, ADBC, …)Multi-client analytical access

Where to next

Released under the Apache-2.0 License.