How Cypress Architecture Works: Inside the Electron, Node, and Browser Stack

Cypress is a monorepo-based Electron application that orchestrates tests through a Node.js server process, a browser-injected driver, and a WebSocket proxy, enabling native network interception and real-time DOM control.

The cypress-io/cypress repository implements a sophisticated Cypress architecture defined in AGENTS.md that bundles a desktop Electron application, a CLI tool, and a multi-process test runner. This architecture enables Cypress to run tests directly inside the browser while maintaining full control over network traffic, automation APIs, and cross-origin navigation.

Core Components of the Cypress Architecture

Cypress organizes its codebase into a monorepo where each package owns a distinct responsibility in the test execution lifecycle.

CLI and Distribution Layer (cli/)

The cli/ package contains the cypress npm package that users install. When you execute cypress open or cypress run, the CLI parses the configuration and spawns the remaining system. According to cli/src/cli.ts, this entry point handles command routing and initial environment setup before delegating to the server layer.

Browser Driver and Test Runner (@packages/driver)

The driver is a JavaScript library loaded inside the Application-Under-Test (AUT) iframe. Located in packages/driver/src/driver.ts, it executes cy.* commands, handles automatic retries, manages assertions, and emits events to the runner. The driver works alongside the runner (@packages/runner), which hosts the AUT iframe and bridges communication between the driver and the server via WebSocket.

Server and Network Proxy (@packages/server)

The @packages/server package runs as a Node.js process that serves spec files, launches browsers, and coordinates the entire test run. It works in tandem with @packages/proxy to intercept all HTTP/HTTPS traffic, allowing cy.intercept to stub or spy on network requests. The packages/net-stubbing/lib/intercept.ts file implements the high-level matching and response manipulation logic used when tests call cy.intercept().

Desktop Electron Shell (@packages/electron)

The @packages/electron package wraps the Vue 3 front-end (defined in @packages/app) into a desktop binary. This layer includes the launcher (@packages/launcher), which detects installed browsers (Chrome, Edge, Firefox, WebKit) and starts them with the necessary flags, and the extension (@packages/extension), which injects the driver into the browser and enables cross-origin automation features.

Component Testing Adapters (npm/)

Cypress extends its architecture to component testing through framework-specific adapters located in npm/react/, npm/vue/, and npm/webpack-dev-server/. These packages expose a mount API that bridges component frameworks to the driver, allowing the same driver and proxy infrastructure to test isolated components using Webpack or Vite bundlers.

How Cypress Executes Tests: End-to-End Flow

Understanding how the Cypress architecture functions requires following the execution path from CLI command to test result.

  1. CLI Initialization: The cypress run command triggers cli/src/cli.ts, which parses cypress.config.{js,ts} and spawns the server process.

  2. Server Preparation: The server establishes a WebSocket channel via @packages/socket and launches the requested browser through the launcher.

  3. Browser Bootstrap: The browser loads the Cypress extension, which injects the driver script into the AUT iframe. The driver calls init() from @packages/rewriter to instrument user code with retry logic and command chaining.

  4. WebSocket Connection: The driver establishes a WebSocket connection back to the server, creating a bidirectional communication channel for command execution and event streaming.

  5. Command Execution: When the runner UI sends a command, the driver executes it in the browser context and streams events (logs, screenshots, network activity) back through the WebSocket.

  6. Network Interception: All outgoing HTTP requests pass through the proxy layer. The net-stubbing engine matches requests against cy.intercept rules defined in packages/net-stubbing/lib/intercept.ts and applies stubs or modifications.

  7. Result Aggregation: The server aggregates test results and passes them to the reporter (@packages/reporter), which renders the pass/fail tree in the GUI.

Code-Level Implementation Details

The following snippets illustrate the key entry points in the Cypress architecture.

CLI Entry Point

// cli/src/cli.ts (simplified)
import { launch } from '@packages/launcher'
import { startServer } from '@packages/server'
import { runElectron } from '@packages/electron'

async function run() {
  const config = await loadConfig()                     // reads cypress.config.{js,ts}
  const server = await startServer({ config })
  const browser = await launch(config.browser)          // Chrome, Firefox, etc.
  await runElectron({ serverUrl: server.url, browser }) // start GUI
}
run()

Driver Bootstrap

// packages/driver/src/driver.ts (simplified)
import { init } from '@packages/rewriter'
import { connect } from '@packages/socket'

export function bootstrap() {
  init()                         // instrument test code
  const ws = connect(window.location.origin.replace('http', 'ws')) // WS ↔ server
  ws.on('command', execCommand) // receive ‘cy.*’ calls from runner
}

Network Stubbing Implementation

// packages/net-stubbing/lib/intercept.ts (simplified)
export function intercept(matcher, handler) {
  // Register a rule that the Proxy will query on every request
  proxy.registerRule({ matcher, handler })
}

Reporter UI Component

// packages/reporter/src/Reporter.vue (simplified)
<template>
  <Tree :nodes="testResults" />
</template>

<script>
import { useResults } from '@packages/socket'
export default {
  setup() {
    const testResults = useResults()   // reactive data from server
    return { testResults }
  }
}
</script>

Key Source Files and Entry Points

The cypress-io/cypress repository maintains several critical files that define the architecture:

Summary

  • Cypress architecture is a monorepo-based system combining Electron, Node.js, and browser-based JavaScript.
  • The CLI (cli/) initiates the test run by spawning the server and Electron desktop application.
  • The driver (@packages/driver) executes commands inside the browser iframe and communicates via WebSocket.
  • The server (@packages/server) and proxy (@packages/proxy) handle network interception and test coordination.
  • Net-stubbing (@packages/net-stubbing) enables cy.intercept by matching and modifying HTTP traffic at the proxy layer.
  • The Electron shell (@packages/electron) packages the Vue 3 front-end and manages browser launching via the launcher module.

Frequently Asked Questions

How does Cypress architecture differ from Selenium-based tools?

Cypress architecture runs tests directly inside the browser using a JavaScript driver injected into the application under test, whereas Selenium uses the WebDriver protocol to send commands via HTTP to browser-specific drivers. This allows Cypress to execute commands in the same run loop as the application, enabling native network interception and automatic waiting without the latency of external protocol translation.

What is the role of the Cypress driver in the browser?

The driver (@packages/driver) is a JavaScript library loaded into the AUT iframe that executes cy.* commands, handles automatic retries, and manages assertions. According to packages/driver/src/driver.ts, it bootstraps by calling the rewriter to instrument code, then establishes a WebSocket connection to the server to receive commands and emit events.

How does Cypress intercept HTTPS requests without browser certificate errors?

Cypress uses the proxy (@packages/proxy) and HTTPS-proxy (@packages/https-proxy) packages to perform TLS termination. The proxy intercepts all browser traffic, decrypts HTTPS requests using its own certificate authority, and allows the net-stubbing layer to inspect or modify contents before re-encrypting and forwarding to the destination, enabling seamless cy.intercept() functionality on encrypted traffic.

Why does Cypress use a WebSocket connection between the driver and server?

The WebSocket connection (implemented in @packages/socket) provides a persistent, bidirectional communication channel that allows the driver to stream real-time events (DOM snapshots, network logs, console output) to the runner UI while receiving commands from the server. This architecture enables Cypress to display live test execution and time-travel debugging features that require instantaneous state synchronization between the browser and the desktop application.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →