How to run tests in parallel with pytest-xdist
A large test suite that runs sequentially can take minutes. pytest-xdist distributes tests across multiple worker processes, which can lead to considerable speed ups depending on the test suite and hardware.
Installation
Add pytest-xdist as a dev dependency using uv:
uv add --dev pytest-xdistRunning tests in parallel
Pass -n auto to let pytest-xdist detect the number of available CPU cores and spawn that many workers:
uv run pytest -n autoTo specify an exact number of workers:
uv run pytest -n 4Each worker runs in its own process with its own Python interpreter. Tests are distributed to workers as they become available. The output is collected and displayed as a single report.
Making it the default
Add -n auto to your pyproject.toml so parallel execution happens without remembering the flag:
[tool.pytest.ini_options]
addopts = "-n auto"To temporarily override this and run tests sequentially (useful for debugging):
uv run pytest -n 0When tests are not safe to parallelize
Parallel execution assumes tests are independent. Tests that share mutable state will produce intermittent failures when run concurrently. Common sources of trouble:
Shared files or databases. Two workers writing to the same SQLite file or temp directory will collide. Use pytest’s tmp_path fixture to give each test its own directory, or use session-scoped fixtures with worker-aware setup.
Shared external resources. Because each worker is a separate process, in-memory state like module-level variables and singletons is already isolated. The real problems come from shared external resources: databases, files on disk, network ports, or external services that multiple workers access simultaneously.
Port binding. Tests that start a server on a fixed port will fail when two workers try to bind the same port. Use port 0 to let the OS assign a free port.
Worker-scoped fixtures
pytest-xdist assigns each worker an ID (gw0, gw1, etc.). Fixtures that need to be unique per worker can use worker_id:
@pytest.fixture(scope="session")
def db_name(worker_id):
return f"test_db_{worker_id}"For session-scoped fixtures that should run only once across all workers (not once per worker), use tmp_path_factory with a file lock. The first worker to acquire the lock performs setup; others wait and then read the result:
import pytest
from filelock import FileLock
@pytest.fixture(scope="session")
def shared_data(tmp_path_factory, worker_id):
if worker_id == "master":
# not running with xdist, set up directly
data_dir = tmp_path_factory.mktemp("data")
populate_test_data(data_dir)
return data_dir
root_tmp = tmp_path_factory.getbasetemp().parent
lock = root_tmp / "data.lock"
data_dir = root_tmp / "shared_data"
with FileLock(str(lock)):
if not data_dir.exists():
data_dir.mkdir()
populate_test_data(data_dir)
return data_dirThis requires the filelock package (uv add --dev filelock). The populate_test_data function is whatever setup your tests need (creating files, seeding a database, etc.).
Controlling test distribution
By default, pytest-xdist distributes tests to available workers using load balancing (--dist load). It sends pending tests in chunks to whichever worker is free. The most useful alternative modes:
--dist loadscopegroups tests by module or class, keeping them on the same worker. This avoids redundant setup when tests share module- or class-scoped fixtures.--dist loadfilegroups tests from the same file on one worker. Similar toloadscopebut scoped to files only.--dist workstealstarts with an even split, then lets idle workers steal tests from busy ones. Good for suites with uneven test durations.
uv run pytest -n auto --dist loadscopeSee the pytest-xdist distribution docs for the full list of modes.
Measuring the speedup
Compare sequential and parallel run times:
uv run pytest --durations=10 # sequential, shows slowest tests
uv run pytest -n auto --durations=10 # parallelIf the speedup is less than expected, check for a few slow tests that dominate total time. Parallelism helps most when many tests take roughly the same amount of time.
See also
- Setting up testing with pytest and uv for project setup
- pytest reference
- pytest-xdist documentation
Also Mentioned In
Get Python tooling updates
Subscribe to the newsletter