QA How-To
Cypress parallelization: Examples
Copy practical Cypress parallelization examples for Cloud, GitHub Actions, GitLab CI, cross-browser groups, manual sharding, data isolation, and reports.
24 min read | 2,579 words
TL;DR
The standard Cypress parallelization example creates several CI workers that run `cypress run --record --parallel` with the same build ID and group. Use a matrix for worker count, keep spec discovery identical, and isolate all mutable data and artifacts.
Key Takeaways
- Use one identical recorded command on every worker in a Cypress Cloud parallel group.
- Build IDs identify a workflow attempt, while group names identify a test family inside that run.
- GitHub matrix jobs and GitLab parallel jobs can both act as independent Cloud workers.
- Cross-browser and component runs need distinct groups even when they share one recorded build.
- Manual shards must print assignments, handle zero-spec partitions, and preserve unique artifact paths.
- Provide every worker an explicit namespace for users, tenants, records, files, and reporter output.
A Cypress parallelization example needs more than --parallel. It must show how several CI workers join one run, how the shared build ID is formed, how the application starts on every worker, where secrets live, and how data plus artifacts remain isolated.
This cookbook provides complete patterns for Cypress Cloud, GitHub Actions, GitLab CI, cross-browser groups, component tests, and Cloud-free sharding. Replace project scripts, ports, and test-data endpoints with your repository's actual contract, but preserve the orchestration rules described with each example.
TL;DR
npx cypress run \\
--record \\
--parallel \\
--group chrome-e2e \\
--browser chrome \\
--ci-build-id \"$RUN_ID-$RUN_ATTEMPT\"
Run that exact command on every worker in the chrome-e2e group. Set CYPRESS_RECORD_KEY through protected CI secrets and keep projectId in cypress.config.ts.
| Example | Distribution | Required shared value | Unique per worker |
|---|---|---|---|
| GitHub plus Cypress Cloud | Dynamic spec assignment | Build ID and group | Matrix worker number |
| GitLab plus Cypress Cloud | Dynamic spec assignment | Pipeline-based build ID and group | CI_NODE_INDEX |
| Cross-browser Cloud run | Dynamic within each browser group | Build ID | Group name per browser |
| Static GitHub shard | Fixed paths | Source revision | Shard and spec list |
| Node-computed shard | Deterministic modulo partition | Shard total | Shard index and report file |
1. Minimal Cypress Parallelization Example
First prove recording on one worker, then start the same parallel command on two or more workers. The Cypress config contains the public Cloud project identifier.
// cypress.config.ts
import { defineConfig } from 'cypress'
export default defineConfig({
projectId: 'abc123',
video: true,
e2e: {
baseUrl: 'http://127.0.0.1:4173',
specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}',
},
})
Each worker receives the secret record key in the standard environment variable and runs:
export CYPRESS_RECORD_KEY="value-from-ci-secret-store"
npx cypress run \\
--record \\
--parallel \\
--group chrome-e2e \\
--browser chrome \\
--ci-build-id "$CI_BUILD_ID"
Do not copy the export with a real value into a repository. In CI, map the secret directly into the step environment. Many supported CI providers expose an identifier Cypress recognizes automatically, so the explicit --ci-build-id is optional when detection is correct.
All workers in this group must discover the same specs. They do not need different --spec arguments, and adding them would defeat Cloud's common queue. Cloud assigns one whole spec at a time. When a worker finishes, it asks for another until no work remains.
If only one job runs the command, the run records and accepts the parallel option but has no second machine with which to share specs. Worker provisioning belongs to the CI configuration.
2. GitHub Actions with Four Cloud Workers
This example uses a matrix to produce four jobs. Each job checks out the same revision, installs from the lockfile, builds the Vite-style application, starts its own preview server, and joins one Cloud group.
name: E2E parallel
on:
pull_request:
workflow_dispatch:
jobs:
cypress:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
worker: [1, 2, 3, 4]
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
CYPRESS_BUILD_ID: ${{ github.run_id }}-${{ github.run_attempt }}
CYPRESS_WORKER_ID: ${{ matrix.worker }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run build
- name: Start preview server
run: npm run preview -- --host 127.0.0.1 --port 4173 &
- name: Wait for preview server
shell: bash
run: |
for attempt in {1..60}; do
if curl --fail --silent http://127.0.0.1:4173 >/dev/null; then
exit 0
fi
sleep 1
done
echo "Application did not become ready"
exit 1
- name: Run Cypress
run: |
npx cypress run \
--record \
--parallel \
--group chrome-e2e \
--browser chrome \
--ci-build-id "$CYPRESS_BUILD_ID"
- name: Upload local artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: cypress-${{ matrix.worker }}
path: |
cypress/screenshots
cypress/videos
if-no-files-found: ignore
${{ github.run_id }} remains common to the workflow, and ${{ github.run_attempt }} distinguishes a rerun. ${{ matrix.worker }} must not be part of the Cypress build ID because that would create four separate recorded runs. It is useful for test-data ownership and artifact names.
fail-fast: false is a matrix policy that keeps sibling jobs from being canceled automatically by GitHub. Cypress Cloud auto-cancellation, if enabled, is a separate project decision.
3. GitLab CI with Native Parallel Jobs
GitLab's parallel keyword creates identical job instances. CI_NODE_INDEX distinguishes a worker, while CI_NODE_TOTAL provides the count. All instances use the same pipeline-based Cypress build ID.
stages:
- test
cypress-e2e:
stage: test
image: cypress/browsers:24.14.1
parallel: 4
variables:
CYPRESS_BUILD_ID: "$CI_PIPELINE_ID-$CI_PIPELINE_IID"
CYPRESS_WORKER_ID: "$CI_NODE_INDEX"
before_script:
- npm ci
- npm run build
- npm run preview -- --host 0.0.0.0 --port 4173 &
- |
for attempt in $(seq 1 60); do
curl --fail --silent http://127.0.0.1:4173 >/dev/null && break
test "$attempt" -eq 60 && exit 1
sleep 1
done
script:
- >
npx cypress run
--record
--parallel
--group chrome-e2e
--browser chrome
--ci-build-id "$CYPRESS_BUILD_ID"
artifacts:
when: always
name: "cypress-$CI_NODE_INDEX"
paths:
- cypress/screenshots/
- cypress/videos/
Pin the Cypress browsers image supported by your repository and update it through normal dependency maintenance. The short tag above resolves to a published multi-browser image, but pin the full immutable tag or digest when reproducibility matters. A project that installs system Chrome another way can use its standard Node image.
Store CYPRESS_RECORD_KEY as a masked, protected GitLab CI variable. Do not declare the secret value in the YAML. GitLab is one of the providers Cypress can identify from CI variables, so an explicit build ID may be unnecessary. Keeping it visible in this example demonstrates the requirement and distinguishes manual pipeline reruns according to the chosen ID.
4. Cross-Browser Parallel Groups
Chrome and Firefox runs should use distinct group names because they are separate execution families. They can share one recorded build ID so Cypress Cloud presents them under one run.
strategy:
fail-fast: false
matrix:
include:
- browser: chrome
group: chrome-e2e
worker: 1
- browser: chrome
group: chrome-e2e
worker: 2
- browser: firefox
group: firefox-e2e
worker: 1
- browser: firefox
group: firefox-e2e
worker: 2
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- name: Run browser group
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
run: |
npx cypress run \
--record \
--parallel \
--browser "${{ matrix.browser }}" \
--group "${{ matrix.group }}" \
--ci-build-id "${{ github.run_id }}-${{ github.run_attempt }}"
This snippet omits application startup only to focus on grouping. Add the same build and readiness steps shown in the full GitHub example.
Workers within chrome-e2e share that group's Chrome spec queue. Firefox workers share a separate Firefox queue. Reusing one group name for incompatible browsers causes an inconsistent recorded group. The worker number can repeat across groups because it is only a local namespace input.
Cross-browser coverage increases service load and test result volume. A common strategy runs a primary browser on pull requests and broader groups nightly or before release. Choose based on supported user risk, not on the availability of matrix syntax.
5. End-to-End and Component Test Groups
Component and end-to-end tests use different Cypress testing types and often different setup, so record them as distinct groups. Both groups can run concurrently under one build ID.
strategy:
fail-fast: false
matrix:
include:
- type: e2e
group: chrome-e2e
command: "npx cypress run --e2e"
- type: component
group: chrome-component
command: "npx cypress run --component"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- name: Run recorded test type
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
CI_BUILD_ID: ${{ github.run_id }}-${{ github.run_attempt }}
run: |
${{ matrix.command }} \
--record \
--group "${{ matrix.group }}" \
--ci-build-id "$CI_BUILD_ID"
The example has one worker per group, so it records concurrently but does not use --parallel. To parallelize either group, add multiple identical matrix rows for that group and add --parallel to its command. Grouping and parallelization are independent features of recorded runs.
Component jobs usually do not need a separately started application server because the Cypress dev server mounts components through the configured framework adapter. End-to-end jobs still need the application. Separate jobs let each type use appropriate caches, dependencies, browsers, and timeouts.
6. Monorepo Projects Under One Workflow
In a monorepo, each Cypress project may have its own Cloud projectId. A recorded run belongs to one Cloud project, so do not assume one build ID merges unrelated project IDs into one dashboard run. Use a group per application within its own project invocation and keep working directories explicit.
strategy:
fail-fast: false
matrix:
include:
- app: admin
project: apps/admin
group: admin-chrome
- app: storefront
project: apps/storefront
group: storefront-chrome
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- name: Run app tests
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
run: |
npx cypress run \
--project "${{ matrix.project }}" \
--record \
--group "${{ matrix.group }}"
This is a grouping example, not a parallel group, because each app appears once. Add duplicate workers for the same app and --parallel only if that app's project offers the same spec set on those workers.
If applications have different record keys, map the correct secret by separate jobs or environments. Never select secret names dynamically from untrusted pull request content. Repository structure does not override Cloud project identity.
7. Static GitHub Shards Without Cypress Cloud
For a small stable suite, a fixed matrix is transparent and does not require recorded orchestration. Each shard owns a feature directory.
name: Cypress manual shards
on:
pull_request:
jobs:
e2e:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- shard: account
specs: cypress/e2e/account/**/*.cy.ts
- shard: projects
specs: cypress/e2e/projects/**/*.cy.ts
- shard: reports
specs: cypress/e2e/reports/**/*.cy.ts
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- name: Run shard
run: npx cypress run --spec "${{ matrix.specs }}"
- name: Upload shard artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: cypress-${{ matrix.shard }}
path: |
cypress/screenshots
cypress/videos
if-no-files-found: ignore
Add application startup to every job or target a stable deployed environment. --spec accepts the provided glob and limits discovery to it. Ensure each spec belongs to exactly one shard, and decide whether no matching specs should fail. Cypress offers --pass-with-no-tests when an intentionally empty selection should exit successfully, but use it only with a deliberate empty-shard policy.
Static ownership is easy to review, yet it drifts as one feature grows. Track shard durations and move coherent subdirectories when imbalance becomes material. The how to use Cypress parallelization guide explains how to measure that decision.
8. Deterministic Node Sharding Script
A small script can sort discovered specs and allocate them by modulo. This is deterministic, dependency-free sharding by file count, not duration-aware balancing.
// scripts/cypress-shard.mjs
import { readdirSync } from 'node:fs'
import { join } from 'node:path'
import { spawnSync } from 'node:child_process'
const root = 'cypress/e2e'
const shardIndex = Number(process.env.SHARD_INDEX)
const shardTotal = Number(process.env.SHARD_TOTAL)
if (!Number.isInteger(shardIndex) || !Number.isInteger(shardTotal)) {
throw new Error('SHARD_INDEX and SHARD_TOTAL must be integers')
}
if (shardIndex < 0 || shardIndex >= shardTotal || shardTotal < 1) {
throw new Error('Shard index must be zero-based and less than total')
}
function findSpecs(directory) {
return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
const path = join(directory, entry.name)
if (entry.isDirectory()) return findSpecs(path)
return /\.cy\.(js|jsx|ts|tsx)$/.test(entry.name) ? [path] : []
})
}
const allSpecs = findSpecs(root).sort()
const shardSpecs = allSpecs.filter((_, index) => index % shardTotal === shardIndex)
console.log(JSON.stringify({ shardIndex, shardTotal, shardSpecs }, null, 2))
if (shardSpecs.length === 0) process.exit(0)
const result = spawnSync(
'npx',
['cypress', 'run', '--spec', shardSpecs.join(',')],
{ stdio: 'inherit', shell: process.platform === 'win32' },
)
process.exit(result.status ?? 1)
Run it from a zero-based CI matrix:
SHARD_INDEX=0 SHARD_TOTAL=4 node scripts/cypress-shard.mjs
Sorting ensures every worker sees the same ordered inputs. The script prints assignments so a missing spec is diagnosable. Modulo by file count can still produce unequal durations. A mature version can read committed duration weights and use a greedy allocation algorithm, but those weights need updating and review.
Do not let two workers calculate from different working trees or spec filters. Store reporter output under a path derived from the shard index.
9. Worker-Safe Test Data Example
Expose build and worker namespaces to Cypress. In GitHub Actions, environment variables prefixed with CYPRESS_ become Cypress environment values without hardcoding them into the spec.
env:
CYPRESS_BUILD_ID: ${{ github.run_id }}-${{ github.run_attempt }}
CYPRESS_WORKER_ID: ${{ matrix.worker }}
Use those values in an API-assisted setup helper:
type Project = { id: string; name: string }
function createOwnedProject() {
const buildId = Cypress.env('BUILD_ID') as string
const workerId = Cypress.env('WORKER_ID') as string
const suffix = Cypress._.random(100_000, 999_999)
const name = `e2e-${buildId}-${workerId}-${suffix}`
return cy.request<Project>({
method: 'POST',
url: '/test-support/projects',
body: { name, owner: { buildId, workerId } },
}).its('body')
}
it('edits its own project', () => {
createOwnedProject().then((project) => {
cy.visit(`/projects/${project.id}`)
cy.get('input[name=name]').clear().type(`${project.name}-edited`)
cy.contains('button', 'Save').click()
cy.contains('Changes saved').should('be.visible')
})
})
The server should authorize and label test-support data properly. Disable test-support routes in production. Cleanup can delete records matching the build owner after all workers finish, or each test can remove its exact ID in an idempotent after hook.
For authentication reuse on one worker, apply Cypress cy.session examples, but remember that each machine creates its own session cache.
10. Unique JUnit Reports and Merge Job
When each worker emits JUnit, give the file a unique name. Cypress CLI passes options to the configured reporter.
- name: Run Cypress with JUnit
run: |
npx cypress run \
--reporter junit \
--reporter-options "mochaFile=reports/junit-worker-${{ matrix.worker }}-[hash].xml,toConsole=true"
- name: Upload JUnit fragment
if: always()
uses: actions/upload-artifact@v4
with:
name: junit-${{ matrix.worker }}
path: reports/*.xml
if-no-files-found: error
[hash] prevents one spec from replacing another report generated by the same worker. A downstream job can download all fragments and merge them with the chosen JUnit tooling, or the CI platform can ingest multiple XML files directly.
Do not use a single shared filesystem path across concurrent jobs unless the storage guarantees safe unique writes. Even then, explicit worker and spec names make diagnosis easier.
The artifact upload runs with if: always(), but the Cypress step still controls job success. If a merge job publishes a report, configure its dependencies so it runs after every shard and fails when inputs are unexpectedly missing. Report merging must not convert failed Cypress exits into a successful pipeline.
11. Selective Pull Request and Nightly Topologies
Not every workflow needs the same worker count. Pull requests often prioritize quick Chrome feedback, while nightly runs add browsers, broader environments, and more recorded groups.
strategy:
matrix:
worker: ${{ fromJSON(github.event_name == 'schedule' && '[1,2,3,4,5,6]' || '[1,2,3]') }}
Complex expressions in CI YAML can be hard to maintain. Separate workflow files or jobs are often clearer:
- Pull request: three Chrome end-to-end workers, two component workers.
- Main branch: four Chrome end-to-end workers plus a smoke browser group.
- Nightly: six Chrome workers, selected Firefox and Edge groups, and slower integration environments.
Give each group a stable descriptive name and tag the recorded run with a low-cardinality purpose. Do not change group names merely to include the worker number. Cloud needs workers of the same family to join one group.
Capacity matters. A nightly run with three browser groups can triple login calls and data creation. Confirm identity-provider, database, and application limits before expanding the matrix. If broad browser coverage is serially cheap and operationally risky in parallel, keep it deliberately smaller.
12. Complete Cypress Parallelization Example with Verification
Treat the parallel workflow like production infrastructure and add a focused verification plan. Create at least twice as many specs as workers so dynamic assignment is visible, and give one spec a controlled additional duration only in a disposable demonstration branch. Confirm that workers request multiple files and the run completes under one build and group.
Then verify failure behavior:
- Make one assertion fail and confirm the worker exits nonzero.
- Confirm sibling workers follow the selected CI and Cloud cancellation policies.
- Check the first failed attempt, screenshot, video, and browser metadata.
- Rerun the workflow and confirm the attempt gets a distinct build ID.
- Remove the deliberate failure and verify no stale artifact is reported.
Verify data isolation by running two copies of a mutation-heavy spec at the same time with different worker namespaces. Each should create, read, update, and delete only its own record. Inspect server logs for cross-worker IDs.
Finally, record a baseline and several parallel runs. Compare full job duration, not only Cypress test time. Include environment startup, install, browser launch, Cloud completion, report merge, and artifact upload. The most successful example is the smallest topology that meets the team's feedback target reliably.
For framework-level interview explanations, use Cypress interview questions and answers.
13. Troubleshooting Example Failures
If Cloud shows separate runs instead of one run, print the build ID and group on every worker. A worker-specific suffix in the build ID is a common mistake. Also confirm the project ID and record key target the same Cloud project.
If one worker reports a different spec set, compare the checkout revision, generated files, specPattern, environment flags, and --config values. All workers in one parallel group must offer compatible discovery. Do not use --spec to give each Cloud worker a different manual shard.
If a matrix job hangs after tests finish, inspect application background processes, reporter completion, artifact upload, and Cypress Cloud run completion behavior. Ensure shell scripts propagate signals and exit codes. A preview server launched in the background should end when the isolated CI job ends.
If failures increase with worker count, reduce concurrency to confirm the relationship, then inspect database connections, API rate limits, authentication quotas, CPU, and memory. A slower application can trigger real client timeouts. The durable response is capacity planning or test boundary isolation, not a blanket Cypress timeout increase.
If a manual shard finds no specs, verify glob quoting and the current working directory. Decide whether that is a configuration error or an allowed empty partition, and use --pass-with-no-tests only for the latter.
Interview Questions and Answers
Q: What values are shared across Cloud workers?
Workers share the build ID, group name, Cloud project, revision, spec discovery, and compatible configuration. Worker IDs and data namespaces remain unique. The record key is the same secret but is never printed.
Q: Why is the matrix worker not part of the build ID?
The build ID links workers into one run. Adding the worker makes each value different and separates the jobs. The worker belongs in artifact and test-data names instead.
Q: How do cross-browser groups work?
Each browser has a distinct group under the same recorded build. Workers with the same browser and group can parallelize that group's queue. Incompatible browsers should not share one group name.
Q: Is a static matrix load balanced?
Only if maintainers or a script assigned balanced spec sets. Fixed jobs do not request new work after finishing, so a slow shard determines completion. Cloud dynamic assignment is a different model.
Q: How do you merge reports safely?
Every worker writes uniquely named files, uploads them even on failure, and a downstream job gathers the fragments. The merge process preserves Cypress failures and treats unexpectedly missing input as an error.
Q: What does a good worker namespace contain?
It contains a traceable build identifier, a worker identifier, and a unique test suffix where needed. The backend records ownership so cleanup deletes only resources created by that worker or test.
Q: How do you test the CI configuration itself?
I verify joined workers, deliberate failure propagation, rerun identity, artifact retention, and data isolation. I then compare full pipeline duration across several representative runs before choosing worker count.
Common Mistakes
- Including the matrix worker number in the shared Cypress build ID.
- Reusing one group name for Chrome, Firefox, end-to-end, and component runs.
- Supplying different
--speclists to workers in one Cloud parallel group. - Committing the record key in a sample workflow.
- Copying a container tag without verifying its browser and Cypress compatibility.
- Starting the application without a readiness check.
- Letting worker artifacts overwrite files under one shared name.
- Assuming modulo sharding by file count balances duration.
- Allowing empty shards to pass without an explicit policy.
- Reusing mutable test accounts because browser sessions are machine-local.
Conclusion
Use the Cypress parallelization example that matches your orchestration model. Cypress Cloud workers should execute the same recorded parallel command with one build ID and group, while manual shards should receive explicit, non-overlapping specs. In both cases, give every worker unique data and artifact ownership.
Start with the complete two-worker version, verify joined scheduling and failure propagation, then scale from measured wall-clock results. Keep the topology readable enough that another SDET can explain why every ID, group, worker, and report path exists.
Interview Questions and Answers
Describe a GitHub Actions Cypress parallel setup.
I use a matrix to create identical worker jobs. Each checks out the same revision, installs from the lockfile, starts and verifies the application, then runs the same recorded parallel command with one build ID and group. Worker IDs are reserved for data and artifacts.
What happens if workers use different build IDs?
Cypress cannot associate them as one parallel run, so they appear separately or fail the intended orchestration. I print non-secret identity inputs during diagnosis and remove worker-specific suffixes from the shared ID.
Why use separate groups for browser and test type?
A group represents one compatible execution family. Browser and testing-type differences affect configuration, spec sets, and duration history. Distinct names keep recorded results and scheduling coherent.
What is the tradeoff of a modulo sharding script?
It is simple, deterministic, and Cloud-independent, but it balances file count rather than actual duration. It also cannot reassign work when one job finishes early, so the slowest shard controls completion.
How do you isolate data in a matrix?
I expose the workflow build and matrix worker as non-secret Cypress environment values. Setup APIs label every record with that ownership, and cleanup removes only matching resources. Mutating flows receive distinct users or tenants.
How do you preserve failure status when uploading artifacts?
The Cypress command remains its own step and returns the test exit code. Artifact steps use an always condition so they run after failure, but they do not replace or suppress the earlier status.
How do you handle an empty manual shard?
I decide whether emptiness is expected. A calculation script can exit successfully for an intentionally empty partition, or Cypress can use --pass-with-no-tests. Unexpected emptiness should fail with printed discovery inputs.
What do you measure after implementing a parallel example?
I measure complete wall-clock duration, slowest worker, setup and artifact overhead, compute minutes, application capacity, and retry-assisted passes. Several representative runs are needed before selecting the production worker count.
Frequently Asked Questions
What is a working Cypress parallelization command?
Run npx cypress run with --record, --parallel, a group, and a shared CI build ID on every worker. Supply CYPRESS_RECORD_KEY securely and configure the Cloud project ID.
How do I parallelize Cypress in GitHub Actions?
Create a matrix with two or more worker jobs, then run the same Cloud parallel command in each. Use github.run_id plus github.run_attempt as a shared build identity and matrix.worker only for local namespacing.
How do I parallelize Cypress in GitLab CI?
Use GitLab's parallel job count to create workers and run the same recorded Cypress command in every instance. CI_NODE_INDEX is useful for data and artifact names, while the pipeline build ID stays common.
Can I use different specs on each Cypress Cloud worker?
Not within one dynamically balanced group. Workers should offer the same spec list so Cypress Cloud can assign files. Use separate groups or manual sharding for intentionally different lists.
How do I run Cypress shards without Cloud?
Create a CI matrix and pass each job an explicit glob or computed comma-separated list through --spec. Your pipeline must handle balancing, empty shards, reporting, and reruns.
How should parallel Cypress artifacts be named?
Include a worker or shard identifier in artifact names and reporter filenames. Use a hash or spec-specific token when one worker creates multiple report files.
What build ID should a rerun use?
Use a value that changes with the workflow attempt, not only the commit. In GitHub Actions, run ID plus run attempt is a practical explicit choice.