Frequently Asked Questions
Answers here are kept consistent with the status table, which is the page to trust when any two disagree.
What is Felix?
Section titled “What is Felix?”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.
Is Felix production-ready?
Section titled “Is Felix production-ready?”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.
How is Felix different from Kafka?
Section titled “How is Felix different from Kafka?”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.
How is Felix different from Redis?
Section titled “How is Felix different from Redis?”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.
Why QUIC instead of TCP?
Section titled “Why QUIC instead of TCP?”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.
How does Felix handle backpressure?
Section titled “How does Felix handle backpressure?”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.
What is ephemeral vs durable storage?
Section titled “What is ephemeral vs durable storage?”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.
How does clustering work?
Section titled “How does clustering work?”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).
What about exactly-once?
Section titled “What about exactly-once?”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.
What latency should I expect?
Section titled “What latency should I expect?”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.
What’s the most important tuning knob?
Section titled “What’s the most important tuning knob?”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.
Can I run Felix in Docker or Kubernetes?
Section titled “Can I run Felix in Docker or Kubernetes?”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).
How do I monitor Felix?
Section titled “How do I monitor Felix?”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.
How is Felix secured?
Section titled “How is Felix secured?”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.
How do I contribute?
Section titled “How do I contribute?”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.
