Understanding Parallel Workers in Playwright
Playwright Test runs test files in parallel by default, spinning up multiple worker processes—separate OS processes, not just threads—each with its own browser instance and isolated global state. By default the worker count is based on available CPU cores, and each worker executes entire test files serially unless fullyParallel is enabled, in which case individual tests within a file can also run concurrently across workers. This isolation means a crashed browser or a global variable mutation in one worker never leaks into another, at the cost of the memory and startup overhead of launching many browser instances.
Cricket analogy: Like IPL franchises fielding separate squads that each play their own matches simultaneously in different stadiums, Playwright workers are independent processes with their own browser instance, so a bug in one worker's state never bleeds into another's innings.
Configuring Worker Count
You control worker count via the workers property in playwright.config.ts, either as an absolute number or a fraction of CPU cores (e.g., '50%'), and you can override it per run with the --workers=N CLI flag. On CI machines, which often have fewer usable cores or shared resource limits, teams typically pin workers to 1 or 2 to avoid resource contention and flaky timing, while local development machines can safely use higher counts since fullyParallel tests still respect the retries and timeout settings independently per worker.
Cricket analogy: A captain like Rohit Sharma picks how many bowlers to rotate in a death over based on conditions; similarly you tune the workers setting between a packed CI pitch report and a spacious home-ground laptop, using more resources only when the surface allows it.
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
fullyParallel: true,
// Use half the cores locally, but only 2 workers on CI
workers: process.env.CI ? 2 : '50%',
retries: process.env.CI ? 2 : 0,
});
// Override on the command line for a one-off run:
// npx playwright test --workers=4Sharding Across Machines
Sharding splits the entire test suite across multiple independent CI machines using the --shard=<index>/<total> flag, so a suite of 300 tests spread across 4 shards runs roughly 75 tests per machine in parallel job runners, cutting wall-clock CI time roughly by the shard count when jobs run concurrently. Playwright distributes test files (not individual tests within fullyParallel files) across shards using a static allocation based on file order and estimated duration when available, so shard 2/4 and shard 3/4 might each get a different mix of long and short spec files.
Cricket analogy: Sharding a 300-test suite across 4 machines is like splitting a five-day Test match's overs across four different bowlers on the same day so the innings finishes faster without any one bowler wearing down.
# .github/workflows/tests.yml
jobs:
test:
strategy:
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- uses: actions/upload-artifact@v4
with:
name: blob-report-${{ matrix.shardIndex }}
path: blob-report/Sharding and workers solve different problems: workers parallelize within one machine's process pool, while sharding parallelizes across separate machines entirely. Most CI setups combine both — a handful of shards, each shard running a couple of workers internally.
Merging Shard Reports
Because each shard produces its own partial report, Playwright's blob reporter writes a compact binary report per shard that you then combine with the npx playwright merge-reports CLI command after all shard jobs finish, producing a single unified HTML report with combined pass/fail counts, traces, and screenshots across the whole suite. Skipping this merge step means you're left debugging four separate, incomplete reports instead of one coherent view of the full run, which is why CI workflows upload blob-report artifacts and run a dedicated merge job that depends on all shard jobs completing.
Cricket analogy: After a rain-affected match is completed at four different grounds in a tournament, the scorers combine each venue's scoresheet into one official tournament table, just as merge-reports stitches four shards' results into a single scorecard.
Setting too many workers on a memory-constrained CI runner is a common cause of flaky failures — each browser instance consumes real RAM, and oversubscribing cores leads to timeouts that look like application bugs but are actually resource starvation.
- Workers are isolated OS processes, each running its own browser instance with independent global state.
- The workers config option and --workers CLI flag control how many run concurrently on one machine.
- fullyParallel: true allows individual tests within a file, not just whole files, to run across workers.
- Sharding (--shard=<index>/<total>) splits the suite across multiple independent CI machines for further speedup.
- Playwright allocates whole test files to shards based on file order and estimated duration.
- The blob reporter plus npx playwright merge-reports combines per-shard results into one unified HTML report.
- CI typically uses fewer workers per machine than local development to avoid resource contention.
Practice what you learned
1. What is the key isolation boundary between Playwright workers?
2. Which config option allows individual tests within a single file to run across different workers?
3. What does the --shard=2/4 flag do?
4. Why is the blob reporter used when sharding across CI machines?
5. Why do CI pipelines typically use fewer workers per machine than local development?
Was this page helpful?
You May Also Like
Playwright in CI/CD Pipelines
How to configure Playwright to run reliably on CI, including GitHub Actions setup, Docker images, and CI-aware config adjustments.
Retries and Flaky Test Handling
Understanding why Playwright tests flake, how to configure retries safely, and how auto-waiting fixes root causes instead of masking them.
Reporters and HTML Reports
How Playwright's built-in reporters work, how to configure and combine them, and how to build a custom reporter for bespoke workflows.