| Crates.io | ankurah |
| lib.rs | ankurah |
| version | 0.7.17 |
| created_at | 2025-01-20 00:27:45.89721+00 |
| updated_at | 2026-01-23 00:28:36.580724+00 |
| description | Observable, event-driven state management for native and web |
| homepage | https://github.com/ankurah/ankurah |
| repository | https://github.com/ankurah/ankurah |
| max_upload_size | |
| id | 1523373 |
| size | 116,431 |
The root of all cosmic projections of state
A distributed state-management framework that enables real-time data synchronization
across multiple nodes with built-in observability.
Ankurah is a real-time reactive database for building collaborative and multiplayer applications. Define your data model once in Rust, and use it everywhere—native servers, browser clients, mobile apps—with automatic synchronization across all connected nodes.
Building applications where multiple users interact with shared state is hard. You need real-time sync, offline support, conflict resolution, reactive UI updates, and query pushdown—and it all has to work consistently across your server (Postgres) and clients (IndexedDB in browsers). Most teams either build fragile ad-hoc solutions or accept significant compromises.
Ankurah is event-sourced: every change is an operation that can be replayed, merged, and synchronized. Entities can reference each other (graph-style navigation), and you can subscribe to live queries that automatically update as data changes anywhere in the system.
Your model is defined once in Rust with a derive macro. The same code compiles to native binaries for servers and WASM for browsers. TypeScript interfaces and React hooks are generated automatically.
Local-first by default. Your queries execute against the local cache instantly, then sync with durable servers in the background. Users get sub-millisecond reads and offline support without you writing sync logic.
Live queries that just work. Subscribe to a query and your UI stays in sync automatically—changes flow in from anywhere.
Graph-ready data model. Entities can reference each other, and you can navigate those relationships directly in queries. Full graph traversal is on the roadmap.
Collaborative editing built in. Text fields can use Yjs-backed CRDTs for real-time collaborative editing with automatic conflict resolution.
One codebase, multiple backends. Swap between Sled, SQLite, Postgres, and IndexedDB without changing application code. Your server uses Postgres while browsers use IndexedDB—same queries, same models.
Teams building collaborative tools, local-first apps, multiplayer experiences, or anything where users interact with shared state in real-time.
#[derive(Model, Debug, Serialize, Deserialize)]
pub struct Album {
#[active_type(YrsString)]
pub name: String,
pub artist: String,
pub year: i32,
}
YrsString is default backend for String, LWW otherwise
Rust
let q: LiveQuery<AlbumView> = ctx.query("year > 1985")?;
TypeScript
const q: AlbumLiveQuery = Album.query(ctx(), "year > 1985");
Views and WASM bindings generated by the Model macro
/* creates and Binds a ReactObserver to the component */
const AlbumList = signalObserver(({ albums }: Props) => {
return (
<ul>
/* React Observer automatically tracks albums */
{albums.items.map((album) => (
<li>{album.name}</li>
))}
</ul>
);
});
ReactObserver tracks livequery.items
Sled
let storage = SledStorageEngine::new()?;
Postgres
let storage = Postgres::open(uri).await?;
SQLite
let storage = SqliteStorageEngine::open("myapp.db").await?;
IndexedDB
let storage = IndexedDBStorageEngine::open("myapp").await?;
TiKV planned
export class Album {
static query(context: Context, selection: string, ...args: any): AlbumLiveQuery;
...
}
WebSocket server & client • HTTP/REST endpoints • Authentication hooks • Query routing & pushdown
Server
let storage = SledStorageEngine::with_path(storage_dir)?;
let node = Node::new_durable(Arc::new(storage), PermissiveAgent::new());
node.system.create().await?;
let mut server = WebsocketServer::new(node);
println!("Running server...");
server.run("0.0.0.0:9797").await?;
Rust Client
let storage = SledStorageEngine::new_test()?;
let node = Node::new(Arc::new(storage), PermissiveAgent::new());
let _client = WebsocketClient::new(node.clone(), "ws://localhost:9797").await?;
node.system.wait_system_ready().await;
// Create album
let ctx = node.context(ankurah::policy::DEFAULT_CONTEXT)?;
let trx = ctx.begin();
trx.create(&Album { name: "Parade".into(), artist: "Prince".into(), year: 1986 }).await?;
trx.commit().await?;
WASM Client
let storage = IndexedDBStorageEngine::open("myapp").await?;
let node = Node::new(Arc::new(storage), PermissiveAgent::new());
let _client = WebsocketClient::new(node.clone(), server_url)?;
node.system.wait_system_ready().await;
let context = node.context(DEFAULT_CONTEXT)?;
let _albums = context.query::<ankurah_doc_example_model::AlbumView>("year > 1985")?;
React Component
/* creates and Binds a ReactObserver to the component */
const AlbumList = signalObserver(({ albums }: Props) => {
return (
<ul>
/* React Observer automatically tracks albums */
{albums.items.map((album) => (
<li>{album.name}</li>
))}
</ul>
);
});
Get up and running quickly with our React + Sled template:
cargo generate https://github.com/ankurah/react-sled-template
Or run the example manually:
# Start the server
cargo run -p ankurah-example-server
# Build WASM bindings (in examples/wasm-bindings)
wasm-pack build --target web --debug
# Run the React app (in examples/react-app)
bun install && bun dev
Then open http://localhost:5173/ in two browser tabs (one regular, one incognito) to see real-time sync.
| Concept | Description |
|---|---|
| Model | A struct describing fields and types for entities in a collection |
| Collection | A group of entities of the same type (like a database table) |
| Entity | A discrete identity in a collection with dynamic schema |
| View | A read-only, typed representation of an entity |
| Mutable | A mutable, typed state representation of an entity |
| Event | An atomic change used for synchronization and audit trail |
Milestone 2 - TiKV backend, Graph functionality, User-definable data types
Milestone 3 - P2P, Portable cryptographic identities, E2EE, Hypergraph