# How to Extend Cypress Commands: A Complete Guide to Custom Commands and Queries

> Learn how to extend Cypress commands with custom commands and queries using Cypress.Commands.add and Cypress.Commands.overwrite. Enhance your test automation.

- Repository: [Cypress.io/cypress](https://github.com/cypress-io/cypress)
- Tags: how-to-guide
- Published: 2026-06-16

---

**You can extend Cypress commands by using `Cypress.Commands.add()` for new commands, `Cypress.Commands.overwrite()` for modifying existing ones, and `Cypress.Commands.addQuery()` for custom queries, all of which are managed by the driver in [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts).**

The `cypress-io/cypress` repository exposes a global `Cypress.Commands` API that allows you to extend Cypress commands to encapsulate repetitive logic, enforce project-specific conventions, and blend custom utilities seamlessly into the Cypress command chain. Understanding how to properly add and overwrite commands requires knowledge of the internal validation system, command types, and the TypeScript implementation found in the driver package.

## Understanding the Cypress.Commands API

The core implementation of how to extend Cypress commands lives in [[`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts)](https://github.com/cypress-io/cypress/blob/develop/packages/driver/src/cypress/commands.ts). When a test runs, the driver creates a `Commands` manager that handles registration, validation, and execution of all custom and built-in commands.

### Internal Command Lifecycle

According to the source code in [`commands.ts`](https://github.com/cypress-io/cypress/blob/main/commands.ts), the driver implements several safeguards when you extend Cypress commands:

- **Reserved Name Protection**: The system builds a `reservedCommandNames` set during initialization to prevent overwriting core Cypress APIs like `cy.visit` or `cy.get` directly through the add API.
- **Built-in Tracking**: All built-in commands are recorded in `builtInCommandNames` and `builtInCommands` to prevent duplicate custom names and to enable the overwrite functionality.
- **Type Derivation**: The command type (`parent`, `child`, or `dual`) is automatically derived from the `options.prevSubject` parameter.

### Command Types and prevSubject

When you extend Cypress commands, the `prevSubject` option determines how the command interacts with the command chain:

- **Parent** (`prevSubject: false`): Starts a new chain, receiving no subject from previous commands.
- **Child** (`prevSubject: 'element'` or `true`): Requires a previous subject to operate on.
- **Dual** (`prevSubject: 'optional'`): Can work with or without a previous subject.

## Adding Custom Commands to Cypress

The `Cypress.Commands.add(name, options?, fn)` method is the primary way to extend Cypress commands. The implementation in [`commands.ts`](https://github.com/cypress-io/cypress/blob/main/commands.ts) (lines 87-121) validates the name, determines the command type, and registers it via `cy.addCommand`.

### Parent Commands (No Previous Subject)

Use parent commands to start a new chain. These are utilities that don't require an existing DOM element or subject.

```typescript
// cypress/support/commands.ts
Cypress.Commands.add('login', (email: string, password: string) => {
  cy.request('POST', '/api/login', { email, password })
    .its('body')
    .then(body => {
      window.localStorage.setItem('authToken', body.token)
    })
})

```

Usage: `cy.login('joe@example.com', 's3cr3t')`

### Child Commands (Receiving a Previous Subject)

Child commands receive the subject yielded by the previous command as their first argument. Specify `{ prevSubject: 'element' }` in the options.

```typescript
Cypress.Commands.add(
  'dragTo',
  { prevSubject: 'element' },
  (subject, targetSelector) => {
    // `subject` is the element yielded by cy.get()
    cy.wrap(subject).trigger('mousedown')
    cy.get(targetSelector).trigger('mousemove').trigger('mouseup')
  },
)

```

Usage: `cy.get('.draggable').dragTo('#dropzone')`

### Dual Commands (Optional Subject)

Dual commands can operate whether or not they receive a previous subject, making them flexible for different chain contexts.

```typescript
Cypress.Commands.add(
  'clickIfExists',
  { prevSubject: 'optional' },
  (subject, selector) => {
    if (subject) {
      cy.wrap(subject).click()
    } else {
      cy.get(selector).click()
    }
  },
)

```

Usage: `cy.get('.maybe').clickIfExists('.fallback')` or `cy.clickIfExists('.standalone')`

## Creating Custom Queries in Cypress

Unlike commands, **queries** in Cypress are designed to return values rather than chainable Cypress instances. You can extend Cypress commands with queries using `Cypress.Commands.addQuery()`, implemented in [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts) (lines 158-173).

```typescript
Cypress.Commands.addQuery('getAll', () => {
  return () => Cypress.$('*')
})

// In a test
const allElements = cy.getAll()
expect(allElements).to.have.length.greaterThan(0)

```

Queries cannot clash with existing commands or reserved names, and they are validated separately from the command registry.

## Overwriting Built-in Cypress Commands

When you need to modify existing behavior rather than create new commands, use `Cypress.Commands.overwrite(name, fn)`. The source code (lines 123-156 in [`commands.ts`](https://github.com/cypress-io/cypress/blob/main/commands.ts)) wraps the original implementation so your new function can invoke it via the `originalFn` parameter.

```typescript
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
  // Prepend a base URL automatically
  const base = Cypress.env('BASE_URL')
  return originalFn(`${base}${url}`, options)
})

```

This approach preserves the original command's signature while allowing you to inject custom logic, such as automatic authentication, logging, or environment-specific URL handling.

## Internal Validation and Error Handling

When you extend Cypress commands, the driver performs strict validation. The `internalError` function (lines 30-39 in [`commands.ts`](https://github.com/cypress-io/cypress/blob/main/commands.ts)) throws detailed Cypress errors using messages defined in [[`error_messages.ts`](https://github.com/cypress-io/cypress/blob/main/error_messages.ts)](https://github.com/cypress-io/cypress/blob/develop/packages/driver/src/cypress/error_messages.ts).

Key validation rules include:

- **Name Conflicts**: You cannot add a custom command with the same name as a built-in command unless you use `overwrite`.
- **Reserved Names**: Attempting to use names reserved for core Cypress APIs triggers an immediate error.
- **Query Separation**: Query names must not conflict with command names or reserved names.

## Summary

- **Extend Cypress commands** using `Cypress.Commands.add(name, options?, fn)` for new functionality or `Cypress.Commands.overwrite(name, fn)` to modify existing commands.
- **Specify command types** via `prevSubject`: use `false` for parent commands, `'element'` for child commands, and `'optional'` for dual commands.
- **Add custom queries** with `Cypress.Commands.addQuery()` when you need to return values rather than chainable Cypress instances.
- **The driver validates** all custom additions against reserved names and built-in commands in [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts), throwing detailed errors from [`error_messages.ts`](https://github.com/cypress-io/cypress/blob/main/error_messages.ts) when conflicts occur.
- **Overwrite existing commands** by calling `originalFn` within your custom implementation to preserve core functionality while adding custom logic.

## Frequently Asked Questions

### What is the difference between Cypress.Commands.add() and Cypress.Commands.addQuery()?

`Cypress.Commands.add()` creates a standard command that returns a chainable Cypress instance, suitable for actions like clicking, typing, or API requests. `Cypress.Commands.addQuery()` creates a query that returns a static value or DOM element directly without the Cypress chain wrapper, making it ideal for reading state or selecting elements that don't need additional command chaining.

### Can I overwrite built-in Cypress commands like cy.visit or cy.get?

Yes, you can overwrite built-in commands using `Cypress.Commands.overwrite(name, fn)`, but you cannot overwrite them using `add()`. The overwrite method provides access to `originalFn`, allowing you to wrap the existing implementation. However, you cannot overwrite reserved names that are part of the core Cypress API surface beyond the standard commands.

### How does Cypress prevent me from accidentally breaking core commands?

The driver maintains `reservedCommandNames` and `builtInCommandNames` sets during initialization in [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts). When you attempt to add a command with a conflicting name, the `internalError` function throws a descriptive error before registration completes, protecting core functionality from accidental overrides.

### Where should I place my custom command definitions in a Cypress project?

Define custom commands in [`cypress/support/commands.ts`](https://github.com/cypress-io/cypress/blob/main/cypress/support/commands.ts) (or `.js`). This file is typically imported in [`cypress/support/e2e.ts`](https://github.com/cypress-io/cypress/blob/main/cypress/support/e2e.ts) (or [`index.js`](https://github.com/cypress-io/cypress/blob/main/index.js) in older projects) to ensure commands are available throughout your test suite. The TypeScript definitions for your custom commands should also be added to [`cypress/support/index.d.ts`](https://github.com/cypress-io/cypress/blob/main/cypress/support/index.d.ts) or included in your [`commands.ts`](https://github.com/cypress-io/cypress/blob/main/commands.ts) file for IDE autocomplete support.