skip to content

Batch and Watch Runs

One binary, two modes: an interactive session that reruns a spec every time you save it, and a one-shot batch run that finishes and exits with a code the pipeline reads.

on this pageshow

explore

questions

5

In Cypress, what is the difference between `cypress open` and `cypress run`?

level: juniorimportance: must knowfreq 85%

answer

  1. One binary, two subcommands
  2. One is a session, one a job
  3. Who decides when it stops
  4. Which mode a pipeline can call
  5. Headless is already the batch default

basics

~20 s

cypress open launches the interactive Cypress app: you pick a spec, watch it run in a visible browser, and it reruns every time you save. cypress run executes matching specs once, headlessly, then exits with a status code a pipeline reads.

solid answer

~40 s

They are two subcommands of the same binary reading the same `cypress.config.js`. `cypress open` starts an interactive session: you choose a testing type (`--e2e` is the default), a browser and a spec, Cypress runs that one spec in a visible browser, and a file watcher reruns it on every save. The process stays alive until you quit, and `Cypress.config('isInteractive')` is `true`. `cypress run` is a one-shot batch job: it runs every spec matching `specPattern` — or just those matching `--spec` — headlessly by default, prints results through a Mocha reporter, and exits with a status code. `--headed` makes the browser visible; `--reporter` chooses the reporter. Open mode accepts neither `--spec` nor `--reporter`, because you pick the spec by clicking it.

go deeper

for a junior

Be ready to name both subcommands and say plainly what each is for: one you develop tests in, one a pipeline calls. Knowing that the batch run is headless by default is the detail most often checked.

for a middle

Explain the mechanics behind the split — the file watcher, the spec-selection difference, and the fact that only the batch run produces a status code anything downstream can read.

for a senior

Show that you know which defaults are derived from the mode, and how that explains a spec behaving differently under each. Be ready to say what you would change first when the two disagree.

for a principal

Own the question of what each mode is allowed to be the source of truth for on your team, and what it costs when developers only ever see the interactive session.

