# How Cypress Implements Custom Commands and the Command Queue

> Discover how Cypress implements custom commands and the command queue. Learn about deterministic scheduling, automatic retries, and failure propagation for robust test automation.

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

---

**Cypress registers custom commands through the global `Cypress.Commands` API and executes them via a centralized `CommandQueue` class that manages deterministic scheduling, automatic retries, and failure propagation.**

The `cypress-io/cypress` repository implements a sophisticated command-chaining architecture that treats every test instruction as a queued task. This design ensures that custom commands integrate seamlessly with built-in ones while maintaining strict execution order and robust error handling.

## Command Queue Architecture

The execution model centers on the **Command Queue**, implemented in [`packages/driver/src/cypress/command_queue.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/command_queue.ts). This class maintains an ordered list of pending commands and coordinates their lifecycle from enqueueing to completion. At its core, the queue relies on a lightweight FIFO utility defined in [`packages/driver/src/util/queue.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/util/queue.ts), which `CommandQueue` extends to add Cypress-specific semantics like retry logic and subject propagation.

### The Command Class

Each instruction—whether built-in or custom—is encapsulated by the `Command` class in [`packages/driver/src/cypress/command.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/command.ts). This class stores critical metadata including the command name, arguments, timeout duration, and a reference to the factory function that executes the actual logic. It also maintains a link to the command's log entry for debugging purposes.

### The Queue Infrastructure

The underlying data structure in [`packages/driver/src/util/queue.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/util/queue.ts) provides simple `push()` and `shift()` operations. The `CommandQueue` wraps this utility to implement `add()`, `run()`, and `retryQuery()` methods, transforming a basic queue into a sophisticated execution engine that handles asynchronous boundaries and DOM retries.

## Registering Custom Commands via Cypress.Commands

Custom commands enter the system through the global registration API defined in [`packages/driver/src/cypress/custom_commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/custom_commands.ts). When you call `Cypress.Commands.add()`, the implementation stores your function in an internal registry keyed by command name.

```javascript
// User-facing API
Cypress.Commands.add('login', (username, password) => {
  cy.request('POST', '/login', { username, password })
})

// Internal implementation (simplified)
Cypress.Commands.add = (name, fn) => {
  Cypress.Commands._commands[name] = fn
}

```

The registry (`Cypress.Commands._commands`) acts as a lookup table. When a test calls `cy.login()`, the queue retrieves the factory function from this registry to instantiate the command.

## Execution Flow and Enqueueing

When you invoke `cy.<command>()`, the call flows through the proxy to `CommandQueue.add()` in [`packages/driver/src/cypress/command_queue.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/command_queue.ts).

### From cy.call() to Queue Insertion

The `add()` method performs three critical actions:

1. Looks up the command factory in the registry
2. Instantiates a new `Command` object with the resolved arguments
3. Pushes the command onto the internal queue

```javascript
// Conceptual implementation in command_queue.ts
add(name, args) {
  const factory = Cypress.Commands._commands[name]
  const cmd = new Command({ 
    name, 
    args, 
    fn: factory,
    timeout: Cypress.config('defaultCommandTimeout')
  })
  this.queue.push(cmd)
  return this  // Enables chaining
}

```

### The Run Loop and Retry Mechanism

The `run()` method processes commands sequentially. For each command, it shifts the next item from the queue and invokes its factory function. Query commands (like `cy.get`) are wrapped in `retryQuery()`, which re-executes the command until the assertion passes or the timeout expires.

```javascript
// Simplified execution loop
run() {
  while (this.queue.length) {
    const cmd = this.queue.shift()
    try {
      const result = cmd.fn(...cmd.args)
      // Handle promises, wait for resolution, then proceed
    } catch (err) {
      this.commandRunningFailed(cmd, err)
    }
  }
}

```

## Error Handling and Command Failure

When a command throws or times out, `commandRunningFailed()` in [`command_queue.ts`](https://github.com/cypress-io/cypress/blob/main/command_queue.ts) captures the error, attaches it to the command's log object, and halts queue execution. Unless the test has a `cy.on('fail')` handler that prevents default behavior, the failure propagates to the Cypress UI and terminates the test.

## Summary

- **Command Registration**: `Cypress.Commands.add()` stores factory functions in an internal registry at [`packages/driver/src/cypress/custom_commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/custom_commands.ts).
- **Queue Management**: 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) maintains execution order using a FIFO queue from [`packages/driver/src/util/queue.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/util/queue.ts).
- **Command Instances**: Each queued item is 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)) that encapsulates arguments, timeout settings, and execution logic.
- **Retry Logic**: Query commands automatically retry via `retryQuery()` until they succeed or exceed their timeout.
- **Error Propagation**: The `commandRunningFailed()` method handles exceptions by logging them and aborting the queue unless explicitly caught.

## Frequently Asked Questions

### How do I register a custom command in Cypress?

Use `Cypress.Commands.add(name, callbackFunction)` in your support file. This stores your function in the internal `_commands` registry, making it available as `cy.<name>()` in your tests. The registration happens before tests run, so the command is available throughout your spec files.

### What is the difference between Cypress.Commands.add and Cypress.Commands.overwrite?

`Cypress.Commands.add()` registers a new command name, while `Cypress.Commands.overwrite()` replaces the implementation of an existing command. When you overwrite, you receive the original command as the first argument, allowing you to wrap or modify behavior while preserving the ability to call the original functionality.

### How does Cypress handle asynchronous commands in the queue?

The `CommandQueue` automatically detects when a command returns a Promise or a Cypress-chainable object. The `run()` loop pauses execution until the Promise resolves, ensuring that subsequent commands wait for asynchronous operations (like network requests or DOM animations) to complete before proceeding.

### Where is the command queue implemented in the Cypress source code?

The primary implementation resides in [`packages/driver/src/cypress/command_queue.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/command_queue.ts), which defines the `CommandQueue` class. Supporting files include [`packages/driver/src/cypress/command.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/command.ts) (the `Command` class definition), [`packages/driver/src/util/queue.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/util/queue.ts) (the underlying FIFO structure), and [`packages/driver/src/cypress/custom_commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/custom_commands.ts) (the global registration API).