As a suite grows, CI time grows with it. Turning up workers helps until the machine runs out of CPU and memory. After that, the only way to go faster is more machines — which is exactly what sharding does.
Playwright Workers vs Shards
| Workers | Shards | |
|---|---|---|
| What it is | Parallel worker processes on one machine | Slices of the suite on separate machines |
| Configure with | workers in config or --workers=4 | --shard=1/4 on each CI job |
| Limited by | CPU cores and memory of the runner | How many CI jobs you can run at once |
| Reports | One report automatically | One per shard — merge them afterwards |
They stack: four shards with two workers each run up to eight tests at a time. For tuning workers on a single machine, see our parallel testing guide.
Playwright Sharding Basics
Pass --shard=x/y, where y is the total number of shards and x is the one this machine should run:
npx playwright test --shard=1/4 npx playwright test --shard=2/4 npx playwright test --shard=3/4 npx playwright test --shard=4/4
Each command runs a different quarter of the suite. In CI, you run these as four parallel jobs.
Balancing Shards with fullyParallel
How Playwright splits the suite depends on fullyParallel:
- With
fullyParallel: true— tests are split at the individual test level, so shards come out evenly balanced. - Without it — tests are split at the file level. One huge spec file can make its shard much slower than the rest, so keep files small and similar in size.
- Tests marked
test.skip()ortest.fixme()do not run, so they do not count toward balancing.
import { defineConfig } from '@playwright/test';
export default defineConfig({
fullyParallel: true,
// blob reports can be merged after sharding; keep html locally
reporter: process.env.CI ? 'blob' : 'html',
});
Playwright Sharding in GitHub Actions
This is the workflow from the official Playwright docs. A matrix starts four shard jobs, each uploads a blob report, and a final job merges them into one HTML report:
name: Playwright Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
playwright-tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: lts/*
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload blob report to GitHub Actions Artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: blob-report-${{ matrix.shardIndex }}
path: blob-report
retention-days: 1
merge-reports:
if: ${{ !cancelled() }}
needs: [playwright-tests]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: lts/*
- name: Install dependencies
run: npm ci
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v5
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge into HTML Report
run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: Upload HTML report
uses: actions/upload-artifact@v4
with:
name: html-report--attempt-${{ github.run_attempt }}
path: playwright-report
retention-days: 14
fail-fast: false matters. Without it, one failing shard cancels the others and you lose most of the results.
New to Actions? Start with our Playwright GitHub Actions guide.
Playwright Sharding in GitLab CI
GitLab's parallel keyword starts N copies of a job and sets CI_NODE_INDEX (1-based) and CI_NODE_TOTAL — a perfect fit for --shard:
stages: [test, report]
playwright:
stage: test
image: mcr.microsoft.com/playwright:v1.64.0-noble # match your @playwright/test version
parallel: 4
script:
- npm ci
- npx playwright test --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
artifacts:
when: always
paths: [blob-report]
expire_in: 1 day
merge-reports:
stage: report
image: mcr.microsoft.com/playwright:v1.64.0-noble
when: always
script:
- npm ci
- mkdir -p all-blob-reports && cp blob-report/*.zip all-blob-reports/ || true
- npx playwright merge-reports --reporter html ./all-blob-reports
artifacts:
when: always
paths: [playwright-report]
Blob files from parallel jobs have unique names, so GitLab can collect them into one blob-report folder for the merge job. Keep the Docker image tag in sync with your installed Playwright version.
Playwright Sharding in Jenkins
In a declarative pipeline, use parallel stages — one per shard. Each stage needs an agent so the shards really run on separate executors:
pipeline {
agent none
stages {
stage('Playwright') {
parallel {
stage('Shard 1') {
agent any
steps {
sh 'npm ci && npx playwright install --with-deps'
sh 'npx playwright test --shard=1/3'
}
post { always { stash name: 'blob1', includes: 'blob-report/**', allowEmpty: true } }
}
stage('Shard 2') {
agent any
steps {
sh 'npm ci && npx playwright install --with-deps'
sh 'npx playwright test --shard=2/3'
}
post { always { stash name: 'blob2', includes: 'blob-report/**', allowEmpty: true } }
}
stage('Shard 3') {
agent any
steps {
sh 'npm ci && npx playwright install --with-deps'
sh 'npx playwright test --shard=3/3'
}
post { always { stash name: 'blob3', includes: 'blob-report/**', allowEmpty: true } }
}
}
}
stage('Merge reports') {
agent any
steps {
dir('all-blob-reports') {
unstash 'blob1'
unstash 'blob2'
unstash 'blob3'
}
sh 'npm ci'
sh 'npx playwright merge-reports --reporter html ./all-blob-reports/blob-report'
archiveArtifacts artifacts: 'playwright-report/**', allowEmptyArchive: true
}
}
}
}
If a shard fails, the pipeline stops before the merge stage — add catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') around the test step if you always want the merged report. For the base Jenkins setup, see our Playwright Jenkins tutorial.
Playwright Sharding in Azure DevOps
Azure Pipelines can fan out a job with strategy: parallel. Each copy knows its position through predefined variables:
jobs:
- job: playwright
strategy:
parallel: 4
pool:
vmImage: ubuntu-latest
steps:
- task: NodeTool@0
inputs:
versionSpec: '22.x'
- script: npm ci
- script: npx playwright install --with-deps
- script: npx playwright test --shard=$(System.JobPositionInPhase)/$(System.TotalJobsInPhase)
env:
CI: 'true'
- publish: blob-report
artifact: blob-report-$(System.JobPositionInPhase)
condition: always()
Add a second job that depends on playwright, downloads all blob-report-* artifacts into one folder, and runs merge-reports just like the GitHub example.
Merging Sharded Reports into One
Each shard writes a blob-report folder. Once all shards finish, collect the blob files into one folder and run:
npx playwright merge-reports --reporter html ./all-blob-reports
The result is a single playwright-report with every test from every shard, including traces and screenshots. You can merge to other formats too, for example --reporter junit for CI dashboards. Our reporting tools guide covers the options.
How Many Shards Should You Use?
- Start from your slowest acceptable run time. If the suite takes 40 minutes on one machine and you want 10, start with 4 shards.
- Remember the fixed cost. Every shard repeats checkout,
npm ciand browser install — often 1–2 minutes. Past a point, more shards add cost without saving time. - Use workers too. A 4-core runner can usually run 2–4 workers; shards multiply that.
- Watch for imbalance. If one shard is always much slower, turn on
fullyParallelor split its big spec files. - Retries stay inside each shard. A failed test retries on the same machine, so flaky tests can still slow one shard down — fix them with our flaky tests guide.
Frequently Asked Questions
What is the difference between Playwright sharding and workers?
Workers are parallel processes on one machine, set with workers or --workers. Sharding splits the suite across separate machines with --shard=x/y. You can combine both.
Can I use sharding and workers together?
Yes. Each shard still uses the workers setting, so 4 shards with 2 workers each run up to 8 tests at the same time.
Why are my Playwright shards unbalanced?
Without fullyParallel: true, Playwright splits by file, so one large spec file makes its shard slow. Enable fullyParallel or split large files into smaller ones.
How do I merge Playwright reports from multiple shards?
Set reporter: 'blob' in CI, collect every shard's blob-report files into one folder, then run npx playwright merge-reports --reporter html ./all-blob-reports.
How do retries work with sharding?
Retries happen inside the shard that ran the test. The merged report shows each test's attempts, so flaky tests are still easy to spot.
Asim Noaman
Senior QA Automation Engineer & AI Testing Specialist
With years of hands-on experience building test automation frameworks for production applications, Asim specializes in combining traditional QA methodologies with cutting-edge AI tools. He has helped teams adopt Playwright and AI-driven testing workflows to ship faster with fewer bugs.
Complete Course
Take Your Playwright Suite to Production CI
The complete Udemy course covers parallel runs, CI/CD pipelines and reporting hands-on — plus AI-powered test generation and maintenance with Claude.
- Parallel workers and CI pipelines
- GitHub Actions end to end
- Reports teams actually read
- AI-assisted test maintenance