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

FileTableNotes
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:

  1. Environment variables (FLUX_*)
  2. flux.toml
  3. pyproject.toml [tool.flux]
  4. 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.

TableModelsPurpose
[flux]FluxConfig (top-level fields)Server host/port, log level, database URL and pool/executor sizing, paths, serializer.
[flux.workers]WorkersConfigBootstrap 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]DispatchConfigDispatch mode (poll/event), batch size, fallback tick. See Dispatch modes.
[flux.retention]RetentionConfigExecution-history retention: toggle, age, sweep interval, batch size. See Retention.
[flux.scheduling]SchedulingConfigScheduler poll interval and tolerance, auto-schedule toggle.
[flux.security]SecurityConfigExecution-token secret and TTL.
[flux.security.encryption]EncryptionConfigEncryption key for the secrets store.
[flux.security.auth.oidc]OIDCConfigOIDC issuer, audience, JWKS cache, default user roles.
[flux.security.auth.api_keys]APIKeyAuthConfigAPI-key auth toggle, worker-key TTL.
[flux.observability]ObservabilityConfigOTLP endpoint, Prometheus, trace sampling.
[flux.mcp]MCPConfigMCP 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