Skip to content

Frequently Asked Questions

Answers here are kept consistent with the status table, which is the page to trust when any two disagree.

A distributed data backend that serves streams (pub/sub), work queues (consumer groups), and a key-value cache — all as readings of one replicated append-only log, reached over QUIC. The design optimizes for predictable tail latency, high fanout, and strict slow-consumer isolation. The overview is the ten-minute version.

No. Felix is in early active development and has not been run in production by anyone. Quite a lot works — multi-broker clusters, durable replicated streams, quorum acknowledgement, failover, consumer groups, the log-backed cache, OIDC auth with RBAC — and it is tested hard, including fault-injection suites. But there are no releases, no second implementation of anything, and the faults it is proven against are the ones a single machine can produce. Use it for prototyping, benchmarking, and contributing.

Different centre of gravity. Kafka is a durable log first: everything is persisted, consumers pull, latency is a throughput trade-off, and the ecosystem is enormous. Felix is latency-and-fanout first: streams can be ephemeral (no disk on the hot path), each subscriber is isolated, and the same log also serves cache and queue semantics so you run one system instead of three.

Use Kafka when you need long retention, stream processing, or its connector ecosystem. Felix keeps durable logs and replays by offset, but there is no tiered storage and retention is bounded by one machine’s disk — it is built for live distribution, not for being your system of record.

Redis is a data-structure server with basic pub/sub bolted on; Felix is a log with a cache reading. If you need sorted sets, Lua, or transactions, that’s Redis. If you need high-fanout delivery with per-subscriber isolation, a cache whose changes you can watch (with offsets, so reconnects are gapless), and durable counters — and you’d rather not operate a broker and a cache separately — that’s what Felix is for.

Mostly for one property: streams multiplex over a connection without head-of-line blocking, so a retransmission for one subscription never stalls another. Beyond that: TLS 1.3 is part of the protocol (no unencrypted mode to misconfigure), handshakes are one round trip, and flow control exists per stream as well as per connection, which is where Felix’s backpressure story starts. The trade-off is real but small: some networks still block UDP, and TCP has better debugging tooling. Details in QUIC Transport.

At every level, and always bounded: QUIC flow-control windows per connection and per stream; a bounded publish queue whose overflow is a visible error rather than unbounded buffering; and a bounded per-subscription queue whose overflow policy (drop-new by default) is the isolation mechanism — a slow subscriber loses its own events instead of slowing anyone else. See Publish/Subscribe for the full story and the policy trade-off.

Per stream. An ephemeral stream lives in memory: lowest latency, lost on restart, right for data whose old values are worthless. A durable stream (durable: true, and the broker must run with FELIX_DURABLE_STORAGE_DIR) writes every record to a segmented, CRC-checked, crash-safe log before acknowledging, and subscribers can replay from any retained offset. A stream marked durable on a broker without a storage dir is rejected, not silently downgraded.

Retention is available and off by default — set FELIX_DURABLE_RETENTION_BYTES / FELIX_DURABLE_RETENTION_SECONDS, or a log grows until the disk ends. See Durable Storage.

Streams and caches are split into shards; the control plane assigns each shard a leader (and replicas) by rendezvous hashing, and brokers follow its assignment feed. One leader accepts a shard’s writes; a broker that receives a request for a shard it doesn’t lead forwards it or redirects the client. Leaders ship log records to followers — deliberately not per-shard Raft; docs/replication-design.md records why leases plus log shipping were chosen — and a lost leader is replaced only by a replica that provably holds the log. A Quorum stream’s publishes wait for a majority before acknowledging.

Not built: follower reads (every read goes to the leader) and rebalancing (a shard whose leader is alive is never moved, however uneven that leaves the cluster).

Not implemented, and not planned as a delivery guarantee. Felix offers at-most-once (plain subscriptions) and at-least-once (durable streams and consumer groups). Deduplication has to live in the application anyway — only it knows what makes two records “the same” — so put it there, keyed on something the record carries.

Measured numbers live in one place, Benchmarks, with methodology. The shape of it: single-message publish-and-ack round trips are low hundreds of microseconds on loopback, cache operations similar, and batched throughput runs trade per-message latency for rate. Always benchmark release builds (--release); debug builds are 10–100x slower and tell you nothing.

For latency, FELIX_EVENT_BATCH_MAX_DELAY_US — the longest an event waits for its batch to fill, and therefore the latency floor batching adds. For throughput, FELIX_EVENT_BATCH_MAX_EVENTS and its byte sibling. For memory, the flow-control windows (FELIX_*_RECV_WINDOW), since window × connections bounds in-flight data. The environment variable reference has the full list with defaults; change things off a measurement.

Yes to both — see Docker Compose and Kubernetes. There are no pre-built images or published Helm charts yet; you build from the provided Dockerfiles. The broker ships what an orchestrator expects: /live and /ready that answer different questions, and a bounded drain on SIGTERM (graceful shutdown).

Prometheus metrics on the metrics endpoint (/metrics), structured logs via RUST_LOG, and optional OTLP tracing. Which metrics answer which operational questions is the whole point of the observability page.

TLS 1.3 on every connection; OIDC token exchange at the control plane; tenant-scoped EdDSA tokens; RBAC enforced at the broker with delegation rules that prevent privilege escalation; broker-to-broker mTLS, bound to the node id, when certificates are configured. Not built: encryption at rest, end-to-end payload encryption, audit logging. The security page states each plainly.

Can I grant stream access by IdP group instead of per-user?

Section titled “Can I grant stream access by IdP group instead of per-user?”

Yes. Configure groups_claim for the tenant issuer, then bind RBAC roles to group:<name> subjects. During token exchange, Felix maps incoming group claims to those subjects and evaluates role permissions:

  • grouping: g, group:g1, role:reader, tenant-a
  • policy: p, role:reader, tenant-a, stream:tenant-a/payments/*, stream.subscribe

Will there be clients for other languages?

Section titled “Will there be clients for other languages?”

Rust, Python and TypeScript ship today, the latter two as bindings over the Rust client rather than reimplementations. Both pass every required scenario in the client conformance catalogue, and CI is gated on it. Go and C# are not started. The wire protocol is language-neutral and documented precisely for this reason — see Wire Protocol — and a conformance runner exists to check an implementation against it.

Why won’t the broker start? / Why is latency high? / Connection issues?

Section titled “Why won’t the broker start? / Why is latency high? / Connection issues?”

The troubleshooting guide covers these with commands. The three most common answers: you’re running a debug build (use --release), a firewall is dropping UDP on the broker port, or FELIX_EVENT_BATCH_MAX_DELAY_US is set high and you’re measuring the batch delay.

Fork, branch, make the change with tests, run task lint and task test, open a PR. The contributing guide has the details, and How Felix Works is the fastest way to build a mental model of the codebase.