Requirements
Multi-server deployments require:- PostgreSQL database version 14.9 or higher (SQLite does not support multi-server synchronization)
- Redis for event messaging
- Load balancer for API traffic distribution
Architecture
A scaled Prefect deployment typically includes:- Multiple API server instances - Handle UI and API requests
- Background services - Runs the scheduler, automation triggers, and other loop services. Can be scaled horizontally by running multiple instances coordinated through Redis
- PostgreSQL database - Stores all persistent data and synchronizes state across servers
- Redis - Distributes events between services and coordinates background service work
- Load balancer - Routes traffic to healthy API instances (e.g. NGINX or Traefik)
Configuration
Database setup
Configure PostgreSQL as your database backend:AWS RDS IAM Authentication
To use AWS IAM authentication for your PostgreSQL database (experimental):-
Install the AWS integration:
-
Create an IAM policy with
rds-db:connectpermission and attach it to your IAM user/role. -
Enable plugins and IAM authentication:
-
Configure your connection URL:
Azure Managed Identity Authentication
To use Azure managed identity (Microsoft Entra ID) authentication for your PostgreSQL database (experimental):-
Install the Azure integration:
-
Enable Microsoft Entra authentication on your Azure Database for PostgreSQL flexible server and grant the identity a database principal via the
pgaadauthextension. -
Enable plugins and managed identity authentication:
-
Configure your connection URL:
Redis setup
Configure Redis as your server’s message broker, cache, and lease storage:PREFECT_REDIS_MESSAGING_URL is set, it takes precedence and the individual host, port, db, username, password, and SSL fields are ignored:
rediss:// for TLS connections:
Redis Cluster mode (
redis+cluster:// and rediss+cluster:// URL schemes) is not yet supported. If you configure a cluster URL, Prefect raises an error at startup rather than attempting a partial connection.Docket URL for background services
Prefect uses Docket to coordinate background services like the scheduler, late run detection, and automation triggers. By default, Docket uses in-memory storage (memory://), which only works for single-server deployments.
For high-availability deployments, configure Docket to use Redis:
The Docket URL can use the same Redis instance as the messaging configuration above, but you may use a different database number (e.g.,
/1 instead of /0) to keep the data separate.Service separation
For optimal performance, run API servers and background services separately: API servers (multiple instances):Running multiple background services
For high availability and throughput, you can run multipleprefect server services start processes in parallel. Prefect uses Docket (backed by Redis) to coordinate work across background service processes so that periodic work (like scheduling, late run detection, and automation trigger evaluation) runs exactly once per interval even when multiple processes are running.
To run multiple background service processes:
- Configure
PREFECT_SERVER_DOCKET_URLto point at a shared Redis instance (see Docket URL for background services). The default in-memory backend (memory://) is only safe for a single process. - Ensure every background service process connects to the same PostgreSQL database, Redis messaging instance, and Docket URL as the API servers.
- Start one
prefect server services startprocess per replica. Each replica runs the same set of enabled services; Docket ensures only one replica picks up each scheduled run.
Running specific services on dedicated processes
All services run together in a singleprefect server services start process by default. To dedicate a process to a specific subset of services (for example, to scale a noisy neighbor independently), disable the services you don’t want to run on that process with their *_ENABLED environment variable.
List all services and their enable/disable environment variable:
Some services maintain their own at-least-once semantics at the database or Redis level rather than relying on Docket’s run-once guarantee. Running multiple processes with the same service enabled is supported, but starting with one process per service (and scaling up only when you observe a specific bottleneck) keeps operations simple.
Database migrations
Disable automatic migrations in multi-server deployments:Load balancer configuration
Configure health checks for your load balancer:- Health endpoint:
/api/health(verifies the HTTP server is running) - Readiness endpoint:
/api/ready(verifies database connectivity and returns503when Postgres is unreachable) - Expected response: HTTP 200 with JSON
truefrom/api/health - Check interval: 5-10 seconds
/api/health for liveness-style checks where you only need to confirm the process is up. Use /api/ready when the check should fail if the database is unavailable—for example, to stop routing traffic during a Postgres outage. See Kubernetes health and readiness probes for probe configuration on Kubernetes.
Example NGINX configuration:
Reverse proxy configuration
When hosting Prefect behind a reverse proxy, ensure proper header forwarding:UI proxy settings
When self-hosting the UI behind a proxy:PREFECT_UI_API_URL: Connection URL from UI to APIPREFECT_UI_SERVE_BASE: Base URL path to serve the UIPREFECT_UI_URL: URL for clients to access the UI
SSL certificates
For self-signed certificates:-
Add certificate to system bundle and set:
-
Or disable verification (testing only):
Environment proxy settings
Prefect respects standard proxy environment variables:Deployment examples
Docker Compose
3 API servers, 2 background services, postgres, redis
3 API servers, 2 background services, postgres, redis
Operations
Migration considerations
Handling large databases
When running migrations on large database instances (especially where tables likeevents, flow_runs, or task_runs can reach millions of rows), the default database timeout of 10 seconds may not be sufficient for creating indexes.
If you encounter a TimeoutError during migrations, increase the database timeout:
Index creation time scales with table size. A database with millions of events may require 30+ minutes for some migrations. If a migration fails due to timeout, you may need to manually clean up any partially created indexes before retrying.
Recovering from failed migrations
If a migration times out while creating indexes, you may need to manually complete it. For example, if migration7a73514ca2d6 fails:
-
First, check which indexes were partially created:
-
Manually create the missing indexes using
CONCURRENTLYto avoid blocking: -
Mark the migration as complete:
Monitoring
Monitor your multi-server deployment:- Database connections: Watch for connection pool exhaustion
- Redis memory: Ensure adequate memory for message queues
- API response times: Track latency across different endpoints
- Background service lag: Monitor time between event creation and processing
Best practices
- Start with 2-3 API instances and scale based on load
- Use connection pooling to manage database connections efficiently
- Monitor extensively before scaling further (e.g. Prometheus + Grafana or Logfire)
- Test failover scenarios regularly
Further reading
- Database maintenance - Monitor table sizes, configure event retention, and manage data growth
- Server concepts
- Deploy Helm charts for Kubernetes