Q24 of 48 · Cypress

How does Cypress retry failed tests, and what config options control this?

CypressMidcypressretriesflakemid

Short answer

Short answer: Cypress retries failed *tests* (not just commands) when configured via `retries`. Default is no retry; `{ runMode: 2, openMode: 0 }` is a common setting that retries up to twice in CI and never in interactive mode. Retries should mask flake while you fix it, not be a permanent crutch.

Detail

Two distinct retry mechanisms exist in Cypress:

  1. Command retry-ability — Cypress automatically re-runs query commands and assertions for up to defaultCommandTimeout (4s by default). This isn't configurable per-test because it's the core mechanism.

  2. Test retry — when an entire test fails, Cypress can re-run it from beforeEach. This is what retries config controls.

The retries setting accepts a number or an object:

// Same retry count for both modes
retries: 2

// Per-mode override
retries: {
  runMode: 2,    // CI / cypress run
  openMode: 0,   // local cypress open — never retry, see flakes immediately
}

Per-test override:

it('flaky network call', { retries: { runMode: 3 } }, () => { ... });

The opinionated take: retries are a temporary mitigation, not a strategy. If a test passes only on retry 2, the underlying flake is still there — and a real bug masked as flake will pass eventually too. The right workflow is:

  • Allow retries in CI to keep the team moving.
  • Track which tests retry (Cypress Cloud or a custom reporter).
  • Treat consistent retriers as bugs to fix, not "just flaky tests."

Setting openMode: 0 is critical — locally you want to see flakes immediately, not have them hidden by retries.

// EXAMPLE

cypress.config.ts

import { defineConfig } from 'cypress';

export default defineConfig({
  retries: {
    runMode: 2,    // up to 2 retries in CI
    openMode: 0,   // never retry locally — surface flake immediately
  },
  e2e: {
    setupNodeEvents(on, config) {
      // Track retries via afterSpec / Cypress Cloud
      return config;
    },
  },
});

// Per-test override (use sparingly, with a TODO to fix root cause)
it(
  'handles a known-flaky third-party widget',
  { retries: { runMode: 3 }, defaultCommandTimeout: 10000 },
  () => { /* ... */ },
);

// WHAT INTERVIEWERS LOOK FOR

Knowing the per-mode object syntax, the case for `openMode: 0`, and treating retries as a mitigation not a strategy.

// COMMON PITFALL

Setting `retries: 5` globally and shipping a chronically flaky suite — interviewers see that as a quality red flag.