> ## Documentation Index
> Fetch the complete documentation index at: https://docs.testdino.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Split Playwright tests across CI jobs

> Partition Playwright specs into separate CI jobs with --split and merge them into one TestDino test run.

Split mode merges several manually partitioned Playwright jobs into one TestDino test run. Each job runs the specs you assign it, tagged with `--split i/N`, and TestDino aggregates them into a single run with per-split results.

<Note>
  Split mode requires `@testdino/playwright` 2.3.0 or later. Earlier versions exit with `error: unknown option '--split'`.
</Note>

## Quick Reference

| Topic                                                       | Link                                     |
| :---------------------------------------------------------- | :--------------------------------------- |
| [Pick split mode or sharding](#pick-split-mode-or-sharding) | Which partitioning fits your pipeline    |
| [Group jobs with a split ID](#group-jobs-with-a-split-id)   | The 1 ID that joins jobs into a test run |
| [Run a split group](#run-a-split-group)                     | Working example                          |
| [Configure a CI matrix](#configure-a-ci-matrix)             | GitHub Actions config                    |
| [Shard a split](#shard-a-split)                             | Sharding inside one split                |
| [CLI flags](#cli-flags)                                     | Flags and environment variables          |
| [Read the Splits panel](#read-the-splits-panel)             | Per-split results on the run detail      |
| [Filter by split and shard](#filter-by-split-and-shard)     | Scoping Detailed Analysis                |
| [Troubleshooting](#troubleshooting)                         | Errors and fixes                         |

## Pick split mode or sharding

Sharding and split mode both spread one test run across parallel continuous integration (CI) jobs. They differ in who decides the partition.

| Behavior                      | Sharding                  | Split mode                                       |
| :---------------------------- | :------------------------ | :----------------------------------------------- |
| Partitioned by                | Playwright, automatically | You, by spec, project, or command                |
| Flag                          | `--shard=1/4`             | `--split 1/4` with `--split-id`                  |
| Every job runs                | The same command          | A different command per job                      |
| Grouped by                    | `--ci-run-id`             | `--split-id`                                     |
| Configurable in a config file | Command only              | `--split` command only, `splitId` also in config |
| Run detail section            | **Shards**                | **Splits**                                       |

Use sharding when every job runs the same suite and Playwright balances the load. Use split mode when the jobs differ: an API project on one runner, browser tests on another, or a slow spec isolated so it stops blocking the rest.

Split mode and sharding combine. A split can itself be sharded, covered in [Shard a split](#shard-a-split).

## Group jobs with a split ID

`--split-id` is the only grouping ID split mode needs. Every job that passes the same split ID joins one test run, and `--split i/N` identifies each job's position within it. Together with Playwright's own `--shard`, that pair identifies every job in the group, including the shards inside a split.

| Flag         | Scope              | Value                                                           |
| :----------- | :----------------- | :-------------------------------------------------------------- |
| `--split-id` | The whole test run | Identical in every job of the group                             |
| `--split`    | One job's position | `i/N`, distinct per split, identical across that split's shards |

A group of 3 splits where split 2 runs on 2 shards needs 1 split ID across its 4 jobs:

| Job | `--split` | `--shard` | `--split-id` |
| :-- | :-------- | :-------- | :----------- |
| 1   | `1/3`     | -         | `build-42`   |
| 2   | `2/3`     | `1/2`     | `build-42`   |
| 3   | `2/3`     | `2/2`     | `build-42`   |
| 4   | `3/3`     | -         | `build-42`   |

Jobs 2 and 3 share a split position, so their shards merge into split 2 rather than becoming separate splits.

<Note>
  `--ci-run-id` is optional in split mode. The split and shard indexes already identify each job, and the reporter generates a CI run ID when you omit the flag. Pass it only when another system needs to correlate the job by a known ID.
</Note>

## Run a split group

Split mode runs from the `tdpw test` command. `--split` is a command-line flag with no config file or environment variable equivalent, which keeps a static value from pinning every machine to the same position. Only `splitId` is also readable from a config file.

<Note>
  `--split` labels the results TestDino files for this job. It does not select which tests run. Assign the tests yourself with spec paths, `--project`, or `--grep`.
</Note>

```bash theme={null}
SPLIT_ID="build-$(date +%s)"

npx tdpw test -t "$TESTDINO_TOKEN" \
  --split 1/3 --split-id "$SPLIT_ID" \
  --project=api tests/checkout-api.spec.ts

npx tdpw test -t "$TESTDINO_TOKEN" \
  --split 2/3 --split-id "$SPLIT_ID" \
  --project=chromium tests/checkout-ui.spec.ts

npx tdpw test -t "$TESTDINO_TOKEN" \
  --split 3/3 --split-id "$SPLIT_ID" \
  --project=api tests/orders.spec.ts tests/refunds.spec.ts
```

The 3 jobs produce one test run on the Test Runs page, labeled **SPLITTED**, with 3 splits in its Splits panel.

<img src="https://tdstorageus.blob.core.windows.net/public/docs/installation-and-setup/ci-setup/playwright-split-mode/split-run-active-test-runs.webp" alt="Active Test Runs section showing test run #127 with a SPLITTED badge, a segmented progress bar reading Split 2 of 3, and per-split tabs with Split 2 expanded to its shard 1 workers" />

### Set the split ID in a config file

`splitId` is the one split-mode option a config file can carry. Set it there when the group ID is stable, and pass `--split` per job on the command line.

```typescript testdino.config.ts theme={null}
export default {
  splitId: process.env.GITHUB_RUN_ID,
};
```

The command-line `--split-id` flag wins over a config file value, and `TESTDINO_SPLIT_ID` applies when neither is set.

## Configure a CI matrix

One workflow run is one split group. Set the group ID once as `TESTDINO_SPLIT_ID` at the workflow level so every job inherits it, then give each matrix entry its own `--split` position.

Derive the group ID from a value that is stable across the jobs of a run and distinct across re-runs. In GitHub Actions that is `github.run_id` paired with `github.run_attempt`.

```yaml .github/workflows/playwright-split.yml theme={null}
name: Playwright split mode

on: [push]

jobs:
  split:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - { split: "1/3", shard: "", project: "api", specs: "tests/checkout-api.spec.ts" }
          - { split: "2/3", shard: "1/2", project: "chromium", specs: "tests/checkout-ui.spec.ts" }
          - { split: "2/3", shard: "2/2", project: "chromium", specs: "tests/checkout-ui.spec.ts" }
          - { split: "3/3", shard: "", project: "api", specs: "tests/orders.spec.ts tests/refunds.spec.ts" }
    env:
      TESTDINO_TOKEN: ${{ secrets.TESTDINO_TOKEN }}
      TESTDINO_SPLIT_ID: "gh-${{ github.run_id }}-${{ github.run_attempt }}"
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npx playwright install --with-deps
      - name: Run split ${{ matrix.split }}
        run: |
          npx tdpw test \
            --split ${{ matrix.split }} \
            ${{ matrix.shard && format('--shard={0}', matrix.shard) || '' }} \
            --project=${{ matrix.project }} \
            ${{ matrix.specs }}
```

Each job reads the group ID from `TESTDINO_SPLIT_ID`, so no `--split-id` flag appears in the command. Splits 1 and 3 run unsharded while split 2 runs across 2 shards, and no CI run ID is passed anywhere.

Keep both settings below in place, or the group loses a split:

| Setting                              | Why                                                                                                       |
| :----------------------------------- | :-------------------------------------------------------------------------------------------------------- |
| `fail-fast: false`                   | A failing split must not cancel its siblings, which would leave the group with a split that never reports |
| `github.run_attempt` in the group ID | Keeps a re-run from merging into the original test run                                                    |

If your provider cancels in-progress jobs on a new push, exclude split jobs from that rule. A cancelled job leaves its split unreported.

## Shard a split

A split can use Playwright sharding internally. Pass `--shard` alongside `--split`, and give every shard of that split the same `--split` position.

```bash theme={null}
npx tdpw test -t "$TESTDINO_TOKEN" \
  --split 2/3 --split-id "$SPLIT_ID" \
  --shard=1/2 --project=chromium tests/checkout-ui.spec.ts

npx tdpw test -t "$TESTDINO_TOKEN" \
  --split 2/3 --split-id "$SPLIT_ID" \
  --shard=2/2 --project=chromium tests/checkout-ui.spec.ts
```

Split 2 then expands in the Splits panel to a per-shard table. Splits in one group are independent: split 1 can be unsharded while split 2 runs across 2 shards, and shard numbering restarts inside each split.

## CLI flags

Split mode adds 2 flags to `tdpw test`. Learn about the remaining flags in the [Node.js CLI reference](/cli/testdino-playwright-nodejs#cli-flags).

| Flag                      | Environment variable | Config file | Description                                                                                   |
| :------------------------ | :------------------- | :---------- | :-------------------------------------------------------------------------------------------- |
| `--split <current/total>` | -                    | -           | This job's split position and the group's total split count, for example `1/3`. Command only. |
| `--split-id <id>`         | `TESTDINO_SPLIT_ID`  | `splitId`   | Group ID shared by every job of one test run. Required with `--split`.                        |

`--split` and `--split-id` are required together. Passing one without the other exits with `Split mode requires both a position (--split) and a group id`.

Split positions stay on the command line because a config file value would pin every machine in the matrix to the same position. `splitId` is the exception: set it in `testdino.config.ts` or as `TESTDINO_SPLIT_ID`.

`--ci-run-id` is optional and is not a split-mode flag. It works the same as in a standard run, and split grouping ignores it.

## Read the Splits panel

A split run carries a **SPLITTED** badge in the Test Runs list and on the run detail. Its Summary tab shows a **Splits** section in place of the Shards section, headed with the split count and total test cases.

<img src="https://tdstorageus.blob.core.windows.net/public/docs/installation-and-setup/ci-setup/playwright-split-mode/split-run-summary-splits-panel.webp" alt="Run detail Summary tab showing the Splits panel with a 2 of 3 reported badge, a passed Split 1 row, a running Split 2 row, and a notice that Split 3 did not report" />

| Element         | Shows                                                                                  |
| :-------------- | :------------------------------------------------------------------------------------- |
| Split row       | Split number, status, duration bar, duration, and pass / fail / flaky / skipped counts |
| Shard table     | Per-shard duration, breakdown, and test results, for splits that used `--shard`        |
| Imbalance badge | Slowest split against the fastest, for example `3.0× slower · split 2`                 |
| Anomaly warning | Raised when splits overlapped or reported inconsistent totals                          |

The imbalance badge names the slowest split. Because you assign the specs in split mode, rebalancing means moving specs off that split onto a faster one.

### When counts are unreliable

If 2 splits report the same test cases, TestDino cannot attribute those cases to one split. The panel shows **Per-split counts may be unreliable** and dims the per-split totals. Split statuses stay accurate; only the counts are approximate. A split whose cases collapsed into an overlapping split shows its status with no totals of its own.

The cause is almost always a spec assigned to more than one job. Each spec belongs to exactly one split.

A split that never reports is named under the panel header, and the test run is marked incomplete.

## Filter by split and shard

Split and shard are independent filters on the Summary tab, and both accept multiple values. Selecting split 2 and shard 1 shows split 2's test cases that ran on its own shard 1, not every shard 1 in the run.

| Action                                  | Result                                            |
| :-------------------------------------- | :------------------------------------------------ |
| Click a split row                       | Scopes Detailed Analysis to that split            |
| Click a shard row                       | Scopes to that shard within its split             |
| **Split** and **Shard** filter controls | Select multiple splits or shards at once          |
| Chip `✕`                                | Clears that one value and leaves the rest applied |

Active filters are reflected in the page URL, so a filtered view is shareable.

## Watch a split group in real time

Split groups stream like any other test run. The Active Test Runs section shows the group as one run with a segmented progress bar, one segment per split, and per-split tabs for the splits currently executing. Sharded splits nest their shards under the split tab.

Progress advances per split as each job reports, so a group whose jobs run concurrently fills in steps rather than smoothly. Aggregate counts stay correct throughout.

TestDino finalizes the test run once every declared split has reported. If a split never reports, the group finalizes after an idle grace period of roughly 10 minutes instead of waiting indefinitely. Learn more about streaming in [Real-Time Reporting](/guides/playwright-real-time-test-streaming).

## Troubleshooting

<AccordionGroup>
  <Accordion title="error: unknown option '--split'">
    The installed reporter predates split mode. Upgrade to `@testdino/playwright` 2.3.0 or later:

    ```bash theme={null}
    npm install @testdino/playwright@latest
    ```
  </Accordion>

  <Accordion title="Split mode requires both a position (--split) and a group id">
    `--split` was passed without a group ID. Add `--split-id`, or set `TESTDINO_SPLIT_ID` in the environment:

    ```bash theme={null}
    TESTDINO_SPLIT_ID="build-42" npx tdpw test --split 1/3
    ```
  </Accordion>

  <Accordion title="Splits appear as separate test runs">
    The jobs did not share one group ID. Set it from a CI value that is identical across every job of the run, such as `github.run_id`, and confirm each job resolved it to the same string.
  </Accordion>

  <Accordion title="Per-split counts may be unreliable">
    2 or more splits reported the same test cases. Check the spec paths, `--project`, and `--grep` for each split: a spec matched by 2 jobs is reported twice. Split statuses remain accurate while counts stay approximate.
  </Accordion>

  <Accordion title="A split is missing and the test run stays incomplete">
    The job for that split ended before reporting, usually a cancelled job, a failed setup step, or a runner timeout. Set `fail-fast: false` and exclude split jobs from cancel-in-progress concurrency rules.
  </Accordion>

  <Accordion title="Shards landed under the wrong split">
    Shards merge by their `--split` position. 2 jobs that pass the same `--split i/N` merge into a single split. Give every split a distinct position, and every shard of that split the same position paired with its own `--shard`.
  </Accordion>
</AccordionGroup>

<CardGroup cols={2}>
  <Card title="Node.js CLI" icon="terminal" href="/cli/testdino-playwright-nodejs">
    Flags, environment variables, and sharded runs
  </Card>

  <Card title="Real-Time Reporting" icon="tower-broadcast" href="/guides/playwright-real-time-test-streaming">
    Live progress while a test run executes
  </Card>

  <Card title="Test Runs" icon="play" href="/platform/playwright-test-runs">
    Filter runs and read the run detail tabs
  </Card>

  <Card title="CI Setup" icon="infinity" href="/guides/ci-setup-overview">
    Pipeline configs for every CI provider
  </Card>
</CardGroup>
