Skip to content

Configuration Reference

Complete reference for all Felix broker configuration options.

Felix supports three configuration methods, applied in order (later sources override earlier):

  1. Built-in defaults: Sensible defaults for development
  2. Environment variables: FELIX_* variables for quick overrides
  3. YAML config file: Structured configuration for production
Terminal window
# Default: quic_bind = 0.0.0.0:5000
# Environment: FELIX_QUIC_BIND=127.0.0.1:5001
# YAML: quic_bind: "0.0.0.0:6000"
# Result: 0.0.0.0:6000 (YAML wins)

Location priority:

  1. $FELIX_BROKER_CONFIG (explicit path)
  2. /usr/local/felix/config.yml (default, optional)

Example:

quic_bind: "0.0.0.0:5000"
metrics_bind: "0.0.0.0:8080"
controlplane_url: "http://controlplane:8443"
controlplane_sync_interval_ms: 2000
ack_on_commit: false
max_frame_bytes: 16777216
publish_queue_wait_timeout_ms: 2000
ack_wait_timeout_ms: 2000
disable_timings: false
control_stream_drain_timeout_ms: 50
cache_conn_recv_window: 268435456
cache_stream_recv_window: 67108864
cache_send_window: 268435456
event_batch_max_events: 64
event_batch_max_bytes: 65536
event_batch_max_delay_us: 250
fanout_batch_size: 64
pub_workers_per_conn: 4
pub_queue_depth: 64
pub_inflight_bytes: 67108864
pub_conn_inflight_bytes: 16777216
subscriber_queue_capacity: 512
max_subscriptions_per_conn: 4096
subscriber_writer_lanes: 4
subscriber_lane_queue_depth: 64
max_subscriber_writer_lanes: 8
subscriber_lane_shard: auto

Description: QUIC listener bind address and port.

Type: SocketAddr (IP:Port)

Default: 0.0.0.0:5000

Environment: FELIX_QUIC_BIND

Example:

quic_bind: "0.0.0.0:5000"

Notes:

  • UDP port for QUIC transport
  • Use 0.0.0.0 to listen on all interfaces
  • Use 127.0.0.1 for localhost only

Description: HTTP metrics and health endpoint bind address.

Type: SocketAddr (IP:Port)

Default: 0.0.0.0:8080

Environment: FELIX_BROKER_METRICS_BIND

Example:

metrics_bind: "0.0.0.0:8080"

Endpoints:

  • /healthz: Health check
  • /metrics: Prometheus metrics (if enabled)

Description: Optional control plane base URL for metadata sync.

Type: String (URL)

Default: None

Environment: FELIX_CONTROLPLANE_URL

Example:

controlplane_url: "http://felix-controlplane:8443"

