Resource library

QA How-To

Parallel test sharding in CI: Step by Step (2026)

Learn parallel test sharding in CI with balanced workers, isolated data, merged reports, failure handling, and a production-ready Playwright workflow.

22 min read | 3,650 words

TL;DR

Split one deterministic test inventory across independent CI jobs, give every job a stable shard index, and merge machine-readable results after all jobs finish. Start with two to four shards, measure the slowest shard plus overhead, then rebalance tests or adjust capacity.

Key Takeaways

  • Measure file or test duration before choosing a shard count, because equal test counts rarely create equal workloads.
  • Make every shard independently runnable with isolated accounts, ports, databases, and output directories.
  • Use a CI matrix to fan out workers and a separate always-running job to merge reports and artifacts.
  • Treat worker startup, installation, and queue time as part of the sharding cost model.
  • Keep retries visible and quarantine ownership explicit so parallelism does not hide flaky tests.
  • Change shard count from observed critical-path data, not from an arbitrary target.

Parallel test sharding in CI means dividing one automated test suite into deterministic partitions and running those partitions on separate CI workers at the same time. A good implementation shortens feedback while preserving the same test coverage, failure visibility, and evidence that a single-worker run provides.

The difficult part is not adding a matrix to YAML. It is controlling test selection, shared state, uneven durations, retries, artifacts, and the final status. This guide builds a production-ready model with Playwright and GitHub Actions, then shows how to apply the same reasoning to other test frameworks.

TL;DR

Decision Practical starting point Evidence to watch
Shard count 2 to 4 workers for an established suite Slowest shard duration and queue time
Distribution Duration-aware when supported, file-based otherwise Difference between fastest and slowest shard
Isolation Unique data namespace per shard Collisions, throttling, and cleanup failures
Reporting Per-shard machine output plus one merged report Missing tests and duplicate test IDs
Failure policy Run merge job even when a shard fails Final CI status and complete artifacts
Optimization target Total feedback time, not test runtime alone Provisioning, install, execution, and merge time

A shard is a partition of tests. A worker is the machine or container that executes a shard. Framework workers inside one CI job are another layer of concurrency, so tune both layers deliberately.

1. Plan parallel test sharding in CI around a measurable goal

Start with a baseline from several representative CI runs. Record checkout and dependency installation time, application startup, test execution, artifact upload, report generation, and queue delay. The useful baseline is not the best run. Use a recent median and also note a slow run so the team understands normal variation.

Define the goal as an observable outcome. For example, reduce pull request feedback from 24 minutes to under 12 minutes while keeping the same browser coverage and no more than four hosted workers. That statement exposes constraints that a vague goal such as make tests faster does not.

Parallel speedup is never perfectly linear. If a 20-minute suite is split four ways, the result is not automatically five minutes. A slow shard might take eight minutes, while every worker repeats a three-minute installation. Queue time and report merging also remain. An illustrative model is:

feedback time =
  queue delay
  + max(worker setup + shard execution + upload)
  + report merge

Inventory test types before partitioning. Unit tests, API integration tests, and browser tests often have different resource profiles and should not share one arbitrary matrix. CPU-heavy browser workers can contend inside a small runner, while API tests may be limited by environment rate limits. Separate jobs let each group use an appropriate image, timeout, and concurrency setting.

Finally, decide what must remain invariant: selected projects, retries, environment, test data, and required checks. Sharding changes placement, not scope. A full unsharded list and the union of all sharded lists should identify the same tests.

2. Understand sharding, framework workers, and matrix jobs

Three concurrency controls are commonly confused. CI matrix jobs create separate machines. A framework shard assigns part of the suite to one matrix job. Local framework workers run tests concurrently within that job. Increasing all three at once can overwhelm the application and make failures harder to interpret.

Layer Example Shares process or machine resources? Primary risk
CI job One GitHub Actions matrix entry No Repeated setup and queue cost
Test shard Playwright --shard=2/4 Usually no across jobs Uneven partitions
Framework worker Playwright workers: 2 Yes CPU, memory, and account contention
Test-level async work Concurrent API calls inside one test Yes Unrealistic load and race conditions

A useful first experiment holds local worker count constant and changes only the shard count. That isolates the impact of extra CI machines. If each runner has two dependable CPU cores, two Playwright workers may be more stable than the default percentage-based value. Measure rather than copying a workstation setting.

