Configuration files
flux.toml and pyproject.toml [tool.flux] — schema, precedence, and how Flux loads them.
Flux loads configuration from TOML files via pydantic-settings. Two paths are read, in this order, from the current working directory.
The two files
| File | Table | Notes |
|---|---|---|
flux.toml | [flux] (top-level) | Primary config file. Most deployments use this. |
pyproject.toml | [tool.flux] | For projects that prefer a single Python config file. |
Both are optional. If neither exists, defaults apply.
Precedence
FluxConfig.load() applies the following order, highest first:
- Environment variables (
FLUX_*) flux.tomlpyproject.toml[tool.flux]- Built-in defaults
When both files set the same field, flux.toml wins — pyproject.toml [tool.flux] is the lower-precedence file. Environment variables override either file.
Schema overview
The top-level [flux] table covers server, logging, database, and storage fields. Nested tables cover each subsystem.
| Table | Models | Purpose |
|---|---|---|
[flux] | FluxConfig (top-level fields) | Server host/port, log level, database URL and pool/executor sizing, paths, serializer. |
[flux.workers] | WorkersConfig | Bootstrap token, server URL, retry defaults, heartbeat tuning, module cache, runners, capacity slots, drain timeout, transient fast path, self-health probes (loop_lag_threshold, loop_lag_probe_interval), advertised metrics (metrics_provider, metrics_interval, builtin_metrics). |
[flux.dispatch] | DispatchConfig | Dispatch mode (poll/event), batch size, fallback tick. See Dispatch modes. |
[flux.retention] | RetentionConfig | Execution-history retention: toggle, age, sweep interval, batch size. See Retention. |
[flux.scheduling] | SchedulingConfig | Scheduler poll interval and tolerance, auto-schedule toggle. |
[flux.security] | SecurityConfig | Execution-token secret and TTL. |
[flux.security.encryption] | EncryptionConfig | Encryption key for the secrets store. |
[flux.security.auth.oidc] | OIDCConfig | OIDC issuer, audience, JWKS cache, default user roles. |
[flux.security.auth.api_keys] | APIKeyAuthConfig | API-key auth toggle, worker-key TTL. |
[flux.observability] | ObservabilityConfig | OTLP endpoint, Prometheus, trace sampling. |
[flux.mcp] | MCPConfig | MCP server host/port, transport, name. |
[flux.security.auth] takes a settable enabled key — the master switch for authentication (see Environment variables) — plus resolution_cache_ttl (per-process auth-resolution cache, default 30 s) and allow_anonymous. Enabling a provider implies auth is on; enabling auth.enabled with no provider configured is rejected at startup.
Example: flux.toml
A production-shaped layout: PostgreSQL with ${VAR} interpolation, API-key auth enabled, OTLP push:
[flux]
log_level = "INFO"
server_host = "0.0.0.0"
server_port = 8000
home = "/var/lib/flux"
database_url = "postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:5432/flux"
database_type = "postgresql"
database_pool_size = 20
database_max_overflow = 20
database_executor_threads = 16
[flux.workers]
# Omit to let the server auto-generate at <home>/bootstrap-token
# bootstrap_token = "..."
module_cache_ttl = 300
runners = ["inprocess", "subprocess"]
max_concurrent_executions = 16
drain_timeout = 60
# Worker-advertised metrics for routing policies (built-ins are on by default)
# metrics_provider = "myapp.routing:collect"
metrics_interval = 10.0
builtin_metrics = true
[flux.dispatch]
mode = "event" # scalable dispatch on PostgreSQL; "poll" is the default
[flux.retention]
enabled = true # off by default; enable in production
retention_days = 30
[flux.security]
execution_token_ttl = 86400
[flux.security.encryption]
# Set via FLUX_SECURITY__ENCRYPTION__ENCRYPTION_KEY in production
# encryption_key = "..."
[flux.security.auth.api_keys]
enabled = true
[flux.observability]
enabled = true
service_name = "flux-prod"
otlp_endpoint = "http://otel-collector:4317"
prometheus_enabled = true
trace_sample_rate = 0.1
Example: pyproject.toml
The same fields fit under [tool.flux] in pyproject.toml. Nested tables use dotted form:
[tool.flux]
log_level = "INFO"
server_host = "0.0.0.0"
server_port = 8000
home = "/var/lib/flux"
database_url = "postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:5432/flux"
database_type = "postgresql"
[tool.flux.workers]
module_cache_ttl = 300
max_concurrent_executions = 16
[tool.flux.dispatch]
mode = "event"
[tool.flux.retention]
enabled = true
[tool.flux.security]
execution_token_ttl = 86400
[tool.flux.security.auth.api_keys]
enabled = true
[tool.flux.observability]
enabled = true
otlp_endpoint = "http://otel-collector:4317"
${VAR} interpolation works inside database_url regardless of which file declares it.
Reload behaviour
There is no runtime reload. Configuration.get() caches a singleton FluxConfig instance built at first access. Editing flux.toml, exporting a new env var, or changing pyproject.toml while a server is running has no effect — restart the process.
The Python API exposes Configuration.get().reload() and .override(...), but these are intended for tests, not for re-reading files on a live process.
What can go wrong
Wrong type in TOML. server_port = "8000" (string, not int) raises a Pydantic ValidationError at startup naming the field and the expected type. Do not quote integers.
Wrong table name. There is no [flux.server] table — top-level fields live directly under [flux]. Keys placed under non-existent tables are silently ignored.
Both files set the same key. flux.toml wins over pyproject.toml [tool.flux], and an env var wins over both. Keeping one source of truth per field still makes the effective config easier to reason about.
What’s next
- Environment variables — the
FLUX_*convention and the single vs double-underscore foot-gun. - Server and worker settings — the full tabular reference of every option.
- Server configuration — operator-side coverage with deployment context.