# How the Cypress Driver Works: Core Architecture and Command Execution

> Discover how the Cypress driver engine translates cy commands into a retry queue, synchronizes with your AUT, and manages state for stable cross-origin execution. Learn Cypress core architecture.

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

---

**The Cypress driver is the core runtime engine in the `@packages/driver` workspace that translates `cy.*` commands into a deterministic, retry-aware FIFO queue, synchronizes with the application under test (AUT), and manages state, stability, and cross-origin execution.**

The Cypress driver powers every end-to-end test in the `cypress-io/cypress` repository. Located in the `@packages/driver` workspace, it exposes the `cy` object and orchestrates the command queue, stability checks, and subject chaining that make Cypress tests reliable. Understanding how the driver initializes, enqueues commands, and manages execution flow is essential for debugging complex test scenarios or extending the framework with custom commands.

## Initialization and Bootstrapping ([`main.ts`](https://github.com/cypress-io/cypress/blob/main/main.ts))

The driver entry point begins at [`packages/driver/src/main.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/main.ts), which prepares the runtime environment before exposing the `$Cypress` object.

```ts
// packages/driver/src/main.ts
import 'setimmediate'               // polyfill for Node.js environments
import './config/bluebird'          // Bluebird promise patches
import './config/jquery'            // jQuery globals for the AUT
import './config/lodash'            // lodash patches
import $Cypress from './cypress'    // the $Cypress entry point

import { telemetry } from '@packages/telemetry/browser/client'
telemetry.attach()                 // link driver telemetry to the app instance

export default $Cypress

```

This bootstrap phase loads critical side-effects including `setimmediate`, Bluebird, jQuery, and lodash configurations. Telemetry attaches here to instrument driver behavior. The file ultimately exports the `$Cypress` object that the test runner imports to begin execution.

## The `cy` Instance and Public API ([`cy.ts`](https://github.com/cypress-io/cypress/blob/main/cy.ts))

When the runner loads a spec, it instantiates the `Cy` class defined in [`packages/driver/src/cypress/cy.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/cy.ts). This class implements the public API for all `cy.get()`, `cy.click()`, and other commands.

The constructor initializes core traits and wires the command queue:

```ts
// packages/driver/src/cypress/cy.ts
constructor (specWindow, Cypress, Cookies, state, config) {
  super()                                 // EventEmitter2
  state('specWindow', specWindow)         // store the spec's window
  this.id = _.uniqueId('cy')
  this.state = state
  this.config = config
  this.Cypress = Cypress
  this.Cookies = Cookies

  // initialize traits (timeouts, stability, assertions, jquery, location, etc.)
  const timeouts   = createTimeouts(state)
  const stability  = createStability(Cypress, state)
  const assertions = createAssertions(Cypress, this)

  this.timeout = timeouts.timeout
  this.isStable = stability.isStable
  this.assert = assertions.assert
  …
  this.queue = new CommandQueue(state, stability, this)

  setTopOnError(Cypress, this)            // global error handler for the AUT
  specWindow.cy = this                     // expose `cy` in the spec window
  extendEvents(this)                       // bind Cypress events (e.g. `window:alert`)
}

```

Key architectural components include:

- **State management** – A thin wrapper in [`packages/driver/src/cypress/state.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/state.ts) shares data between the driver, queue, and UI.
- **Traits** – Factory functions like `createTimeouts`, `createStability`, and `createAssertions` return bound methods for specific domains.
- **CommandQueue** – The `new CommandQueue(state, stability, this)` instantiation creates the FIFO pipeline that executes commands sequentially.

## Command Queue Architecture ([`command_queue.ts`](https://github.com/cypress-io/cypress/blob/main/command_queue.ts))

The `CommandQueue` class in [`packages/driver/src/cypress/command_queue.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/command_queue.ts) inherits from a generic queue implementation and drives the entire test execution lifecycle.

### Command Lifecycle and $Command Objects

