# Understanding the Cypress Server's Role in Test Execution

> Discover the Cypress server's role in test execution. Learn how this Node.js orchestrator creates a deterministic environment by managing network traffic and browser control.

- Repository: [Cypress.io/cypress](https://github.com/cypress-io/cypress)
- Tags: internals
- Published: 2026-06-21

---

**The Cypress server is a full-stack Node.js orchestrator that creates an HTTP server, proxies network traffic, handles cross-origin communication, and drives the browser via socket connections to provide a deterministic test environment.**

The `cypress-io/cypress` repository implements a sophisticated server architecture that powers end-to-end testing. The **Cypress server** operates as a full-stack Node.js application living in the `@packages/server` package, coordinating everything from serving test files to intercepting network requests and managing browser communication through a tightly coupled stack of specialized components.

## Core Server Architecture

The server architecture centers on a small set of core classes that work together to provide deterministic control over the application under test (AUT).

### ServerBase - The Central Orchestrator

The **`ServerBase<TSocket>`** class in [`packages/server/lib/server-base.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/server-base.ts) serves as the central orchestrator. It creates the HTTP server, file server, and optional HTTPS proxy, while also owning the socket that communicates with the Cypress driver and the remote-state manager that tracks ports and URLs.

When Cypress starts, the `ServerBase` instance performs the initialization sequence:

1. Creates an Express app
2. Instantiates the HTTP server via `this._createHttpServer(app)`
3. Attaches socket.io for driver communication (`this.server.on('upgrade', …)`)
4. Starts the file server (`fileServer.create`) for fixtures and screenshots
5. Optionally creates an HTTPS proxy to handle Chrome's automatic HTTPS upgrades
6. Begins listening on the configured port via `this._listen(port)`

### NetworkRuntime and Proxy Infrastructure

The **`NetworkRuntime`** (exposed via `createProxyRuntime` in [`packages/server/lib/network-runtime.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/network-runtime.ts)) sets up the **`NetworkProxy`** from `@packages/proxy` together with net-stubbing state, network-policy registration, and the interception core. This layer enables **`cy.intercept`**, automatic handling of redirects, and credential forwarding.

All outbound HTTP requests that the application under test makes flow through this **NetworkProxy**, which intercepts requests via the `handleHttpRequest` hook, applies Cypress-defined stubbing rules by consulting the `NetStubbingState`, and injects cookies and Chrome-specific headers.

### Request Handling Wrapper

The **`Request`** class in [`packages/server/lib/request.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/request.ts) provides a thin wrapper around `@cypress/request` that adds Cypress-specific defaults including **keep-alive** headers (`Connection: keep-alive`), **TLS trust** configuration, and **retry logic** for network failures. It also serializes request/response data for the driver using the `pick` method.

## Server Initialization and Boot Sequence

### From CLI to HTTP Server

The entry point in [`packages/server/lib/cypress.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/cypress.ts) provides the CLI wrapper that parses arguments and boots the server. When `cypress start` executes, the **`Cypress.start`** function creates a new `ServerBase` instance and calls `createServer` to spin up the main HTTP server:

```ts
// Inside cypress.ts → start()
await server.createServer(app, config, onWarning)

```

