Skip to content

Configuration

Fanout resolves built-in defaults followed by nonempty process environment values. Every setting is listed under Settings, grouped by the part of the product it belongs to.

Those pages and .env.example are generated from internal/config by cmd/fanout-docgen. just docs-generate-check verifies that they match the schema the binary uses.

All settings are read once at startup and require a restart. An empty environment value means unset and preserves the built-in default. Native installs listen on 127.0.0.1:7520; the image supplies FANOUT_ADDR=:7520 and FANOUT_DATA_DIR=/var/lib/fanout/data.

The binary reads only process environment. .env.example comments out every empty entry and documents types, defaults, and secret file forms in comments. Copying the template sets nothing and preserves image ENV. For a source checkout, copy it to ignored .env and uncomment personal settings and development credentials as needed. Build the binary, then use just run: Node’s native parseEnv loads optional ./.env, and inherited environment values win, including empty values. Values are never executed as shell code or interpolated. The binary validates unknown names and types. Production deployments supply their own environment values or managed secret mounts.

Custom names use FANOUT_ plus a clear name, adding the area only when it clarifies. Vendor credentials and endpoints keep ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL, OPENAI_API_KEY, and OPENAI_BASE_URL.

FANOUT_AI_PROVIDER defaults to empty, disabling chat. Exactly anthropic or openai enables chat and requires that provider’s key. Only the selected provider’s endpoint is validated and used. Inherited credentials never select a provider. FANOUT_AI_MODEL selects the model; unrelated vendor/tool settings such as ANTHROPIC_MODEL and OPENAI_MODEL are ignored. See AI settings for base URL meanings. Both provider base URLs accept a trailing slash.

Unknown FANOUT_ names fail startup. Platform-injected service-discovery names are tolerated, and unrelated names in shared vendor namespaces are ignored. Errors name the relevant environment variable. Boolean, integer, and Go duration values must parse as their declared types.

Every secret accepts either its value or its file path:

Value variableFile path variable
FANOUT_AUTH_CODE_SECRETFANOUT_AUTH_CODE_SECRET_FILE
FANOUT_OIDC_CLIENT_SECRETFANOUT_OIDC_CLIENT_SECRET_FILE
FANOUT_SMTP_PASSWORDFANOUT_SMTP_PASSWORD_FILE
FANOUT_METRICS_TOKENFANOUT_METRICS_TOKEN_FILE
ANTHROPIC_API_KEYANTHROPIC_API_KEY_FILE
OPENAI_API_KEYOPENAI_API_KEY_FILE

Setting both forms nonempty fails startup. File contents lose exactly one trailing LF or CRLF; an empty result fails. Errors name variables and paths, never contents. The deployment controls file access; Fanout performs no file-mode check. Secrets are redacted from startup logs. Unselected AI providers’ value and file forms are ignored.

Use deployment environment injection, Docker/Compose secrets, Kubernetes Secrets, or a private selected SOPS profile. This public repository ships no operator profiles or recipients. See runtime secret delivery for examples.

The whole configuration is validated before data files or listeners open. A value the binary cannot accept stops startup. First boot lists what is checked. The healthcheck command derives its probe from the listener and TLS environment settings without validating unrelated settings or secrets.

Most deployments should not set DuckDB variables. Give the process or container the CPU and memory limits it may use; at startup Fanout reserves headroom for Go and sizes the DuckDB connection pool from available CPUs. The resolved values and whether Fanout chose them are available in the runtime_sizing block returned by /readyz.

These variables are escape hatches for measured, unusual workloads:

VariableAutomatic behaviorWhen to override
FANOUT_DUCKDB_MEMORY60% of the container or host memory available to FanoutA measured co-tenant workload needs a different Go/DuckDB split
FANOUT_DUCKDB_MAX_CONNECTIONSAvailable Go CPUs, bounded to 2–16 connectionsQuery concurrency has been benchmarked for this machine
FANOUT_DUCKDB_THREADSDuckDB chooses its own query worker countQuery-heavy work must leave specific cores free for ingest

An explicit value always wins. Startup logs and /readyz report the detected host and cgroup limits, the selected source, and whether detection was incomplete. If Fanout cannot conclusively inspect a container limit, it warns; set FANOUT_DUCKDB_MEMORY for a guaranteed bound. See storage settings for types and defaults.