Each command enqueued becomes a `$Command` instance defined in [`packages/driver/src/cypress/command.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/command.ts). These objects track:

- Lifecycle states (`queued`, `pending`, `passed`, `failed`)
- Arguments and yielded subjects
- Chainer IDs for subject chaining
- Logging and snapshot metadata

### Queue Execution and Stability Checks

The `run()` method orchestrates execution through several phases:

1. **Preparation** – Waits for the application under test (AUT) to become stable via `this.stability.whenStable`.
2. **Dequeue** – Retrieves the next command and calls `runCommand(command)`.
3. **Execution** – Marks the command as pending and invokes the user-supplied function.
4. **Retry Logic** – For queries, the `retryQuery` function repeatedly invokes the command until assertions pass or the timeout expires.
5. **Subject Management** – Updates the subject chain via `addQueryToChainer` or `setSubjectForChainer`.
6. **Finalization** – Calls `command.finishLogs()` and handles errors through `onError`.

The core execution logic in `runCommand` looks like this:

```ts
// packages/driver/src/cypress/command_queue.ts (excerpt)
private runCommand (command: $Command) {
  const isQuery = command.get('query')
  this.state('current', command)
  this.state('chainerId', command.get('chainerId'))

  return this.stability.whenStable(() => {
    this.state('nestedIndex', this.index)
    return command.get('args')
  })
  .then((args) => {
    // invoke user fn (wrapped in __stackReplacementMarker)
    command.start()
    let ret = __stackReplacementMarker(command.get('fn'), [command.get('chainerId'), ...args])

    if (isQuery) {
      command.set('queryFn', ret)          // keep original fn
      ret = retryQuery(command, ret, this.cy)
    }

    // … error handling, promise checks, etc.
    return ret
  })
  .then((subject) => {
    // subject → logs → subject chaining
    if (isQuery) {
      this.cy.addQueryToChainer(command.get('chainerId'), command.get('queryFn'))
    } else {
      this.cy.setSubjectForChainer(command.get('chainerId'), [subject])
    }
    return subject
  })
}

```

## Command Registration and Enqueuing (`addCommand`)

When tests call `cy.get('button')`, the `Cy.addCommand` method in [`packages/driver/src/cypress/cy.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/cy.ts) wraps the raw implementation and hooks it into the queue.

```ts
// packages/driver/src/cypress/cy.ts (excerpt)
addCommand ({ name, fn, type, prevSubject }) {
  this.commandFns[name] = fn               // store raw implementation
  const wrap = (firstCall) => {
    if (type === 'parent') {
      return (chainerId, ...args) => fn.apply(this.runnableCtx(name), args)
    }
    // for child commands we need to push the subject first
    return (chainerId, ...args) => {
      if (firstCall) this.validateFirstCall(name, args, prevSubject)
      args = this.pushSubject(name, args, prevSubject, chainerId)
      return fn.apply(this.runnableCtx(name), args)
    }
  }

  const cyFn = wrap(true)           // the first call (user's call)
  const chainerFn = wrap(false)     // subsequent chained calls

  // Hook into Cypress' `command:enqueued` event so the queue can pick it up
  $Chainer.add(name, (chainer, stack, args, verification, firstCall = false) => {
    if (this.state('onInjectCommand')?.(... ) === false) return
    this.enqueue($Command.create({
      name,
      args,
      type,
      chainerId: chainer.chainerId,
      userInvocationStack: stack,
      fn: firstCall ? cyFn : chainerFn,
      privilegeVerification: verification,
    }))
  })

  // expose the command on the `cy` instance
  this[name] = (...args) => {
    ensureRunnable(this, name)
    const priv = Cypress.emitMap('command:invocation', { name, args })
    const chainer = new $Chainer(this.specWindow)

    // link subject chains for nested commands
    if (this.state('chainerId')) this.linkSubject(chainer.chainerId, this.state('chainerId'))

    const stack = $stackUtils.captureUserInvocationStack(this.specWindow.Error)
    this.enqueueCallback(chainer, stack, args, priv)
    return chainer
  }
}

```

