PostgreSQL

Run Flux against PostgreSQL — driver, DSN format, pool settings, managed options, and backups.

PostgreSQL is Flux’s recommended storage backend for any deployment that isn’t a single laptop. Flux uses Postgres for the workflow catalog, the execution event log, schedules, secrets, configs, agent definitions, and worker registration — everything that needs durability and cross-process visibility lives there.

This page is the operator’s recipe for plugging Flux into Postgres. For the full deployment story (high-availability, replication, performance tuning), see Operate → Server → Storage backends.

Install

Postgres support is an optional Poetry extra:

pip install "flux-core[postgresql]"

The extra pulls psycopg[binary,pool] ^3.2 — psycopg v3. Flux 0.56.0 uses one driver for both its synchronous SQLAlchemy engine and the async LISTEN/NOTIFY listener behind event-driven dispatch. Application tasks can use whichever driver they like; this only constrains Flux’s own engine.

DSN format

Set database_url in flux.toml or via the FLUX_DATABASE_URL env var:

[flux]
database_url = "postgresql://flux:${FLUX_DB_PASSWORD}@db.internal:5432/flux"

Two things to know:

The host segment must be non-empty — postgresql:///flux (no host, peer auth) is rejected. Use localhost explicitly when you mean it.

Keep the driverless postgresql:// form: Flux pins the psycopg (v3) dialect internally (flux/models.py::normalize_postgresql_url). Legacy postgresql+psycopg2:// URLs from pre-0.53 configs keep working — they are normalized to psycopg automatically.

On first connect Flux migrates the schema to the latest revision automatically (Alembic); to control the timing, run flux db upgrade yourself — see Upgrades and migrations.

Pool defaults

The shipping defaults in flux/config.py:

SettingDefaultEnv var
database_pool_size20FLUX_DATABASE_POOL_SIZE
database_max_overflow20FLUX_DATABASE_MAX_OVERFLOW
database_executor_threads16FLUX_DATABASE_EXECUTOR_THREADS
database_pool_timeout30 (seconds)FLUX_DATABASE_POOL_TIMEOUT
database_pool_recycle3600 (seconds)FLUX_DATABASE_POOL_RECYCLE
database_health_check_interval300 (seconds)FLUX_DATABASE_HEALTH_CHECK_INTERVAL

Effective max concurrency per process is pool_size + max_overflow = 40 connections by default. The API server, each worker process, and any external flux CLI invocation all open their own pool — size Postgres max_connections at replicas × (pool_size + max_overflow) plus the workers’ LISTEN connections plus headroom for ad-hoc admin sessions. Keep database_executor_threads at or below pool_size so the server’s DB threads never block waiting for a connection.

pool_recycle=3600 reopens connections every hour, which sidesteps the most common breakage when Postgres or a connection-pooler (PgBouncer, RDS Proxy) idle-times connections out.

Postgres version

PostgreSQL 14 or newer is expected. Multi-node Flux — a worker fleet, multiple server replicas — requires PostgreSQL; the dispatcher’s SKIP LOCKED claims, advisory-lock coordination, and LISTEN/NOTIFY signaling all assume PostgreSQL semantics, and the upstream Docker compose exercises postgres:16.

Managed options

Flux works with any standards-compliant Postgres, including:

For any of these, the DSN goes into database_url. No code change.

Backups

Two patterns, neither Flux-specific:

The operational details (cron, encryption, off-site copies) belong in Operate → Maintenance → Backups and restore. The Flux-specific concern is just that the event log is the source of truth — a workflow that finished before the last backup is recoverable, anything claimed but not yet checkpointed after the backup is not.

What goes wrong

See also