Notes:

  • Optional for single-node deployments
  • Required for multi-node clusters
  • Should include scheme (http:// or https://)

Description: Interval for polling control plane changes.

Type: u64 (milliseconds)

Default: 2000

Environment: FELIX_CONTROLPLANE_SYNC_INTERVAL_MS

Example:

controlplane_sync_interval_ms: 2000

Recommendations:

  • Fast changes: 500-1000ms
  • Normal operation: 2000-5000ms
  • Stable clusters: 5000-10000ms

Description: Send acknowledgements after message commit.

Type: bool

Default: false

Environment: FELIX_ACK_ON_COMMIT (1, true, yes = enabled)

Example:

ack_on_commit: true

Trade-offs:

  • false: Lower latency, fire-and-forget semantics
  • true: Higher latency, explicit acknowledgement

Description: Maximum frame size accepted on QUIC streams.

Type: usize (bytes)

Default: 16777216 (16 MiB)

Environment: FELIX_MAX_FRAME_BYTES

Example:

max_frame_bytes: 16777216

Notes:

  • Limits individual message size
  • Affects memory usage per stream
  • Must match client expectations

Description: Maximum time to wait when backpressuring publish enqueue.

Type: u64 (milliseconds)

Default: 2000

Environment: FELIX_PUBLISH_QUEUE_WAIT_MS

Example:

publish_queue_wait_timeout_ms: 2000

Behavior:

  • Publish blocks if queue is full
  • Returns error after timeout
  • Prevents unbounded memory growth

Description: Maximum time to wait for ack-on-commit completion.

Type: u64 (milliseconds)

Default: 2000

Environment: FELIX_ACK_WAIT_TIMEOUT_MS

Example:

ack_wait_timeout_ms: 2000

Notes:

  • Only applies when ack_on_commit: true
  • Publisher receives error if exceeded

Description: Maximum events per batched subscription frame.

Type: usize (count)

Default: 64

Environment: FELIX_EVENT_BATCH_MAX_EVENTS

Example:

event_batch_max_events: 64

Tuning:

  • Low latency: 1-16
  • Balanced: 32-64
  • High throughput: 128-256

Description: Maximum bytes per batched subscription frame.

Type: usize (bytes)

Default: 65536 (64 KiB)

Environment: FELIX_EVENT_BATCH_MAX_BYTES

Example:

event_batch_max_bytes: 65536

Notes:

  • Whichever limit hits first triggers batch send
  • Consider payload size when tuning

Description: Maximum delay before flushing a subscription batch.

Type: u64 (microseconds)

Default: 250

Environment: FELIX_EVENT_BATCH_MAX_DELAY_US

Example:

event_batch_max_delay_us: 250

Tuning:

  • Ultra-low latency: 50-100us
  • Balanced: 250-500us
  • High throughput: 1000-5000us

Description: Publish-side fanout batching hint and subscribe delivery batch cap.

Type: usize (count)

Default: 64

Environment: FELIX_FANOUT_BATCH

Example:

fanout_batch_size: 64

Recommendations:

  • Low fanout (1-10): 16-32
  • Medium fanout (10-100): 64-128
  • High fanout (100+): 128-256

Subscription event delivery uses binary EventBatch frames.

Broker outbound subscribe delivery uses lane-sharded writer tasks to reduce contention under high fanout / large payload workloads.

Description: Per-subscriber queue capacity in broker core (drop-on-full boundary).

Type: usize (count)

Default: 512

Environment: FELIX_SUBSCRIBER_QUEUE_CAPACITY (alias: FELIX_SUB_QUEUE_CAPACITY)

subscriber_queue_capacity: 512

Description: Max concurrent subscriptions a single QUIC connection may hold. subscriber_queue_capacity bounds the size of one subscription’s buffer; this bounds how many subscriptions one connection can open in total, which is otherwise unbounded — a connection issuing unlimited Subscribe requests could grow broker memory without limit.

Type: usize (count)

Default: 4096

Environment: FELIX_MAX_SUBSCRIPTIONS_PER_CONN

max_subscriptions_per_conn: 4096

Description: Backpressure policy when a subscriber’s broker-core queue (subscriber_queue_capacity) is full — this is the fanout enqueue path, upstream of the writer lanes below.

Type: enum (block, drop_new, drop_old)

Default: drop_new

Environment: FELIX_SUB_QUEUE_POLICY

subscriber_queue_policy: drop_new

Tuning:

  • drop_new (default): sheds the newest event when the queue is full — bounds latency, overload becomes visible as drops (felix_subscribe_dropped_total).
  • block: publish waits for queue space — strongest delivery guarantee, but a single slow subscriber can add latency to publishers. Used by the benchmark harness’s lossless throughput mode alongside pub_ingress_wait.
  • drop_old: currently emulated with drop_new semantics; tracked separately in metrics.

Description: Requested number of outbound writer lanes.

Type: usize (count)

Default: 4

Environment: FELIX_SUB_WRITER_LANES

subscriber_writer_lanes: 4

Description: Bounded command queue depth per writer lane.

Type: usize (count)

Default: 64

Environment: FELIX_SUB_LANE_QUEUE_DEPTH (alias: FELIX_SUB_QUEUE_BOUND)

subscriber_lane_queue_depth: 64

Description: Backpressure policy for the writer-lane command queue (downstream of subscriber_queue_policy; gates the actual QUIC write).

Type: enum (block, drop_new, drop_old)

Default: drop_new

Environment: FELIX_SUB_QUEUE_MODE (alias: FELIX_SUB_LANE_QUEUE_POLICY)

subscriber_lane_queue_policy: drop_new

Same semantics as subscriber_queue_policy, applied one stage later in the pipeline. Control commands (subscriber register/unregister) always use blocking send regardless of this setting.

Description: Safety clamp for subscriber_writer_lanes to avoid oversubscription regressions.

Type: usize (count)

Default: 8

Environment: FELIX_MAX_SUB_WRITER_LANES

max_subscriber_writer_lanes: 8

Description: Lane assignment policy for subscriber outbound writes.

Type: enum (auto, subscriber_id_hash, connection_id_hash, round_robin_pin)

Default: auto

Environment: FELIX_SUB_LANE_SHARD

subscriber_lane_shard: auto

Policy guidance:

  • auto: Prefer connection-aware routing when connection id is available; fallback to subscriber id.
  • subscriber_id_hash: Good general distribution independent of connection topology.
  • connection_id_hash: Useful when many subscribers share connections and connection-local contention dominates.
  • round_robin_pin: Pins lane at subscribe-time; preserves ordering, but can underperform in skewed workloads.

Description: If true, route all subscribers on the same QUIC connection to one writer lane (serializes writes per connection instead of spreading them across lanes).

Type: bool

Default: false

Environment: FELIX_SUB_SINGLE_WRITER_PER_CONN (1, true, yes = enabled)

subscriber_single_writer_per_conn: false

Tuning: The latency-focused benchmark profile (batch = 1) enables this for stable per-message ordering; the throughput profile leaves it off to use parallel lanes.

Description: Maximum queued lane commands drained per flush before a write is issued.

Type: usize (count)

Default: 16

Environment: FELIX_SUB_FLUSH_MAX_ITEMS

subscriber_flush_max_items: 16

Description: Maximum time spent waiting to fill a lane flush buffer before writing what’s accumulated.

Type: u64 (microseconds)

Default: 50

Environment: FELIX_SUB_FLUSH_MAX_DELAY_US

subscriber_flush_max_delay_us: 50

Description: Upper bound on coalesced bytes per QUIC write call to a subscriber stream.

Type: usize (bytes)

Default: 65536 (64 KiB)

Environment: FELIX_SUB_MAX_BYTES_PER_WRITE

subscriber_max_bytes_per_write: 65536

Description: Number of delivery streams to use per connection in hashed-pool mode (sub_stream_mode: hashed_pool).

Type: usize (count)

Default: 4

Environment: FELIX_SUB_STREAMS_PER_CONN

sub_streams_per_conn: 4

Description: Strategy for mapping subscribers to event streams.

Type: enum (per_subscriber, hashed_pool)

Default: per_subscriber

Environment: FELIX_SUB_STREAM_MODE

sub_stream_mode: per_subscriber

Notes: hashed_pool is not yet enabled — the broker currently falls back to per_subscriber and logs a debug warning if hashed_pool is requested.

Description: Cache connection flow-control receive window.

Type: u64 (bytes)

Default: 268435456 (256 MiB)

Environment: FELIX_CACHE_CONN_RECV_WINDOW

Example:

cache_conn_recv_window: 268435456

Notes:

  • Per-connection receive credit
  • Multiplied by connection pool size
  • Affects burst tolerance

Description: Cache stream flow-control receive window.

Type: u64 (bytes)

Default: 67108864 (64 MiB)

Environment: FELIX_CACHE_STREAM_RECV_WINDOW

Example:

cache_stream_recv_window: 67108864

Notes:

  • Per-stream receive credit
  • Multiplied by streams per connection
  • Total credit = stream_window × streams_per_conn × conn_pool

Description: Cache connection send window.

Type: u64 (bytes)

Default: 268435456 (256 MiB)

Environment: FELIX_CACHE_SEND_WINDOW

Example:

cache_send_window: 268435456

Notes:

  • Per-connection send credit
  • Affects concurrent request throughput

Description: Publish worker count per QUIC connection.

Type: usize (count)

Default: 4

Environment: FELIX_BROKER_PUB_WORKERS_PER_CONN

Example:

pub_workers_per_conn: 4

Recommendations:

  • Low concurrency: 2-4
  • High concurrency: 8-16
  • Match to expected concurrent publishers per connection

Description: Per-worker publish queue depth.

Type: usize (count)

Default: 64

Environment: FELIX_BROKER_PUB_QUEUE_DEPTH

Example:

pub_queue_depth: 64

Tuning:

  • Larger values allow more buffering under burst but increase saturation latency
  • Affects memory usage per worker
  • Consider with publish_queue_wait_timeout_ms

Description: Shared in-flight publish byte budget across all publish workers (process-wide, not per-connection).

Type: usize (bytes)

Default: 67108864 (64 MiB)

Environment: FELIX_BROKER_PUBLISH_INFLIGHT_BYTES

Example:

pub_inflight_bytes: 67108864

Tuning:

  • pub_queue_depth bounds the number of queued jobs, but a job’s payload can be as large as max_frame_bytes; pub_inflight_bytes bounds actual queued-or-processing bytes regardless of item count.
  • The budget is acquired before a job is handed to a worker queue and released only once the job finishes processing, so it reflects real resident memory, not just admission-time bytes.
  • Should be set well above max_frame_bytes — a job larger than the remaining budget waits (and can time out under EnqueuePolicy::Wait) rather than being admitted.
  • Lower this to shrink worst-case ingress memory under large-payload workloads; raise it to allow more large batches in flight concurrently.

Description: Per-connection share of pub_inflight_bytes. pub_inflight_bytes is intentionally process-wide (see its description above), which on its own means nothing stops one connection from occupying the entire shared budget. pub_conn_inflight_bytes closes that gap: it’s a second, independent byte-budget gate sized per connection, checked before the shared budget on every publish admission.

Type: usize (bytes)

Default: 16777216 (16 MiB)

Environment: FELIX_BROKER_PUBLISH_CONN_INFLIGHT_BYTES

Example:

pub_conn_inflight_bytes: 16777216

Tuning:

  • Must be smaller than pub_inflight_bytes to have any effect; setting it equal to or above pub_inflight_bytes means a single connection can once again claim the whole shared budget.
  • Roughly pub_inflight_bytes / N for the expected number of concurrently active connections gives each a fair share while still allowing the shared budget to absorb bursts from fewer connections.

Description: When true, un-acked (fire-and-forget) publishes wait — bounded by publish_queue_wait_timeout_ms — for ingress capacity instead of being shed when the publish queue or byte budget is full.

Type: bool

Default: false

Environment: FELIX_PUB_INGRESS_WAIT

Example:

pub_ingress_wait: true

Tuning:

  • Off (default): overload sheds fire-and-forget publishes visibly (felix_broker_ingress_dropped_total) and keeps latency bounded.
  • On: backpressure propagates through QUIC flow control to the publisher — nothing is shed, producers slow down. Use for lossless pipelines and sustainable-throughput benchmarking.

Description: Number of core-pinned shard executors owning stream work (thread-per-core). Each stream’s handle id deterministically selects an owning shard; that shard runs the stream’s publish worker and its subscriptions’ lane feeders on one dedicated single-threaded runtime (pinned to a CPU core on Linux). Publish append, fanout enqueue, and subscriber dequeue all stay core-local.

Type: usize (count; 0 = disabled)

Default: 0

Environment: FELIX_CORE_SHARDS

Example:

core_shards: 4

Tuning:

  • When enabled, the publish worker count becomes the shard count (one worker per shard), superseding pub_workers_per_conn.
  • Benefits scale with stream count: workloads spread across many streams gain parallel, contention-free per-core pipelines (measured +34% delivered throughput at 4 streams × 4 shards, unpinned). Single-stream workloads serialize on one shard by design — neutral to mildly positive.
  • Core pinning requires Linux (sched_setaffinity); elsewhere shards still get dedicated threads, preserving the single-writer ownership model without hard affinity.
  • Reasonable starting point: number of physical cores minus 2 (leaving headroom for QUIC I/O on the main runtime).

Description: Disable per-stage timing collection for lower overhead.

Type: bool

Default: false

Environment: FELIX_DISABLE_TIMINGS (1, true, yes = disabled)

Example:

disable_timings: true

Trade-offs:

  • false: Detailed latency metrics, slight overhead
  • true: Maximum performance, no per-stage timings

Recommendations:

  • Development: false (debug performance)
  • Production low-load: false (observability)
  • Production high-load: true (reduce overhead)

Description: Maximum time to wait for control-stream writer to drain.

Type: u64 (milliseconds)

Default: 50

Environment: FELIX_CONTROL_STREAM_DRAIN_TIMEOUT_MS

Example:

control_stream_drain_timeout_ms: 50

Notes:

  • Affects graceful connection shutdown
  • Balance between responsiveness and reliability

While this reference covers broker configuration, clients also have tunable parameters:

Environment: FELIX_EVENT_CONN_POOL

Default: 8

Description: Number of QUIC connections in the event pool.

Environment: FELIX_CACHE_CONN_POOL

Default: 8

Description: Number of QUIC connections for cache operations.

Environment: FELIX_CACHE_STREAMS_PER_CONN

Default: 4

Description: Concurrent cache streams per connection.

Environment: FELIX_PUBLISH_CHUNK_BYTES

Default: 16384 (16 KiB)

Description: Chunk size for publishing large messages.

Felix validates configuration at startup:

Terminal window
# Test configuration
cargo run --release -p broker -- --dry-run
# Explicit config file
FELIX_BROKER_CONFIG=/path/to/config.yml cargo run --release -p broker

Common validation errors:

  • Invalid socket address format
  • Negative or zero values where positive required
  • Conflicting settings
event_batch_max_events: 1
event_batch_max_delay_us: 50
fanout_batch_size: 16
subscriber_writer_lanes: 2
subscriber_lane_shard: auto
subscriber_queue_capacity: 64
disable_timings: true
event_batch_max_events: 64
event_batch_max_bytes: 65536
event_batch_max_delay_us: 250
fanout_batch_size: 64
subscriber_writer_lanes: 4
subscriber_lane_shard: auto
subscriber_queue_capacity: 512
disable_timings: false
cache_conn_recv_window: 268435456
event_batch_max_events: 256
event_batch_max_bytes: 1048576
event_batch_max_delay_us: 1000
fanout_batch_size: 128
subscriber_writer_lanes: 8
max_subscriber_writer_lanes: 8
subscriber_lane_shard: auto
subscriber_queue_capacity: 4096
pub_ingress_wait: true
core_shards: 4
disable_timings: true
cache_conn_recv_window: 536870912
cache_stream_recv_window: 134217728
cache_send_window: 536870912
subscriber_queue_capacity: 2048
subscriber_lane_queue_depth: 16384
pub_queue_depth: 2048
quic_bind: "127.0.0.1:5000"
metrics_bind: "127.0.0.1:8080"
disable_timings: false
event_batch_max_events: 32
quic_bind: "0.0.0.0:5000"
metrics_bind: "0.0.0.0:8080"
ack_on_commit: true
disable_timings: true
event_batch_max_events: 64
event_batch_max_delay_us: 250
subscriber_writer_lanes: 4
subscriber_lane_shard: auto
cache_conn_recv_window: 268435456
quic_bind: "0.0.0.0:5000"
metrics_bind: "0.0.0.0:8080"
controlplane_url: "http://felix-controlplane:8443"
controlplane_sync_interval_ms: 2000
ack_on_commit: true
disable_timings: true
event_batch_max_events: 128
event_batch_max_bytes: 262144
fanout_batch_size: 128
subscriber_writer_lanes: 4
subscriber_lane_shard: auto