Skip to main content
One of pyinfra’s key strengths is its ability to execute operations in parallel across hundreds or thousands of hosts. This guide explains how parallel execution works and how to optimize your deploys for maximum performance.

How Parallel Execution Works

Pyinfra uses a two-phase approach that enables fast, parallel execution:

Phase 1: Prepare (Sequential)

Deploy code runs once per host to determine what operations to execute:
During preparation, pyinfra:
  1. Executes deploy code for each host
  2. Builds operation order and dependencies
  3. Gathers facts needed for change detection
  4. Determines what commands will run

Phase 2: Execute (Parallel)

Operations execute in parallel across all hosts:
Each operation runs on all hosts in parallel, but operations execute sequentially - operation 2 starts only after operation 1 completes on all hosts.
Operations are sequential (ordered), but each operation executes in parallel across all hosts.

Operation Ordering

Operations execute in the order they appear in your deploy file:
deploy.py
Execution flow:

Performance Benefits

Parallel execution provides massive time savings:
pyinfra can manage thousands of hosts with predictable performance - the time to deploy is roughly the time for the slowest host.

Controlling Parallelism

Limit Parallel Hosts

Control how many hosts execute operations simultaneously:
Use cases:
  • Rate limiting - Avoid overwhelming external services
  • Resource constraints - Limit load on control machine
  • Staged rollouts - Deploy to small batches first

Serial Execution for Specific Operations

Force an operation to run serially with _serial=True:
Execution flow:
Use _serial=True for operations that must not run simultaneously (database migrations, shared resource access, etc.).

Group-Based Execution

Execute operations on specific groups in order:
deploy.py
Execution flow:

Handling Failures

By default, pyinfra continues executing even if some hosts fail:
Example output:

Fail Fast

Stop execution on first failure:

Continue on Error

Force an operation to continue even if it fails:
The deploy continues even if this operation fails on some hosts.

Progress Monitoring

Watch execution progress in real-time:
Example output:

Large-Scale Deployments

Optimizations for deploying to many hosts:

Use Connection Pooling

SSH connections are pooled and reused:

Limit Fact Gathering

Only gather facts you actually use:
Pyinfra automatically optimizes fact gathering based on operations used.

Batch Operations

Group similar operations together:

Real-World Example: Rolling Update

Deploy updates in waves to maintain availability:
deploy.py
With 10 web servers:
This pattern maintains availability - app servers restart one at a time while others continue serving traffic.

Targeted Execution

Run operations on specific hosts:

Performance Comparison

Real-world deployment times:
Times assume each operation takes ~3 seconds per host. Actual times vary based on operation complexity and network speed.

Best Practices

Batch similar operations - Install all packages at once instead of individually:
Use serial execution for critical operations - Protect shared resources:
Limit parallelism for external services - Don’t overwhelm APIs or databases:
Monitor failures - Use verbose mode to debug parallel execution:
Test at scale - Use --dry with full inventory to estimate timing:

Understanding the Prepare Phase

The prepare phase is critical for parallel execution:
deploy.py
What happens:
The prepare phase must complete for all hosts before any operations execute. This ensures correct operation ordering.

Next Steps