mrkeyoor.com_
Sun 20 Sept 04:58 UTC
PyPITestingupdated 20 Sept 2026

pytest-xdist review

pytest-xdist 3.8.0 runs one pytest session through several worker processes, usually on the CPUs of a single machine. Each worker collects the suite, and the controller assigns matching test indexes using schedulers such as load, loadfile, loadscope, or loadgroup. This helps independent CPU-heavy tests; it exposes shared databases, ports, files, and session fixtures that were never isolated. Version 3.8.0 adds --no-loadscope-reorder and a matching ini option, letting loadscope preserve the input file order when that matters more than maximum scheduling freedom. Our Python 3.12 import of xdist completed in 0.52 seconds.

Verdict

Our pytest-xdist 3.8.0 install took 0.5 seconds and 8 MB, but each of its workers repeats collection and session fixtures. Install it after resources are isolated per worker; leave a short or shared-state suite serial.

We installed it

Lab card: what happened when we installed pytest-xdistScreenshot of pytest-xdist documentation
Install✓ · 0.5s7 packages on disk · 8 MB
Importimport xdist in 0.52s · pure Python · requires Python >=3.9
Known vulns0(pip-audit)

Answers from our run

Does pytest-xdist install cleanly?

Yes. In a fresh container with an empty cache, pip install pytest-xdist finished in 0.5s, leaving 7 packages and 8 MB on disk. pip-audit reported no known vulnerabilities.

What does pytest-xdist need to run?

Python >=3.9, and nothing compiled: it is pure Python. In our run import xdist succeeded in 0.52s.

pytest-xdist or pytest-split: which should you use?

pytest-split: Choose it to divide tests among CI jobs from recorded durations. Our pytest-xdist 3.8.0 install took 0.5 seconds and 8 MB, but each of its workers repeats collection and session fixtures.

When should you not use pytest-xdist?

Tests write to one database, Redis namespace, file, port, or singleton that cannot be divided by worker

API stability5/5The 3.x line keeps -n, --dist, worker_id, testrun_uid, xdist_group, and the scheduler hooks familiar. Version 3.8.0 adds loadscope ordering controls without changing the existing default command. Compatibility floors are explicit at Python 3.9, pytest 7, and execnet 2.1. Scheduler behavior is still observable test infrastructure, so pinning the plugin avoids an unexpected distribution change during a CI image refresh.
Docs4/5The Read the Docs site returned HTTP 200 and explains controller and worker roles, scheduler modes, remote gateways, fixtures, hooks, and known limitations. It calls out the identical-collection rule and the missing distributed equivalents for interactive debugging and uncaptured output. Resource isolation remains project-specific: examples can show worker_id and testrun_uid, but they cannot design safe database provisioning or cleanup for a particular stack.
Maintenance4/5pytest-dev owns an unarchived repository that was pushed on 2026-08-25. GitHub reported 315 open issues and pull requests, while release 3.8.0 was published on 2025-07-01. That release added a concrete loadscope ordering control, and repository work continued more than a year later. The backlog is large enough that teams with scheduler edge cases should search existing reports before assuming a quick maintainer response.
Ecosystem5/5PyPI Stats recorded 35,845,434 downloads in the latest week, and GitHub showed 1,898 stars. pytest plugins such as coverage tools commonly account for xdist workers, and the project exposes hooks for custom worker counts and schedulers. Popularity does not solve local isolation: databases, ports, caches, log files, and session fixtures still need an explicit per-worker or per-run ownership plan.

Use it if

  • A long pytest suite contains independent work that can use several CPU processes
  • Each worker can receive its own database, port range, cache, and temporary directory
  • Tests sharing an expensive module or class fixture should travel together under loadscope or loadfile
  • One CI machine has spare cores and adding more hosted jobs would cost more
Skip it if

Setup reality

We installed pytest-xdist 3.8.0 in 0.5 seconds on Python 3.12. Seven packages used 8 MB on disk, and pip-audit reported 0 known vulnerabilities. The measured package had 5 direct dependencies and pure Python code. import xdist worked in 0.52 seconds. It requires Python 3.9 or newer, does not ship py.typed, and exposed no license value in the installed metadata we inspected.

