Environment variables
Most behaviour lives in the TOML, but the binary reads the environment variables on this page too. Precedence is not uniform, so each row states it: an override such as XERJ_BIND_ADDRESS beats the config file (and loses to its CLI flag), while a secret such as XERJ_CLUSTER_AUTH_SECRET or the rerank provider pair is a fallback that a non-empty config value wins over. The first table finds the config file and filters logs.
--config CLI flag wins if both are set; with neither, the built-in defaults are used (no ./xerj.toml lookup).tracing_subscriber syntax, e.g. xerj_api=debug,info.XERJ_LOG is unset.Server overrides and secrets
server.bind_address; --bind wins. An empty value is a startup error.server.allow_insecure_network_bind in both directions. Strict boolean (1/true/yes/on, 0/false/no/off); any other value refuses to start.embedding.mode: lexical, neural, proxy, auto or onnx-experimental; --embed-mode wins.embedding.mode = "proxy"). Environment only — there is no config key for it.cluster.auth_secret is empty (the config value wins). At least 16 characters.auto, off, unlimited or MiB. Wins over limits.max_process_memory_mb.limits.max_segment_hydration_cache_mb; clamped to 50% of memory.merge.max_concurrent is not wired).elasticsearch or opensearch, and a version); the --compat-* flags win./_decide tier (history or local) and the local model directory; the --decide-* flags win.--embed-mode onnx-experimental (flags win) and the ONNX runtime log level (default warn)..xerj_master_key file. A malformed value is an error.Client subcommands
xerj search, def, code, gain, init, mcp, ask and hub; --url wins. When nothing answers at a loopback address, xerj ask, xerj hub pull and the MCP hub tools start their own node instead. xerj autoindex deliberately ignores it (and says so) — pass --url.autoindex included; --api-key wins.xerj mcp (e.g. ApiKey <key>); --auth wins.xerj corpus / xerj code keep corpora and state.xerj ask, xerj hub pull and sync fetch the signed catalogue from <url>/api/v1/catalogue.json (+ .sig), then the packs it names. Downloads only; no question text is sent. See Corpus Hub.--disable-feedback does the same).s3:// / r2:// roots and the S3 storage backend. See Object storage.Benchmarking and debug knobs
The binary also reads a set of XERJ_* variables meant for benchmarks, A/B runs and profiling — XERJ_FLUSH_SIZE_MB, XERJ_FLUSH_DOCS, XERJ_MERGE_INTERVAL_SECS, XERJ_DISABLE_QUERY_CACHE, XERJ_DISABLE_FAST_AGGS and others. Leave them unset in production. One is dangerous: XERJ_SKIP_WAL disables the write-ahead log, so acknowledged writes are lost on a crash.
Rerank provider
The rerank search stage sends document text to a third-party judge, so it needs a provider key. The key and endpoint may come from the environment as a fallback: a non-empty value under [rerank] in the config file wins, so a stray variable in a service's environment cannot silently re-point where document text is sent. Both are read once, at startup — changing them on a running node does nothing. Setting the key does not switch reranking on for any search; a request still has to carry a rerank block, and [rerank] enabled = false overrides both variables.
rerank.api_key is empty. Unset in both places means a rerank request gets HTTP 503. Never echoed: GET /_xerj/rerank reports only that a key is set and that it came from env.rerank.endpoint is empty. Point it at a proxy or a test double; it is where judged document text is POSTed. Validated at boot like the config value: it must be an absolute http:// or https:// URL with no user:password@ in it, or the node refuses to start.Source · engine/crates/xerj-server/src/main.rs · engine/crates/xerj-rerank/src/lib.rs