# How Cypress Integrates with CI/CD Pipelines and Provides Exit Codes

> Learn how Cypress detects CI environments and uses deterministic exit codes to signal test outcomes for seamless integration with your CI/CD pipelines.

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

---

**Cypress automatically detects CI environments using environment variable inspection and returns deterministic exit codes—either a generic `1` or the exact count of failed tests when POSIX mode is enabled—to signal test outcomes to surrounding automation.**

Cypress is engineered for seamless CI/CD integration, automatically recognizing popular automation platforms and reporting test results through standardized exit codes. The framework combines the `ci-info` package with custom detection logic in [`ci_provider.ts`](https://github.com/cypress-io/cypress/blob/main/ci_provider.ts) to identify the execution environment, then configures exit behavior based on pass/fail status. This architecture ensures that CI systems receive deterministic signals they can act upon without requiring manual configuration.

## Detecting CI Environments Automatically

Cypress determines whether it is running inside a CI pipeline by checking for provider-specific environment variables. This detection runs once at startup, setting `process.env.CI` and enabling `getIsCi()` to return `true` for any subsequent operations.

### The Provider Detection Logic

The detection mechanism is implemented in [`packages/server/lib/util/ci_provider.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/util/ci_provider.ts). Lines 31-75 define helper functions that identify more than 30 providers, including Azure Pipelines, AWS CodeBuild, Google Cloud Build, Jenkins, CircleCI, GitHub Actions, and Travis CI.

The `CI_PROVIDERS` map (lines 123-157) pairs each provider name with its identifying environment variable or detection function. For example, it checks for `CIRCLECI`, `GITHUB_ACTIONS`, or `TRAVIS` environment variables. The `_detectProviderName()` function (lines 59-75) walks this map and returns the first truthy match, providing Cypress with a canonical provider name used for telemetry and metadata extraction (such as pull-request IDs and build URLs).

```typescript
// Simplified view of the detection logic in ci_provider.ts
const CI_PROVIDERS = {
  'CircleCI': () => process.env.CIRCLECI,
  'GitHub Actions': () => process.env.GITHUB_ACTIONS,
  'Travis CI': () => process.env.TRAVIS,
  // ... 30+ additional providers
}

function _detectProviderName() {
  // Returns the first matching provider name
  return Object.keys(CI_PROVIDERS).find(name => CI_PROVIDERS[name]()) || null
}

```

## Exit Code Behavior and Configuration

When `cypress run` completes, the framework must convey the outcome to the CI system through process exit codes. The behavior follows a strict rule set implemented in [`packages/server/lib/cypress.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/cypress.ts).

### Standard Exit Codes vs. POSIX Mode

By default, Cypress returns the following exit codes:

- **0**: All tests passed
- **1**: One or more tests failed (generic failure)
- **Non-zero (e.g., 130)**: Run was aborted or canceled (SIGINT)

However, when **POSIX exit codes** are enabled via the `--posix` flag or the `posixExitCodes` CLI option (defined in [`cli/lib/cli.ts`](https://github.com/cypress-io/cypress/blob/main/cli/lib/cli.ts)), Cypress returns the **exact number of failed tests** as the exit code instead of the generic `1`. This allows pipelines to distinguish between "1 test failed" and "10 tests failed" without parsing stdout.

The implementation is verified in [`system-tests/test/posix_exit_codes_spec.ts`](https://github.com/cypress-io/cypress/blob/main/system-tests/test/posix_exit_codes_spec.ts), which asserts that the correct numeric code is emitted both when POSIX mode is enabled and when it is disabled.

```bash

# Run with POSIX exit codes to get exact failure count

npx cypress run --posix
echo $?  # Will output the number of failed tests, or 0 if all passed

```

### Handling Canceled Runs and Internal Errors

When a run is manually canceled, Cypress emits a specific non-zero exit code to distinguish it from test failures. In [`packages/server/lib/cypress.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/cypress.ts) (lines 269-276), the runner prints a message and exits with a non-zero status:

```typescript
// packages/server/lib/cypress.ts
if (runWasCanceled) {
  console.log(require('chalk').magenta('\n  Exiting with non-zero exit code because the run was canceled.'))
  // All other exit codes are "number of tests that failed," so collapse
}

```

Internal errors or configuration problems typically return exit code `1`, or a higher code if POSIX mode is enabled and the error maps to a specific count.

## Consuming Exit Codes in CI Pipelines

Most CI platforms treat any non-zero exit code as a failure, automatically marking the step as failed. Because Cypress can report the exact number of failures in POSIX mode, pipelines can implement conditional logic based on the specific exit code value.

A typical GitHub Actions or CircleCI script pattern looks like this:

```bash

# Example for GitHub Actions with POSIX mode

npx cypress run --headless --posix
exit_code=$?

if (( exit_code > 0 )); then
  echo "::error ::Cypress tests failed (exit code $exit_code)"
  exit $exit_code
fi

```

This pattern works identically across Azure Pipelines, GitLab CI, and Travis CI because they all propagate the process exit status. When POSIX mode is disabled, the script simply checks if `exit_code != 0` rather than inspecting the specific value.

## Summary

- **Automatic Detection**: Cypress identifies CI providers via [`packages/server/lib/util/ci_provider.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/util/ci_provider.ts) by scanning for unique environment variables using the `CI_PROVIDERS` map and `_detectProviderName()`.

- **Exit Code Semantics**: Exit code `0` indicates success, while non-zero codes indicate failure, cancellation, or errors.

- **POSIX Mode**: The `--posix` flag (configured in [`cli/lib/cli.ts`](https://github.com/cypress-io/cypress/blob/main/cli/lib/cli.ts)) returns the exact count of failed tests rather than the generic `1`, enabling richer pipeline reporting.

- **Cancellation Handling**: Interrupted runs emit specific codes (e.g., `130` for SIGINT) as implemented in [`packages/server/lib/cypress.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/cypress.ts).

- **Pipeline Integration**: CI systems automatically react to non-zero exit codes, allowing Cypress to control job success or failure without additional parsing logic.

## Frequently Asked Questions

### How does Cypress detect which CI provider is running?

Cypress uses the `ci-info` package combined with a custom detection layer in [`packages/server/lib/util/ci_provider.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/util/ci_provider.ts). The `CI_PROVIDERS` map (lines 123-157) pairs provider names with identifying environment variables such as `CIRCLECI`, `GITHUB_ACTIONS`, and `TRAVIS`. The `_detectProviderName()` function (lines 59-75) iterates through this map and returns the first matching provider, enabling environment-specific metadata extraction.

### What exit code does Cypress return when tests fail?

By default, Cypress returns exit code `1` when any test fails. However, when POSIX mode is enabled via the `--posix` flag or `posixExitCodes` option in [`cli/lib/cli.ts`](https://github.com/cypress-io/cypress/blob/main/cli/lib/cli.ts), it returns the exact number of failed tests as the exit code. This behavior is validated in [`system-tests/test/posix_exit_codes_spec.ts`](https://github.com/cypress-io/cypress/blob/main/system-tests/test/posix_exit_codes_spec.ts).

### How can I make my CI pipeline fail when Cypress tests fail?

Standard CI platforms automatically fail the job when the Cypress process exits with a non-zero code. You can capture the exit code in shell scripts using `exit_code=$?` and implement conditional logic to customize error messages or subsequent pipeline steps based on whether the value is greater than zero.

### Does Cypress handle interrupted test runs differently?

Yes. When a run is canceled (for example, via SIGINT), Cypress exits with a specific non-zero code such as `130`. This distinguishes manual cancellation from test failures, as implemented in [`packages/server/lib/cypress.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/cypress.ts) (lines 269-276), allowing CI systems to differentiate between "failed tests" and "aborted execution."