Installing the plugin registers -n and --dist; no account, service credential, or required config file is involved. PyPI declares pytest >=7 and execnet >=2.1. pytest -n auto follows detected physical CPU availability. A container can see a host count larger than its CPU quota, so a fixed -n value is easier to reason about in CI. Optional extras bring psutil or setproctitle.

Each worker imports conftest.py and owns a pytest session. A session-scoped fixture therefore runs once in every worker. Build resource names from worker_id, which is gw0, gw1, and so on during distribution. testrun_uid is shared across workers for one invocation and can namespace a common external resource. Shared creation still needs a file or service lock because worker startup order is not defined.

All workers must collect the same test IDs in the same order. Unsorted sets, filesystem enumeration, random parametrization, or environment-dependent skips can stop the run before execution. Begin with 2 workers and inspect failures before selecting loadfile or loadscope for fixture reuse. Version 3.8.0's --no-loadscope-reorder preserves file order under loadscope, though that choice can leave a worker idle when one file is much slower.

Patterns

Run a fixed worker count parallel-workers

pytest -n 4
pytest -n auto
pytest -n 0

A fixed count respects a known CI quota. -n 0 returns to serial execution for diagnosis.

Choose how tests are grouped scheduler-mode

pytest -n 4 --dist loadfile
pytest -n 4 --dist loadscope
pytest -n 4 --dist loadgroup
pytest -n 4 --dist worksteal

loadfile and loadscope keep wider fixture owners together. loadgroup only acts on xdist_group marks.

Keep file order with loadscope loadscope-order

pytest -n 4 --dist loadscope --no-loadscope-reorder

Version 3.8.0 added this switch. Preserved order can balance worse than the default reorder.

Give every worker a database worker-database

import pytest

@pytest.fixture(scope='session')
def database_name(worker_id):
    suffix = 'serial' if worker_id == 'master' else worker_id
    return f'test_app_{suffix}'

worker_id is master without distribution and gw0, gw1, and onward with xdist.

Name one distributed test run run-namespace

@pytest.fixture(scope='session')
def bucket_name(testrun_uid):
    return f'integration-{testrun_uid}'

testrun_uid is identical in every worker for one invocation. Lock shared provisioning.

Keep resource tests on one worker group-tests

@pytest.mark.xdist_group(name='payments')
def test_charge(): ...

@pytest.mark.xdist_group(name='payments')
def test_refund(): ...

# pytest -n 4 --dist loadgroup

The marker changes placement only under the loadgroup scheduler.

Sort parametrized input deterministic-collection

@pytest.mark.parametrize('region', sorted(load_regions()))
def test_region(region):
    ...

A different test ID order in any worker makes the controller reject collection.

Run setup only in the controller controller-only-hook

import xdist

def pytest_configure(config):
    if xdist.is_xdist_worker(config):
        return
    start_controller_service()

pytest_configure can execute in the controller and workers. Guard a side effect that should happen once.

Limit crashed-worker retries worker-restarts

pytest -n 4 --max-worker-restart 0
pytest -n 4 --max-worker-restart 2

A killed or crashed process may restart. A low ceiling exposes repeated OOM or native crashes.

Reproduce one case serially serial-debug

pytest -n 0 -s --pdb tests/test_orders.py::test_race

Serial mode restores the ordinary interactive debugger and uncaptured terminal behavior.

Collect coverage from workers parallel-coverage

pytest -n 4 --cov=myapp --cov-report=term-missing

Use a pytest-cov version that combines worker data, then compare once against -n 0.

Cap automatic workers auto-worker-hook

def pytest_xdist_auto_num_workers(config):
    return 4

This hook gives the project one ceiling even when developers type -n auto.

Alternatives

PackageRegistryPick it when
pytest-splitPyPIChoose it to divide tests among CI jobs from recorded durations.
pytest-parallelPyPIEvaluate it when you specifically need its thread and process execution model.
pytest-forkedPyPIChoose it for per-test process isolation without xdist scheduling.

More testing guides

pytest · chai · vitest · jsdom · playwright · coverage · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.