Shards also differ from test retries. A retry reruns a failed test, normally on the same shard. It does not redistribute remaining work. If a shard crashes, the CI provider can rerun that job, but all tests assigned to it may execute again. Design tests and cleanup so repetition is safe.

For a broader comparison of distributed browser execution models, see Selenium Grid vs Playwright sharding. The essential interview-level distinction is that a Grid distributes browser sessions, while framework sharding distributes a test inventory. A team can use both concepts together, but each needs separate capacity and failure controls.

3. Make the suite deterministic before splitting it

A sharded suite must be order-independent. Any test that expects another test to create data, warm a cache, or leave a user logged in can fail when those tests land on different workers. Run individual files repeatedly and in random order where the framework supports it. Fix dependencies before adding more machines.

Each test should establish its own preconditions through an API, fixture, database seed, or controlled UI flow. It should clean up what it creates, or use disposable namespaced data that expires. Avoid shared mutable globals, singleton browser state, and a single account used by every test. Parallel execution turns those shortcuts into real races.

Stable identification is equally important. Test titles should be unique within their project and file. Do not generate test cases from data whose order changes between runs unless the generated identifiers remain stable. Report merging and historical analytics depend on consistent identities.

Use a collection-only or list command to inspect the inventory. In Playwright, the following prints discovered tests without running them:

npx playwright test --list

Save the output while diagnosing selection differences. Compare a normal job with the same commit and configuration used by all shards. Environment-controlled conditionals can silently exclude tests on one worker if variables differ.

Determinism also includes time. Freeze or inject clocks for date-sensitive application behavior. Use explicit time zones. Generate random data from a reproducible seed when a failure must be replayed. These practices improve a normal suite, but sharding makes them mandatory because scheduling is intentionally nondeterministic.

4. Configure Playwright for stable shard behavior

Playwright supports --shard=x/y, where x is a one-based shard index and y is the total number of shards. With fullyParallel: true, Playwright can distribute individual tests across shards, which usually balances large suites better. Without full parallel mode, it distributes at test-file granularity, so one oversized file can dominate a shard.

This configuration gives CI a deterministic worker count, enables detailed evidence on retries, and produces blob reports that Playwright can merge:

import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: Boolean(process.env.CI),
  retries: process.env.CI ? 1 : 0,
  workers: process.env.CI ? 2 : undefined,
  reporter: process.env.CI
    ? [['blob'], ['line']]
    : [['html', { open: 'never' }]],
  use: {
    baseURL: process.env.BASE_URL ?? 'http://127.0.0.1:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure'
  }
});

Run one of four shards locally with:

CI=1 npx playwright test --shard=1/4

Keep the total identical across all jobs. Indices must cover every integer from 1 through the total exactly once. A missing index omits tests, while a duplicate repeats a partition.

Full parallel mode changes lifecycle assumptions. Hooks and fixtures must be safe when tests from the same file execute concurrently. If a file deliberately uses serial mode, treat it as an exception and understand how it affects balancing. Do not enable full parallelism merely to make the timing chart look even.

The Playwright sharding guide for distributed suites covers framework-specific configuration in more depth. This article keeps the focus on the CI system around it.

5. Build a GitHub Actions test matrix

Use one matrix dimension for the shard index and a fixed value for the total. Set fail-fast: false so one failure does not cancel unrelated shards. Cancellation saves compute, but it also removes evidence and prevents you from knowing whether the commit produced one failure or several.

The workflow below uses current action generations and Playwright's official blob-report pattern:

name: Sharded browser tests

on:
  pull_request:
  workflow_dispatch:

