Sharding
Several CI jobs can upload parts of one build. The check reports once, after the last part.
When you know the shard count
Each job passes its shard and the total. The first job to upload creates the build, the others join it, and the build finishes when every shard is done.
jobs:
visual:
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npx playwright test --shard ${{ matrix.shard }}/4
- run: npx stateofpixel upload screenshots --shard ${{ matrix.shard }}/4While shards upload, the check says "Waiting for screenshots (2 of 4 shards)". The Playwright reporter reads Playwright's own --shard, so with it you skip the upload step. Storybook capture splits the stories only with --shard i/n, like --shard 2/4. It does not take --shard auto.
When you do not
Each job uploads with --shard auto, and one last job calls finalize:
jobs:
visual:
# ... each job ends with:
steps:
- run: npx stateofpixel upload screenshots --shard auto
finalize:
needs: visual
if: always()
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- run: npx stateofpixel finalize --skip-if-empty--skip-if-empty makes finalize report a build with no changes when no shard ran, so the check still reports.
How shards find each other
Shards of one build share a nonce. On GitHub Actions it is the run id plus the attempt, so every job of a run joins the same build. When you re-run failed jobs, they join the build of the earlier attempt while it is still waiting for shards. Once that build has finished or expired, a re-run starts a fresh build. Elsewhere, set it yourself:
export STATEOFPIXEL_TOKEN=sop_...
export STATEOFPIXEL_NONCE="$CI_PIPELINE_ID"
npx stateofpixel upload screenshots --shard 2/4Builds that never finish
A build that is not finished 60 minutes after its first shard expires. The check shows "Build never finished". See how to recover. A build takes up to 256 shards.