The `ServerBase.createServer` method (see lines 62-94 of [`server-base.ts`](https://github.com/cypress-io/cypress/blob/main/server-base.ts)) performs the initialization steps. When a `baseUrl` is supplied, the server validates that the URL is reachable or emits a warning to the user.

You can also start the server programmatically:

```ts
import { ServerBase } from '@packages/server/lib/server-base'
import express from 'express'

async function launchServer() {
  const app = express()
  const server = new ServerBase({/* config */})

  // Create and start the HTTP server
  await server.createServer(app, config, onWarning)

  console.log(`Cypress server listening on ${await server._port()}`)
}
launchServer()

```

### Routing and Control Endpoints

The **`Routes`** module in [`packages/server/lib/routes.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/routes.ts) (specifically `createCommonRoutes`) wires up Express endpoints for Cypress-specific functionality. Key routes include:

- **`/<namespace>/tests`** – Serves test files to the runner
- **[`/socket.io.js`](https://github.com/cypress-io/cypress/blob/main//socket.io.js)** – Serves the Socket.io client for driver-server communication
- **`/__cypress-studio/*`** – Exposes internal Studio APIs to child processes

A special middleware (lines 70-100 of [`routes.ts`](https://github.com/cypress-io/cypress/blob/main/routes.ts)) detects when Chrome automatically upgrades an `http:` request to `https:` and replies with a **301 redirect** back to the original `http:` URL. This prevents the "Chrome HTTPS-upgrade loop" (issue #25891) that would otherwise cause infinite redirects during test execution.

## Network Traffic Management

### Intercepting Requests with NetworkProxy

The NetworkProxy sits between the browser and external network, enabling deterministic control over all traffic. Here is how `cy.intercept` works internally:

```ts
import { createProxyRuntime } from '@packages/server/lib/network-runtime'

const runtime = createProxyRuntime({
  config,
  remoteStates,
  getFileServerToken,
  getCookieJar,
  socket,
  request: new Request(),
  serverBus,
  getCurrentBrowser,
})

// Example: a stub for GET /api/users
runtime.networkProxy.addRequestHandler({
  method: 'GET',
  url: '/api/users',
  handler: (req, res) => {
    res.statusCode = 200
    res.body = [{ id: 1, name: 'Alice' }]
  },
})

```

The proxy handles request serialization, redirect chains, and credential forwarding while maintaining the stubbing state that makes `cy.intercept` possible.

## Cross-Origin Communication and Socket Bridge

### Socket-Based Driver Communication

`ServerBase` creates either a **`SocketE2E`** (for end-to-end testing) or **`SocketCt`** (for component testing) instance exposed via `this.socket`. This socket layer bridges the test runner (Node) and the browser (driver), forwarding commands (`cy.*`) and emitting events such as cross-origin cookies and protocol manager updates.

The server manages cross-origin cookie synchronization through socket events:

```ts
// Cross-origin cookie sync (simplified)
server.socket.localBus.on('cross:origin:cookies:received', () => {
  // driver notifies server that cookies have been set
  server._eventBus.emit('cross:origin:cookies:received')
})

// The server forwards the cookie data to the driver
server.socket.toDriver('cross:origin:cookies', cookies)

```

This mechanism ensures that cookies set across different origins during test execution are properly tracked and synchronized between the browser and the Node server.

## Lifecycle Management and Cleanup

When a spec finishes execution, `ServerBase` calls `reset` on the `NetworkProxy` to clear the net-stubbing state, shuts down the file server, and prepares for the next test file. Graceful shutdown handling is provided by utilities like [`graceful-exit.ts`](https://github.com/cypress-io/cypress/blob/main/graceful-exit.ts) and [`graceful-crash-handling.ts`](https://github.com/cypress-io/cypress/blob/main/graceful-crash-handling.ts) in the server package.

## Summary

- **`ServerBase`** in [`packages/server/lib/server-base.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/server-base.ts) orchestrates the HTTP server, file server, HTTPS proxy, and socket communication.
- **`createProxyRuntime`** in [`packages/server/lib/network-runtime.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/network-runtime.ts) initializes the NetworkProxy that enables `cy.intercept` and traffic interception.
- **`Request`** in [`packages/server/lib/request.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/request.ts) wraps HTTP calls with keep-alive, retry logic, and serialization for the driver.
- **`createCommonRoutes`** in [`packages/server/lib/routes.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/routes.ts) defines control endpoints and fixes Chrome HTTPS-upgrade loops.
- The **socket layer** bridges Node and the browser, handling cross-origin cookie sync and command forwarding.
- The server provides deterministic control over the AUT by proxying all network traffic and managing the browser lifecycle.

## Frequently Asked Questions

### What does the Cypress server do during test execution?

The Cypress server creates a full-stack Node.js environment that serves test files, proxies all network traffic from the browser, intercepts requests for stubbing via `cy.intercept`, and manages cross-origin communication through a socket bridge. It runs in the `@packages/server` package and coordinates with the browser driver to execute commands and collect results.

### How does Cypress handle network interception?

Cypress routes all outbound application traffic through the **`NetworkProxy`** (initialized via `createProxyRuntime` in [`packages/server/lib/network-runtime.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/network-runtime.ts)). This proxy intercepts requests using the `handleHttpRequest` hook, applies rules from the `NetStubbingState`, and injects authentication headers before forwarding requests to the actual destination.

### Why does Cypress need an HTTPS proxy?

The HTTPS proxy handles Chrome's automatic HTTPS upgrade behavior. When Chrome upgrades an `http:` URL to `https:` automatically, the proxy (configured in `ServerBase`) rewrites these requests back to the HTTP server. The routes middleware in [`packages/server/lib/routes.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/routes.ts) (lines 70-100) also implements a 301 redirect fix to prevent infinite loops during these upgrades.

### How does the server communicate with the browser?

The server uses **Socket.io** via the `SocketE2E` or `SocketCt` classes created by `ServerBase`. This socket connection forwards commands from the Node runner to the browser driver and emits events back to the server, including cross-origin cookie updates and request lifecycle events. The socket attaches to the HTTP server during the upgrade event in `createServer`.