One log, many ways to use it
Streams, caches and queues on one replicated log, with conditional publish, range reads, fine-grained access and Kafka clients.
What Felix does
Felix is an open-source, distributed platform for streams, caches, queues and counters, all on one replicated log. Written in Rust.
Most applications piece together one system for events, another for queues, another for state, and one more to move data between them. In Felix, events, work and state are three ways of operating over the same data.
One system. One durable foundation.
Multiple ways to use your data.
Fast enough for real-time applications, durable enough to trust, and simple enough that you can easily figure out what happened when something fails.
Streams, key-value caches, queues and counters all sit on one replicated log, behind one access model. And a slow subscriber falls behind on its own.
The publisher waits for C, and so do A and B.
Or C is disconnected.
Offsets 41–44 dropped; C resumes from 41.
Once felixctl has a context for your cluster, each step is one command. The guide starts a local cluster with a stream named orders and a cache named users.
# one terminal
felixctl sub orders
# another
felixctl pub orders 'hello'
felixctl cache put users alice 'online'
felixctl cache get users alice
felixctl topology orders
use felix_client::{AckMode, Client, ClientConfig};
use std::net::SocketAddr;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let quinn = quinn::ClientConfig::with_platform_verifier();
let config = ClientConfig::optimized_defaults(quinn);
let addr: SocketAddr = "127.0.0.1:5000".parse()?;
let client = Client::connect(addr, "localhost", config).await?;
let publisher = client.publisher().await?;
publisher
.publish("acme", "prod", "events", b"Hello Felix".to_vec(), AckMode::None)
.await?;
let mut subscription = client.subscribe("acme", "prod", "events").await?;
while let Some(event) = subscription.next_event().await? {
println!("Received: {:?}", event.payload);
}
Ok(())
}
import os
import felix
with felix.Client(
"127.0.0.1:5000", tenant_id="acme", token=os.environ["FELIX_TOKEN"]
) as client:
with client.subscribe("acme", "prod", "events") as events:
client.publish("acme", "prod", "events", b"Hello Felix")
for event in events:
print("Received:", event.payload)
import { Client } from "felix-client";
const client = await Client.connect("127.0.0.1:5000", "acme", process.env.FELIX_TOKEN!);
const events = await client.subscribe("acme", "prod", "events");
await client.publish("acme", "prod", "events", Buffer.from("Hello Felix"));
for (;;) {
const event = await events.nextEvent();
if (event === null) break;
console.log("Received:", event.payload.toString());
}
Every service reads the current value, then every change after it, with no gap.
One publish reaches every subscriber, and a slow one never holds up the rest.
Compare-and-set writes with expiry times that survive a restart.
Write an event and the state it changes as one record, with no outbox.
Jobs retried after a timeout and set aside after too many attempts.
Point existing Kafka producers at Felix and move consumers over one at a time.
Each project keeps all of its state in Felix, with no other datastore, and can be self-hosted.
A multiplayer drawing canvas with live cursors, rich text, history you can scrub, and per-room sign-in.
A browser team deathmatch in 3D, played through Felix with the simulation deciding every hit. A kill cam replayed from the match's log is next.
A webhook relay that stores each webhook durably, delivers it with retries, and replays any endpoint after an outage.
A WebSocket gateway between browsers and Felix, with sign-in narrowed to one room or match.
Install 0.6.0 from your package manager:
docker pull ghcr.io/getfelix/felix-broker:0.6.0