Compare the pull request’s base and head revisions, select the changed files that match your Cypress spec configuration, run that subset with Cypress’s --spec option, and then run the complete suite. The first run can surface relevant failures sooner; it does not replace the full run, because changes to shared application code, support files, or configuration can affect specs that were not edited.
How changed-spec-first works
Git identifies paths changed across the pull request; a filter keeps only paths Cypress recognizes as specs; Cypress runs those paths before the full suite. Cypress’s --spec option narrows the configured spec set, while specPattern determines which files qualify as specs. A file outside that configured pattern will not become runnable just because Git reports it as changed.
As an Amazon Associate I earn from qualifying purchases.
This is different from Cypress Cloud Spec Prioritization, which orders specs based on failures in the previous run. Changed-spec-first selects from the pull request’s changed paths. The two approaches use different signals.
Configure the workflow for your repository
Check your spec location and pattern
Do not copy an old cypress/integration path without checking your project. Cypress configuration controls the spec pattern, and project layouts vary. The workflow below assumes specs are under cypress/e2e and use the common .cy.js, .cy.jsx, .cy.ts, or .cy.tsx suffixes. Change the filter to match your actual specPattern.
Make the pull request diff available
The comparison must include the intended base and head revisions. A shallow checkout may not contain enough history or the base ref, so the example uses fetch-depth: 0 and explicitly fetches the base branch. It compares the merge base with the checked-out commit, which selects changes introduced on the pull request branch relative to its base.
For forked pull requests, use the checkout event’s pull-request merge commit carefully: GitHub Actions commonly checks out a synthetic merge commit for pull_request. In this workflow, the head revision is the checked-out commit. If your repository uses a different checkout strategy, confirm that HEAD is the pull request head you intend to test and adjust the comparison accordingly.
GitHub Actions example
Save as .github/workflows/cypress.yml. This assumes the project has an npm ci install step and an npm run cy:run script that runs cypress run with the project’s normal configuration. Replace the install and full-suite commands if your project uses another package manager or command.
name: Cypress
on:
pull_request:
jobs:
cypress:
runs-on: ubuntu-latest
steps:
- name: Check out pull request
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
run: npm ci
- name: Fetch pull request base
env:
BASE_REF: ${{ github.base_ref }}
run: git fetch origin "$BASE_REF"
- name: Run changed Cypress specs
shell: bash
env:
BASE_REF: ${{ github.base_ref }}
run: |
set -euo pipefail
base="origin/$BASE_REF"
merge_base="$(git merge-base "$base" HEAD)"
changed_specs=()
while IFS= read -r -d '' path; do
case "$path" in
cypress/e2e/*.cy.js|cypress/e2e/*.cy.jsx|cypress/e2e/*.cy.ts|cypress/e2e/*.cy.tsx|cypress/e2e/**/*.cy.js|cypress/e2e/**/*.cy.jsx|cypress/e2e/**/*.cy.ts|cypress/e2e/**/*.cy.tsx)
changed_specs+=("$path")
;;
esac
done < <(git diff --name-only -z "$merge_base" HEAD --)
if ((${#changed_specs[@]})); then
printf 'Running changed specs:n'
printf ' %sn' "${changed_specs[@]}"
spec_list=$(IFS=,; printf '%s' "${changed_specs[*]}")
npx cypress run --spec "$spec_list"
else
echo 'No changed Cypress specs matched the configured path filter.'
fi
- name: Run all Cypress specs
run: npm run cy:run
The shell collects paths without splitting on spaces and skips the targeted command if no matching specs changed. Cypress accepts a comma-separated spec list; if your spec filenames can contain commas, use a different selection strategy rather than passing those names through this list format. Also check that your shell glob patterns cover nested folders as intended and align with the configured spec pattern.
Why the full suite still runs
A changed spec file is not the same thing as a changed behavior boundary. Editing a shared component, an application module, a fixture, Cypress support code, or the Cypress configuration can affect many tests without editing their spec files. Git-based selection does not infer those dependencies. Run the complete suite after the targeted run to preserve regression coverage. If you later add dependency-based selection, maintain an explicit mapping and validate it against full-suite runs.
Use Cypress’s GitHub Action instead
The official Cypress GitHub Action can run specs through its spec input. The current Cypress GitHub Actions guide recommends the cypress-io/github-action@v7 major tag. You can use that action for both targeted and full runs, but the selection logic is still yours: calculate the changed paths first, skip the targeted invocation when the list is empty, then invoke a complete run. Review the action guide for its current setup inputs and adapt the example to your package manager and application startup process.
An older 2020 example used cypress-io/github-action@v1, runTests: false for setup, and install: false for the later full run. Treat that as a historical illustration, not a current copy-and-paste workflow.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Performance, reliability, and cost trade-offs
- Feedback timing: the targeted run may report failures in changed specs before the full run finishes. No fixed time saving is guaranteed; it depends on the number and duration of selected specs and the CI setup.
- Total work: when you run both steps, the selected specs are run again as part of the full suite. That duplication is the cost of getting earlier targeted feedback while retaining a complete run.
- Selection reliability: correctness depends on comparing the right revisions, having their Git history available, and matching the repository’s real spec pattern. Validate the selection against representative pull requests.
- Coverage: a changed-spec run alone can miss failures in specs affected indirectly by shared code or configuration. Keep the full-suite step unless you have a deliberate, tested alternative.
- CI provider: the same Git-diff-and-filter approach can run on other CI systems; checkout and ref-fetch behavior will differ by provider.
Troubleshooting
No changed specs run
Check that the base ref was fetched, that the merge base resolves, and that the changed files match your filter. Then compare the filter with Cypress’s configured specPattern. A PR with no changed spec files should skip only the targeted step; the complete run should still execute.
Cypress says a selected file is not a spec
The path may not match specPattern, or the filter may point at a historical directory such as cypress/integration while the project uses another layout. Update the filter and Cypress configuration consistently.
Rank #4
The diff misses pull request changes
Verify that both revisions are present and that your workflow compares the PR branch against its base, not merely the last commit. Ensure checkout depth and ref-fetch configuration provide the required history. For unusual merge or rebase workflows, inspect the resolved merge base and chosen HEAD.
Spec paths with spaces or commas cause trouble
The example reads Git’s NUL-delimited output into a Bash array, so spaces are preserved during collection. Cypress’s comma-separated --spec argument still makes commas in filenames ambiguous. If such filenames are permitted in your repository, choose a tested invocation strategy that avoids comma ambiguity or standardize filenames.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →The targeted run passes but the full run fails
This can happen when an edited shared dependency affects an unedited spec, or when tests behave differently in the broader run. Treat the complete run as authoritative for suite coverage; investigate the failing test and any shared code, fixture, environment, or configuration changes.
Best Value
Or skip the browser setup
ScreenshotNeo is a website screenshot API, not a Cypress runner: it cannot select or execute changed Cypress specs. If your adjacent task is capturing a page rather than testing it, one GET request can return an image or PDF. For example, this cURL call saves a screenshot of your application’s page:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
See the ScreenshotNeo API documentation. Its cookie/consent-banner handling and removal of 60+ known consent platforms, newsletter popups, and chat widgets are optional per step. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed; response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Learn about ScreenshotNeo, or sign up for 1,000 free screenshots a month with no card.
Frequently Asked Questions
Does changed-spec-first replace running every Cypress spec?
No. Run it as an early-feedback step, then run the full suite to cover tests affected indirectly by shared code or configuration.
Is Cypress Cloud Spec Prioritization the same as changed-spec-first?
No. Changed-spec-first selects spec paths from the pull request’s Git diff; Spec Prioritization orders tests based on failures in a previous run.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




