What do Pest's --parallel and --tia options each do to a slow suite, and why does only one belong in the CI command?
answer
- more workers versus fewer tests
- ParaTest, one process per CPU core
- --processes=N overrides the count
- --tia records a graph via PCOV or Xdebug
- replays cached results; keep off CI
basics
~20 s--parallel runs the whole suite across several processes through ParaTest, so it belongs in CI; --tia (Pest 5) records which files each test touches and later runs only affected tests, replaying cached results, so it is meant for local runs.
solid answer
~50 s`--parallel` (or `-p`) hands the run to ParaTest, which starts one worker process per CPU core by default, or `--processes=N`. Every test still runs, so the result is as trustworthy as a serial run, provided the tests are isolated: no shared database rows, no dependence on order, no races on files. `--tia`, new in Pest 5, is test impact analysis: the first run records, through PCOV or Xdebug, which source files each test touches; later runs execute only tests affected by your changes and replay cached results for the rest. That makes it a local feedback tool. CI exists to verify every test on a clean checkout, so the docs keep `--tia` out of the CI command, except for a dedicated job that records a shared baseline. `pest()->tia()->locally()` turns it on for local runs only.
code
bash · 5 lines# CI: every test, spread over 8 worker processes
./vendor/bin/pest --parallel --processes=8
# local: only tests affected by the working-tree changes
./vendor/bin/pest --parallel --tiago deeper
Recall that --parallel spreads tests over several processes and --tia runs only tests affected by your changes.
Explain ParaTest workers, the default of one process per CPU core, --processes, and the isolation rules a suite must meet to run in parallel.
Diagnose parallel-only failures as shared state, set up per-worker databases, and argue why --tia stays out of the CI command apart from baseline recording.
Balance local feedback speed against CI trust: where cached results are acceptable, who owns the baseline workflow, and when to shard across machines instead.
## Two different answers to "the suite is slow" A slow suite can be made faster by running **the same tests on more workers** or by running **fewer tests**. Pest has one option for each, and they are often used together locally: `./vendor/bin/pest --parallel --tia`. | | `--parallel` | `--tia` (Pest 5) | |---|---|---| | What changes | how many processes run tests | which tests run at all | | Runs every test | yes | no, affected tests only; others are replayed from cache | | Needs | isolated tests | a coverage driver, PCOV or Xdebug, for the recording run | | Belongs in CI | yes | no, apart from a baseline-recording job | ## --parallel: the same suite on more processes - Pest's `Parallel` plugin passes the run to **ParaTest** (`brianium/paratest`, a Pest dependency). `-p` is a short form of `--parallel`. - By default Pest starts **one process per available CPU core**; `--processes=10` sets the number explicitly. - Each worker is a separate PHP process, so static state and in-memory singletons are not shared between workers, but **external resources are**: one database, one cache directory, one set of temp files. - ParaTest gives each worker a `TEST_TOKEN` environment variable, which is the usual key for giving each worker its own database or directory. The docs list the three rules a parallel-safe suite obeys: 1. Tests must not share database state; each test sets up and cleans up its own. 2. Tests must not depend on execution order. 3. Tests must not race on shared resources such as a fixed file path. Pest also drops parallelism silently for a few options: when you pass `--retry`, `--todo`, `--todos`, `--notes`, `--issue`, `--pr`, `--pull-request` or `--flaky`, the run falls back to a single process. ## --tia: fewer tests, cached results for the rest The **Tia Engine** (test impact analysis) arrived in Pest 5. 1. The first `--tia` run is the **baseline**. Pest enables PCOV or Xdebug and records a graph of which files each test touches. Without a coverage driver the graph cannot be recorded and Tia does not run. 2. On later runs Pest compares your working tree with the graph, runs the affected tests, and **replays** stored results, including their coverage, for everything else. 3. Structural changes such as `composer.lock` or `phpunit.xml` rebuild the graph; `--tia --fresh` rebuilds it by hand, `--no-tia` disables it for one run. ## Sharding: the third lever Pest also splits a suite across several CI machines with `--shard=1/4`, `--shard=2/4` and so on. In Pest 5, running `./vendor/bin/pest --update-shards` writes timing data to `tests/.pest/shards.json`; when that file is committed, `--shard` distributes tests by measured execution time rather than by count, so every shard finishes at about the same moment. Sharding and `--parallel` combine: each machine takes one shard and runs it across its own worker processes. Like `--parallel`, sharding still runs every test somewhere, so it is compatible with a full CI verification in a way that Tia is not. ## Why CI runs the full suite - CI is the place where every test is verified against a clean checkout. A replayed result is a cached claim, and a graph that missed a dependency would let a real regression pass. - The Pest docs therefore say to keep `--tia` out of the CI test command. The single exception is a separate workflow that records a baseline once per merge to the main branch, which developers can download with `pest()->tia()->baselined()` or `--tia --baselined`. - `pest()->tia()->locally()` in `tests/Pest.php` enables Tia on developer machines without the flag, and skips it on CI or whenever `--ci` is passed. `--parallel`, by contrast, changes nothing about which tests run, so it is a safe CI speed-up once the suite is isolated. If parallel runs turn up failures that serial runs never show, that is shared state being exposed, and the fix is in the tests.
- A suite passes serially but fails intermittently with --parallel; what do you look for?Shared external state between worker processes: rows another test inserted, a fixed temp file path, a cache directory, or a test that assumes it runs after another. Give each worker its own database keyed by the `TEST_TOKEN` environment variable, and make every test create and clean up its own data.
- Why does the first --tia run fail to speed anything up, and what does it need?The first run records the baseline graph of which files each test touches, so every test executes, with some coverage overhead. It needs PCOV or Xdebug available; without a coverage driver Pest cannot record the graph and Tia does not run.
--parallel is opening more checkout lanes: every item is still scanned, just sooner. --tia is a cashier who re-scans only the items that changed since yesterday's receipt and copies the rest from it; fast, but only as trustworthy as that receipt, which is why the end-of-day audit (CI) still scans everything.
saying these in an interview costs you the question
- --parallel skips tests that did not change
- --tia is safe to use as the main CI test command
- Parallel workers share PHP static state between them
- --tia works without PCOV or Xdebug installed
- Pest always uses exactly four processes for --parallel