# Cypress Custom Commands: How to Create, Extend, and Overwrite

> Learn to create Cypress custom commands effortlessly. Extend and overwrite `cy` commands to streamline your test automation and boost reusability.

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

---

**Cypress custom commands are user-defined functions that extend the `cy` namespace, allowing you to encapsulate reusable test logic by registering them via `Cypress.Commands.add()` in your support files.**

Cypress custom commands let you abstract repetitive test operations into reusable functions that behave like native Cypress APIs. By registering commands in [`cypress/support/commands.ts`](https://github.com/cypress-io/cypress/blob/main/cypress/support/commands.ts), you can create domain-specific testing languages that keep your specs clean and maintainable. The command registration engine lives in the core driver at [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts), exposing methods to add, overwrite, and query custom behavior.

## What Are Cypress Custom Commands?

Cypress custom commands are functions that become part of the `cy` object, callable just like built-in methods such as `cy.get()` or `cy.click()`. According to the **Cypress** source code in [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts), the framework maintains a registry of built-in commands, reserved names, and placeholder commands that you can extend or override. When you invoke `Cypress.Commands.add()`, the engine validates the name against protected internal commands (like `log` or `prompt`) and throws informative errors if you attempt to shadow reserved functionality.

## How to Create Cypress Custom Commands

### Adding a Simple Command

The most common way to create a custom command is through `Cypress.Commands.add()`, which accepts a name, optional options, and a callback function.

```typescript
// cypress/support/commands.ts
Cypress.Commands.add('login', (email: string, password: string) => {
  cy.get('#email').type(email)
  cy.get('#password').type(password)
  cy.get('button[type=submit]').click()
})

```

Now any test can call `cy.login('user@example.com', 'secret')`. The registration logic in [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts) (lines 88-95) ensures you cannot accidentally overwrite built-in commands unless they are explicitly whitelisted as placeholders.

### Commands That Accept a Previous Subject

Some commands need to operate on elements yielded by previous commands. Specify the `prevSubject` option to create chainable commands.

```typescript
Cypress.Commands.add(
  'drag',
  { prevSubject: 'element' },
  (subject, { x, y }) => {
    cy.wrap(subject).trigger('mousedown')
    cy.wrap(subject).trigger('mousemove', { clientX: x, clientY: y })
    cy.wrap(subject).trigger('mouseup')
  }
)

```

With `prevSubject: 'element'`, the command only works when chained off a command that yields DOM elements, receiving the subject as the first argument.

## Overwriting Existing Commands

To modify built-in behavior, use `Cypress.Commands.overwrite()`, which provides access to the original function.

```typescript
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
  const fullUrl = `${Cypress.env('BASE_URL')}${url}`
  return originalFn(fullUrl, options)
})

```

The engine validates that the target command exists in `builtInCommandNames` before allowing the overwrite, preventing typos and undefined behaviors.

## Creating Custom Queries

Cypress supports **custom queries** for reusable selectors via `Cypress.Commands.addQuery()`.

```typescript
Cypress.Commands.addQuery('getByTestId', (testId: string) => {
  return () => cy.get(`[data-test-id="${testId}"]`)
})

```

This registers `cy.getByTestId()` as a first-class query command that integrates with Cypress's internal retry logic.

## Placeholder Commands and Component Testing

The framework reserves specific command names as placeholders. In [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts) (line 9), the `PLACEHOLDER_COMMANDS` array includes `['mount', 'hover']`, allowing component testing adapters like `@cypress/react` to implement `cy.mount` without colliding with core commands.

## Practical Examples

### Login Command

```typescript
// cypress/support/commands.ts
Cypress.Commands.add('login', (username, password) => {
  cy.get('#username').type(username)
  cy.get('#password').type(password)
  cy.get('button[type=submit]').click()
})

// In your spec
it('authenticates user', () => {
  cy.login('alice', 'pwd123')
  cy.contains('Welcome Alice')
})

```

### Drag and Drop with Previous Subject

```typescript
Cypress.Commands.add(
  'dragTo',
  { prevSubject: 'element' },
  (subject, targetSelector) => {
    const dataTransfer = new DataTransfer()
    cy.wrap(subject).trigger('dragstart', { dataTransfer })
    cy.get(targetSelector).trigger('drop', { dataTransfer })
    cy.wrap(subject).trigger('dragend')
  }
)

// Usage
cy.get('#source-item').dragTo('#target-container')

```

### Overwriting Visit with Base URL

```typescript
Cypress.Commands.overwrite('visit', (original, url, opts) => {
  const base = Cypress.env('BASE_URL') || ''
  return original(`${base}${url}`, opts)
})

```

## Summary

- **Cypress custom commands** extend the `cy` namespace through `Cypress.Commands.add()`, defined in [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts).
- Use the `prevSubject` option to create commands that operate on elements yielded by previous commands.
- **Overwrite** built-in commands using `Cypress.Commands.overwrite()` to modify default behavior while preserving access to the original function.
- **Custom queries** registered with `Cypress.Commands.addQuery()` provide reusable selector logic that participates in Cypress's automatic retry mechanism.
- Reserved names and built-in commands are protected by validation logic that throws descriptive errors when collision attempts occur.

## Frequently Asked Questions

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

No. The registration engine in [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts) maintains a `builtInCommandNames` list that prevents overwriting core commands. Only commands listed in `PLACEHOLDER_COMMANDS` (such as `mount` and `hover`) can be implemented or overwritten by user code or plugins.

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

`Cypress.Commands.add()` creates standard commands that perform actions or assertions, while `Cypress.Commands.addQuery()` creates custom queries designed to return elements for chaining. Queries retry automatically according to Cypress's default timeout settings, making them ideal for complex selector logic.

### Where should I define custom commands in my project?

Define custom commands in [`cypress/support/commands.ts`](https://github.com/cypress-io/cypress/blob/main/cypress/support/commands.ts) (or `.js`), which Cypress automatically imports before test files execute. For TypeScript projects, type definitions in [`cypress/support/index.d.ts`](https://github.com/cypress-io/cypress/blob/main/cypress/support/index.d.ts) ensure your IDE recognizes custom commands on the `cy` object.

### Why do I get an error when trying to create a command named `log` or `prompt`?

These are **reserved command names** protected by internal validation logic at lines 88-95 of [`packages/driver/src/cypress/commands.ts`](https://github.com/cypress-io/cypress/blob/main/packages/driver/src/cypress/commands.ts). The framework reserves these names for internal use and throws an `internalError` if you attempt to register them, preventing conflicts with Cypress's logging and prompt systems.