Postgres Backend
Multi-machine workers and concurrent writes with the PostgreSQL backend.
Multi-machine workers and concurrent writes with the PostgreSQL backend.
flexiq supports PostgreSQL as an alternative storage backend for production deployments that need multi-machine workers or higher write throughput.
Choose Postgres over the default SQLite backend when you need:
For single-machine workloads, SQLite remains the simpler choice — no external dependencies required.
pip install flexiq[postgres]from flexiq import Queue
queue = Queue(
backend="postgres",
db_url="postgresql://user:password@localhost:5432/myapp",
schema="flexiq", # optional, default: "flexiq"
)| Parameter | Type | Default | Description |
|---|---|---|---|
backend | str | "sqlite" | Set to "postgres" or "postgresql" |
db_url | str | None | PostgreSQL connection URL (required for Postgres) |
schema | str | "flexiq" | PostgreSQL schema for all tables |
workers | int | 0 (auto) | Number of worker threads |
All other Queue parameters (default_retry, default_timeout,
default_priority, result_ttl, retention) work identically to the
SQLite backend.
Configure the Postgres backend via Django settings:
# settings.py
FLEXIQ_BACKEND = "postgres"
FLEXIQ_DB_URL = "postgresql://user:password@localhost:5432/myapp"
FLEXIQ_SCHEMA = "flexiq"Then use the Django integration as normal:
from flexiq.contrib.django.settings import get_queue
queue = get_queue()All Django settings:
| Setting | Default | Description |
|---|---|---|
FLEXIQ_BACKEND | "sqlite" | Storage backend ("sqlite" or "postgres") |
FLEXIQ_DB_URL | None | PostgreSQL connection URL |
FLEXIQ_SCHEMA | "flexiq" | PostgreSQL schema name |
FLEXIQ_DB_PATH | ".flexiq/flexiq.db" | SQLite database path (ignored with Postgres) |
FLEXIQ_WORKERS | 0 | Worker thread count (0 = auto-detect) |
FLEXIQ_DEFAULT_RETRY | 3 | Default max retries |
FLEXIQ_DEFAULT_TIMEOUT | 300 | Default task timeout in seconds |
FLEXIQ_DEFAULT_PRIORITY | 0 | Default task priority |
FLEXIQ_RESULT_TTL | None | Legacy queue-wide result TTL in seconds |
Retention is on by default: leaving FLEXIQ_RESULT_TTL unset does not
disable auto-cleanup — the queue applies the recommended per-table
retention windows automatically. See Retention &
auto-cleanup
for the defaults and how to opt out.
flexiq creates all tables inside a dedicated PostgreSQL schema (default:
flexiq). The schema is created automatically if it doesn't exist.
# Use a custom schema
queue = Queue(backend="postgres", db_url="postgresql://...", schema="myapp_tasks")Schema names must contain only alphanumeric characters and underscores.
Invalid names raise a ConfigError at startup.
This lets you run multiple independent flexiq instances in the same database by using different schemas, or keep flexiq tables separate from your application tables.
The Postgres backend keeps a pool of reusable connections (default size:
10) rather than opening a new connection per query. Each connection has
the search_path set to the configured schema on acquisition.
Unlike the SQLite backend — where the pool size is fixed and not exposed to
Python (see Deployment)
— the Postgres pool size is tunable from the Queue constructor:
queue = Queue(
backend="postgres",
db_url="postgresql://user:password@localhost:5432/myapp",
pool_size=20, # default: 10
)For most workloads, the default of 10 connections is sufficient. Lower it for managed services with strict per-database connection limits (e.g. Supabase); raise it if workers are blocking waiting for a free connection under load.
Migrations run automatically on first connection. flexiq creates the following 11 tables inside the configured schema:
| Table | Purpose |
|---|---|
jobs | Core job storage |
dead_letter | Dead letter queue |
rate_limits | Token bucket rate limiting state |
periodic_tasks | Cron-scheduled task definitions |
job_errors | Per-attempt error tracking |
job_dependencies | Task dependency edges |
task_metrics | Execution time and memory metrics |
replay_history | Job replay audit trail |
task_logs | Structured task log entries |
circuit_breakers | Circuit breaker state |
workers | Worker heartbeat tracking |
All tables use PostgreSQL-native types (TEXT, BYTEA, BIGINT,
BOOLEAN, DOUBLE PRECISION) rather than SQLite-compatible types.
| Aspect | SQLite | Postgres |
|---|---|---|
| Connection model | Embedded, file-based | Client/server, networked |
| Write concurrency | Single writer (WAL mode) | Multiple concurrent writers |
| Distribution | Single machine only | Multi-machine workers |
| Setup | Zero config, bundled | Requires Postgres server |
| Connection pool default | 8 connections | 10 connections |
| Schema isolation | N/A (file per database) | Custom PostgreSQL schema |
| Tables | 6 tables | 11 tables (additional: job_dependencies, task_metrics, replay_history, task_logs, circuit_breakers) |
| Backup | sqlite3 .backup | pg_dump |
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: myapp
POSTGRES_USER: flexiq
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
worker:
build: .
environment:
FLEXIQ_BACKEND: postgres
FLEXIQ_DB_URL: postgresql://flexiq:secret@postgres:5432/myapp
depends_on:
- postgres
stop_signal: SIGINT
stop_grace_period: 35s
dashboard:
build: .
command: flexiq dashboard --app myapp:queue --host 0.0.0.0
environment:
FLEXIQ_BACKEND: postgres
FLEXIQ_DB_URL: postgresql://flexiq:secret@postgres:5432/myapp
depends_on:
- postgres
ports:
- "8080:8080"
volumes:
pgdata:With Postgres, there are no shared-file constraints — workers and dashboard connect over the network. You can run multiple worker containers across different hosts.
[Unit]
Description=flexiq worker
After=network.target postgresql.service
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/.venv/bin/flexiq worker --app myapp:queue
Restart=always
RestartSec=5
KillSignal=SIGINT
TimeoutStopSec=35
Environment=PYTHONPATH=/opt/myapp
Environment=FLEXIQ_BACKEND=postgres
Environment=FLEXIQ_DB_URL=postgresql://flexiq:secret@db.internal:5432/myapp
[Install]
WantedBy=multi-user.targetWith Postgres, you can run workers on multiple machines. Each worker connects to the same database and coordinates through PostgreSQL's row-level locking:
# Machine 1
flexiq worker --app myapp:queue
# Machine 2
flexiq worker --app myapp:queue
# Machine 3
flexiq worker --app myapp:queueAll workers share the same job queue and dequeue work atomically.
Use standard PostgreSQL backup tools instead of SQLite-specific commands:
# Dump the flexiq schema
pg_dump -h localhost -U flexiq -d myapp -n flexiq > backup.sql
# Restore
psql -h localhost -U flexiq -d myapp < backup.sqlFor continuous backups, use PostgreSQL's built-in WAL (write-ahead logging — see WAL mode and backups for what WAL means in the SQLite backend; Postgres uses WAL primarily for crash recovery and replication rather than reader/writer concurrency) archiving, or a tool like pgBackRest.