## One binary, two entry points The `cypress` npm package installs a single CLI. `cypress open` and `cypress run` are two subcommands of that one binary. They read the same `cypress.config.js`, resolve the same `specPattern`, load the same support file, and execute the same spec code. What changes is who drives the run, whether a human is watching it, and whether the process is ever expected to end. ## `cypress open` — the interactive session `cypress open` launches the Cypress app. You pick a testing type (`--e2e` is the default, `--component` switches), pick a browser, and pick a spec from the spec list. Cypress launches that browser visibly and runs the one spec you chose. - The process **stays alive** until you quit it. It is a session, not a job. - A file watcher recompiles and reruns the spec whenever you save it. - `Cypress.config('isInteractive')` is `true`, so spec code can branch on it. - There is no meaningful exit status, because nothing downstream is waiting on one. - Its option list is short — `--browser`, `--e2e`/`--component`, `--config`, `--config-file`, `--env`, `--expose`, `--global`, `--detached`, `--port`, `--project`. There is **no `--spec`** and **no `--reporter`**: you choose the spec by clicking it, and you read results on screen. ## `cypress run` — the batch job `cypress run` executes every spec matching `specPattern`, one after another, then exits. - It runs **headlessly by default**. `--headed` forces a visible browser; `--headless` is simply the default spelled out. - `--spec` narrows the set to a path or a glob, and `--browser chrome` pins the browser. - Output goes to stdout through a Mocha reporter — the `spec` reporter unless `--reporter` names another one, with `--reporter-options` for its settings. - Nothing is watched, because nothing is going to rerun. - The process exits with a status code, and by default that code is the **number of failed tests** rather than a POSIX `0`/`1`. ## Side by side | | `cypress open` | `cypress run` | |---|---|---| | Lifetime | stays up until you quit | exits when the last spec finishes | | Browser | always visible | headless unless `--headed` | | Spec selection | clicked in the app | all of `specPattern`, or `--spec` | | Reruns on save | yes | no | | `isInteractive` | `true` | `false` | | Result surface | the app's own UI | Mocha reporter on stdout, plus an exit code | | Video | not captured | captured when `video` is enabled | ## Config keys whose default comes from the mode Most configuration resolves identically either way. A handful take their default from the mode itself, which is the usual source of "it behaves differently in CI" surprises: - `watchForFileChanges` — `true` under `cypress open`, `false` under `cypress run`, and inert in the latter because nothing is watched at all. - `numTestsKeptInMemory` — `50` under `cypress open`, `0` under `cypress run`. - `isInteractive` — `true` under `cypress open`, `false` under `cypress run`. As of Cypress 16, `video` still defaults to `false`, so a batch run records nothing unless you turn it on, and `electron` is a deprecated choice for `--browser`. ## Which one the question is actually about 1. **Writing or fixing a spec** — `cypress open`. The save-and-rerun loop is the entire point of the mode, and it is why nobody develops tests against `cypress run`. 2. **A pipeline stage** — `cypress run`. It terminates and reports a status, which is the only thing an automated caller can consume. 3. **Reproducing a batch-only failure** — still `cypress run`, but with `--headed` so you can see it and `--no-exit` so the app stays up after the spec finishes. Two traps show up constantly in interviews. The first is believing these are separate executables, or that CI needs an extra install; there is one binary and one install. The second is inverting the headless default and claiming `cypress run` needs a `--headless` flag to be unattended — it is already headless, and `--headed` is the flag that departs from the default. ## How the two look in a project In a multi-package storefront monorepo the split usually shows up as two npm scripts over the same config file, and the shape of each is a good summary of the mode: - `"cy:open": "cypress open --e2e"` — no spec, no reporter, no browser pinned. Everything else is a choice the developer makes in the app, session by session. - `"cy:run": "cypress run --e2e --browser chrome"` — every decision made up front, because there is nobody there to make it. Callers narrow it further with `--spec`. `--e2e` and `--component` select the testing type on **both** subcommands, and `--e2e` is the default for both. That is why a component spec disappearing from a run is a testing-type question before it is anything else. Everything else on the `cypress run` list — `--spec`, `--reporter`, `--reporter-options`, `--no-exit`, `--quiet`, `--record` — exists because a batch job has to be told things an interactive user would simply click.

  • Can `cypress open` be limited to one spec the way `cypress run --spec` is?
    No. `cypress open` has no `--spec` option; you pick the spec from the spec list in the app. You can narrow what appears there by changing `specPattern`, via the config file or `--config specPattern=...`, but that changes the project's spec set rather than the invocation.
  • What does `cypress run --headed` change, and what does it not?
    It makes the browser window visible instead of hidden. It does not turn the batch run into an interactive session: the run still executes every selected spec unattended, still exits when it finishes, and still has no file watcher. Add `--no-exit` if you want it to stay up afterwards.

saying these in an interview costs you the question

  • Says cypress open and cypress run are separate binaries or installs
  • Thinks cypress run needs a --headless flag to be headless
  • Claims cypress run reruns a spec when its file changes
  • Believes cypress open accepts --spec and --reporter
  • Says cypress open reports an exit code CI can gate on
open as a page

What exit code does `cypress run` return, and what does `--posix-exit-codes` change?

level: middleimportance: must knowfreq 62%

basics

~20 s

By default cypress run exits with the number of failed tests, Mocha-style: three failures give status 3, and 0 means everything passed. Passing --posix-exit-codes makes any test failure exit 1 instead, and adds 112 for a Cypress Cloud network failure.

open as a page

Which edits make a `cypress open` session rerun your Cypress spec?

level: middleimportance: should knowfreq 40%

basics

~20 s

Only edits inside the spec graph: the active spec file, the support file, and any module they import or require. Application source, node_modules and cypress/fixtures are deliberately not watched, and the whole watcher is governed by watchForFileChanges.

open as a page

A storefront checkout spec fails only under `cypress run`, never in `cypress open`. How do you inspect it?

level: seniorimportance: should knowfreq 48%

basics

~20 s

Keep using cypress run and remove what hides it: narrow with --spec, pin the browser with --browser, add --headed to see the window, and --no-exit so Cypress stays up after the spec finishes. Then compare the browser, the spec set, and the inherited state.

open as a page

Why does Cypress's `cypress.run()` resolve instead of rejecting when tests fail?

level: seniorimportance: nice to knowfreq 26%

basics

~20 s

Because a failing test is a normal outcome of running a suite, not an error in running it. cypress.run() resolves with a results object carrying totalFailed and per-spec stats; it rejects only when Cypress could not run at all, such as an uninstalled binary.

open as a page