The broker has no configuration file and no command-line flags. Every knob is an
environment variable, read once by config::load() during boot, before the HTTP
listener binds. There is no reload: changing a variable means restarting the
process. The one argument the binary accepts is the subcommand migrate, which
exists only to report that offline migration was retired and exit non-zero.
One boolean parser
Every boolean in the broker goes through the same parser, so =on, =1 and
=true mean the same thing everywhere. The accepted spellings are
true/false, 1/0, yes/no, on/off, case-insensitive, surrounding
whitespace trimmed.
Three outcomes, and only three:
- Recognised value: used.
- Unset, or present but empty or whitespace-only: the documented default.
JWT_ENABLED=in a Compose file means “leave it alone”, notfalse. - Anything else: a fatal boot error. The process logs
FATAL: JWT_ENABLED="maybe" is not a boolean (expected true/false, 1/0, yes/no, on/off)and exits 1.
That last rule exists because the alternative failed in both directions: a
strict parser with a silent fallback turned JWT_ENABLED=1 into a broker
running with authentication off and nothing in the log. Booleans read outside
config.rs (QUEEN_LOG_JSON, QUEEN_APPLY_SCHEMA, QUEEN_V2_BUNDLE_LOG)
are validated eagerly at the same moment, so every boolean mistake in a
deployment surfaces on the same boot with the same message.
Several numeric knobs are also clamped after parsing. Interval and size knobs
are floored at 1, and STATS_INTERVAL_MS and METRICS_FLUSH_MS are floored at
1000 ms: a value below the floor is raised without comment.
The effective configuration is printed at boot
After the JWT configuration is validated, the broker emits one boot block per
subsystem (config: server, postgres, auth, sync, engine, flow,
jobs, file_buffer, security, logging) carrying the values it actually
resolved. A misspelled variable, a defaulted knob, or a value that came from a
legacy alias is visible there instead of having to be inferred from behaviour.
Read that block first when a setting appears not to have taken effect.
Secrets are masked, never printed: JWT_SECRET, PG_PASSWORD,
QUEEN_ENCRYPTION_KEY and QUEEN_SYNC_SECRET render as <unset> or
<set:32 chars>. That is enough to tell “I forgot to mount the secret” from “I
mounted the wrong one” without putting key material into a log shipper.
What kills the boot
The broker prefers to die at startup over serving in a state you did not ask for. All four of these exit 1:
- an unparseable boolean, as above;
JWT_ENABLED=truewith no usable key material for the configured algorithm, or an algorithm outsideHS256,HS384,HS512,RS256,RS384,RS512,EdDSA,auto;- a schema apply failure (unless
QUEEN_APPLY_SCHEMA=0); - failure to bind
0.0.0.0:$PORT.
One important omission from that list: a malformed QUEEN_ENCRYPTION_KEY (not
64 hex characters, or not hex) logs a single warning and disables
encryption. Queues flagged encryptionEnabled then store plaintext and the
pushes succeed. Grep the boot config: security block for
encryption_key=<set:64 chars> before trusting at-rest encryption.
Which variables actually matter
Most of the table below is measured engine tuning that should be left alone. In practice a deployment sets variables from these groups only.
| Purpose | Variables |
|---|---|
| Reach PostgreSQL | PG_HOST, PG_PORT, PG_USER, PG_PASSWORD, PG_DATABASE |
| Size the connection pool and bound statements | DB_POOL_SIZE, QUEEN_STMT_TIMEOUT_MS |
| Encrypt broker-to-PostgreSQL traffic | PG_USE_SSL, PG_SSL_REJECT_UNAUTHORIZED |
| Serve on a different port | PORT |
| Turn on authentication | JWT_ENABLED, JWT_ALGORITHM, then JWT_SECRET or JWT_PUBLIC_KEY or JWT_JWKS_URL |
| Run more than one broker | QUEEN_MESH_PEERS, QUEEN_MESH_PORT, QUEEN_SYNC_SECRET |
| Survive a database outage | FILE_BUFFER_DIR (must be writable and persistent) |
| Change the maintenance cadence | RETENTION_INTERVAL |
| Accept larger request bodies | QUEEN_MAX_BODY_BYTES |
| Encrypt payloads at rest | QUEEN_ENCRYPTION_KEY |
| Shape the logs | LOG_LEVEL, QUEEN_LOG_JSON, QUEEN_LOG_RATES_MS |
| Let a privileged role own the DDL | QUEEN_APPLY_SCHEMA |
| Scope queues by tenant behind a proxy | QUEEN_TENANCY_HEADER. See Self-hosting |
Two conventions in that list are worth stating explicitly.
LOG_LEVEL accepts the full EnvFilter syntax, not just a bare level:
info,queen::pop=debug works. RUST_LOG takes precedence over it, and an
unparseable filter falls back to info.
PG_DATABASE resolves through a non-empty chain (PG_DATABASE, then the
legacy PG_DB, then postgres), so an explicitly empty value falls through.
Every other string variable keeps a present-but-empty value verbatim, which is
how JWT_SKIP_PATHS="" can be used to clear the default skip list.
The variables
Defaults below are the ones the code applies, extracted from config.rs at
build time. Where a variable has an alias, both names read the same setting and
the newer name wins.
The broker is configured entirely through environment variables: 85 of them, listed below with the defaults the code actually applies. Booleans go through one strict parser: an unparseable value is a fatal boot error, while unset and empty both fall back to the default.
Server
| Variable | Type | Default | Also read as |
|---|---|---|---|
PORT |
string | 6632 |
|
QUEEN_APPLY_SCHEMA |
boolean | true |
|
QUEEN_MAX_BODY_BYTES |
integer | 67108864 (64 MiB) |
PostgreSQL
| Variable | Type | Default | Also read as |
|---|---|---|---|
DB_POOL_SIZE |
integer | 160 |
|
PG_DATABASE |
string | postgres |
PG_DB |
PG_HOST |
string | localhost |
|
PG_PASSWORD |
string | postgres |
|
PG_PORT |
integer | 5432 |
|
PG_SSL_REJECT_UNAUTHORIZED |
boolean | true |
|
PG_USE_SSL |
boolean | false |
|
PG_USER |
string | postgres |
|
QUEEN_STMT_TIMEOUT_MS |
integer | 30000 |
Authentication
| Variable | Type | Default | Also read as |
|---|---|---|---|
JWT_ALGORITHM |
string | HS256 |
|
JWT_AUDIENCE |
string | (empty) |
|
JWT_CLOCK_SKEW |
integer | 30 |
|
JWT_ENABLED |
boolean | false |
|
JWT_ISSUER |
string | (empty) |
|
JWT_JWKS_REFRESH_INTERVAL |
integer | 3600 |
|
JWT_JWKS_TIMEOUT_MS |
integer | 5000 |
|
JWT_JWKS_URL |
string | (empty) |
|
JWT_PUBLIC_KEY |
string | (empty) |
|
JWT_ROLE_ADMIN |
string | admin |
|
JWT_ROLE_READ_ONLY |
string | read-only |
|
JWT_ROLE_READ_WRITE |
string | read-write |
|
JWT_ROLE_WRITE_ONLY |
string | write-only |
|
JWT_ROLES_ARRAY_CLAIM |
string | roles |
|
JWT_ROLES_CLAIM |
string | role |
|
JWT_SECRET |
string | (empty) |
|
JWT_SKIP_PATHS |
string | /health,/metrics/prometheus,/metrics,/ |
Multi-broker mesh
| Variable | Type | Default | Also read as |
|---|---|---|---|
QUEEN_CACHE_REFRESH_INTERVAL_MS |
integer | 60000 |
|
QUEEN_MESH_PEERS |
string | (empty) |
|
QUEEN_MESH_PORT |
integer | 6633 |
QUEEN_UDP_NOTIFY_PORT |
QUEEN_SYNC_DEAD_THRESHOLD_MS |
integer | 5000 |
|
QUEEN_SYNC_ENABLED |
boolean | true |
|
QUEEN_SYNC_HEARTBEAT_MS |
integer | 1000 |
|
QUEEN_SYNC_SECRET |
string | (empty) |
|
QUEEN_UDP_NOTIFY_PORT |
integer | 6633 |
|
QUEEN_UDP_PEERS |
string | (empty) |
Consume and long-poll
| Variable | Type | Default | Also read as |
|---|---|---|---|
DEFAULT_TIMEOUT |
integer | 30000 |
POP_DEFAULT_TIMEOUT_MS |
POP_DEFAULT_TIMEOUT_MS |
integer | 30000 |
|
POP_WAIT_BACKOFF_MULTIPLIER |
number | 2.0 |
|
POP_WAIT_BACKOFF_THRESHOLD |
integer | 3 |
|
POP_WAIT_INITIAL_INTERVAL_MS |
integer | 100 |
|
POP_WAIT_MAX_INTERVAL_MS |
integer | 1000 |
Storage engine
| Variable | Type | Default | Also read as |
|---|---|---|---|
QUEEN_ACK_FUSION |
boolean | true |
|
QUEEN_ACK_FUSION_HOLD_MS |
integer | 3 |
|
QUEEN_ACK_FUSION_SHARDS |
integer | 8 |
QUEEN_V2_FUSION_SHARDS |
QUEEN_ACK_REGISTRY |
boolean | true |
|
QUEEN_ACK_REGISTRY_MB |
integer | 64 |
|
QUEEN_DEDUP_CACHE |
boolean | true |
|
QUEEN_DEDUP_CACHE_MB |
integer | 512 |
|
QUEEN_HOTLIST |
boolean | true |
|
QUEEN_HOTLIST_IDLE_SWEEP_MS |
integer | 300_000 |
|
QUEEN_HOTLIST_RESEED_MS |
integer | 30000 |
|
QUEEN_HOTLIST_SHARDS |
integer | 8 |
QUEEN_V2_FUSION_SHARDS |
QUEEN_HOTLIST_WINDOW_BATCH |
integer | 100 |
|
QUEEN_V2_FUSION_HOLD_MS |
integer | 15 |
|
QUEEN_V2_FUSION_SHARDS |
integer | 8 |
|
QUEEN_V2_ZSTD_LEVEL |
integer | 3 |
Flow control
| Variable | Type | Default | Also read as |
|---|---|---|---|
QUEEN_SEG_POP_INIT |
integer | 16 |
|
QUEEN_SEG_POP_MAX |
integer | 64 |
|
QUEEN_SEG_POP_MIN |
integer | 4 |
|
QUEEN_SEG_PUSH_INIT |
integer | 16 |
|
QUEEN_SEG_PUSH_MAX |
integer | 64 |
|
QUEEN_SEG_PUSH_MIN |
integer | 4 |
|
QUEEN_VEGAS_ALPHA |
number | 3.0 |
|
QUEEN_VEGAS_BETA |
number | 6.0 |
Background jobs
| Variable | Type | Default | Also read as |
|---|---|---|---|
METRICS_FLUSH_MS |
integer | 60000 |
|
METRICS_RETENTION_DAYS |
integer | 90 |
|
PARTITION_CLEANUP_DAYS |
integer | 30 |
|
QUEEN_PARTITION_CLEANUP_ENABLED |
boolean | true |
|
RETENTION_BATCH_SIZE |
integer | 1000 |
|
RETENTION_INTERVAL |
integer | 5000 |
|
STATS_INTERVAL_MS |
integer | 10000 |
Durability spool
| Variable | Type | Default | Also read as |
|---|---|---|---|
FILE_BUFFER_DIR |
string | /var/lib/queen/buffers |
|
FILE_BUFFER_EVENTS_PER_FILE |
integer | 10000 |
|
FILE_BUFFER_FLUSH_MS |
integer | 100 |
|
FILE_BUFFER_MAX_BATCH |
integer | 100 |
Security
| Variable | Type | Default | Also read as |
|---|---|---|---|
QUEEN_ENCRYPTION_KEY |
string | (empty) |
|
QUEEN_TENANCY_HEADER |
boolean | false |
Logging
| Variable | Type | Default | Also read as |
|---|---|---|---|
LOG_LEVEL |
string | info |
|
QUEEN_LOG_JSON |
boolean | false |
|
QUEEN_LOG_RATES_MS |
integer | 10000 |
|
QUEEN_LOG_TOPN_QUEUES |
integer | 10 |
|
RUST_LOG |
string | &env_str("LOG_LEVEL", "info |
Experiment-only
These exist to run experiments against the storage engine. The source marks them as such, they are not part of any compatibility promise, and a deployment should not set them.
| Variable | Default | Why it is not a product knob |
|---|---|---|
QUEEN_V2_BUNDLE_MAX |
see notes |
fusion.rs: internal override only |
QUEEN_V2_FUSION_MAX_INFLIGHT |
see notes |
fusion.rs: internal override only |
QUEEN_V2_FUSION_MIN_FRAMES |
see notes |
fusion.rs: “a knob for experiments, not a product contract” |
QUEEN_V2_FUSION_MIN_WAIT_MS |
see notes |
fusion.rs: “a knob for experiments, not a product contract” |
Read but inert
The broker still parses these and still prints them in its boot configuration block, so they look live in a log. They change nothing.
| Variable | Default | Status |
|---|---|---|
QUEEN_V2_FUSION_FRAMES |
500 |
kept for env compatibility; no longer a flush trigger (fusion.rs) |
RETENTION_PARALLELISM |
1 |
read and ignored; retention runs one bounded step at a time |
Node identity
One variable does not appear in the table because it is not read through the
same helper: QUEEN_SERVER_ID names this instance in mesh heartbeats and peer
stats. Unset, the broker uses HOSTNAME; with neither, it generates
queen-<8 hex>. The value is cosmetic (nothing routes on it), but it is what
makes a peer list readable in the config: sync boot block.