Environment variables
The FLUX_* environment variable convention — single vs double underscore, precedence, and the most commonly-needed names.
Flux reads every configuration field from environment variables prefixed FLUX_. The naming rule is not uniform: top-level fields use a single underscore, nested sections use double underscore.
Naming convention
FluxConfig sets env_prefix = "FLUX_" and env_nested_delimiter = "__". The delimiter only applies between a section name and a key inside it. Top-level fields like server_host already contain an underscore in the field name itself — that is a single underscore in the env var, not double.
| Source field | Env var |
|---|---|
server_host (top-level) | FLUX_SERVER_HOST |
server_port (top-level) | FLUX_SERVER_PORT |
database_url (top-level) | FLUX_DATABASE_URL |
home (top-level) | FLUX_HOME |
workers.bootstrap_token (nested) | FLUX_WORKERS__BOOTSTRAP_TOKEN |
workers.server_url (nested) | FLUX_WORKERS__SERVER_URL |
security.encryption.encryption_key (twice nested) | FLUX_SECURITY__ENCRYPTION__ENCRYPTION_KEY |
security.auth.oidc.enabled (twice nested) | FLUX_SECURITY__AUTH__OIDC__ENABLED |
observability.otlp_endpoint (nested) | FLUX_OBSERVABILITY__OTLP_ENDPOINT |
Precedence
Environment variables win over both TOML files:
- Env vars (
FLUX_*) flux.tomlpyproject.toml [tool.flux]- Defaults
FluxConfig.load() drops any TOML key whose env var is present before passing the merged dict to pydantic-settings, so a single FLUX_DATABASE_URL overrides a database_url set in either TOML file without ambiguity.
Most commonly-set names
| Env var | Field | Notes |
|---|---|---|
FLUX_DATABASE_URL | database_url | Top-level, single underscore. Supports ${VAR} interpolation. |
FLUX_HOME | home | Working directory for the secrets store, bootstrap token, SQLite DB. |
FLUX_SERVER_HOST | server_host | Bind address. |
FLUX_SERVER_PORT | server_port | Bind port. |
FLUX_WORKERS__BOOTSTRAP_TOKEN | workers.bootstrap_token | Required on workers. Server auto-generates if unset. |
FLUX_WORKERS__SERVER_URL | workers.server_url | Worker → server URL. |
FLUX_WORKERS__MAX_CONCURRENT_EXECUTIONS | workers.max_concurrent_executions | Capacity slots the worker advertises (default 16, 0 = unlimited). |
FLUX_WORKERS__DRAIN_TIMEOUT | workers.drain_timeout | Seconds a stopping worker waits for running executions before cancelling (default 60). |
FLUX_WORKERS__RUNNERS | workers.runners | Runners enabled on the worker. List field — set as JSON, e.g. '["inprocess","subprocess"]'. |
FLUX_WORKERS__DEFAULT_RUNNER | workers.default_runner | Runner used when a workflow does not declare one (default subprocess). |
FLUX_WORKERS__LOOP_LAG_THRESHOLD | workers.loop_lag_threshold | Event-loop-lag breach threshold for worker self-health (default 1.0 s, 0 disables). |
FLUX_WORKERS__LOOP_LAG_PROBE_INTERVAL | workers.loop_lag_probe_interval | Seconds between event-loop lag probes (default 1.0). |
FLUX_WORKERS__METRICS_PROVIDER | workers.metrics_provider | Custom metrics callable ("package.module:callable") advertised on heartbeats for routing policies. Unset by default. |
FLUX_WORKERS__METRICS_INTERVAL | workers.metrics_interval | Seconds between metrics-provider refreshes (default 10.0). |
FLUX_WORKERS__BUILTIN_METRICS | workers.builtin_metrics | Publish the built-in flux.* worker metrics on heartbeats (default true). |
FLUX_DISPATCH__MODE | dispatch.mode | poll (default) or event — the scalable dispatch mode on PostgreSQL. |
FLUX_RETENTION__ENABLED | retention.enabled | Turn on the execution-history retention job (off by default). |
FLUX_RETENTION__RETENTION_DAYS | retention.retention_days | Age after which terminal executions are deleted (default 30). |
FLUX_SECURITY__ENCRYPTION__ENCRYPTION_KEY | security.encryption.encryption_key | Passphrase for the secrets store (PBKDF2-derived). |
FLUX_SECURITY__EXECUTION_TOKEN_SECRET | security.execution_token_secret | HMAC secret for execution tokens. Required in production. |
FLUX_SECURITY__AUTH__ENABLED | security.auth.enabled | Master switch for authentication. Enabling a provider forces it on; enabling it with no provider is rejected at startup. |
FLUX_SECURITY__AUTH__OIDC__ENABLED | security.auth.oidc.enabled | Toggle OIDC auth. |
FLUX_SECURITY__AUTH__API_KEYS__ENABLED | security.auth.api_keys.enabled | Toggle API-key auth. |
FLUX_OBSERVABILITY__ENABLED | observability.enabled | Turn the OpenTelemetry pipeline on. |
FLUX_OBSERVABILITY__OTLP_ENDPOINT | observability.otlp_endpoint | OTLP collector URL. |
Special cases
auth.enabled is a real settable field
AuthConfig.enabled is a settable field, bound to FLUX_SECURITY__AUTH__ENABLED. It is the master switch for authentication. Two rules reconcile it with the providers:
- Enabling a provider implies auth is on. If
oidc.enabledorapi_keys.enabledistrue, Flux forcesauth.enabledtotrue(and logs the override if you had explicitly set itfalse). - Enabling auth with no provider is rejected at startup. Setting
FLUX_SECURITY__AUTH__ENABLED=truewithout enablingoidcorapi_keysfails fast — auth needs at least one provider to validate against.
So you can either set the master switch and a provider, or just enable a provider and let the switch follow:
export FLUX_SECURITY__AUTH__ENABLED=true
export FLUX_SECURITY__AUTH__API_KEYS__ENABLED=true
# or simply enable a provider — auth.enabled follows automatically
export FLUX_SECURITY__AUTH__OIDC__ENABLED=true
${VAR} interpolation in database_url
A field validator on database_url expands ${VAR} and $VAR references from the process environment at load time. Both forms work:
# flux.toml
database_url = "postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:5432/flux"
Unresolved references are left literal — the validator does not raise. This interpolation applies to database_url only; other string fields take env-var values directly via FLUX_*.
List-valued fields take JSON
Pydantic-settings parses list fields from JSON-encoded strings. For example, runners on WorkersConfig and default_user_roles on OIDCConfig:
export FLUX_WORKERS__RUNNERS='["inprocess","subprocess","docker"]'
export FLUX_SECURITY__AUTH__OIDC__DEFAULT_USER_ROLES='["viewer"]'
A bare comma-separated list (viewer,operator) does not parse — the value must be a JSON array. The same applies to FLUX_WORKERS__DOCKER_EXTRA_ARGS.
Encryption key is a passphrase
security.encryption.encryption_key is fed to PBKDF2 (SHA-256, 1,000,000 iterations) as the password. Flux does not hex-decode or base64-decode the value. openssl rand -hex 32 produces a fine high-entropy passphrase, but the hex bytes are not interpreted as raw key material — the entire ASCII string becomes the PBKDF2 password.
The full table
For the complete option-by-option reference — every field, type, default, and env var — see Server and worker settings. For deployment-oriented coverage with operator context, see Server configuration.