Playwright in GitHub Actions: Parallel, Fast, Production-Ready CI
Run Playwright tests in GitHub Actions with parallel workers, sharding, environment variables, and HTML reports. Includes a full working workflow file.
· 8 min read
Playwright in GitHub Actions is the default CI setup for most teams in 2026. Done right, your suite finishes in minutes with parallel workers and produces an HTML report you can browse on every PR. Here is the workflow that works.
The minimum viable workflow
`name: Playwright Tests on: [pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 20 } - run: npm ci - run: npx playwright install --with-deps - run: npx playwright test - uses: actions/upload-artifact@v4 if: always() with: { name: playwright-report, path: playwright-report/ }`
That is it for a small project. Pin Node to your local version, cache `~/.cache/ms-playwright` to skip the browser install, and you have a 5-minute green build.
Sharding for parallel execution
Playwright supports test sharding natively. Use a matrix strategy: `strategy: matrix: { shard: [1/4, 2/4, 3/4, 4/4] }` and pass `--shard=${{ matrix.shard }}` to the test command. Four parallel runners, roughly a quarter of the total time.
Combine with Playwright's per-worker parallelism (`workers: 4` in config) for true parallel-of-parallel execution.
Environment variables and secrets
Store `BASE_URL`, `TEST_EMAIL`, `TEST_PASSWORD`, and any API keys in repository secrets. Reference them in the workflow with `env:`. Never echo secrets directly in workflow steps — they can surface in logs and break the masking on edge cases.
For test data that rotates often, pull it at runtime from TestAssets via the REST API — your suite reads the same staging credentials your QA team uses, and rotation does not require a workflow file change.
Caching browsers and dependencies
Playwright downloads ~300MB of browsers on every fresh install. Cache them: `- uses: actions/cache@v4 with: { path: ~/.cache/ms-playwright, key: playwright-${{ hashFiles('package-lock.json') }} }`. Combined with npm cache, your green path is under 90 seconds.
HTML reports on every PR
The default Playwright HTML reporter is great. Upload it as an artifact (always, including on failure) and reviewers can download and browse it locally. For richer integration, use a hosted reporter like Currents or Allure.
Common gotchas
Forget `--with-deps` and your CI will work locally but fail with missing system libraries. Forget `if: always()` on the report upload and you will never see the report when you most need it (on failure). Forget to set `workers: 4` in config and your sharded matrix runs serially within each shard.