FACTS-FIRST EVENT STORE BUILT IN RUST
FACTSTR

Facts-First Event Sourcing for Real Applications

FACTSTR is an open-source event store built in Rust for applications that use business facts as the source of truth. Store, retrieve, and stream your facts with ease.

Start quickly

Start with the first feature

FACTSTR is easy to integrate and simple to use. A feature can append facts, read the facts it needs, check its context safely, and keep its own query model current from committed batches. That lets a system start small, stay clear, and grow feature by feature.

Example: initialize a PostgreSQL store in Rust

use factstr_postgres::PostgresStore;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let database_url =
        std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");

    let _store = PostgresStore::connect(&database_url)?;

    Ok(())
}

Read the Getting Started docs

Projections

Keep query models current from committed facts

A feature can update its own query model from committed batches, and durable streams can resume from a stored cursor to replay what was missed before continuing live. That supports feature-owned projections, replay, and catch-up in the same model.

Feature-owned query models

A feature can keep its own query model current from the facts it cares about.

Committed batches drive updates

Streams deliver committed batches only after append succeeds.

Durable replay resumes from a stored cursor

Durable streams replay what was missed and then continue with future committed batches.

Problem

Build features from facts from the start.

FACTSTR is built for starting with a real feature instead of designing a large structure first. A feature can append facts, read the relevant facts, check its context safely, and keep its own query model current from committed batches.

That keeps the model direct and lets a system grow feature by feature.

Facts stay in one ordered log

Facts are appended to one ordered log, which keeps history and replay simple.

Context stays explicit

`append_if` checks the relevant context directly, so safety stays close to the feature.

Read position and context version are separate

Reads return a position for what was returned, and a separate version for the full relevant context.

Committed batches can drive query models

Committed batches can keep feature-owned query models current, and durable streams add replay and catch-up from a stored cursor.

Storage Options

Choose the storage that fits the job.

Use Memory for tests and local reasoning, SQLite for embedded persistence, and PostgreSQL when that already fits your environment.

Memory Store

The semantic reference implementation. Useful for tests, local development, and reasoning about the contract without persistence.

SQLite Store

The embedded persistent store. It keeps events and durable stream cursors in SQLite and supports replay and catch-up across restart.

PostgreSQL Store

The PostgreSQL-backed implementation of the same contract, using SQL transactions and persisted durable stream cursors.

Current boundary

The repository contains the contract crate, the three stores, and conformance tests. It does not currently include HTTP or gRPC adapters.

Semantics

Exact behavior stays explicit

FACTSTR keeps the important behavior explicit: reads are ordered, `append_if` checks the relevant context, committed batches are delivered only after append succeeds, and durable streams replay from a stored cursor before continuing live.

Events are immutable facts in one append-only log with global monotonically increasing sequence numbers.
Queries return events in ascending sequence order.
last_returned_sequence_number and current_context_version are separate on purpose.
append_if checks the full relevant context and returns a typed conflict on stale context.
Streams deliver committed batches only after successful append.
Durable streams replay from the stored cursor, then continue without gaps or duplicates.
The same model is available with Memory, SQLite, and PostgreSQL.
Background

Background and further reading

FACTSTR is the current Rust implementation of the same general direction explored earlier in TypeScript. These links are here for readers who want the longer background.