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.

Build feature by feature

Why FACTSTR?

FACTSTR gives you the event-store mechanics for facts-first event sourcing without forcing an aggregate-first model.

Atomic appends

Record one or more facts as one committed batch with one consecutive sequence range.

Query by type and payload

Read facts by event type and payload predicates, so commands and projections can load the facts they need.

Command Context Consistency

Append new facts only when the relevant fact context is still current.

Committed-batch streams

Subscribe to facts after they are successfully recorded, with committed batches delivered in order.

Durable replay

Resume stream processing from a stored cursor and catch up without skipping committed facts.

Multiple stores, one contract

Use Memory, SQLite, or PostgreSQL behind the same event-store contract.

Rust core with Node/TypeScript binding

Use the Rust implementation directly or call it from Node.js with TypeScript types.

Quick Start

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.

Facts First

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

Storage Options

FACTSTR has one event-store contract with three runtime stores.

PostgreSQL Store

First-class database-backed storage for applications that already run on PostgreSQL. The PostgreSQL store persists facts, committed batches, and durable stream cursors with the same FACTSTR semantics as the other stores.

SQLite Store

Embedded persistence in one local database file. The SQLite store keeps facts, committed batches, and durable stream cursors available across restart without requiring a separate database server.

Memory Store

Fast feedback for tests, examples, and local development. The memory store is the simplest way to exercise FACTSTR behavior without persistence or external infrastructure.

One contract across stores

Append, query, conditional append, streams, and durable streams keep the same observable behavior across PostgreSQL, SQLite, and Memory.

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.