Skip to content

Cypress with GitHub Actions

GitHub Actions is one of the most common CI platforms for Cypress suites. This lesson walks through a complete, practical workflow configuration using the official Cypress GitHub Action.

A Complete GitHub Actions Workflow

The official cypress-io/github-action handles installing dependencies, caching the Cypress binary, starting your application, waiting for it to be ready, and running your tests, all in a single, well-maintained action step.

# .github/workflows/e2e.yml
name: E2E Tests
on: [push, pull_request]

jobs:
  cypress-run:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: cypress-io/github-action@v6
        with:
          build: npm run build
          start: npm start
          wait-on: 'http://localhost:3000'

This single action step covers dependency install, caching, building, starting the app, waiting for readiness, and running Cypress.

Key Action Inputs

build: npm run build       // optional build step before starting
start: npm start           // command to start the app
wait-on: 'http://...'      // URL to wait for before running tests
browser: chrome            // choose a specific browser
record: true                // enable Cypress Cloud recording
  • wait-on accepts a URL and polls it until it responds successfully.
  • record: true (with a project id and recording key) sends results to Cypress Cloud.
  • The action automatically caches node_modules and the Cypress binary between runs by default.
  • Multiple jobs can use matrix strategy to run across browsers or in parallel shards.

GitHub Actions Cheat Sheet

Common workflow configuration additions for a mature Cypress + GitHub Actions setup.

Need Configuration
Upload screenshots/videos on failure actions/upload-artifact@v4 with if: failure()
Run across multiple browsers strategy: matrix: browser: [chrome, firefox]
Parallelize across machines Cypress Cloud record: true + parallel: true
Cache dependencies explicitly actions/cache@v4 keyed on the lockfile hash
Run only on specific paths changing on.push.paths / on.pull_request.paths

Uploading Screenshots and Videos on Failure

Adding an explicit artifact upload step, conditioned on failure, ensures debugging evidence is preserved and downloadable directly from the GitHub Actions run summary, without needing to reproduce the failure locally.

- uses: actions/upload-artifact@v4
  if: failure()
  with:
    name: cypress-screenshots
    path: cypress/screenshots
- uses: actions/upload-artifact@v4
  if: failure()
  with:
    name: cypress-videos
    path: cypress/videos

Testing Across Multiple Browsers with a Matrix

A GitHub Actions matrix strategy runs the same job definition multiple times with different variable values, letting you test across several browsers in parallel jobs with minimal extra configuration.

jobs:
  cypress-run:
    strategy:
      matrix:
        browser: [chrome, firefox, edge]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: cypress-io/github-action@v6
        with:
          browser: ${{ matrix.browser }}

Common Mistakes

  • Not conditioning artifact upload steps on if: failure(), uploading unnecessary artifacts for every successful run.
  • Forgetting wait-on entirely, causing Cypress to start against an application that isn't ready yet.
  • Hardcoding a browser instead of using a matrix when multi-browser coverage is actually needed.
  • Running the entire suite on every workflow trigger without considering path filters for unrelated changes.

Key Takeaways

  • The official cypress-io/github-action handles install, caching, starting, and running tests in one step.
  • Explicit wait-on configuration prevents tests from starting before the app is ready.
  • Artifact upload steps, conditioned on failure, preserve debugging evidence directly in the Actions UI.
  • Matrix strategies enable multi-browser (or parallel) testing with minimal extra configuration.

Pro Tip

Start with the official cypress-io/github-action rather than hand-rolling install, cache, and wait-on logic yourself, it is actively maintained alongside Cypress itself and handles several caching edge cases that are easy to get subtly wrong in a custom workflow.