The command is never executed directly upon invocation. Instead, `$Command.create` generates a command object that enters the `CommandQueue`, ensuring deterministic execution order and automatic retry capabilities.

## Cross-Origin Support and State Management

The Cypress driver handles multi-origin tests through careful state isolation and unique command identification. When using `cy.origin()`, the driver:

- Generates unique command IDs incorporating **chainer IDs** (defined in [`packages/driver/src/cypress/command.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/command.ts) line 19) to prevent collisions across origins.
- Stores remote references like `state('remotejQueryInstance')` and `state('remoteLocation')`.
- Proxies messages via `Cypress.primaryOriginCommunicator`.
- Wraps AUT errors in cross-origin safe formats using [`packages/driver/src/cypress/error_utils.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/error_utils.ts).

The state wrapper in [`packages/driver/src/cypress/state.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/state.ts) provides a simple getter/setter interface shared across all driver components, ensuring consistency between the queue, UI, and application under test.

## Stability, Retries, and Cleanup

**Stability** checks reside in [`packages/driver/src/cypress/stability.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/stability.ts). Before each command executes, the driver waits for the AUT to become "stable"—meaning no pending network requests or timers—preventing flaky timing issues.

**Retry logic** automatically re-executes queries and assertions until they pass or the command timeout expires. This logic lives in `retryQuery` (within the command queue) and the assertions trait in [`packages/driver/src/cypress/assertions.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/assertions.ts).

After test completion, the `cleanup()` method:

- Resets the runnable timeout
- Clears temporary state (`commandIntermediateValue`, `nestedIndex`)
- Marks the system as stable for `after`/`afterEach` hooks
- Optionally runs `cleanSubjects()` to free unreachable command memory

## Summary

- The **Cypress driver** lives in `@packages/driver` and exposes the `cy` API through the `Cy` class in [`packages/driver/src/cypress/cy.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/cy.ts).
- **Command execution** follows a FIFO queue pattern managed by `CommandQueue` in [`packages/driver/src/cypress/command_queue.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/command_queue.ts), ensuring commands run sequentially with automatic retries.
- **Stability checks** wait for the AUT to settle before each command, while the **state manager** shares data across driver components via [`packages/driver/src/cypress/state.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/state.ts).
- **Cross-origin support** uses unique chainer IDs and the `primaryOriginCommunicator` to isolate and proxy commands between different origins.
- Commands are wrapped as **$Command objects** that track lifecycle states, handle logging, and manage subject chaining for subsequent commands.

## Frequently Asked Questions

### What is the Cypress driver responsible for?

The Cypress driver is the core runtime engine that interprets `cy.*` commands and manages their execution. It handles command queuing, stability checks, subject chaining, retries, and cross-origin communication, living primarily in the `@packages/driver` workspace of the `cypress-io/cypress` repository.

### How does the Cypress driver handle automatic retries?

The driver implements retry logic in the `CommandQueue.runCommand` method and the assertions trait. For query commands, it calls `retryQuery` repeatedly until the query function returns a passing result or the command timeout expires. This ensures assertions eventually pass when the application under test reaches the expected state.

### Where does the Cypress driver initialize its dependencies?

Dependency initialization occurs in [`packages/driver/src/main.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/main.ts), which imports side-effects like `setimmediate`, Bluebird promise patches, jQuery globals, and lodash configurations. It also attaches telemetry before exporting the `$Cypress` object that bootstraps the entire test runtime.

### How are custom commands added to the Cypress driver?

Custom commands added via `Cypress.Commands.add()` ultimately invoke `Cy.addCommand` in [`packages/driver/src/cypress/cy.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/cy.ts). This method wraps the user-provided function, creates a `$Command` object via `$Command.create()`, and enqueues it in the `CommandQueue`, giving custom commands the same retry, stability, and logging capabilities as built-in commands.