Cypress: Getting Started
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Cypress is an end-to-end and component test runner for web applications that executes your tests inside the browser, next to
the application, and ships its own interactive app for writing and debugging them. This page takes you from an empty project to
a running suite and then through every day-to-day command, option and setting you need first. It was written against Cypress
16.2.0 (released 13 October 2026) and checked on 25 October 2026. Every example that tests an application was run against the
Bookshelf application, started on a local port, with Cypress
16.2.0 and Chrome 155 on macOS. The interactive parts of the product (the Launchpad and cypress open) need a display and a
person to click, so they are described from the official documentation and were not run. For why Cypress is built the way it is,
see How Browser Automation Works; for choosing it over Playwright or
Selenium, see Choosing a Tool. The commands, ideas and files here come back in the
rest of the Cypress pages, starting with Core Concepts.
System requirements
Cypress 16 documents these requirements:
| Item | Requirement |
|---|---|
Node.js |
22.x, 24.x or 26.x and later. Node.js 20 and 25 were dropped in 16.0.0. Cypress itself bundles Node.js 24.15.0 for the code it
runs in |
macOS |
13.5 or later, on Intel or Apple Silicon. |
Linux |
x64 or arm64: Ubuntu 22.04 or later (arm64 needs 24.04 or later), Debian 12 or later (arm64 needs 13 or later), Fedora 43 or later. The prebuilt binary needs a glibc-based distribution (glibc 2.31 or later since Cypress 15). |
Windows |
Windows 10 and 11 (x64); Windows 11 25H2 on arm64 runs in x64 emulation and is a preview; Windows Server 2019, 2022 and 2025. |
Package manager |
npm 10.1.0 or later, Yarn Classic 1.22.22 or later, Yarn 4 or later, pnpm 8 or later, or Bun 1.2.22 or later. |
Hardware |
Any modern development machine. In CI use at least 2 CPUs and 4 GB of RAM, and 8 GB or more for long runs or when recording video. Abrupt exits, frozen video frames and slow runs are the usual signs of too little. |
Supported browsers
Cypress supports the latest three major versions of Google Chrome, Microsoft Edge and Mozilla Firefox (Firefox 140 or later, because Cypress automates Firefox through WebDriver BiDi only). It also finds Chrome for Testing, Chromium, the beta, canary and developer channels of the Chrome and Edge families, Firefox Developer Edition and Nightly, and offers experimental WebKit support. Every release also bundles an Electron-based Chromium browser. Electron has been deprecated as a test browser since Cypress 16.0.0 and will be removed in a future major version, so the examples on this page always name an installed browser. The reasons the project gives are that Electron’s Chromium trails the current Chrome by weeks or months and that its behaviour diverges from the browser your users run.
When you pass no --browser flag and no defaultBrowser is set, Cypress still falls back to Electron, and prints a warning.
This is the real output of cypress run with no browser chosen:
│ Browser: Electron 146 (headless) (deprecated) │
Warning: The Electron browser is deprecated as a test browser and will be removed in a future version of Cypress.
Switch to Chrome or another installed browser to avoid a breaking change when you upgrade.
Read more about supported browsers: https://on.cypress.io/launching-browsers
Linux libraries and Docker
On a bare Linux machine Cypress needs a few system libraries. For Ubuntu 22.04 and Debian the documented command is
apt-get install libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2 libxtst6 xauth xvfb; on Ubuntu 24.04 and
later the libgtk-3-0t64 and libasound2t64 package names replace two of them. The Cypress Docker images
(cypress/base, cypress/browsers and cypress/included) already contain everything, and the cypress/factory image builds
a custom combination of Node.js, browser and Cypress versions. Install unzip as well, so that the binary download does not fall
back to a slower unzip implemented in Node.js. Running in CI is covered in the continuous-integration pages of this section.
Installing Cypress
Install Cypress as a development dependency of the project that holds your tests. The cypress npm package is a small command
line wrapper; its postinstall script downloads the real application, called the binary, into a per-user cache that every
project on the machine shares.
mkdir bookshelf-e2e && cd bookshelf-e2e
npm init -y
npm install cypress --save-dev
npm install typescript @types/node --save-dev # needed for TypeScript specs, see below
Source: Cypress — Install Cypress
The first command printed (from an empty project, with the binary already in the cache, so no download happened):
added 171 packages, and audited 172 packages in 2s
found 0 vulnerabilities
npm warn install-scripts 1 package has install scripts not yet covered by allowScripts:
npm warn install-scripts cypress@16.2.0 (postinstall: node dist/index.js --exec install)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
Source: Cypress — Install Cypress
That last warning matters. Package managers are moving to block dependency lifecycle scripts by default, and Cypress depends on one to fetch its binary: npm 11.16.0 and later warn (as above) and npm 12.0.0 will block, Yarn 4.14.0 and later block, pnpm requires an allow-list entry, and Bun runs the script only for trusted dependencies. When the script is blocked the binary is not downloaded and Cypress will not start. The fix differs per package manager:
| Package manager | Allow the Cypress install script |
|---|---|
npm 11.16 or later |
|
Yarn 4.14 or later |
In |
pnpm |
|
Bun |
|
Any |
Skip the script and install the binary explicitly: |
Checking the installation
Four commands tell you what is installed. All of them were run:
npx cypress verify
# ❯ Verifying Cypress can run ~/Library/Caches/Cypress/16.2.0/Cypress.app
# ✔ Verified Cypress! ~/Library/Caches/Cypress/16.2.0/Cypress.app
npx cypress version
# Cypress package version: 16.2.0
# Cypress binary version: 16.2.0
# Electron version: 41.7.0
# Bundled Node version: 24.15.0
npx cypress cache path
# ~/Library/Caches/Cypress
npx cypress info
# Detected 2 browsers installed:
#
# 1. Chrome
# - Name: chrome
# - Channel: stable
# - Version: 155.0.8059.85
# - Executable: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
# 2. Firefox
# - Name: firefox
# - Channel: stable
# - Version: 153.0.4
# ...
# Binary Caches: ~/Library/Caches/Cypress
# Cypress Version: 16.2.0 (stable)
The related commands are cypress install --force (download the binary again even if the cache holds it), cypress cache list
(with --size), cypress cache prune (keep only the version the project uses) and cypress cache clear. Useful environment
variables are CYPRESS_INSTALL_BINARY=0 (install the package without the binary), CYPRESS_CACHE_FOLDER (move the cache),
CYPRESS_VERIFY_TIMEOUT (default 30 seconds) and CYPRESS_SKIP_VERIFY=true. Since 16.0.0, cypress info no longer prints
proxy variables or CYPRESS_* variables, so its output is safe to paste into a bug report.
Source: Cypress — Installation options
Opening the app: the Launchpad
Cypress has two ways to run tests, which are covered in detail under cypress open and cypress run. The first command you
type in a new project is the interactive one:
npx cypress open
Source: Cypress — Open the app
The Cypress Launchpad appears. It is the setup wizard for a project and it also decides which browser to start. The first time it runs in a project it asks three things, in this order:
-
Choose a testing type. E2E Testing runs your whole application in the browser and visits pages the way a user would. Component Testing mounts single components in isolation. The choice is not permanent; the other type can be set up later.
-
Review the generated configuration. The Launchpad lists the files it will create for the chosen type and writes them when you click Continue:
cypress.config.ts(or.jsfor a JavaScript project), the support files, and an example fixture. If you chose Component Testing there are two extra screens first, which detect your front-end framework and bundler and check that the dependencies are installed. -
Launch a browser. The Launchpad shows the compatible browsers it found on the machine, including Electron. You can switch browser at any time, even in the middle of a session.
Once the project is configured you can skip the wizard by choosing the testing type and the browser on the command line. The Launchpad still opens briefly, because it handles configuration errors, and then lands directly on the Specs page:
npx cypress open --e2e --browser chrome
Source: Cypress — Open mode: Launchpad
The Launchpad is the only thing that writes the initial configuration. cypress run in a folder without a configuration file does
not scaffold one; it stops. This is the real output:
$ npx cypress run
Could not find a Cypress configuration file in this folder: /path/to/empty-project
If you prefer to create the files by hand, the section The Cypress configuration file and the folder layout under Folder structure are all you need; the Launchpad adds nothing else.
You can use the Cypress app without an account. Signing in to Cypress Cloud from the profile menu adds run history, a Debug page
for CI failures and the AI features of Studio and cy.prompt; those are covered in
Cypress Cloud.
Choosing a testing type
Cypress names four kinds of test and the Launchpad offers the first two:
| Type | What it does | Reach for it when |
|---|---|---|
End-to-end (E2E) |
Visits URLs in a real browser and exercises the whole application, front end to back end and third-party services, the way a user does. |
Authentication and purchase flows, data that has to survive several screens, smoke tests before a deployment. Slower and harder to set up, because it needs a running back end. |
Component |
Mounts one component with |
Many states and props of a button, a form or a table. Fast and independent of any server, but passing component tests say nothing about the application as a whole. |
API |
Sends requests with |
The REST contract, and fast set-up of state for UI tests. |
Accessibility |
Checks pages or components against accessibility rules, with an axe-based plugin or the Cypress Accessibility product. |
Catching regressions in labels, roles and contrast early. |
A healthy suite combines them, the way the test pyramid recommends. This page and the next ones concentrate on end-to-end tests; component testing has its own page, Component Testing.
Source: Cypress — Testing types
Your first end-to-end test
The official tutorial writes a spec against Cypress’s own demo site. The same steps against Bookshelf are shown here, so that you can compare them with the Playwright page in this section. Start Bookshelf in another terminal (the application is described in Example Application & Test Layout):
cd bookshelf
PORT=3921 BOOKSHELF_REVIEW_DELAY_MS=100 node server.js
Source: Node.js: Command-line API
Every Cypress test follows three phases: put the application into a known state, take an action, and assert on the result. The
recommended shape of a chain is query, query, then an action or assertions. In the Cypress vocabulary that becomes four steps:
visit a page, query for an element, interact with it, and assert on the outcome. The spec below contains each step as its own
test. It uses cy.task('resetBookshelf') (defined in The Cypress configuration file) to restore the 24 seeded books before
each test, and a custom command getByTestId (defined under TypeScript):
// cypress/e2e/first-test.cy.ts
describe('My first Bookshelf test', () => {
beforeEach(() => {
cy.task('resetBookshelf');
});
it('does not do much', () => {
expect(true).to.equal(true);
});
it('visits the catalogue', () => {
cy.visit('/books');
cy.title().should('include', 'Bookshelf');
});
it('finds a book, opens it and checks the address', () => {
cy.visit('/');
cy.contains('A Field Guide to Clouds').click();
cy.url().should('include', '/books/3');
cy.getByTestId('book-detail').should('contain', 'Nora Quill');
});
it('types into the search box and filters the catalogue', () => {
cy.visit('/books');
cy.getByTestId('search-input').type('quiet{enter}');
cy.getByTestId('book-card').should('have.length', 1);
cy.getByTestId('search-input').should('have.value', 'quiet');
});
});
Source: Cypress — Write your first test
The run (headless Chrome, BASE_URL pointing at the local server):
BASE_URL=http://localhost:3921 npx cypress run --browser chrome --spec cypress/e2e/first-test.cy.ts
│ Cypress: 16.2.0 │
│ Browser: Chrome 155 (headless) │
│ Specs: 1 found (first-test.cy.ts) │
My first Bookshelf test
✓ does not do much (46ms)
✓ visits the catalogue (88ms)
✓ finds a book, opens it and checks the address (126ms)
✓ types into the search box and filters the catalogue (154ms)
4 passing (440ms)
A few things in these four tests are worth understanding before moving on:
-
describe,itand the hooks (before,beforeEach,afterEach,after) come from Mocha, andexpectandshouldassertions come from Chai, both bundled with Cypress. You do not install them. -
Commands retry.
cy.contains(),cy.get()and the other queries keep looking for their element until it appears or the timeout passes. The defaultdefaultCommandTimeoutis 4000 ms, so a test that looks for something that never appears fails after about four seconds, not at once. -
Many commands assert implicitly.
cy.visit()fails on a non-2xx response or an uncaught application exception;cy.contains('text')fails if the text is not found, even without a.should(). You do not need an assertion after every command. -
Page transitions are handled for you. After
.click()navigates to a new page Cypress pauses the command queue until the next page has loaded, and raises the timeout topageLoadTimeout(60 seconds by default) for that one page load. Commands never run against a stale or half-loaded page. -
Do not chain after an action. The shape query, query, action is deliberate: a command that follows an action is not retried together with it, so put the next query on a new
cy.chain, as the search test does with its secondgetByTestId. -
type('quiet{enter}')types the characters and then presses Enter, which submits the search form. The{enter}is one of the special character sequences of.type().
A failing test
The official tutorial makes a test fail on purpose so that you can see what Cypress shows. The spec below looks for text that Bookshelf does not contain:
// cypress/e2e/failing-on-purpose.cy.ts
describe('A test that fails on purpose', () => {
it('cannot find the text "hype"', () => {
cy.visit('/');
cy.contains('hype');
});
});
The real output of cypress run:
A test that fails on purpose
1) cannot find the text "hype"
0 passing (4s)
1 failing
1) A test that fails on purpose
cannot find the text "hype":
AssertionError: Timed out retrying after 4000ms: Expected to find content: 'hype' but never did.
at Context.eval (webpack:///./cypress/e2e/failing-on-purpose.cy.ts:4:7)
(Screenshots)
- .../cypress/screenshots/failing-on-purpose.cy.ts/A test that fails on purpose -- cannot
find the text hype (failed).png (1280x633)
The four seconds are the retry period of cy.contains(). The run also saved a screenshot of the failure; cypress run does that
by default (screenshotOnRunFailure). In cypress open the same failure appears in red in the Command Log with a code frame, a
stack trace and a clickable file link that opens your editor.
If you would rather record than type, Cypress Studio generates commands from your clicks. It is covered with debugging in Debugging, Studio, Plugins & Reporters.
Testing your own application
Cypress is built to run against an application you control, on a development server you start yourself. Three rules follow from that, all from the official guide:
-
Start the server before Cypress, and not from inside a test. Starting a web server from Cypress scripts is documented as an anti-pattern. Start it in a terminal or as a CI step, wait for it to answer, and then run Cypress.
-
Prefer a local server over production. A local server is one you can control: reset state, seed data, expose routes that exist only in the test environment and relax security features that make automation hard. Many teams run most tests locally and keep a small set of smoke tests for the deployed site.
-
Do not test sites you do not control. Third-party sites change without notice, run A/B tests and may block automation. The exceptions are sign-in providers and complementary services your application is designed to integrate with.
Set baseUrl so that a test never contains the host name, which is the first thing the guide asks you to configure:
// cypress/e2e/uses-base-url.cy.ts
describe('baseUrl', () => {
it('prefixes cy.visit and cy.request', () => {
cy.visit('/');
cy.location('pathname').should('eq', '/');
cy.request('/api/books').its('body.total').should('eq', 24);
expect(Cypress.config('baseUrl')).to.match(/^http:\/\/localhost:\d+$/);
});
});
The test passed (1 passing). Cypress restarts itself and closes the browser whenever you edit the configuration file, which is normal; click the spec again to relaunch.
To prepare data, the guide offers two tools: cy.task() to run Node.js code defined in setupNodeEvents, and cy.request() to
call your own HTTP endpoints. Bookshelf has /api/test/reset and /api/test/seed for this, and the resetBookshelf task below
uses the first. The other approach Cypress promotes, replacing server responses with cy.intercept(), is covered in
Network, Stubs, Spies & Clocks, and signing in once per spec
with cy.session() in Sessions, Authentication & Cross-Origin.
Keeping tests independent of each other and of page markup is explained in
Test Design & Page Objects.
cypress open and cypress run
Cypress has two modes, and the choice is the main difference between writing a test and running it in a pipeline.
| Aspect | cypress open (open mode) |
cypress run (run mode) |
|---|---|---|
Purpose |
Writing and debugging. The Launchpad, the Specs page and the Command Log with time travel. |
Running to completion and exiting with a status. Pre-push checks and CI. |
Browser |
Visible (headed) always. |
Headless by default; |
Specs |
You click a spec; Cypress re-runs it whenever you save the file. |
All specs matching |
Defaults that differ |
|
|
Output |
The app window. |
The terminal, plus screenshots, optional videos and any reporter. |
Testing type |
Chosen in the Launchpad or with |
E2E by default; |
Headed and headless
cypress run launches the browser headless: no window is drawn, which is what CI needs. Pass --headed to see the browser, or
--headless to make the default explicit. The header of the run output states what was used. These three commands were run:
npx cypress run --browser chrome --spec cypress/e2e/uses-base-url.cy.ts
# │ Browser: Chrome 155 (headless)
npx cypress run --browser chrome --headless --spec cypress/e2e/uses-base-url.cy.ts
# │ Browser: Chrome 155 (headless)
npx cypress run --browser chrome --headed --spec cypress/e2e/uses-base-url.cy.ts
# │ Browser: Chrome 155
cypress run --headed --no-exit keeps the browser open after the last spec has finished, so that you can look at the Command
Log or open the browser’s developer tools. Headless runs use the same browser engine, but the window size and display configuration can differ between a laptop and a
headless CI machine, so when a test passes headed and fails headless, compare the viewport first. The default viewport is 1000 by 660
(viewportWidth and viewportHeight); the failure screenshot above was 1280 by 633, so set the viewport explicitly when a
test depends on the layout.
Source: Cypress — Browser launch options
Choosing a browser
--browser accepts chrome, chromium, edge, firefox, electron (deprecated) and a name:channel form such as
chrome:canary or firefox:nightly. A file system path points at a browser Cypress did not detect (only Chrome-family browsers
and Firefox are supported). In open mode the Launchpad and a drop-down at the top right of the app select the browser. To make
the choice permanent, set defaultBrowser in the configuration file, as the example config below does; it only affects the first
launch of a project.
Source: Cypress — Browser launch options
The flags of cypress run
These are the options of cypress run in Cypress 16. Only the ones named under "Ran" were executed for this page; the others are
quoted from the reference.
| Option | Effect | Ran |
|---|---|---|
|
Browser name or path. Without it, |
yes |
|
Testing type. E2E is the default. |
no |
|
Spec files to run: a path, a quoted glob such as |
yes |
|
Override configuration values: |
yes |
|
Use a different configuration file. |
yes |
|
Secret values for |
no |
|
Public values for |
yes |
|
Show or hide the browser. |
yes |
|
Keep Cypress open after the specs finish; combine with |
no |
|
A Mocha reporter, for example |
yes ( |
|
Print only the reporter output. |
yes |
|
Exit with success when no spec is found (since 15.11.0). |
yes |
|
Exit with 1 on any failure instead of the number of failed tests. |
yes |
|
Run a Cypress project in another folder. |
no |
|
Override the port Cypress itself listens on. |
no |
|
Hide or force the Runner UI (relevant with Test Replay). |
no |
|
Cypress Cloud options; see Cypress Cloud. |
no |
cypress open accepts --browser, --e2e, --component, --config, --config-file, --env, --expose, --port,
--project, --global (one installation for several nested projects) and --detached. The flags you pass persist for every
project you open until you quit.
Source: Cypress — Command line
Exit codes
By default the exit code of cypress run is the number of failed tests, with some reserved values, which is not POSIX
compliant and can mislead: most shells apply modulo 256, so exactly 256 failures look like success. --posix-exit-codes makes
the code 1 for any failure and also reports Cypress Cloud network failures as 112. With one failing test both modes returned 1;
the difference only shows with two or more failures, which was not run.
npx cypress run --browser chrome --spec cypress/e2e/failing-on-purpose.cy.ts; echo $?
# 1
npx cypress run --browser chrome --posix-exit-codes --spec cypress/e2e/failing-on-purpose.cy.ts; echo $?
# 1
npx cypress run --pass-with-no-tests --spec cypress/e2e/nothing.cy.ts; echo $?
# 0
npx cypress run --spec cypress/e2e/nothing.cy.ts; echo $?
# 1
The JSON reporter and quiet output
npx cypress run --quiet --reporter json --spec cypress/e2e/uses-base-url.cy.ts
{
"stats": {
"suites": 1,
"tests": 1,
"passes": 1,
"pending": 0,
"failures": 0,
"duration": 153
},
"tests": [
{
"title": "prefixes cy.visit and cy.request",
"fullTitle": "baseUrl prefixes cy.visit and cy.request",
"duration": 144
}
]
}
The output above is shortened to the fields that matter. Reporters are covered in Debugging, Studio, Plugins & Reporters.
Name your scripts
Put the commands you type often in package.json. The official guide’s one rule is to never name a script cypress, because
yarn cypress verify would then run your script instead of the Cypress CLI. Extra flags go after -- with npm:
{
"scripts": {
"cy:open": "cypress open",
"cy:run": "cypress run",
"cy:chrome": "cypress run --browser chrome",
"typecheck": "tsc --noEmit"
}
}
npm run cy:run -- --spec cypress/e2e/first-test.cy.ts
Both snippets were run in a freshly installed project: npm run cy:run -- --spec cypress/e2e/first-test.cy.ts ran the four tests of the first spec and
npm run typecheck reported no errors.
The Cypress configuration file
The Launchpad writes cypress.config.ts (or .js, .mjs, .cjs, .mts, .cts) in the project root. It is a normal module
that exports an object, which you should wrap in defineConfig() so that editors can complete and check it. The file below is
the one used for every example on this page, and the test project that ran them was a plain folder with the layout shown under
Folder structure:
// cypress.config.ts
import { defineConfig } from 'cypress';
const baseUrl = process.env.BASE_URL ?? 'http://localhost:3000';
export default defineConfig({
// Electron is deprecated as a test browser: name an installed browser explicitly.
defaultBrowser: 'chrome',
video: false,
e2e: {
baseUrl,
specPattern: 'cypress/e2e/**/*.cy.ts',
supportFile: 'cypress/support/e2e.ts',
setupNodeEvents(on, config) {
on('task', {
// Runs in Node, not in the browser: reset Bookshelf through its test API.
async resetBookshelf() {
const response = await fetch(`${baseUrl}/api/test/reset`, { method: 'POST' });
return response.json();
},
});
return config;
},
},
});
The file has three levels:
-
Top-level options apply to both testing types:
defaultBrowser,video, the timeouts, the viewport,retries,screenshotsFolder,env,exposeand so on. -
The
e2eobject holds options for end-to-end tests only:baseUrl,specPattern,excludeSpecPattern,supportFile,slowTestThreshold,testIsolation,setupNodeEvents. Acomponentobject does the same for component tests, withdevServeras its required option. An option ine2eorcomponentoverrides the same option at the top level for that type. -
setupNodeEvents(on, config)is a function that runs in Node.js, in the background process, before the project loads, before the browser launches and while tests run. It registers listeners withon()(such astask,before:run,after:screenshotandbefore:browser:launch) and may return a modifiedconfig. Tests reach it throughcy.task(). TheresetBookshelftask above is called ascy.task('resetBookshelf')and its return value, the JSON the server answers, comes back to the test. Tasks run in Node.js, so they can read files and call databases, which a spec running in the browser cannot. The plugin events have their own page: Debugging, Studio, Plugins & Reporters.
The options you will meet first
| Option | Default | Meaning |
|---|---|---|
|
|
Prefix for |
|
|
Glob (or array of globs) that decides which files are specs. |
|
|
Globs removed from the list of specs. |
|
|
File loaded before every spec. |
|
|
Clear the page, cookies, local storage and session storage before each test (see Core Concepts). |
|
|
Browser used when |
|
|
Milliseconds to retry most DOM commands. |
|
|
Milliseconds to wait for |
|
|
Waits for a request to leave, for a response, and for a |
|
|
Size of the application viewport; |
|
|
Times to retry a failing test, separately for |
|
|
Record a video of |
|
|
Take a screenshot when a test fails in |
|
|
Where generated files go and where fixtures are read from. |
|
|
Empty the screenshots, videos and downloads folders before each |
|
|
Delay between keystrokes of |
|
|
Secret values read with |
|
|
Identifier for Cypress Cloud, written when you connect the project. |
|
open mode true, run mode false |
Re-run a spec when its file changes. |
This is a selection; the configuration reference lists every option, including the actionability options (waitForAnimations,
animationDistanceThreshold, scrollBehavior), blockHosts, hosts, userAgent, chromeWebSecurity, includeShadowDom,
redirectionLimit, numTestsKeptInMemory, manageBrowserMemory, the experimental flags and the certificate options
(clientCertificates, trustedCertificates), which come back in
Sessions, Authentication & Cross-Origin.
Source: Cypress — Configuration: Options
Overriding configuration
The same option can be set in six places, from the weakest to the strongest: its default, the configuration file, a
cypress.env.json file (for env), a CYPRESS_* environment variable, a command line flag, and an override in the test. The
Project settings panel of the app shows where each resolved value came from.
| Where | Example |
|---|---|
Command line |
|
Environment variable |
|
Suite or test |
|
Inside a test |
|
The following spec reads values that came from the command line and from the environment. It needs a secret and a public value, and shows the split Cypress 16 enforces:
// cypress/e2e/config-and-env.cy.ts
describe('Configuration, secrets and public values', () => {
it('uses the viewport passed with --config', () => {
cy.log(`isInteractive = ${Cypress.config('isInteractive')}`);
cy.window().its('innerWidth').should('eq', Cypress.config('viewportWidth'));
});
it('reads a secret with cy.env() and a public value with Cypress.expose()', () => {
cy.env(['READER_PASSWORD']).then(({ READER_PASSWORD }) => {
expect(READER_PASSWORD).to.be.a('string').and.not.be.empty;
});
expect(Cypress.expose('channel')).to.equal('smoke');
});
});
CYPRESS_READER_PASSWORD="$BOOKSHELF_READER_PASSWORD" npx cypress run --browser chrome \
--spec cypress/e2e/config-and-env.cy.ts \
--config viewportWidth=1280,viewportHeight=720 \
--expose channel=smoke
Configuration, secrets and public values
✓ uses the viewport passed with --config (26ms)
✓ reads a secret with cy.env() and a public value with Cypress.expose() (12ms)
2 passing (52ms)
Cypress.env() no longer exists in Cypress 16: a CYPRESS_ variable is read with cy.env() (asynchronous, and only the keys
you ask for are exposed to the page) and public values with Cypress.expose(). The migration, cy.origin() behaviour and the
risks of the yielded value are covered in
Sessions, Authentication & Cross-Origin.
ESM or CommonJS
Since Cypress 15.17.0 the configuration and everything setupNodeEvents imports are loaded as ECMAScript modules or as
CommonJS using the same rules as Node.js, and there is no fallback to the other format when loading fails.
| Config file | Nearest package.json "type" |
Loaded as |
|---|---|---|
|
any |
ES module |
|
any |
CommonJS |
|
|
ES module |
|
absent or |
CommonJS |
The project that ran these examples is CommonJS ("type": "commonjs"), so import and export default in the .ts file are
transpiled to require and module.exports. If you move to "type": "module", remember that __dirname does not exist in an
ES module and import.meta.dirname takes its place.
Generated files are emptied before every run
With trashAssetsBeforeRuns on, cypress run removes the entire contents of the screenshots, videos and downloads folders at
the start of each run, subfolders included, so a download you keep there is lost. On macOS and Windows items go to the system
trash and on Linux they are deleted for good. On the Apple Silicon host used for this page the trash step failed on every run
with the message below and the old screenshots piled up as (1), (2) copies; the run itself and its exit code were not
affected. Keep nothing you need in those folders, and ignore the warning if you see it on a similar host.
Warning: We failed to trash the existing run results.
This error will not affect or change the exit code.
TypeScript
Cypress ships its own type declarations and understands TypeScript natively: specs, support files and the configuration file can
all be .ts with no build step. Cypress transpiles specs itself, and since Cypress 15.0.0 it runs the configuration file with
tsx (earlier versions used ts-node). It does not type-check; the editor and tsc do.
Install TypeScript 5, 6 or 7 (TypeScript 6.0 support arrived in 15.14.0 and TypeScript 7.0 in 15.19.0) together with the Node.js
types, and create a tsconfig.json that limits the global types to the ones Cypress needs. Limiting types also avoids clashes
when the project has Jest or another test runner that declares its own describe, it and expect:
{
"compilerOptions": {
"target": "es2022",
"lib": ["es2022", "dom"],
"sourceMap": true,
"types": ["cypress", "node"]
},
"include": ["**/*.ts"]
}
Source: Cypress — TypeScript support
The official page recommends es6 as target and library; a newer target works equally well and was used here. Without
@types/node installed, TypeScript 7.0.2 stops with error TS2688: Cannot find type definition file for 'node' because
"node" is listed in types; installing @types/node fixes it, after which npx tsc --noEmit reported no errors for the whole
project (the specs, the configuration and the support files).
Custom commands need declarations
A command added with Cypress.Commands.add() is invisible to TypeScript until you declare it on the Cypress.Chainable
interface. Put both in cypress/support/commands.ts, which the support file imports. The file must be a module, so end it with an
empty export {}; otherwise declare global is an error. This is the command the first-test spec uses:
// cypress/support/commands.ts
declare global {
namespace Cypress {
interface Chainable {
/** Select an element by its data-testid attribute. */
getByTestId(id: string): Chainable<JQuery<HTMLElement>>;
}
}
}
Cypress.Commands.add('getByTestId', (id: string) => cy.get(`[data-testid="${id}"]`));
export {};
// cypress/support/e2e.ts
import './commands';
Other declarations follow the same pattern and are covered with custom commands and queries in
Queries, Assertions & Custom Commands: child commands
need the prevSubject option, Cypress.Commands.overwrite<'type', 'element'>() needs generics, custom queries are declared
before addQuery(), properties your application adds to window extend Cypress.ApplicationWindow, and a standalone .d.ts
file may declare namespace Cypress directly if it has no imports (when it does, use declare global). Make sure every
tsconfig.json that should see a declaration file includes it.
If the editor does not pick up the types, restart its TypeScript server (in VS Code, the command "TypeScript: Restart TS Server").
For configuration files, defineConfig() infers the types of setupNodeEvents(on, config) automatically. For a function kept
in another file, annotate it with Cypress.PluginConfig. Align compilerOptions.module with how the file loads: commonjs for a
cypress.config.cts or a CommonJS project, NodeNext or ES2022 for cypress.config.mts or "type": "module".
Folder structure
Cypress prefers convention to configuration. For a TypeScript end-to-end project the Launchpad creates the files marked "created by the Launchpad" below; the rest are the ones this page added:
cy-getting-started/
package.json
cypress.config.ts # created by the Launchpad
tsconfig.json
cypress/
e2e/ # specs; only files named *.cy.ts are run
first-test.cy.ts
failing-on-purpose.cy.ts
uses-base-url.cy.ts
config-and-env.cy.ts
fixtures/
example.json # created by the Launchpad; load with cy.fixture()
support/
e2e.ts # created by the Launchpad; loaded before every spec
commands.ts # created by the Launchpad; custom commands live here
screenshots/ # generated on failures and by cy.screenshot()
downloads/ # generated by downloads in a test
videos/ # generated when video is enabled
Component testing adds cypress/support/component.ts and cypress/support/component-index.html, and the specs sit next to the
components. Every path is a default that can be changed in the configuration file; if you are starting a project, keep the
defaults so that your layout matches the documentation.
Specs and the .cy. rule
Cypress loads only files that match specPattern, and the default pattern needs the .cy. infix. A file called
cypress/e2e/login.ts is invisible; cypress/e2e/login.cy.ts is a spec. That convention lets helpers and specs live in the
same folder without Cypress trying to run helpers. If a spec does not appear, the file name is the first thing to check. Three
settings work together:
-
specPatternis the master list of what counts as a spec. -
excludeSpecPatternsubtracts files from that list. -
--specpicks which of the remaining specs run this time. It can never add a file outsidespecPattern: a spec attests/login.cy.tsis not found by--specuntilspecPatternalso includestests/**.
If specs still do not show up, run Cypress with DEBUG=cypress:cli,cypress:data-context:sources:FileDataSource,cypress:data-context:sources:ProjectDataSource
to see how it searches.
As a rule of thumb use one spec for a feature or user flow, with describe() blocks for related scenarios. Cypress reloads the
browser, the support file and the application for every spec, so many tiny specs are slower, and it distributes whole specs when
you parallelize, so one very long spec delays the run.
Support files, fixtures and node events
-
The support file (
cypress/support/e2e.ts) runs before every spec file. It is the place for custom commands, globalbeforeEachhooks and overrides. It is bundled together with everything it imports, so keep it lean and never import Node.js-only code such asfsinto it. -
Fixtures (
cypress/fixtures) are static data loaded withcy.fixture(), withcy.intercept(){ fixture: 'users.json' }, or attached to an upload with.selectFile(). Usecy.readFile()for files that change while the test runs andcy.task()for large files or work that needs Node.js. -
Specs may be
.js,.jsx,.tsor.tsx, may use ES modules or CommonJS and may import local modules and npm packages. The bundle runs in the browser, so a module that needsfsmust run inside a task.
IDE integration
Cypress works with any editor that understands JavaScript or TypeScript. Five steps give a fully configured editor:
-
Turn on IntelliSense. With a
tsconfig.jsonthat lists"types": ["cypress"](as above) everycy.command completes in VS Code, Visual Studio and WebStorm, which have TypeScript support built in; other editors need an extra TypeScript plugin. In a JavaScript project add/// <reference types="cypress" />to the top of each spec, or ajsconfig.jsonwith"include": ["./node_modules/cypress", "cypress/**/*.js"]. If completion fails, check that the righttsconfig.jsoncovers the spec files, restart the TypeScript server, select the workspace TypeScript version and look for a clash with Jest types. -
Lint. The official
eslint-plugin-cypressdeclares the Cypress and Mocha globals so that spec files do not report undefined variables, and has rules that flag anti-patterns while you type. -
Choose your file opener. The first time you click a file path or an error in the Command Log, Cypress asks where to open files: the file system, an IDE it found, or an application path. Change it later in the Settings tab of the app.
-
Install extensions where useful. Community extensions add running specs from the editor and navigating to custom commands: Cypress Test Explorer, Cypress Helper and Test Utils for Visual Studio Code (and forks such as Cursor, which use the Open VSX registry, so some are missing there), the JetBrains "Test Automation" plugin (official) and Cypresso for JetBrains IDEs, and
vim-testfor Vim and Neovim. Commit a.vscode/extensions.jsonwith the recommended extensions so that every teammate is offered them. -
Add AI tooling if you use an assistant.
npx skills add cypress-io/ai-toolkitinstalls the Cypress AI Skills, and the Cloud MCP server connects an assistant to recorded runs. They are covered in AI Features in Cypress & Selenium and were not run for this page.
{
"recommendations": [
"dbaeumer.vscode-eslint",
"dpanshug.cypress-test-explorer"
]
}
Source: Cypress — IDE integration
Debugging differs from what Playwright users may expect: a Cypress test runs in the browser, not in Node.js, so your editor’s
Node debugger cannot attach to a test. Debug tests with the browser’s developer tools together with debugger, .debug() and
cy.pause(). The editor’s Node debugger does apply to setupNodeEvents and to cy.task() code, which do run in Node.js. These
tools are covered in Debugging, Studio, Plugins & Reporters.
Cypress Studio also opens a code panel beside the running test, so you can edit a test while you watch it.
Common pitfalls
-
The binary is missing because a package manager blocked the
postinstallscript. Allow the script or runnpx cypress install. -
Running on Electron without noticing. Set
defaultBrowseror pass--browser, and look at theBrowser:line of the run output. -
A spec that does not appear. The file name lacks
.cy., or lives outsidespecPattern. -
baseUrlnot set. Every test then repeats the host name, and relative paths such ascy.visit('/')cannot resolve. -
The server was not running when Cypress started. Cypress cannot start it for you; start it first and wait for it.
-
Chaining after an action. Commands after
.click()or.type()on the same chain are not retried together with the action; begin a newcy.chain. -
Assuming
Cypress.env()still works. It was removed in 16.0.0; usecy.env()andCypress.expose(). -
Expecting a 10 ms keystroke delay. Typing is instant since 16.0.0; set
keystrokeDelay: 10if your application needs slower input. -
Secrets on the command line.
--envvalues can appear in CI logs; useCYPRESS_*variables or the CI secret store. -
TypeScript errors on custom commands. The declaration is missing, the file has no
export {}, or thetsconfig.jsonthat covers it does not list the declaration file. -
Keeping files in the generated folders. They are emptied before every
cypress run.
What changed recently
| Version | Change |
|---|---|
16.2.0 (13 Oct 2026) |
|
16.1.0 (15 Sep 2026) |
|
16.0.0 (1 Sep 2026) |
Node.js 22.x, 24.x or 26.x and later required (20 and 25 dropped); bundled Node.js 24.15.0 and Electron 41.7.0. Electron deprecated
as a test browser. |
15.21.0 |
|
15.19.0 |
TypeScript 7.0 supported; Firefox 140 is the minimum. |
15.17.0 |
Configuration and plugin files load as ES modules or CommonJS using Node.js rules, with no fallback. |
15.14.0 |
TypeScript 6.0 supported. |
15.11.0 |
|
15.10.0 |
|
15.0.0 |
|
13.16.0 |
|
Source: Cypress — Changelog