jobs:
  test:
    timeout-minutes: 30
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        shardIndex: [1, 2, 3, 4]
        shardTotal: [4]

    steps:
      - uses: actions/checkout@v5

      - uses: actions/setup-node@v5
        with:
          node-version: lts/*
          cache: npm

      - run: npm ci
      - run: npx playwright install --with-deps chromium

      - name: Run shard
        env:
          CI: 'true'
          BASE_URL: ${{ vars.TEST_BASE_URL }}
          SHARD_ID: ${{ matrix.shardIndex }}
        run: >
          npx playwright test
          --project=chromium
          --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}

      - name: Upload blob report
        if: ${{ !cancelled() }}
        uses: actions/upload-artifact@v4
        with:
          name: blob-report-${{ matrix.shardIndex }}
          path: blob-report
          retention-days: 2

Pinning third-party actions to commit SHAs may be required by your security policy. The example uses major tags for readability. Whichever policy you choose, update versions through a reviewed dependency process.

Keep shard configuration in one obvious place. If the matrix says four but a wrapper script assumes three, the suite will be incomplete. Prefer passing both values directly from the matrix to the framework command.

6. Isolate data, identities, ports, and external limits

Every shard needs a namespace. The matrix index is a convenient input, but include the CI run ID when resources survive longer than a job. An account or tenant name such as e2e-${runId}-s${shardId} is unique across both shards and reruns. Do not use the shard number alone because two workflows can overlap.

Provision accounts before the tests or create them through worker-scoped fixtures. Store secrets in the CI secret manager, never in the matrix. If a test changes permissions, preferences, inventory, or balances, give it a dedicated entity or restore state through a supported API.

Databases need the same discipline. Options include a schema per shard, a tenant key on every record, a transaction rolled back after a test, or a disposable database container per job. The right choice depends on whether the system under test supports those boundaries. Cleaning tables shared by all shards is unsafe because one worker can delete another worker's setup.

Local services must use nonconflicting ports when multiple processes run inside a job. Across isolated hosted runners the same port is normally fine. File output also needs unique locations. Screenshots, traces, and JUnit XML should not overwrite each other before upload.

External dependencies can become the bottleneck. Four shards may quadruple login requests and trigger anti-abuse controls. Coordinate test credentials and documented quotas with service owners. Stub nonessential third parties when the goal is application behavior, and retain a smaller contract suite for genuine integrations. Parallel test sharding in CI should accelerate validation, not accidentally become an uncontrolled performance test.

7. Balance shards using duration and test topology

Equal test counts do not imply equal time. A shard with one 12-minute checkout file finishes after another shard containing 40 ten-second API tests. The pipeline completes when the slowest required shard completes, so optimize the critical path.

First, collect duration per test or file from several successful runs. Use a median to reduce the effect of transient infrastructure. Then identify dominant files, serial groups, expensive setup, and repeated authentication. Split oversized files by coherent behavior, not by arbitrary line count. Moving a slow test to another file only helps when the framework partitions at file level.

A simple offline allocation algorithm sorts test units from slowest to fastest and repeatedly assigns the next unit to the currently lightest bucket. This longest-processing-time heuristic is easy to explain and often improves static sharding:

export function allocate(testDurations, shardCount) {
  const shards = Array.from(
    { length: shardCount },
    (_, index) => ({ index: index + 1, totalMs: 0, tests: [] })
  );

  const sorted = [...testDurations].sort((a, b) => b.durationMs - a.durationMs);

  for (const test of sorted) {
    shards.sort((a, b) => a.totalMs - b.totalMs);
    shards[0].tests.push(test.id);
    shards[0].totalMs += test.durationMs;
  }

  return shards.sort((a, b) => a.index - b.index);
}

This function is runnable JavaScript and returns a plan, but integrating a custom plan depends on the framework's selection options. Prefer native duration-aware distribution if your test platform provides it.

Track imbalance as both minutes and percentage. A small percentage on a long suite may still be valuable. Also watch variance. A shard that alternates between four and twelve minutes may contain a flaky timeout or unstable environment dependency, not merely poor allocation.

8. Merge reports without losing failure evidence

Each shard should produce machine-readable results plus diagnostic attachments. For Playwright, blob reports contain test results and attachments and are designed for merging. Give each uploaded artifact a unique name. The merge job downloads all blobs into one directory, converts them to HTML, and uploads the combined result.

Add this job after the matrix job:

  merge:
    if: ${{ !cancelled() }}
    needs: [test]
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v5

      - uses: actions/setup-node@v5
        with:
          node-version: lts/*
          cache: npm

      - run: npm ci

      - name: Download all blob reports
        uses: actions/download-artifact@v5
        with:
          path: all-blob-reports
          pattern: blob-report-*
          merge-multiple: true

      - name: Merge Playwright reports
        run: npx playwright merge-reports --reporter=html ./all-blob-reports

      - name: Upload merged HTML report
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report-${{ github.run_attempt }}
          path: playwright-report
          retention-days: 14

The if: !cancelled() condition matters. A default successful-only merge hides reports when any required shard fails, exactly when engineers need evidence. It still avoids trying to merge a deliberately cancelled workflow.

Report merging does not decide the test job's status. The matrix job already fails if a shard fails. If branch protection points to a separate summary job, that job must explicitly inspect the dependency result and fail when appropriate. Never turn shard commands into command || true merely to reach the merge step.

Validate completeness periodically. Compare the count and identities in the merged report with --list for the same project selection. Missing artifacts, incompatible package versions between jobs, or changed test paths can produce an incomplete merge.

9. Handle retries, flakes, crashes, and cancellations

Retries can reduce false red builds, but they also add work to the shard that encountered the failure. A few slow retries can turn a balanced matrix into a long tail. Record first-attempt failures separately from final outcomes so the team sees flakiness instead of celebrating a green retry.

Use one controlled retry for browser CI only when the trace or log produced by that retry adds diagnostic value. Do not retry deterministic compilation errors, missing secrets, or environment health failures. A preflight job can validate deployment health and credentials before fanning out expensive shards.

Distinguish a test failure from infrastructure loss. A failed assertion should have a report entry. A runner crash, out-of-disk error, or lost browser process may leave no complete blob. Upload steps with !cancelled() help, but they cannot recover files never flushed. CI logs and runner telemetry remain necessary.

Automatic job reruns are safest when tests are idempotent and data is namespaced by run attempt. If an account created on attempt one is reused unintentionally on attempt two, the rerun may fail for a different reason. Include github.run_attempt in persistent resource names or make setup tolerant of existing resources.

Cancellation policy is a product choice. For pull requests, cancelling older runs after a new commit usually saves capacity. For release candidates, preserving a full run may be more valuable. Configure workflow concurrency accordingly, and ensure cleanup for cancelled jobs is performed by an external expiry policy when job-level teardown cannot run.

10. Measure speed, cost, and reliability together

The primary chart should show end-to-end feedback time and the duration of each shard. Add setup time, test time, artifact time, queue delay, retry count, and final status. These measurements explain why more shards sometimes make a pipeline slower.

Calculate an illustrative efficiency ratio:

parallel efficiency =
  unsharded test duration
  / (shard count * slowest sharded test duration)

If a 24-minute test phase becomes a 7-minute slowest shard with four shards, test-phase efficiency is about 0.86. That is useful, but it excludes repeated installation and queueing. The business decision should use wall-clock feedback and runner consumption as well.

Review p50 and p90 pipeline duration rather than one showcase run. The p90 exposes queue spikes, intermittent environment slowness, and retry tails. Track flake rate per test and per shard. If one shard consistently fails environment setup, its worker image or assigned resources may differ.

Cost has multiple meanings: hosted runner minutes, self-hosted fleet capacity, engineering maintenance, and contention on test environments. A four-way matrix can consume more total compute even when it finishes sooner. That may still be the right trade for pull request feedback, while nightly runs use fewer shards.

Use a controlled experiment. Run the same commit several times at one, two, and four shards. Keep local workers constant. Pick the smallest configuration that meets the feedback objective with acceptable stability. Revisit it when suite size or runner hardware changes.

11. Adapt the pattern to other frameworks and CI providers

The architecture is portable: enumerate tests, partition deterministically, pass an index and total to independent jobs, isolate state, preserve per-job results, and merge them. Only the selection and merge commands change.

Stack Typical partition mechanism Result strategy
Playwright --shard=x/y Blob reports, then merge-reports
Cypress Cloud Recorded run with parallelization and CI build identity Cloud-coordinated results
pytest xdist workers or CI-side test lists JUnit XML per job, then report aggregation
Maven Surefire Includes, tags, or generated class lists Per-module XML plus CI test publisher
Gradle Separate tasks, filters, or test distribution service XML and HTML outputs per task

Do not assume identical semantics. Some systems dynamically claim tests from a central coordinator. Others hash file names or split by historical duration. Some parallelize processes on one machine rather than CI jobs. Understand whether retry placement, test ordering, and report identity remain stable.

For Cypress-specific tradeoffs, read Cypress parallelization in CI. For a broader pipeline foundation, Azure DevOps test pipelines explains environment and publication patterns that also apply outside GitHub Actions.

When a framework lacks native sharding, generate explicit manifests from the discovered inventory. Store the algorithm in source control, log every assigned test, and fail if a requested shard is empty unexpectedly. Hash-based distribution is simple and stable but unaware of duration. A history-based allocator balances better but needs trustworthy data and a fallback for new tests.

12. Operationalize parallel test sharding in CI

Roll out in stages. First, run the matrix as a nonblocking workflow and compare its selected tests and outcomes with the existing job. Next, make the sharded workflow required while keeping the old run available for a short observation window. Finally, remove duplicate execution after report completeness and stability are proven.

Assign ownership for the workflow, runner image, test environment, and flaky-test policy. Without owners, a slow shard becomes permanent background noise. Add a dashboard or scheduled report that highlights imbalance, retry rate, and the ten longest tests.

Document how developers reproduce a shard locally. The commit, project, shard fraction, environment variables, and dependency lockfile should be enough. If reproduction needs a secret, provide a safe developer environment rather than encouraging secret copying.

Define triggers carefully. A small smoke set might run on every pull request, the complete four-shard suite on changes to application code, and broader cross-browser matrices after merge. Path filters save time only when dependency boundaries are reliable. A false negative caused by an overaggressive filter is more expensive than the minutes saved.

Capacity changes need review. Doubling shard count can double login traffic, database connections, and artifact volume. Treat it like an infrastructure change with before-and-after evidence. Parallel test sharding in CI is an operating model, not a one-time YAML trick.

Interview Questions and Answers

Q: What is the difference between parallel execution and test sharding?

Parallel execution is the broad practice of running work simultaneously. Sharding specifically partitions a known test inventory into nonoverlapping subsets, often across separate machines. A shard can still use multiple local workers, so the two concepts can be layered.

Q: Why can four shards take longer than two?

Every shard repeats setup and may wait for runner capacity. More concurrency can also overload the application, database, identity provider, or runner CPU. The slowest shard plus overhead determines feedback time, so uneven distribution can erase the expected gain.

Q: How do you prove that sharding did not skip tests?

Capture a canonical discovered test list for the same commit and configuration. Compare it with the union of test identities in all shard results, checking for both missing and duplicate entries. Repeat this verification when selection logic or framework versions change.

Q: Should CI stop all shards after the first failure?

Usually not for diagnostic browser suites. Continuing provides the complete failure picture and preserves artifacts from independent shards. A fast-fail policy may be appropriate for expensive downstream stages, but it should be a deliberate tradeoff rather than a matrix default.

Q: How would you balance a suite with one very slow file?

First determine whether the file can safely use test-level parallelism. Otherwise split it into cohesive files, reduce repeated setup, or isolate it in a dedicated shard while packing shorter tests around it. Historical duration data is more useful than raw test counts.

Q: What makes a test safe for parallel sharding?

It owns or namespaces mutable data, establishes its own preconditions, does not depend on execution order, and can be repeated safely. It also writes evidence to a unique location and respects documented external service limits.

Q: What metrics would you show to justify the change?

I would compare p50 and p90 end-to-end CI feedback, slowest shard time, setup overhead, total runner minutes, shard imbalance, retry rate, and infrastructure failure rate. That shows speed, cost, and reliability instead of highlighting one unusually fast run.

Q: How should reports be handled when a shard fails?

Each shard should upload its result and attachments with an always-running condition that excludes only cancellation. A dependent merge job should also run after failures, combine available machine-readable reports, and publish a single human report. The test job must still preserve a failing status.

Common Mistakes

  • Choosing a shard count from intuition: Baseline the suite and model repeated setup, runner queueing, and the slowest partition.
  • Sharing one user across workers: Create shard-specific accounts or tenants so permissions and sessions cannot race.
  • Using test count as the only balance signal: Historical duration and serial topology determine the critical path.
  • Enabling full parallel mode without auditing fixtures: File hooks and mutable globals may become unsafe when individual tests overlap.
  • Cancelling the matrix on the first assertion: This hides additional regressions and often prevents useful artifacts.
  • Publishing one report per worker only: Engineers need a merged view, while raw shard artifacts should remain available for diagnosis.
  • Masking exit codes to make merging work: Use job conditions for artifact and merge steps, not || true on the test command.
  • Increasing CI jobs and local workers together: Change one concurrency layer at a time so capacity problems are attributable.
  • Ignoring rerun identity: Persistent data from a previous attempt can make a rerun fail or pass for the wrong reason.
  • Optimizing average duration only: Pull request frustration is often driven by p90 duration and long retry tails.

Conclusion

Reliable parallel test sharding in CI starts with a deterministic suite, explicit isolation, and a measured baseline. The matrix and --shard flag are the easy pieces. Balanced work, complete merged evidence, honest failure status, and controlled environment load are what make the design production-ready.

Begin with a small shard count, compare the canonical inventory with merged results, and measure the slowest shard plus overhead. Once that loop is visible, you can tune capacity confidently without trading away trust in the test signal.

Interview Questions and Answers

What is test sharding in a CI pipeline?

Test sharding partitions one discovered suite into nonoverlapping subsets that run on separate CI workers. Each worker receives a shard index and a common total. The union should equal the original inventory, and results are merged after execution.

How is sharding different from adding more local test workers?

Local workers share one machine and its CPU, memory, filesystem, and network. Shards usually run on separate CI machines and repeat setup independently. Both create concurrency, but their resource limits and failure modes differ.

Why does the slowest shard matter most?

A dependent pipeline stage cannot start until all required shards finish. Therefore the critical path is set by the slowest shard, not the average shard. Improving balance often produces more value than adding another worker.

How would you choose an initial shard count?

I would baseline recent suite duration and setup overhead, then test two and four shards while holding local workers constant. I would select the smallest count that meets the feedback target without unacceptable queue time, total runner use, or environment instability.

What conditions make tests safe to shard?

Tests must be order-independent, own mutable data, create their preconditions, and tolerate safe repetition. Their output paths and external credentials must also avoid collisions. Cleanup should be idempotent or backed by expiry.

How do you prevent report loss when a shard fails?

Upload shard artifacts under an if-not-cancelled condition and run a dependent merge job under the same condition. Do not suppress the test command exit code. This preserves evidence while the required test job remains red.

How can historical timing improve shard balance?

Store median duration per stable test or file, sort units from longest to shortest, and place each next unit into the lightest bucket. Use a fallback estimate for new tests. Recalculate periodically so stale timing does not lock in imbalance.

What is the risk of fail-fast in a test matrix?

One failing job can cancel shards that contain independent regressions, leaving incomplete results and attachments. It may reduce compute, but it weakens diagnosis. The policy should reflect whether speed or a complete failure picture is more important.

How do retries affect sharded execution?

Retries add time only to shards that see failures, which can create a long tail. They may also hide flakiness if only final status is tracked. Report first-attempt failures and keep retries limited to cases that generate useful diagnostic evidence.

How would you verify shard completeness?

I would capture the canonical discovered test IDs and compare them with the set of IDs from every shard result. The comparison checks equality, missing IDs, and duplicates. It must use the same projects, tags, and environment-driven filters.

What would you monitor after rollout?

I would monitor p50 and p90 feedback time, every shard duration, setup overhead, total runner minutes, retries, infrastructure errors, and test-environment health. I would also alert on missing artifacts and unusual test-count changes.

When should a team avoid adding more shards?

Stop when repeated setup and queueing erase wall-clock gains, environment limits are reached, or the extra cost is not justified by the feedback target. First improve oversized tests, fixture scope, caching, and runner sizing.

Frequently Asked Questions

How many CI shards should a test suite use?

Start with two to four shards and compare end-to-end feedback with the unsharded baseline. Increase only while the slowest shard improves enough to offset repeated setup, queue time, environment load, and added runner cost.

Does Playwright sharding split test files or individual tests?

With fullyParallel enabled, Playwright can distribute individual tests across shards. Without it, distribution is primarily at file level, so large files can create imbalance.

Can sharded tests share the same test account?

They should not share an account if tests mutate its state, session, permissions, or data. Give each shard or worker an isolated identity, or prove that every operation is read-only and concurrency-safe.

How are Playwright reports merged after sharding?

Configure the blob reporter in CI, upload each shard blob under a unique artifact name, download them into one directory, and run npx playwright merge-reports. Publish the generated HTML report while retaining raw evidence for diagnosis.

Why is a sharded CI suite still slow?

Common causes are one dominant shard, repeated dependency installation, limited runner availability, local worker contention, retries, or an overloaded test environment. Break the timeline into queue, setup, execution, upload, and merge phases before changing shard count.

Should matrix fail-fast be enabled for test sharding?

For regression diagnostics, fail-fast is usually disabled so every shard completes and uploads evidence. It can be enabled for tightly budgeted gates, but the team accepts an incomplete failure picture.

How do I detect missing tests across shards?

Generate the framework test inventory for the same commit and selection options, then compare unique test identities with the union in merged results. Fail a periodic audit when there are missing or duplicate identities.

Related Guides