---
title: "Configuration reference"
description: "Reference for .circleci/config.yml"
doc_version: "unversioned"
last_updated: "2026-09-02"
---

> For the complete documentation index, see [llms.txt](https://circleci.com/docs/llms.txt)

# Configuration reference

This document is a reference for the CircleCI 2.x configuration keys that are used in the `.circleci/config.yml` file.

You can see a complete `config.yml` in our [full example](#example-full-configuration).

* * *

## **`version`**

The `version` field is intended to be used in order to issue warnings for deprecation or breaking changes.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `version` | Y | String | `2`, `2.0`, or `2.1`. See the [Reusable Configuration](https://circleci.com/docs/reference/reusing-config/) page for an overview of 2.1 keys available to simplify your `.circleci/config.yml` file, reuse, and parameterized jobs. |

**Example:**

Version

```yaml
version: 2.1
```

* * *

## **`setup`**

The `setup` field enables you to conditionally trigger configurations from outside the primary `.circleci` parent directory, update pipeline parameters, or generate customized configurations.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `setup` | N | Boolean | Designates the `config.yaml` for use of CircleCI’s [Dynamic Configuration](https://circleci.com/docs/guides/orchestrate/dynamic-config/) feature. |

**Example:**

```yaml
version: 2.1

setup: true
```

* * *

## **`orbs`**

The `orbs` key is supported in `version: 2.1` configuration

Use the `orbs` key to reference or define reusable configuration blocks (orbs) for use in your configuration.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `orbs` | N | Map | A map of user-selected names to either: orb references (strings) or orb definitions (maps). Orb definitions must be the orb-relevant subset of 2.1 config. See the [Creating Orbs](https://circleci.com/docs/orbs/author/create-test-and-publish-a-registry-orb/) documentation for details. |
| `executors` | N | Map | A map of strings to executor definitions. See the [**`executors`**](#executors) section below. |
| `commands` | N | Map | A map of command names to command definitions. See the [**`commands`**](#commands) section below. |

The following example uses the `node` orb that exists in the certified `circleci` namespace. Refer to the Node orb page in the [Orb Registry](https://circleci.com/developer/orbs/orb/circleci/node) for more examples and information.

**Example:**

```yaml
version: 2.1

orbs:
  node: circleci/node@x.y

jobs:
  install-node-example:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - node/install:
          install-yarn: true
          node-version: '16.13'
      - run: node --version
workflows:
  test_my_app:
    jobs:
      - install-node-example
```

Documentation is available for orbs in the following sections:

*   [Using Orbs](https://circleci.com/docs/orbs/use/orb-intro/).
    
*   [Authoring Orbs](https://circleci.com/docs/orbs/author/orb-author/).
    

Public orbs are listed in the [Orb Registry](https://circleci.com/developer/orbs).

* * *

## **`commands`**

The `commands` key is supported in `version: 2.1` configuration

A `command` defines a sequence of steps as a map to be executed in a job, enabling you to reuse a single command definition across multiple jobs. For more information see the [Reusable Config Reference Guide](https://circleci.com/docs/reference/reusing-config/).

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `steps` | Y | Sequence | A sequence of steps run inside the calling job of the command. |
| `parameters` | N | Map | A map of parameter keys. See the [Parameter Syntax](https://circleci.com/docs/reference/reusing-config/#parameter-syntax) section of the [Reusing Config](https://circleci.com/docs/reference/reusing-config/) document for details. |
| `description` | N | String | A string that describes the purpose of the command. |

**Example:**

```yaml
version: 2.1

commands:
  sayhello:
    description: "A very simple command for demonstration purposes"
    parameters:
      to:
        type: string
        default: "Hello World"
    steps:
      - run: echo << parameters.to >>
```

* * *

## **`parameters`**

The pipeline `parameters` key is supported in `version: 2.1` configuration

Use the `parameters` key at the top level of your config to declare _pipeline parameters_ for use in the configuration. See [Pipeline Values and Parameters](https://circleci.com/docs/guides/orchestrate/pipeline-variables/#pipeline-parameters-in-configuration) for usage details.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `parameters` | N | Map | A map of parameter keys. Supports `string`, `boolean`, `integer` and `enum` types. See [Parameter Syntax](https://circleci.com/docs/reference/reusing-config/#parameter-syntax) for details. |

**Example:**

This example declares a pipeline parameter named `image-tag` with a type of `string` and a default value of `current`.

```yaml
version: 2.1

parameters:
  image-tag:
    type: string
    default: "current"
```

Once you have declared a pipeline parameter, you can pass a pipeline parameter value when triggering a pipeline via the API or from the CircleCI web app.

## **`executors`**

The `executors` key is supported in `version: 2.1` configuration

Executors define the execution environment where job steps run, letting you reuse a single executor definition across multiple jobs.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `docker` | Y (1) | List | Options for [Docker executor](#docker) |
| `resource_class` | N | String | Amount of CPU and RAM allocated to each container in a job. |
| `machine` | Y (1) | Map | Options for [machine executor](#machine) |
| `macos` | Y (1) | Map | Options for [macOS executor](#macos) |
| `windows` | Y (1) | Map | [Windows executor](#windows-execution-environment) currently working with orbs. Check out [the orb](https://circleci.com/developer/orbs/orb/circleci/windows). |
| `shell` | N | String | Shell to use for execution command in all steps. Can be overridden by `shell` in each step (default: See [Default Shell Options](#default-shell-options)) |
| `working_directory` | N | String | The directory where steps run. CircleCI interprets this as an absolute path. |
| `environment` | N | Map | A map of environment variable names and values. |

(1) Specify one executor type per job. If you set more than one, CircleCI returns an error.

**Example:**

```yaml
version: 2.1
executors:
  my-executor:
    docker:
      - image: cimg/ruby:3.0.3-browsers

jobs:
  my-job:
    executor: my-executor
    steps:
      - run: echo "Hello executor!"
```

See the [Using Parameters in Executors](https://circleci.com/docs/reference/reusing-config/#using-parameters-in-executors) section of the [Reusing Config](https://circleci.com/docs/reference/reusing-config/) page for examples of parameterized executors.

* * *

## **`jobs`**

A Workflow is comprised of one or more uniquely named jobs. Jobs are specified in the `jobs` map, see [Sample Config.yml](https://circleci.com/docs/guides/toolkit/sample-config/) for two examples of a `job` map. The name of the job is the key in the map, and the value is a map describing the job.

Jobs have a maximum runtime based on pricing plan, as follows:

*   1 hour (Free).
    
*   3 hours (Performance).
    
*   5 hours (Scale).
    

If your jobs are timing out, consider the following:

*   A larger [**`resource_class`**](#resourceclass).
    
*   Using [Parallelism](https://circleci.com/docs/guides/optimize/parallelism-faster-jobs/).
    
*   Run some of your jobs concurrently using [Workflows](https://circleci.com/docs/guides/orchestrate/workflows/).
    
*   You can upgrade your pricing plan.
    

**Example:**

```yaml
version: 2.1

jobs:
  my-job:
    docker:
      - image: cimg/base:2024.12
    resource_class: xlarge
    steps:
      ... // other config
```

* * *

### **<`job_name`\>**

Each job consists of the job’s name as a key and a map as a value. A name must be unique and case-insensitive within the `jobs` list. The value map has the following attributes:

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `type` | N | String | Job type, can be `build`, `release`, `no-op`, or `approval`. If not specified, defaults to `build`. |
| `docker` | Y (1) | List | Options for the [Docker executor](#docker) |
| `machine` | Y (1) | Map | Options for the [machine executor](#machine) |
| `macos` | Y (1) | Map | Options for the [macOS executor](#macos) |
| `executor` | Y (1) | String | Name of a declared [reusable executor](#executors) |
| `shell` | N | String | Shell to use for execution command in all steps. Can be overridden by `shell` in each step (default: See [Default Shell Options](#default-shell-options)) |
| `parameters` | N | Map | [Parameters](#parameters-job) for making a `job` explicitly configurable in a `workflow`. |
| `steps` | Y | List | A list of [steps](#steps) to be performed |
| `working_directory` | N | String | The directory where steps run. CircleCI interprets this as an absolute path. Default: `~/project` (where `project` is a literal string, not your specific project name). Processes running during the job can use the `$CIRCLE_WORKING_DIRECTORY` environment variable to refer to this directory. **Note:** CircleCI does not expand paths in your YAML configuration file; if your `store_test_results.path` is `$CIRCLE_WORKING_DIRECTORY/tests`, CircleCI attempts to store the `test` subdirectory of the directory literally named `$CIRCLE_WORKING_DIRECTORY`, including the dollar sign `$`. CircleCI creates `working_directory` automatically if it doesn’t exist. |
| `parallelism` | N | Integer | Number of parallel instances of this job to run (default: 1) |
| `environment` | N | Map | A map of environment variable names and values. |
| `branches` | N | Map | This key is deprecated. Use [workflows filtering](#jobfilters) to control which jobs run for which branches. |
| `resource_class` | N | String | Amount of CPU and RAM allocated to each container in a job. |
| `retention` | N | Map | Configure job retention periods for cache data (1-15 days, for example, "1d", "7d", "15d"). This reduces retention from the organization-level default, automatically removing cache data after the specified period. |

(1) Specify one executor type per job. If you set more than one, CircleCI returns an error.

**Example:**

In this example the job name is `my-job`.

```yaml
version: 2.1

jobs:
  my-job:
```

* * *

#### `type`

Configure a job type. Options are `release`, `approval`, `no-op`, `build` (default).

If a type is not specified, the job defaults to a `build` type.

**Example** of a job with a `build` type. `build` is the default type and does not need to be configured:

```yaml
jobs:
  my-job:
    docker:
      - image: cimg/base:2024.12
    resource_class: xlarge
    steps:
      ... // other config
```

Jobs with the `release` type are used to [Connect Your Pipeline Configuration](https://circleci.com/docs/guides/deploy/configure-your-kubernetes-components/#link-release) to a deployment in the CircleCI deploys UI. A release job names the release plan created by a `circleci run release plan` step, using the `plan_name` key. For full details, see the [Deploys Overview](https://circleci.com/docs/guides/deploy/deployment-overview/) page.

**Example** of a job with a `release` type:

```yaml
jobs:
  release-my-service:
    type: release
    plan_name: <my-service-release>
```

##### `validation`

Add a `validation` key to a release job to turn on the release validation engine. The engine gates the release on signals from your monitoring tool, and triggers your rollback pipeline when a release fails. For an overview of the feature, see the [Smart Deployments Overview](https://circleci.com/docs/guides/deploy/smart-deployments-overview/) page.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `enabled` | Y | Boolean | Turns on release validation for this release job. |
| `evaluation_time` | N | String | How long the engine waits for validation signals before treating the release as successful, for example `30m`. Defaults to `20m`. |
| `auto_rollback_on_failure` | N | Boolean | When `true`, the engine triggers your rollback pipeline if validation fails during the evaluation window. |
| `webhooks` | N | List | Webhook validation checks, where each entry defines one named signal from a monitoring provider. When omitted, CircleCI uses a catch-all check that accepts any signal. |

Each entry under `webhooks` takes the following keys:

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `name` | Y | String | Identifier for this check. Your monitoring tool must send a matching `signal_name` so CircleCI can route alerts to it. |
| `provider` | Y | String | One of `datadog`, `prometheus`, `grafana`, `alertmanager`, or `custom`. |
| `data_points` | N | Map | Maps fields in the incoming webhook payload to the values CircleCI matches on. Provider defaults apply to any key you omit. |
| `fail_when` | N | String | Expression that decides when a webhook event counts as a failure. Provider defaults apply when you omit it. |
| `max_failures` | N | Integer | Number of matching failures before this check fails. |

**Example** of a release job with release validation enabled:

```yaml
jobs:
  release-my-service:
    type: release
    plan_name: <my-service-release>
    validation:
      enabled: true
      evaluation_time: 30m
      auto_rollback_on_failure: true
      webhooks:
        - name: error_rate
          provider: datadog
          fail_when: 'criteria == "triggered" or criteria == "re-triggered"'
          max_failures: 2
```

For the `data_points` keys, the provider defaults, and how the engine matches an incoming signal to a check, see the [Release Validation Configuration Reference](https://circleci.com/docs/guides/deploy/release-validation-reference/) page.

The `no-op` type is used to configure a job that performs no actions and consumes no credits. `no-op` is commonly used to organize the order of operations within a workflow and make it easier to maintain. Only the `type` is required for a `no-op` type job, no further job configuration is required. For some examples of using `no-op` jobs, see the [Orchestration Cookbook](https://circleci.com/docs/guides/orchestrate/orchestration-cookbook/#use-no-op-jobs-to-create-a-cleaner-workflow-graph).

**Example** of a job with a `no-op` type:

```yaml
jobs:
  my-no-op-job:
    type: no-op
```

The `approval` type is used to configure a manual approval step. No `job` configuration is required or allowed for an `approval` type job. The `approval` type is most commonly configured within a workflow rather than under the top-level `jobs` key. Only `approval` type jobs can have their `type` configured under `workflows`. See [type under workflows section](#type) for full details.

**Example** of a job with an `approval` type, configured under `workflows`:

```yaml
workflows:
  my-workflow:
    jobs:
      - build
      - test:
          requires:
            - build
      - hold:
          type: approval
          requires:
            - test
      - deploy:
          requires:
            - hold
```

* * *

#### `environment`

A map of environment variable names and values. For more information on defining and using environment variables, and the order of precedence governing the various ways they can be set, see the [Environment Variables](https://circleci.com/docs/guides/security/env-vars/) page.

**Example** to show setting an environment variable named `FOO` with a value of `bar` for use in a job.

```yaml
version: 2.1

jobs:
  build:
    docker:
      - image: cimg/base:2022.04-20.04
    environment:
      FOO: bar
```

* * *

#### `retention`

Configure job retention periods to control how long job data is kept. Job retention specifically controls cache retention at the job level. This setting can be configured from 1 day to 15 days using string values (for example, "1d", "7d", "15d"). Job retention reduces the organization-level retention from the default by automatically removing cache data after the specified period.

**Example:**

```yaml
version: 2.1

jobs:
  test:
    docker:
      - image: cimg/node:18.0
    retention:
      caches: 7d
    steps:
      - checkout
      - run: npm install
      - run: npm test
```

For more information on cache retention, see the [Persisting Data Overview](https://circleci.com/docs/guides/optimize/persist-data/#custom-storage-usage) page.

#### Common errors

When configuring job retention, you may encounter the following validation errors:

*   **Invalid time format**: The retention period must use the format `^([1-9]|[12][0-9]|30)d$` (1-30 days with "d" suffix). For example, use `"7d"` instead of `"12h"` or `"1w"`.
    
*   **Incorrect data type**: The `retention` key expects a map with `caches` as a string value, not a direct string.
    

**Examples:**

Incorrect - direct string value

```yaml
# Incorrect - direct string value
jobs:
  say-hello:
    retention: "12h"  # Error: expected type: String, found: Mapping
```

Incorrect - invalid time format

```yaml
#Incorrect - invalid time format
jobs:
  say-hello:
    retention:
      caches: "12h"  # Error: does not match pattern ^([1-9]|[12][0-9]|30)d$
```

Correct format

```yaml
# Correct format
jobs:
  say-hello:
    retention:
      caches: "7d"   # Valid: 7 days
```

* * *

#### `parallelism`

Use this feature to optimize test steps. If you set `parallelism` to N > 1, CircleCI sets up N independent executors, and each runs the job’s steps in parallel.

You can use the CircleCI CLI to split your test suite across parallel containers so the job completes in a shorter time.

*   Read more about splitting tests across parallel execution environments on the [Parallelism and Test Splitting](https://circleci.com/docs/guides/optimize/parallelism-faster-jobs/) page.
    
*   Refer to the [Use the CircleCI CLI to Split Tests](https://circleci.com/docs/guides/optimize/use-the-circleci-cli-to-split-tests/) how-to guide.
    

<Tabs>
<Tab title="Use an integer">

```yaml
jobs:
  build:
    docker:
      - image: cimg/base:2024.12
    environment:
      FOO: bar
    parallelism: 3
    resource_class: large
    working_directory: ~/my-app
    steps:
      - run: go list ./... | circleci tests run --command "xargs gotestsum --junitfile junit.xml --format testname --" --split-by=timings --timings-type=name
```

</Tab>
<Tab title="Use an expression">

```yaml
jobs:
  build:
    docker:
      - image: cimg/base:2024.12
    environment:
      FOO: bar
    parallelism: << pipeline.git.branch == "main" and 10 or 1 >>
    resource_class: large
    working_directory: ~/my-app
    steps:
      - run: go list ./... | circleci tests run --command "xargs gotestsum --junitfile junit.xml --format testname --" --split-by=timings --timings-type=name
```

</Tab>
</Tabs>

* * *

#### `parameters`

Job-level `parameters` can be used when [calling a `job` in a `workflow`](#jobs-in-workflow).

Reserved parameter-names:

*   `name`
    
*   `requires`
    
*   `context`
    
*   `type`
    
*   `filters`
    
*   `matrix`
    

See [Parameter Syntax](https://circleci.com/docs/reference/reusing-config/#parameter-syntax) for definition details.

**Example** to show using a job parameter to set the parallelism for a job when a workflow is run.

```yaml
version: 2.1

jobs:
  build:
    parameters:
      my-parameter:
        type: integer
        default: 1
    parallelism: << parameters.my-parameter >>
    docker:
      - image: cimg/base:2023.11
    steps:
      - checkout

workflows:
  workflow:
    jobs:
      - build:
          my-parameter: 2
```

* * *

## Executor **`docker`** / **`machine`** / **`macos`**

CircleCI offers several execution environments in which to run your jobs. To specify an execution environment choose an _executor_, then specify an image and a resource class. An executor defines the underlying technology, environment, and operating system in which to run a job.

Set up your jobs to run using the `docker` (Linux), `machine` (LinuxVM, Windows, GPU, Arm), or `macos` executor. Then specify an image with the tools and packages you need, and a resource class.

Learn more about execution environments and executors in the [Introduction to Execution Environments](https://circleci.com/docs/guides/execution-managed/executor-intro/).

* * *

### `docker`

Configure a job to use the Docker execution environment using the `docker` key which takes a list of maps:

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `image` | Y | String | The name of a custom Docker image to use. The first `image` listed under a job defines the job’s own primary container image where all steps will run. |
| `name` | N | String | `name` defines the hostname for the container (the default is `localhost`), which is used for reaching secondary (service) containers. By default, all services are exposed directly on `localhost`. This field is useful if you would rather have a different hostname instead of `localhost`, for example, if you are starting multiple versions of the same service. |
| `entrypoint` | N | String or List | The command used as executable when launching the container. `entrypoint` overrides the image’s [`ENTRYPOINT`](https://docs.docker.com/engine/reference/builder/#entrypoint). |
| `command` | N | String or List | The command to use as PID 1 (or as arguments for entrypoint) when launching the container. `command` overrides the image’s `COMMAND`. If the image has an `ENTRYPOINT`, Docker uses `command` as arguments to it. If the image has no `ENTRYPOINT`, Docker uses `command` as the executable. |
| `user` | N | String | Which user to run commands as within the Docker container |
| `environment` | N | Map | A map of environment variable names and values. The `environment` settings apply to the entrypoint/command run by the Docker container, not the job steps. |
| `auth` | N | Map | Authentication for registries using standard `docker login` credentials |
| `aws_auth` | N | Map | Authentication for AWS Elastic Container Registry (ECR) |
| `gcp_auth` | N | Map | Authentication for GCP Artifact Registry using OIDC |

For a [Primary Container](https://circleci.com/docs/reference/glossary/#primary-container), (the first container in the list) if neither `command` nor `entrypoint` is specified in the configuration, then any `ENTRYPOINT` and `COMMAND` in the image are ignored. The primary container is typically only used for running the `steps` and not for its `ENTRYPOINT`, and an `ENTRYPOINT` may consume significant resources or exit prematurely.

A [Custom Image](https://circleci.com/docs/guides/execution-managed/custom-images/#adding-an-entrypoint) may disable this behavior and force the `ENTRYPOINT` to run.

You can specify image versions using tags or digest. You can use any public images from any public Docker registry (defaults to Docker Hub). Learn more about specifying images on the [Using the Docker Execution Environment](https://circleci.com/docs/guides/execution-managed/using-docker/) page.

**Example:**

```yaml
version: 2.1

jobs:
  hello-job:
    docker:
      - image: cimg/node:17.2.0 # the primary container, where your job's commands are run
    steps:
      - checkout # check out the code in the project directory
      - run: echo "hello world" # run the `echo` command

workflows:
  my-workflow:
    jobs:
      - hello-job
```

* * *

#### Docker registry authentication

Some registries, Docker Hub, for example, may rate limit anonymous Docker pulls. We recommend that you authenticate to pull private and public images. The username and password can be specified in the `auth` field. See [Using Docker Authenticated Pulls](https://circleci.com/docs/guides/execution-managed/private-images/) for details.

**Example:**

```yaml
jobs:
  build:
    docker:
      - image: buildpack-deps:trusty # primary container
        auth:
          username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD  # context / project UI env-var reference
        environment:
          ENV: CI

      - image: mongo:2.6.8
        auth:
          username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD  # context / project UI env-var reference
        command: [--smallfiles]

      - image: postgres:14.2
        auth:
          username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD  # context / project UI env-var reference
        environment:
          POSTGRES_USER: user

      - image: redis@sha256:54057dd7e125ca41afe526a877e8bd35ec2cdd33b9217e022ed37bdcf7d09673
        auth:
          username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD  # context / project UI env-var reference

      - image: acme-private/private-image:321
        auth:
          username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD  # context / project UI env-var reference
```

* * *

#### AWS authentication

Using an image hosted on [AWS ECR](https://aws.amazon.com/ecr/) requires authentication using AWS credentials. The two configuration options are described in the following sections.

#### Use OIDC

Authenticate using OpenID Connect (OIDC) using the `oidc_role_arn` field, as follows:

**Example:**

```yaml
jobs:
  job_name:
    docker:
      - image: <your-image-arn>
        aws_auth:
          oidc_role_arn: <your-iam-role-arn>
```

For steps to get set up with OIDC to pull images from AWS ECR, see the [Pull an Image From AWS ECR With OIDC](https://circleci.com/docs/guides/permissions-authentication/pull-an-image-from-aws-ecr-with-oidc/) page.

#### Use environment variables

By default, CircleCI uses the AWS credentials you provide by setting the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` project environment variables. It is also possible to set the credentials by using the `aws_auth` field as in the following example:

**Example:**

```yaml
jobs:
  build:
    docker:
      - image: account-id.dkr.ecr.us-east-1.amazonaws.com/org/repo:0.1
        aws_auth:
          aws_access_key_id: AKIAQWERVA  # can specify string literal values
          aws_secret_access_key: $ECR_AWS_SECRET_ACCESS_KEY  # or project UI envar reference
```

* * *

#### GCP authentication

Using an image hosted on [GCP Artifact Registry](https://cloud.google.com/artifact-registry) requires authentication using GCP credentials, either via OIDC, or by setting environment variables. The two configuration options are described in the following sections:

#### Use OIDC

Authenticate using OpenID Connect (OIDC) using the `gcp_auth` field, as follows:

**Example:**

```yaml
jobs:
  job_name:
    docker:
      - image: <region>-docker.pkg.dev/<project>/<repository>/<image>:<tag>
        gcp_auth:
          oidc_service_account: <service-account-email>
          workload_identity_pool: projects/<project-number>/locations/global/workloadIdentityPools/<pool-id>
          workload_identity_provider: <provider-id>
```

For steps to get set up with OIDC to pull images from GCP Artifact Registry, see the [Pull an Image From GCP Artifact Registry With OIDC](https://circleci.com/docs/guides/permissions-authentication/pull-an-image-from-gcp-gar-with-oidc/) page.

#### Use environment variables

By default, CircleCI uses the GCP credentials you provide by setting the `GCP_OIDC_SERVICE_ACCOUNT`, `GCP_WORKLOAD_IDENTITY_POOL`, and `GCP_WORKLOAD_IDENTITY_PROVIDER` project environment variables or context environment variables. When these are set and the image is hosted on GCP Artifact Registry, CircleCI automatically authenticates without requiring a `gcp_auth` field in your configuration:

**Example:**

```yaml
jobs:
  build:
    docker:
      - image: us-docker.pkg.dev/my-project/my-repo/my-image:latest
```

* * *

### **`machine`**

**Using CircleCI Cloud?** The use of `machine: true` is deprecated. You must specify an image to use.

The machine executor is configured using the `machine` key, which takes a map:

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `image` | Y | String | The virtual machine image to use. View [available images](https://circleci.com/developer/images?imageType=machine). **Note:** This key is **not** supported for Linux VMs on installations of CircleCI Server. For information about customizing `machine` executor images on CircleCI installed on your servers, see our [Machine Provisioner Documentation](https://circleci.com/docs/server-admin/latest/operator/manage-virtual-machines-with-machine-provisioner/). |
| `docker_layer_caching` | N | Boolean | Set this to `true` to enable [Docker Layer Caching](https://circleci.com/docs/guides/optimize/docker-layer-caching/). |

**Example:**

<Tabs>
<Tab title="Cloud">

```yml
jobs:
  build: # name of your job
    machine: # executor type
      image: ubuntu-2604:current # recommended linux image

    steps:
      # Commands run in a Linux virtual machine environment
```

</Tab>
<Tab title="Server">

```yml
jobs:
  build: # name of your job
    machine: true # executor type
    steps:
      # Commands run in a Linux virtual machine environment
```

</Tab>
</Tabs>

* * *

#### Linux `machine` images

**Specifying an image in your configuration file is strongly recommended.** CircleCI supports multiple Linux machine images that can be specified in the `image` field. For a full list of supported image tags, refer to the following pages in the Developer Hub:

*   [Ubuntu-2204](https://circleci.com/developer/machine/image/ubuntu-2204)
    
*   [Ubuntu-2404](https://circleci.com/developer/machine/image/ubuntu-2404)
    
*   [Ubuntu-2604](https://circleci.com/developer/machine/image/ubuntu-2604)
    

More information on the software available in each image can be found in our [Discuss forum](https://discuss.circleci.com/tag/machine-images).

The machine executor supports [Docker Layer Caching](https://circleci.com/docs/guides/optimize/docker-layer-caching/), which is useful when you are building Docker images during your job or Workflow.

* * *

#### Linux `machine` images on server

If you are using CircleCI Server, contact your system administrator for details of available Linux machine images.

* * *

#### Linux GPU `machine` images

When using the Linux [GPU Executor](https://circleci.com/docs/guides/execution-managed/using-gpu/), the available images are:

*   `linux-cuda-11:default` v11.4, v11.6, v11.8 (default), Docker v20.10.24.
    
*   `linux-cuda-12:default` v12.0, v12.1 (default), Docker v20.10.24.
    

* * *

#### Android `machine` images

CircleCI supports running jobs on Android for testing and deploying Android applications.

To use the [Android image](https://circleci.com/developer/machine/image/android) directly with the machine executor, add the following to your job:

```yaml
version: 2.1

jobs:
  build:
    machine:
      image: android:default
```

The Android image can also be accessed using the [Android orb](https://circleci.com/developer/orbs/orb/circleci/android).

Gen2 resource classes (for example, `large.gen2`) are also available for the Android machine image on CircleCI Cloud. See the [Android Machine Image Generations](https://circleci.com/docs/guides/execution-managed/android-machine-image/#android-generations) section for details.

For examples, refer to the [Using Android Images With the Machine Executor](https://circleci.com/docs/guides/execution-managed/android-machine-image/) page.

* * *

#### Windows `machine` images

**Specifying an image in your configuration file is strongly recommended.** CircleCI supports multiple Windows machine images that can be specified in the `image` field.

For a full list of supported images, refer to one of the following:

*   [`windows-server-2022-gui` image](https://circleci.com/developer/machine/image/windows-server-2022-gui)
    
*   [`windows-server-2019` image](https://circleci.com/developer/machine/image/windows-server-2019)
    

More information on what software is available in each image can be found in our [Discuss forum](https://discuss.circleci.com/c/ecosystem/circleci-images/).

Alternatively, use the [Windows orb](https://circleci.com/developer/orbs/orb/circleci/windows) to manage your Windows execution environment. For examples, see the [Using the Windows Execution Environment](https://circleci.com/docs/guides/execution-managed/using-windows/) page.

* * *

#### Windows `machine` images on server

If you are using CircleCI Server, contact your system administrator for details of available Windows machine images.

* * *

#### Windows GPU `machine` image

When using the Windows [GPU Executor](https://circleci.com/docs/guides/execution-managed/using-gpu/), the available image is:

*   [`windows-server-2019-cuda`](https://circleci.com/developer/machine/image/windows-server-2019-cuda)
    

**Example:**

```yaml
version: 2.1

jobs:
  build:
    machine:
      image: windows-server-2019-cuda:current
```

* * *

### **`macos`**

CircleCI supports running jobs on [macOS](https://developer.apple.com/macos/), to allow you to build, test, and deploy apps for macOS, [iOS](https://developer.apple.com/ios/), [tvOS](https://developer.apple.com/tvos/) and [watchOS](https://developer.apple.com/watchos/). To run a job on a macOS virtual machine, add the `macos` key to the top-level configuration for your job and specify the version of Xcode to use.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `xcode` | Y | String | The version of Xcode that is installed on the virtual machine, see the [Supported Xcode Versions Section of the Testing iOS](https://circleci.com/docs/guides/execution-managed/using-macos/#supported-xcode-versions) document for the complete list. |
| `code_signing` | N | List | A list of signing bundle names to install onto the macOS virtual machine with the `install_signing_bundle` step. See [Set up Code Signing for iOS and macOS Projects](https://circleci.com/docs/guides/execution-managed/ios-codesigning/). |

**Example:** Use a macOS virtual machine with Xcode version 26.6.0:

```yaml
jobs:
  build:
    macos:
      xcode: 26.6.0
```

* * *

#### **`branches` - DEPRECATED**

This key is deprecated. Use [workflows filtering](#jobfilters) to control which jobs run for which branches.

* * *

## **`resource_class`**

The `resource_class` feature allows you to configure CPU and RAM resources for each job. Resource classes are available for each execution environment, as described in the tables below. A resource class is also used as a label to identify a pool of self-hosted runners and to route a job to that pool. For full details on both uses, see the [Resource Class Overview](https://circleci.com/docs/guides/execution-managed/resource-class-overview/) page.

We implement soft concurrency limits for each resource class to ensure our system remains stable for all customers. If you are on a Performance or Custom Plan and experience queuing for certain resource classes, it is possible you are hitting these limits. [Contact CircleCI support](https://support.circleci.com/hc/en-us/requests/new) to request a raise on these limits for your account.

If you do not specify a resource class, CircleCI uses a default value that can change. Specify a resource class instead of relying on a default.

Java, Erlang, and any other languages that introspect the `/proc` directory for CPU count information may require additional configuration. Without it, they can slow down when using the CircleCI resource class feature. Programs with this issue may request 32 CPU cores and run slower than they would when requesting one core. Users of languages with this issue must pin their CPU count to their guaranteed CPU resources.

If you want to confirm how much memory you have been allocated, you can check the cgroup memory hierarchy limit with `grep hierarchical_memory_limit /sys/fs/cgroup/memory/memory.stat`.

* * *

### Self-hosted runner

Use the `resource_class` key to configure a [Self-hosted Runner Instance](https://circleci.com/docs/guides/execution-runner/runner-overview/).

For example:

```yaml
jobs:
  job_name:
    machine: true
    resource_class: <my-namespace>/<my-runner>
```

* * *

### Docker execution environment

Set a resource class for a Docker job

```yaml
jobs:
  build:
    docker:
      - image: cimg/base:2024.12
    resource_class: xlarge
    steps:
      ... // other config
```

Set a resource class for a Docker job using an expression

```yaml
jobs:
  build:
    docker:
      - image: cimg/base:2024.12
    resource_class: << pipeline.git.branch == "main" and "xlarge" or "medium" >>
    steps:
      ... // other config
```

#### x86

For credit and access information, see the [Resource classes page](https://circleci.com/product/features/resource-classes/). Resource class access is dependent on your [Plan](https://circleci.com/docs/guides/plans-pricing/plan-overview/).

| Class | vCPUs | RAM | Cloud | Server |
| --- | --- | --- | --- | --- |
| `small` | 1 | 2GB | **Yes** | **Yes** |
| `medium` | 2 | 4GB | **Yes** | **Yes** |
| `medium+` | 3 | 6GB | **Yes** | **Yes** |
| `large` | 4 | 8GB | **Yes** | **Yes** |
| `xlarge` | 8 | 16GB | **Yes** | **Yes** |
| `2xlarge` | 16 | 32GB | **Yes** | **Yes** |
| `2xlarge+` | 20 | 40GB | **Yes** | **Yes** |

#### x86 (gen2)

For credit and access information, see the [Resource classes page](https://circleci.com/product/features/resource-classes/). Resource class access is dependent on your [Plan](https://circleci.com/docs/guides/plans-pricing/plan-overview/).

| Class | vCPUs | RAM | Cloud | Server |
| --- | --- | --- | --- | --- |
| `small.gen2` | 1 | 2GB | **Yes** | **No** |
| `medium.gen2` | 2 | 4GB | **Yes** | **No** |
| `medium+.gen2` | 3 | 6GB | **Yes** | **No** |
| `large.gen2` | 4 | 8GB | **Yes** | **No** |
| `xlarge.gen2` | 8 | 16GB | **Yes** | **No** |
| `2xlarge.gen2` | 16 | 32GB | **Yes** | **No** |
| `2xlarge+.gen2` | 20 | 40GB | **Yes** | **No** |

Set a resource class for a Docker job

```yaml
jobs:
  build:
    docker:
      - image: cimg/base:2024.12
    resource_class: xlarge.gen2
    steps:
      ... // other config
```

Set a resource class for a Docker job using an expression

```yaml
jobs:
  build:
    docker:
      - image: cimg/base:2024.12
    resource_class: << pipeline.git.branch == "main" and "xlarge.gen2" or "medium.gen2" >>
    steps:
      ... // other config
```

#### Arm

**Arm on Docker** For credit and access information, see the [Resource classes page](https://circleci.com/product/features/resource-classes/). Resource class access is dependent on your [Plan](https://circleci.com/docs/guides/plans-pricing/plan-overview/)

To find out which CircleCI Docker convenience images support Arm resource classes, you can refer to [Docker Hub](https://hub.docker.com/u/cimg):

1.  Select the image (for example, `cimg/python`).
    
2.  Select the **tags** tab.
    
3.  View what is supported under **OS/ARCH** for the latest tags. For example, `cimg/python` has `linux/amd64` and `linux/arm64`, which means Arm **is** supported.
    

| Class | vCPUs | RAM | Cloud | Server |
| --- | --- | --- | --- | --- |
| `arm.medium` | 2 | 8 GB | **Yes** | **No** |
| `arm.large` | 4 | 16 GB | **Yes** | **No** |
| `arm.xlarge` | 8 | 32 GB | **Yes** | **No** |
| `arm.2xlarge` | 16 | 64 GB | **Yes** | **No** |

* * *

### LinuxVM execution environment

**Example:**

<Tabs>
<Tab title="Cloud">

```yaml
jobs:
  build:
    machine:
      image: ubuntu-2604:current # recommended linux image
    resource_class: large
    steps:
      ... // other config
```

</Tab>
<Tab title="Server">

```yaml
jobs:
  build:
    machine: true
    resource_class: large
    steps:
      ... // other config
```

</Tab>
</Tabs>

#### Gen1

| Class | vCPUs | RAM | Disk Size | Cloud | Server |
| --- | --- | --- | --- | --- | --- |
| `medium` | 2 | 7.5 GB | 150GB | **Yes** | **Yes** |
| `large` | 4 | 15 GB | 150GB | **Yes** | **Yes** |
| `xlarge` | 8 | 32 GB | 150GB | **Yes** | **Yes** |
| `2xlarge` | 16 | 64 GB | 150GB | **Yes** | **Yes** |
| `2xlarge+` | 32 | 64 GB | 150GB | **Yes** | **Yes** |

#### Gen2

| Class | vCPUs | RAM | Disk Size | Cloud | Server |
| --- | --- | --- | --- | --- | --- |
| `medium.gen2` | 2 | 8 GiB | 150GB | **Yes** | **No** |
| `large.gen2` | 4 | 16 GiB | 150GB | **Yes** | **No** |
| `xlarge.gen2` | 8 | 32 GiB | 150GB | **Yes** | **No** |
| `2xlarge.gen2` | 16 | 64 GiB | 150GB | **Yes** | **No** |
| `2xlarge+.gen2` | 32 | 128 GiB | 150GB | **Yes** | **No** |

**Example:**

```yaml
jobs:
  build:
    machine:
      image: ubuntu-2604:current # recommended linux image
    resource_class: large.gen2
    steps:
      ... // other config
```

* * *

### macOS execution environment

| Class | vCPUs | RAM | Cloud | Server |
| --- | --- | --- | --- | --- |
| `m4pro.medium` | 6 @ 4.51 GHz | 28GB | **Yes** | **No** |
| `m4pro.large` | 12 @ 4.51 GHz | 56GB | **Yes** | **No** |

**Example:**

```yaml
jobs:
  build:
    macos:
      xcode: 26.6.0
    resource_class: m4pro.medium
    steps:
      ... // other config
```

* * *

### macOS execution environment on server

If you are working on CircleCI Server you can access the macOS execution environment using [Self-hosted Runner](https://circleci.com/docs/guides/execution-runner/runner-overview/).

* * *

### Windows execution environment

| Class | vCPUs | RAM | Disk Size | Cloud | Server |
| --- | --- | --- | --- | --- | --- |
| `windows.medium` (default) | 4 | 16GB | 200 GB | **Yes** | **Yes** |
| `windows.large` | 8 | 32GB | 200 GB | **Yes** | **Yes** |
| `windows.xlarge` | 16 | 64GB | 200 GB | **Yes** | **Yes** |
| `windows.2xlarge` | 32 | 128GB | 200 GB | **Yes** | **Yes** |

**Using server?** Check with your systems administrator whether you have access to the Windows execution environment.

**Example:**

<Tabs>
<Tab title="Cloud">

```yaml
version: 2.1

jobs:
  build: # name of your job
    resource_class: 'windows.medium'
    machine:
      image: 'windows-server-2022-gui:current'
      shell: 'powershell.exe -ExecutionPolicy Bypass'
    steps:
      # Commands are run in a Windows virtual machine environment
      - checkout
      - run: Write-Host 'Hello, Windows'
```

</Tab>
<Tab title="Server">

```yaml
version: 2.1

jobs:
  build: # name of your job
    machine:
      image: windows-default
    steps:
      # Commands are run in a Windows virtual machine environment
      - checkout
      - run: Write-Host 'Hello, Windows'
```

</Tab>
</Tabs>

* * *

### GPU execution environment (Linux)

| Class | vCPUs | RAM | GPUs | GPU model | GPU Memory (GiB) | Disk Size (GiB) | Cloud | Server |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `gpu.nvidia.small` | 4 | 16 | 1 | NVIDIA Tesla P4 | 16 | 150 | **Yes** | **No** |
| `gpu.nvidia.small.gen2` | 4 | 16 | 1 | NVIDIA A10G | 24 | 150 | **Yes** | **No** |
| `gpu.nvidia.small.multi` | 4 | 15 | 2 | NVIDIA Tesla T4 | 16 | 150 | **Yes** | **No** |
| `gpu.nvidia.medium.multi` | 8 | 30 | 4 | NVIDIA Tesla T4 | 16 | 150 | **Yes** | **No** |
| `gpu.nvidia.medium` | 8 | 30 | 1 | NVIDIA Tesla T4 | 16 | 150 | **Yes** | **No** |
| `gpu.nvidia.large` | 8 | 30 | 1 | NVIDIA Tesla V100 | 16 | 150 | **Yes** | **No** |

**Example:**

```yaml
version: 2.1

jobs:
  build:
    machine:
      image: linux-cuda-12:default
    resource_class: gpu.nvidia.medium
    steps:
      - run: nvidia-smi
      - run: docker run --gpus all nvidia/cuda:9.0-base nvidia-smi
```

See the [Available Linux GPU images](#available-linux-gpu-images) section for the full list of available images.

* * *

### GPU execution environment (Windows)

| Class | vCPUs | RAM | GPUs | GPU model | GPU Memory (GiB) | Disk Size (GiB) | Cloud | Server |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `windows.gpu.nvidia.medium` | 16 | 60 | 1 | NVIDIA Tesla T4 | 16 | 200 | **Yes** | **No** |

**Example:**

```yaml
version: 2.1

orbs:
  win: circleci/windows@5.0.0

jobs:
  build:
    executor: win/server-2019-cuda
    steps:
      - checkout
      - run: '&"C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe"'
```

(2) _This resource requires review by our support team. [Open a support ticket](https://support.circleci.com/hc/en-us/requests/new) if you would like to request access._

* * *

### Arm VM execution environment

| Class | vCPUs | RAM | Disk Size | Cloud | Server |
| --- | --- | --- | --- | --- | --- |
| `arm.medium` (default) | 2 | 8GB | 100 GB | **Yes** | **Yes** |
| `arm.large` | 4 | 16GB | 100 GB | **Yes** | **Yes** |
| `arm.xlarge` | 8 | 32GB | 100 GB | **Yes** | **Yes** |
| `arm.2xlarge` | 16 | 64GB | 100 GB | **Yes** | **Yes** |

**Using server?** Check with your systems administrator whether you have access to the Arm execution environment.

**Example:**

<Tabs>
<Tab title="Cloud">

```yaml
jobs:
  my-job:
    machine:
      image: ubuntu-2604:current
    resource_class: arm.medium
    steps:
      - run: uname -a
      - run: echo "Hello, Arm!"
```

</Tab>
<Tab title="Server">

```yaml
jobs:
  my-job:
    machine:
      image: arm-default
    resource_class: arm.medium
    steps:
      - run: uname -a
      - run: echo "Hello, Arm!"
```

</Tab>
</Tabs>

* * *

## **`steps`**

The `steps` setting in a job is a list of single key/value pairs, the key of which indicates the step type. The value may be either a configuration map or a string (depending on what that type of step requires). For example, using a map:

```yaml
jobs:
  build:
    docker:
      - image: cimg/base:2024.01
    working_directory: ~/canary-python
    environment:
      FOO: bar
    steps:
      - run:
          name: Running tests
          command: make test
```

Here `run` is a step type. The `name` attribute is used by the UI for display purposes. The `command` attribute is specific to the `run` step and defines the command to execute.

Some steps may implement a shorthand semantic. For example, `run` may also be called like this:

```yml
jobs:
  build:
    docker:
      - image: cimg/base:2024.01
    steps:
      - run: make test
```

In its short form, the `run` step allows us to directly specify which `command` to execute as a string value. In this case the step itself provides default suitable values for other attributes (`name` here has the same value as `command`, for example).

Another shorthand, which is possible for some steps, is to use the step name as a string instead of a key/value pair:

```yml
jobs:
  build:
    docker:
      - image: cimg/base:2024.01
    steps:
      - checkout
```

In this case, the `checkout` step checks out project source code into the job’s [`working_directory`](#jobs).

In general all steps can be described as:

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `<step_type>` | Y | Map or String | A configuration map for the step or some string whose semantics are defined by the step. |

Each built-in step is described in detail below.

* * *

### **`run`**

Use the `run` step to invoke command-line programs. The `run` step takes either a map of configuration values, or, when you call it in short-form, a string that serves as both the `command` and `name`. CircleCI executes `run` commands using non-login shells by default, so you must explicitly source any `dotfiles` as part of the command.

The `run` step replaces the deprecated `deploy` step. If your job has a parallelism of 1, the deprecated `deploy` step can be swapped out directly for the `run` step. If your job has parallelism `> 1`, see [Migrate From Deploy to Run](https://circleci.com/docs/guides/orchestrate/migrate-from-deploy-to-run/).

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `command` | Y | String | Command to run via the shell |
| `name` | N | String | Title of the step to be shown in the CircleCI UI (default: full `command`) |
| `shell` | N | String | Shell to use for execution command (default: See [Default Shell Options](#default-shell-options)) |
| `environment` | N | Map | Additional environment variables, locally scoped to command |
| `background` | N | Boolean | Whether or not this step runs in the background (default: false) |
| `working_directory` | N | String | The directory where this step runs. CircleCI interprets this relative to the [`working_directory`](#jobs) of the job. (default: `.`) |
| `no_output_timeout` | N | String | Elapsed time the command can run without output. The string is a decimal with unit suffix, such as "20m", "1.25h", "5s". The default is 10 minutes and the maximum is governed by the [maximum time a job is allowed to run](#jobs). |
| `when` | N | String | [Specify when to enable or disable the step](#the-when-attribute). Takes the following values: `always`, `on_success`, `on_fail` (default: `on_success`) |
| `max_auto_reruns` | N | Integer | The maximum number of times to automatically rerun the step if it fails. Must be between `1` and `5`. |
| `auto_rerun_delay` | N | String | The delay between reruns of the step if it fails. This delay can only be set along with `max_auto_reruns`. The string is a decimal with unit suffix using either seconds `s` or minutes `m` up to a maximum of 10 minutes, such as "10s", "2m". |

Each `run` declaration represents a new shell. You can specify a multi-line `command` where each line runs in the same shell.

**Example:**

```yml
jobs:
  my-job:
    docker:
      - image: cimg/base:2024.12
    resource_class: xlarge
    steps:
      - run:
          command: |
            echo Running test
            mkdir -p /tmp/test-results
            make test
```

You can also configure commands to run [in the background](#background-commands) if you do not want to wait for the step to complete before moving on to subsequent run steps.

* * *

#### _Default shell options_

For jobs that run on **Linux**, CircleCI defaults the `shell` option to `/bin/bash -eo pipefail` if `/bin/bash` exists in the build container. Otherwise, CircleCI uses `/bin/sh -eo pipefail`. The default shell is not a login shell (CircleCI does not specify `--login` or `-l`) and thus does not source your `~/.bash_profile`, `~/.bash_login`, or `~/.profile` files.

For jobs that run on **macOS**, the default shell is `/bin/bash --login -eo pipefail`. The shell is a non-interactive login shell. The shell executes `/etc/profile/` followed by `~/.bash_profile` before every step.

For more information about which files are executed when Bash is invoked, [see the `INVOCATION` section of the `bash` manpage](https://linux.die.net/man/1/bash).

Descriptions of the `-eo pipefail` options are provided below.

#### `-e`

Exit immediately if any of the following exits with a non-zero status:

*   A pipeline (which may consist of a single simple command).
    
*   A subshell command enclosed in parentheses.
    
*   One of the commands executed as part of a command list enclosed by braces.
    

In the previous example, `mkdir` failed to create a directory and returned a non-zero status, so the shell terminated command execution and marked the whole step as failed. If you want the opposite behavior, add `set +e` in your `command` or override the default `shell` in your `run` configuration map. For example:

**Example:**

```yml
- run:
    command: |
      echo Running test
      set +e
      mkdir -p /tmp/test-results
      make test

- run:
    shell: /bin/sh
    command: |
      echo Running test
      mkdir -p /tmp/test-results
      make test
```

#### `-o pipefail`

If `pipefail` is enabled, the pipeline’s return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully. The shell waits for all commands in the pipeline to terminate before returning a value.

**Example:**

```yml
- run: make test | tee test-output.log
```

If `make test` fails, the `-o pipefail` option causes the whole step to fail. Without `-o pipefail`, the step always runs successfully because the result of the whole pipeline is determined by the last command (`tee test-output.log`), which always returns a zero status.

If `make test` fails, the rest of the pipeline is executed.

If you want to avoid this behavior, you can specify `set +o pipefail` in the command or override the whole `shell` (see example above).

We recommend using the default options (`-eo pipefail`) because they show errors in intermediate commands and simplify debugging job failures. For convenience, the UI displays the used shell and all active options for each `run` step.

For more information, see the [Using Shell Scripts](https://circleci.com/docs/guides/orchestrate/using-shell-scripts/) document.

* * *

#### _Background commands_

The `background` attribute enables you to configure commands to run in the background. Job execution proceeds to the next step rather than waiting for return of a command with the `background` attribute set to `true`. The following example shows the configuration for running the X virtual framebuffer in the background which is commonly required to run Selenium tests.

**Example:**

```yml
- run:
    name: Running X virtual framebuffer
    command: Xvfb :99 -screen 0 1280x1024x24
    background: true

- run: make test
```

* * *

#### _Shorthand syntax_

`run` has a convenient shorthand syntax.

**Example:**

```yml
- run: make test

# shorthanded command can also have multiple lines
- run: |
    mkdir -p /tmp/test-results
    make test
```

In this case, `command` and `name` become the string value of `run`, and the rest of the config map for that `run` have their default values.

* * *

#### The `when` attribute

By default, CircleCI executes job steps one at a time, in the order you define them in `config.yml`, until a step fails (returns a non-zero exit code). After a command fails, no further job steps execute.

Adding the `when` attribute to a job step allows you to override this default behavior, and selectively run or skip steps depending on the status of the job.

The `when` attribute accepts the following values:

`on_success`

The step runs only if all previous steps succeeded (returned exit code 0). `on_success` is the default value.

`always`

The step runs regardless of the exit status of previous steps. Use `always` when you have a task that must run whether previous steps succeed or fail. For example, you need to upload logs or code-coverage data.

`on_fail`

The step runs only if one of the preceding steps failed (returns a non-zero exit code). Common uses of `on_fail` include storing diagnostic data to debug test failures, or running custom notifications about the failure, such as sending emails or triggering alerts.

Some steps, such as `store_artifacts` and `store_test_results`, always run, even if a **step has failed** (returned a non-zero exit code) previously. However, `store_artifacts`, `store_test_results`, and the `when` attribute are not run if the job has been **killed** by a cancel request or has reached the runtime timeout limit.

**Example:**

```yml
- run:
    name: Upload CodeCov.io Data
    command: bash <(curl -s https://codecov.io/bash) -F unittests
    when: always # Uploads code coverage results, pass or fail
```

* * *

#### Ending a job from within a `step`

A job can exit without failing by using `run: circleci-agent step halt`. However, if a step within the job is already failing, the job continues to fail. This can be useful in situations where jobs need to conditionally execute.

**Example:** `halt` is used to avoid running a job on the `develop` branch:

```yml
- run: |
    if [ "$CIRCLE_BRANCH" = "develop" ]; then
        circleci-agent step halt
    fi
```

* * *

#### Automatic step reruns

The following attributes can be used to automatically rerun a step if it fails, and delay that rerun if required:

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `max_auto_reruns` | N | Integer | The maximum number of times to automatically rerun the step if it fails. Must be between `1` and `5`. |
| `auto_rerun_delay` | N | String | The delay between reruns of the step if it fails. This delay can only be set along with `max_auto_reruns`. The string is a decimal with unit suffix using either seconds `s` or minutes `m` up to a maximum of 10 minutes, such as "10s", "2m". If you do not supply a delay, the rerun starts directly after the step fails. |

Automatic reruns are only supported for `run` steps, not special steps like `checkout` or `setup_remote_docker`.

You must configure the `command` key for the step. You cannot use the short form run step configuration. For example, the following is not supported for use with automatic reruns: `- run: echo "Hello, world!"`

**Example:**

CircleCI job configured to automatically rerun a step up to 3 times if it fails with a 10 second delay between attempts

```yml
version: 2.1

jobs:
  my-job:
    steps:
      - run:
          command: echo "Hello, world!"
          max_auto_reruns: 3
          auto_rerun_delay: 10s
```

For more information, see the [Automatic Reruns](https://circleci.com/docs/guides/orchestrate/automatic-reruns/) page.

* * *

### **The when step**

The `when` and `unless` steps are supported in `version: 2.1` configuration

A conditional step consists of a step with the key `when` or `unless`. Under the `when` key are the subkeys `condition` and `steps`. Use the `when` step to customize commands and job configuration to run on custom conditions. Conditions are determined at config compilation time. This means `when` step conditions are checked before your workflow runs. See the [Conditional Steps Section of the Reusable Configuration Reference](https://circleci.com/docs/reference/reusing-config/#defining-conditional-steps) for more details.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `condition` | Y | Logic | [A Logic Statement](#logic-statements). Expressions are not supported for the `when` step. |
| `steps` | Y | Sequence | A list of steps to execute when the condition is true |

**Example:**

```yml
version: 2.1

jobs: # conditional steps may also be defined in `commands:`
  job_with_optional_custom_checkout:
    parameters:
      custom_checkout:
        type: string
        default: ""
    machine:
      image: ubuntu-2604:current
    steps:
      - when:
          condition: <<parameters.custom_checkout>>
          steps:
            - run: echo "my custom checkout"
      - unless:
          condition: <<parameters.custom_checkout>>
          steps:
            - checkout
workflows:
  build-test-deploy:
    jobs:
      - job_with_optional_custom_checkout:
          custom_checkout: "any non-empty string is truthy"
      - job_with_optional_custom_checkout
```

* * *

### **`checkout`**

A special step used to check out source code to the configured `path` (defaults to the `working_directory`). The reason this is a special step is because it is more of a helper function designed to simplify the process of checking out code. For GitHub OAuth, GitLab, and Bitbucket pipelines, `checkout` configures git to check out over SSH. If you require git over HTTPS, do not use this step as it configures git to check out over SSH. For GitHub App pipelines (GitHub Cloud and GitHub Enterprise Server), `checkout` uses HTTPS.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `method` | N | String | Checkout method. Valid options include `blobless` and `full`. (default: `blobless`) |
| `path` | N | String | The directory where CircleCI checks out code. CircleCI interprets this relative to the [`working_directory`](#jobs) of the job. (default: `.`) |

If `path` already exists and is:

*   A git repository - step does not clone whole repository, but rather fetches origin.
    
*   NOT a git repository - step fails.
    

In the case of `checkout`, the step type is just a string with no additional attributes.

**Example:**

```yml
jobs:
  build:
    docker:
      - image: cimg/go:1.24.2
    steps:
      - checkout
```

The checkout command automatically adds the required authenticity keys for interacting with GitHub and Bitbucket over SSH. These keys are detailed further in the [Integration Guide](https://circleci.com/docs/guides/permissions-authentication/users-organizations-and-integrations-guide/#establish-the-authenticity-of-an-ssh-host). This guide is also helpful if you wish to implement a custom checkout command.

You can specify a checkout strategy by using the `method` key. CircleCI supports full clones or blobless clones. Blobless clones reduce the amount of data fetched from the remote by asking the remote to filter out objects that are not attached to the current commit.

**Example:**

```yml
jobs:
  build:
    docker:
      - image: cimg/go:1.24.2
    steps:
      - checkout:
          method: blobless
```

In certain cases, CircleCI falls back to a full checkout even though blobless was specified. This occurs if Git and SSH clients are not available in the current environment, or if Git version 2.41.0 is installed. Git version 2.41.0 contained a [known issue](https://lore.kernel.org/git/kl6lh6qyrnjm.fsf@chooglen-macbookpro.roam.corp.google.com/) for blobless clones.

If a downstream step requires those objects to exist for scanning or comparisons, a blobless clone can cause failures. In that case, you can specify a full checkout as shown in the following example:

```yml
jobs:
  build:
    docker:
      - image: cimg/go:1.24.2
    steps:
      - checkout:
          method: full
```

CircleCI does not check out submodules. If your project requires submodules, add `run` steps with appropriate commands as shown in the following example:

```yml
jobs:
  build:
    docker:
      - image: cimg/go:1.24.2
    steps:
      - checkout
      - run: git submodule sync
      - run: git submodule update --init
```

The `checkout` step configures Git to skip automatic garbage collection. If you are caching your `.git` directory with [**`restore_cache`**](#restorecache) and want to use garbage collection to reduce its size, use a [**`run`**](#run) step with `git gc` before doing so.

* * *

### **`setup_remote_docker`**

*   `setup_remote_docker` is not compatible with the `machine` executor. See [Docker Layer Caching in Machine Executor](https://circleci.com/docs/guides/optimize/docker-layer-caching/#machine-executor) for information on how to enable DLC with the `machine` executor.
    
*   The `version` key is not currently supported on CircleCI Server. Contact your system administrator for information about the Docker version installed in your remote Docker environment. If you are on server 4.x, find the [Default AWS AMI Lists](https://circleci.com/docs/server-admin/latest/operator/manage-virtual-machines-with-machine-provisioner/#default-aws-ami-lists).
    

Allows Docker commands to be run locally. See [Running Docker Commands](https://circleci.com/docs/guides/execution-managed/building-docker-images/) for details.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `docker_layer_caching` | N | boolean | Set this to `true` to enable [Docker Layer Caching](https://circleci.com/docs/guides/optimize/docker-layer-caching/) in the Remote Docker Environment (default: `false`) |
| `prefer_same_region` | N | boolean | Set this to `true` to pull images from the same region as the VM where possible. If the pull fails, CircleCI falls back to the image’s original region (default: `false`) |
| `version` | N | String | Version string of Docker you would like to use (default: `24.0.9`). View the list of [Supported Docker Versions](https://circleci.com/docs/guides/execution-managed/building-docker-images/#docker-version). |

**Example:**

```yaml
jobs:
  build:
    docker:
      - image: cimg/base:2024.06
    steps:
      # ... steps for building/testing app ...
      - setup_remote_docker:
          version: default
```

* * *

### **`save_cache`**

Generates and stores a cache of a file or directory of files such as dependencies or source code. Caches are stored in CircleCI’s object storage. Later jobs can [restore this cache](#restorecache). Learn more on the [Caching Dependencies](https://circleci.com/docs/guides/optimize/caching/) page.

Cache retention can be customized on the [CircleCI web app](https://app.circleci.com/) by navigating to **Plan**  **Usage Controls**.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `paths` | Y | List | List of directories to add to the cache |
| `key` | Y | String | Unique identifier for this cache |
| `name` | N | String | Title of the step to be shown in the CircleCI UI (default: "Saving Cache") |
| `when` | N | String | [Specify when to enable or disable the step](#the-when-attribute). Takes the following values: `always`, `on_success`, `on_fail` (default: `on_success`) |

The cache for a specific `key` is immutable. If a cache already exists for the given `key`, CircleCI uses the existing cache and proceeds to the next step.

When storing a new cache, the `key` value may contain special, templated, values for your convenience:

| Template | Description |
| --- | --- |
| `{{ .Branch }}` | The VCS branch currently being built. |
| `{{ .BuildNum }}` | The CircleCI build number for this build. |
| `{{ .Revision }}` | The VCS revision currently being built. |
| `{{ .CheckoutKey }}` | The SSH key used to check out the repository. |
| `{{ .Environment.variableName }}` | The environment variable `variableName` (supports any environment variable [Exported by CircleCI](https://circleci.com/docs/guides/security/env-vars/) or added to a specific [context](https://circleci.com/docs/guides/security/contexts/)\--not any arbitrary environment variable). |
| `{{ checksum "filename" }}` | A base64 encoded SHA256 hash of the given filename’s contents. Commit this file to your repository, and reference it as an absolute or relative path from the current working directory. Good candidates are dependency manifests, such as `package-lock.json`, `pom.xml` or `project.clj`. This file must not change between `restore_cache` and `save_cache`, otherwise CircleCI saves the cache under a different cache key than the one it used at `restore_cache` time. |
| `{{ epoch }}` | The current time in seconds since the UNIX epoch. |
| `{{ arch }}` | The OS and CPU information. Useful when caching compiled binaries that depend on OS and CPU architecture, for example, `darwin amd64` versus `linux i386/32-bit`. |

During step execution, CircleCI replaces the templates above with runtime values and uses the resultant string as the `key`.

**Template examples:**

`myapp-{{ checksum "package-lock.json" }}`

CircleCI regenerates the cache every time you change something in the `package-lock.json` file. Different branches of this project generate the same cache key.

`myapp-{{ .Branch }}-{{ checksum "package-lock.json" }}`

Same as the previous one, but each branch generates a separate cache.

`myapp-{{ epoch }}`

Every job run generates a separate cache.

While choosing suitable templates for your cache `key`, keep in mind the following:

*   Cache saving is not a free operation. See the billing section on the [FAQ](https://circleci.com/docs/reference/faq/#calculate-monthly-storage-and-network-costs) page.
    
*   It takes time to upload the cache.
    
*   Best practice is to have a `key` that generates a cache only if something actually changed, and avoid regenerating it every time a job is run.
    
*   Because caches are immutable, start all your cache keys with a version prefix `v1-...`. This lets you regenerate all your caches by incrementing the version in this prefix.
    

**Examples:**

```yml
- save_cache:
    key: v1-myapp-{{ arch }}-{{ checksum "project.clj" }}
    paths:
      - /home/ubuntu/.m2
```

```yml
- save_cache:
    key: v1-{{ checksum "yarn.lock" }}
    paths:
      - node_modules/workspace-a
      - node_modules/workspace-c
```

Wildcards are not currently supported in `save_cache` paths. Visit the [Ideas board](https://ideas.circleci.com/cloud-feature-requests/p/support-wildcards-in-savecachepaths) and vote for this feature if it would be useful for you or your organization.

* * *

### **`restore_cache`**

Restores a previously saved cache based on a `key`. Cache needs to have been saved first for this key using the [`save_cache` step](#savecache). Learn more in [The Caching Documentation](https://circleci.com/docs/guides/optimize/caching/).

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `key` | Y (1) | String | Single cache key to restore |
| `keys` | Y (1) | List | List of cache keys to check. CircleCI restores the cache from the first existing key. |
| `name` | N | String | Title of the step to be shown in the CircleCI UI (default: "Restoring Cache") |

(1) You must specify at least one attribute. If you provide both `key` and `keys`, CircleCI checks `key` first, then `keys`.

A key is searched against existing keys as a prefix.

When multiple matches exist, CircleCI uses the **most recent match**, even if a more precise match exists.

**Example:**

```yml
steps:
  - save_cache:
      key: v1-myapp-cache
      paths:
        - ~/d1

  - save_cache:
      key: v1-myapp-cache-new
      paths:
        - ~/d2

  - run: rm -f ~/d1 ~/d2

  - restore_cache:
      key: v1-myapp-cache
```

In this case, CircleCI restores cache `v1-myapp-cache-new`, the most recent match with the `v1-myapp-cache` prefix. CircleCI restores it even though the first key (`v1-myapp-cache`) is an exact match.

For more information on key formatting, see the `key` section of [`save_cache` step](#savecache).

When CircleCI encounters a list of `keys`, it restores the cache from the first key that matches an existing cache. We recommend you use a more specific key first (for example, cache for exact version of `package-lock.json`) and more generic keys after (for example, any cache for this project). If no key matches an existing cache, CircleCI skips the step with a warning.

A path does not need to be specified here because CircleCI restores the cache to the location where it originally saved it.

**Example:**

```yml
- restore_cache:
    keys:
      - v1-myapp-{{ arch }}-{{ checksum "project.clj" }}
      # if cache for exact version of `project.clj` is not present then load any most recent one
      - v1-myapp-

# ... Steps building and testing your application ...

# cache will be saved only once for each version of `project.clj`
- save_cache:
    key: v1-myapp-{{ arch }}-{{ checksum "project.clj" }}
    paths:
      - /foo
```

* * *

### **`deploy` - DEPRECATED**

See [**`run`**](#run) for current processes. If you have parallelism `> 1` in your job, see the [Migrate From Deploy to Run](https://circleci.com/docs/guides/orchestrate/migrate-from-deploy-to-run/) guide.

* * *

### **`store_artifacts`**

Step to store artifacts (for example logs, binaries, etc.) to be available in the web app or through the API. See the [Uploading Artifacts](https://circleci.com/docs/guides/optimize/artifacts/) page for more information.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `path` | Y | String | Directory in the primary container to save as job artifacts |
| `destination` | N | String | Prefix added to the artifact paths in the artifacts API (default: the directory of the file specified in `path`) |

There can be multiple `store_artifacts` steps in a job. Using a unique prefix for each step prevents them from overwriting files.

Artifact storage retention can be customized on the [CircleCI web app](https://app.circleci.com/) by navigating to **Plan**  **Usage Controls**.

**Example:**

```yml
- run:
    name: Build the Jekyll site
    command: bundle exec jekyll build --source jekyll --destination jekyll/_site/docs/
- store_artifacts:
    path: jekyll/_site/docs/
    destination: circleci-docs
```

* * *

### **`store_test_results`**

Special step used to upload and store test results for a build. Test results are visible on the CircleCI web application under each build’s **Test Summary** section. Storing test results is useful for timing analysis of your test suites. For more information on storing test results, see the [Collecting Test Data](https://circleci.com/docs/guides/test/collect-test-data/) page.

You can also store test results as build artifacts. For steps, refer to [the `store_artifacts` step](#storeartifacts) section.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `path` | Y | String | Path (absolute, or relative to your `working_directory`) to directory containing `JUnit` XML test metadata files, or to a single test file. |

**Example:**

Directory structure:

```shell
test-results
├── jest
│   └── results.xml
├── mocha
│   └── results.xml
└── rspec
    └── results.xml
```

`config.yml` syntax:

```yml
- store_test_results:
    path: test-results
```

* * *

### **`persist_to_workspace`**

Special step used to persist a temporary file to be used by another job in the workflow. For more information on using workspaces, see the [Using Workspaces to Share Data Between Jobs](https://circleci.com/docs/guides/orchestrate/workspaces/) page.

`persist_to_workspace` adopts the storage settings from the storage customization controls on the CircleCI web app. If no custom setting is provided, `persist_to_workspace` defaults to 15 days.

Workspace storage retention can be customized on the [CircleCI web app](https://app.circleci.com/) by navigating to **Plan**  **Usage Controls**.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `root` | Y | String | Either an absolute path or a path relative to `working_directory` |
| `paths` | Y | List | Glob identifying file(s), or a non-glob path to a directory to add to the shared workspace. Interpreted as relative to the workspace root. Must not be the workspace root itself. |

The root key is a directory on the container which is taken to be the root directory of the workspace. The path values are all relative to the root.

**Example for root Key:**

For example, the following step syntax persists the specified paths from `/tmp/dir` into the workspace, relative to the directory `/tmp/dir`.

```yml
- persist_to_workspace:
    root: /tmp/dir
    paths:
      - foo/bar
      - baz
```

After this step completes, the following directories are added to the workspace:

/tmp/dir/foo/bar
/tmp/dir/baz

**Example for paths Key:**

```yml
- persist_to_workspace:
    root: /tmp/workspace
    paths:
      - target/application.jar
      - build/*
```

The `paths` list uses `Glob` from Go, and the pattern matches [filepath.Match](https://golang.org/pkg/path/filepath/#Match).

```
pattern:
        { term }
term:
        '*' matches any sequence of non-Separator characters
        '?' matches any single non-Separator character
        '[' [ '^' ] { character-range }
        ']' character class (must be non-empty)
        c matches character c (c != '*', '?', '\\', '[')
        '\\' c matches character c
character-range:
        c matches character c (c != '\\', '-', ']')
        '\\' c matches character c
        lo '-' hi matches character c for lo <= c <= hi
```

The Go documentation states that the pattern may describe hierarchical names such as `/usr/*/bin/ed` (assuming the Separator is '/').

Everything must be relative to the workspace root directory.

* * *

### **`attach_workspace`**

Special step used to attach the workflow’s workspace to the current container. The full contents of the workspace are downloaded and copied into the directory the workspace is being attached at. For more information on using workspaces, see the [Using Workspaces](https://circleci.com/docs/guides/orchestrate/workspaces/) page.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `at` | Y | String | Directory to attach the workspace to. |

Workspace storage retention can be customized on the [CircleCI web app](https://app.circleci.com/) by navigating to **Plan**  **Usage Controls**.

**Example:**

```yml
- attach_workspace:
    at: /tmp/workspace
```

The lifetime of artifacts, workspaces, and caches can be customized on the [CircleCI web app](https://app.circleci.com/) by navigating to **Plan**  **Usage Controls**. Here you can control the storage retention periods for these objects. If no storage period is set, the default storage retention period of artifacts is 30 days, while the default storage retention period of workspaces and caches is 15 days.

* * *

### **`add_ssh_keys`**

Special step that adds SSH keys from a project’s settings to a container. Also configures SSH to use these keys. For more information on SSH keys see the [Add Additional SSH Keys](https://circleci.com/docs/guides/integration/add-ssh-key/) page.

**Using server?** CircleCI Server supports only MD5 fingerprints. You can see the MD5 fingerprint in CircleCI under **Project Settings**  **SSH keys**  **Additional SSH keys**. An upcoming server release is planned to include SHA256 support.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `fingerprints` | N | List | List of fingerprints corresponding to the keys to be added (default: all keys added) |

```yaml
steps:
  - add_ssh_keys:
      fingerprints:
        - "b7:35:a6:4e:9b:0d:6d:d4:78:1e:9a:97:2a:66:6b:be"
        - "SHA256:NPj4IcXxqQEKGXOghi/QbG2sohoNfvZ30JwCcdSSNM0"
```

Even though CircleCI uses `ssh-agent` to sign all added SSH keys, you **must** use the `add_ssh_keys` key to actually add keys to a container.

* * *

### **`install_signing_bundle`**

A special step that installs the code signing certificates and provisioning profiles from the signing bundles declared in the `code_signing` key of your `macos` executor. CircleCI installs them into a temporary keychain on the runner at build time and removes them when the job completes. See [Set up Code Signing for iOS and macOS Projects](https://circleci.com/docs/guides/execution-managed/ios-codesigning/).

In the case of `install_signing_bundle`, the step type is just a string with no additional attributes.

**Example:**

```yaml
jobs:
  build-and-sign:
    macos:
      xcode: 26.6.0
      code_signing:
        - my-signing-bundle
    steps:
      - install_signing_bundle
      - checkout
```

* * *

### Using `pipeline` values

Pipeline values are available to all pipeline configurations and can be used without previous declaration. For a list of pipeline values, see the [Pipeline Values and Parameters](https://circleci.com/docs/guides/orchestrate/pipeline-variables/) page.

**Example:**

```yaml
version: 2.1
jobs:
  build:
    docker:
      - image: cimg/node:20.18.1
    environment:
      IMAGETAG: latest
    working_directory: ~/main
    steps:
      - run: echo "This is pipeline ID << pipeline.id >>"
```

* * *

## **`circleci_ip_ranges`**

A paid account on a [Performance or Scale Plan](https://circleci.com/pricing/) is required to access IP ranges.

Enables jobs to go through a set of well-defined IP address ranges. See [IP Ranges](https://circleci.com/docs/guides/security/ip-ranges/) for details.

**Example:**

```yaml
version: 2.1

jobs:
  build:
    circleci_ip_ranges: true # opts the job into the IP ranges feature
    docker:
      - image: curlimages/curl
    steps:
      - run: echo “Hello World”
workflows:
  build-workflow:
    jobs:
      - build
```

* * *

## **`job-groups`**

The `job-groups` key lets you define named sets of jobs at the top level of your config. A job group can be invoked in a workflow just like a regular job, and optionally serialized as an atomic unit by adding `serial-group` to the invocation.

### **<`group-name`\>**

Each job group consists of the group’s name as a key and a map as a value. The value map has the following attributes:

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `jobs` | Y | List | A list of job invocations for the group, following the same format as workflow job entries. Jobs within the group can use `requires` to declare internal dependencies on other jobs in the same group. |

**Example:**

```yaml
# Use job-groups to define a reusable set of jobs.
# The group is expanded inline in the workflow without serialization.

job-groups:
  deploy-and-release:
    jobs:
      - deploy
      - release:
          requires:
            - deploy

workflows:
  main-workflow:
    jobs:
      - build
      - deploy-and-release:
          requires:
            - build
      - notify:
          requires:
            - deploy-and-release
```

For more information, see the [Job Groups](https://circleci.com/docs/guides/orchestrate/controlling-serial-execution-across-your-organization/#job-groups) section of the Controlling Serial Execution Across Your Organization page.

* * *

## **`workflows`**

Used for orchestrating all jobs. Each workflow consists of the workflow name as a key and a map as a value. A name must be unique within the current `config.yml`. The top-level keys for the Workflows configuration are `version` and `jobs`. For more information, see the [Using Workflows to Orchestrate Jobs](https://circleci.com/docs/guides/orchestrate/workflows/) page.

* * *

### **`version`**

The workflows `version` key is **not** required for `version: 2.1` configuration

The Workflows `version` field is used to issue warnings for deprecation or breaking changes.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `version` | Y if config version is `2` | String | Must be `2` |

```yml
workflows:
  version: 2
  my-workflow:
    jobs:
      - my-job
```

* * *

### **<`workflow_name`\>**

A unique name for your workflow.

```yml
workflows:
  my-workflow:
    jobs:
      - my-job
```

* * *

### **`max_auto_reruns`**

The `max_auto_reruns` key is used to configure the maximum number of automatic reruns for a workflow.

```yml
version: 2.1

workflows:
  my-workflow:
    max_auto_reruns: 3
    jobs:
      - build
      - test
      - deploy:
          requires:
            - build
            - test
```

The value of `max_auto_reruns` can be an integer between 1 and 5.

For more information, see the [Automatic Reruns](https://circleci.com/docs/guides/orchestrate/automatic-reruns/) page.

* * *

### **`triggers`**

Specifies which triggers will cause this workflow to be executed. Default behavior is to trigger the workflow when pushing to a branch.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `triggers` | N | Array | Must be `schedule`. |

```yml
workflows:
   nightly:
     triggers:
       - schedule:
           cron: "0 0 * * *"
           filters:
             branches:
               only:
                 - main
                 - beta
     jobs:
       - test
```

* * *

#### **`schedule`**

Scheduled workflows are not available for projects integrated through the GitHub App, GitLab or Bitbucket Data Center.

Using **schedule triggers** rather than scheduled workflows offers several benefits. Visit the schedule triggers [Migration Guide](https://circleci.com/docs/guides/orchestrate/migrate-scheduled-workflows-to-schedule-triggers/) to find out how to migrate existing scheduled workflows to schedule triggers. If you would like to set up schedule triggers from scratch, visit the [Schedule Triggers](https://circleci.com/docs/guides/orchestrate/schedule-triggers/) page.

A workflow may have a `schedule` indicating it runs at a certain time, for example a nightly build that runs every day at 12am UTC:

```yml
workflows:
   nightly:
     triggers:
       - schedule:
           cron: "0 0 * * *"
           filters:
             branches:
               only:
                 - main
                 - beta
     jobs:
       - test
```

* * *

#### **`cron`**

The `cron` key is defined using POSIX `crontab` syntax.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `cron` | Y | String | See the [`crontab` man page](https://pubs.opengroup.org/onlinepubs/7908799/xcu/crontab.html). |

```yml
workflows:
   nightly:
     triggers:
       - schedule:
           cron: "0 0 * * *"
           filters:
             branches:
               only:
                 - main
                 - beta
     jobs:
       - test
```

* * *

#### **`filters`**

Trigger filters can have the key `branches`.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `filters` | Y | Map | A map defining rules for execution on specific branches |

```yml
workflows:
   nightly:
     triggers:
       - schedule:
           cron: "0 0 * * *"
           filters:
             branches:
               only:
                 - main
                 - beta
     jobs:
       - test
```

* * *

#### **`branches`**

The `branches` key controls whether the _current_ branch has a schedule trigger created for it, where _current_ branch is the branch containing the `config.yml` file with the `trigger` stanza. That is, a push on the `main` branch only schedules a workflow using [Filters in Your Workflows](https://circleci.com/docs/guides/orchestrate/workflows/#using-filters-in-your-workflows) for the `main` branch.

Branches can have the keys `only` and `ignore` which each map to a single string naming a branch. You may also use regular expressions to match against branches by enclosing them with \`/’s, or map to a list of such strings. Regular expressions must match the **entire** string.

*   The job runs on any branches that match `only`.
    
*   The job does not run on any branches that match `ignore`.
    
*   If you specify neither `only` nor `ignore`, the job runs on all branches. If you specify both `only` and `ignore`, CircleCI uses `only` and ignores `ignore`.
    

```yaml
workflows:
  commit:
    jobs:
      - test
      - deploy
  nightly:
    triggers:
      - schedule:
          cron: "0 0 * * *"
          filters:
            branches:
              only:
                - main
                - /release\/.*/
    jobs:
      - coverage
```

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `branches` | Y | Map | A map defining rules for execution on specific branches |
| `only` 1 | N | String, or List of Strings | Either a single branch specifier, or a list of branch specifiers |
| `ignore` 1 | N | String, or List of Strings | Either a single branch specifier, or a list of branch specifiers |

1: One of either `only` or `ignore` branch filters must be specified. If both are present, `only` is used.

* * *

#### **Using `when` in workflows**

Using `when` or `unless` under `workflows` is supported in `version: 2.1` configuration. Workflows are always run unless there is a `when` or `unless` filter that prevents the workflow from being run. If you want a workflow to run in every pipeline, do not add a `when` or `unless` filter.

You may use a `when` clause (the inverse clause `unless` is also supported) under a workflow declaration with a [logic statement](#logic-statements) to determine whether or not to run that workflow.

The example configuration below uses a pipeline parameter, `run_integration_tests` to drive the `integration_tests` workflow.

```yaml
version: 2.1

workflows:
  integration_tests:
    when: pipeline.git.branch == "main"
    jobs:
      - mytestjob

jobs:
...
```

The `integration_tests` workflow runs only when the pipeline is triggered on the `main` branch.

For more examples and conceptual information, see the [Workflows](https://circleci.com/docs/guides/orchestrate/workflows/) page.

* * *

## **`jobs`**

A job can have the keys `requires`, `name`, `context`, `type`, and `filters`.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `jobs` | Y | List | A list of jobs to run with their dependencies |

* * *

### **<`job_name`\>**

A job name that exists in your `config.yml`.

```yml
version: 2.1

jobs:
  my-job:
    docker:
      - image: cimg/node:20.18.1
    steps:
      - run: echo "Hello World"

workflows:
  my-workflow:
    jobs:
      - my-job
```

* * *

#### **`override-with`**

The `override-with` key is used to override the job configuration with a job from the referenced orb. For more information, see the [How to Override Config](https://circleci.com/docs/guides/orchestrate/how-to-override-config/) page.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `override-with` | N | String | The orb job name you use to override the existing job configuration. (Supports both URL-based and registry orbs) |

**Example:**

```yml
version: 2.1

orbs:
  my-orb: << url-ref >>

jobs:
  build:
    steps: 
      - run: task build
  test:
    steps:
      - run: task test
  deploy:
    steps:
      - run: ccc deploy

workflows:
  - build-test-deploy:
      jobs:
        - build
        - test:
            override-with: my-orb/my-test
            requires: build
        - deploy:
            requires: test
```

In the example above, the `test` job in the workflow is being overridden with the orb job `my-orb/my-test`. The `my-orb/my-test` job might be defined with a different resource class or execution steps.

If the `my-orb/my-test` job is not defined inside the orb, the `test` job will compile using the local job definition.

* * *

#### `serial-group`

The `serial-group` key is used to add a property to a job to allow a group of jobs to run in series, rather than concurrently, across an organization. Serial groups control the orchestration of jobs across an organization, not just within projects and pipelines.

The `serial-group` key is configurable per job, or at the job group invocation level. To apply `serial-group` to an entire job group, see [`job-groups`](#job-groups).

The value of the `serial-group` key is a string that is used to group jobs together to run one after another. The key must meet the following requirements:

*   Must be 512 characters or fewer when compiled.
    
*   Must not be blank.
    
*   Must consist of alphanumeric characters plus, `.`, `-`, `_`, `/`.
    

Note the following features of serial groups:

*   You can use pipeline values and parameters in the `serial-group` key.
    
*   Serial groups wait for five hours. After this time, CircleCI cancels any jobs still waiting in the group. This does not affect the standard limits that apply to a [job’s runtime](#jobs).
    

**Pipeline order protection in serial groups**

Jobs in a serial group follow an order protection mechanism, as follows:

*   Jobs start in the order they join the queue, but are _accepted_ based on pipeline number.
    
*   If a group is waiting/running and another job in the same project attempts to join the queue with a lower pipeline number, the job is skipped.
    
*   This immediate skip process maintains order integrity, preventing unintended work in a build, such as a deployment job running a previous version.
    

If there are no serial groups waiting/running, a pipeline with a lower number can start, such as restoring back to a previous pipeline via a rerun workflow.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `serial-group` | N | String | A string that is used across an org to group jobs together to run one after another. Can include pipeline values and parameters. Use this same serial group across multiple pipelines to control the orchestration of jobs across an organization. |

**Example:**

```yml
# Creating multiple pipelines at the same time with the below config will result in
# all pipelines running test and build but only a single pipeline will run deploy at a time.

workflows:
  main-workflow:
    jobs:
      - test
      - build
      - deploy:
          serial-group: << pipeline.project.slug >>/deploy-group
          requires:
            - test
            - build
```

For more information, see the [Controlling Serial Execution Across Your Organization](https://circleci.com/docs/guides/orchestrate/controlling-serial-execution-across-your-organization/) page.

* * *

#### **`requires`**

Jobs are run concurrently by default, so you must explicitly require any dependencies by their job name if you need some jobs to run sequentially.

<table><thead><tr><th>Key</th><th>Required</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>requires</code></td><td>N</td><td>List</td><td><div><div><p>A list of jobs that must succeed a specified status before the job starts. <strong>Note</strong>: When jobs you list as dependencies do not execute (due to filters, for example), CircleCI ignores them as dependencies for other jobs. However, if all dependencies of a job are filtered, that job doesn’t execute either.</p></div><div><p>Possible types of <code>requires</code> items:</p></div><div><ul><li><p>Job name (a required job that must succeed for the job to start).</p></li><li><p>Map of job name to status (a required job that must attain the specified status for the job to start).</p></li><li><p>Map of job name to a list of statuses (a required job that must attain one of the specified statuses for the job to start).</p></li></ul></div><div><p>The possible <strong>status</strong> values are: <code>success</code>, <code>failed</code>, <code>canceled</code>, <code>unauthorized</code>, <code>not_run</code>, and <code>terminal</code>.</p></div></div></td></tr></tbody></table>

```yml
workflows:
  my-workflow:
    jobs:
      - build
      - test:
          requires:
            - build
      - deploy:
          requires:
            - build
            - test
      - notify-build-canceled:
          requires:
            - build: canceled
      - cleanup:
          requires:
            - deploy:
              - success
              - failed
              - canceled
              - unauthorized
              - not_run
      - cleanup-shorthand:
          requires:
            - deploy: terminal  # equivalent to [success, failed, canceled, unauthorized, not_run]
```

* * *

#### **`name`**

The `name` key can be used to invoke reusable jobs across any number of workflows. Using the name key ensures numbers are not appended to your job name (for example, sayhello-1, sayhello-2, etc.). The name you assign to the `name` key needs to be unique, otherwise the numbers will still be appended to the job name.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `name` | N | String | A replacement for the job name. Useful when calling a job multiple times. If you want to invoke the same job multiple times, and a job requires one of the duplicate jobs, this key is required. (2.1 only) |

```yml
workflows:
  my-workflow:
    jobs:
      - my-job:
          name: my-alternative-job-name
```

* * *

#### **`context`**

Jobs may be configured to use global environment variables set for an organization, see the [Contexts](https://circleci.com/docs/guides/security/contexts/) document for adding a context in the application settings.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `context` | N | String/List | The name of the context(s). The initial default name is `org-global`. Each context name must be unique. If using CircleCI Server, only a single context per workflow is supported. **Note:** A maximum of 100 unique contexts across all workflows is allowed. |

Use a context for a job

```yml
workflows:
  my-workflow:
    jobs:
      - my-job:
          context: org-global
```

It is also possible to use a list of contexts, as follows:

```yml
workflows:
  my-workflow:
    jobs:
      - my-job:
          context:
            - org-global
            - project-global
```

You can also use an expression to determine the contexts for a job:

Use an expression to determine the contexts for a job

```yml
workflows:
  my-workflow:
    jobs:
      - my-job:
          context: << pipeline.git.branch == "main" and "org-global" or "project-global" >>
```

* * *

#### **`type`**

A job may have a `type` of `approval` indicating it must be manually approved before downstream jobs may proceed. For more information see the [Using Workflows to Orchestrate Jobs](https://circleci.com/docs/guides/orchestrate/workflows/#holding-a-workflow-for-a-manual-approval) page.

Jobs run in the dependency order until the workflow processes a job with the `type: approval` key followed by a job on which it depends, for example:

```yml
workflows:
  my-workflow:
    jobs:
      - build
      - test:
          requires:
            - build
      - hold:
          type: approval
          requires:
            - test
      - deploy:
          requires:
            - hold
```

An approval job can have any name. In the example above the approval job is named `hold`. The name you choose for an approval job must not be used to define a job in the main configuration. An approval job only exists as a workflow orchestration device.

* * *

#### Expression-based job filters

Expression-based job filters allow you to conditionally run jobs based on the following:

*   [Pipeline Values](https://circleci.com/docs/reference/variables/#pipeline-values)
    
*   [Pipeline Parameters](https://circleci.com/docs/guides/orchestrate/pipeline-variables/#pipeline-parameters-in-configuration)
    

An expression-based job filter is a rule that is evaluated against pipeline values and parameters to decide whether a job runs.

Using expression-based job filters is one way to optimize your pipelines. Optimizations include the following:

*   Lower costs.
    
*   Decrease time to feedback.
    
*   Run specific jobs based on the context of the source of change.
    

```yml
workflows:
  deploy:
    jobs:
      - init-service
      - test-service
      - build-service-image:
          requires:
            - init-service
      - dry-run-service:
          requires:
            - init-service
          filters: pipeline.git.branch != "main" and pipeline.git.branch != "canary"
      - publish-service:
          requires:
            - build-service-image
            - test-service
          filters: pipeline.git.branch == "main" or pipeline.git.tag starts-with "release"
      - deploy-service:
          context:
            - org-global
          requires:
            - publish-service
          filters: pipeline.git.branch == "main" and pipeline.parameters.my-custom-param starts-with "DEPLOY:"
```

**Examples:**

Only run the job on the project’s `main` branch:

```yml
filters: pipeline.git.branch == "main"
```

Only run the job on the project’s `main` branch, or branches starting with `integration-test`:

```yml
filters: pipeline.git.branch == "main" or pipeline.git.branch starts-with "integration-test"
```

Only run the job on the `main` branch, and disallow use with pipelines [Triggered With Unversioned Configuration](https://circleci.com/docs/guides/toolkit/vs-code-extension-overview/#test-run-your-config-from-vs-code):

```yml
filters: pipeline.git.branch == "main" and not (pipeline.trigger_source starts-with "api")
```

Use pipeline parameters and the pipeline value `pipeline.git.branch` to run a job only on specific branches **or** when triggered via the API with a pipeline parameter set to true:

```yml
version: 2.1

parameters:
  run-storybook-tests:
    type: boolean
    default: false

...
# jobs configuration omitted for brevity

workflows:
  build:
    jobs:
      - setup
      - storybook-tests:
          requires:
            - setup
          filters: |
            pipeline.parameters.run-storybook-tests
            or pipeline.git.branch == "dry-run-deploy"
            or pipeline.git.branch starts-with "deploy"
```

You can use the API to trigger a pipeline with a pipeline parameter set to true:

**Using server?** If you are using CircleCI Server, replace `[https://circleci.com](https://circleci.com)` with your server hostname when interacting with the CircleCI API.

```yml
curl -X POST https://circleci.com/api/v2/project/circleci/<org-id>/<project-id>/pipeline/run \
  --header "Circle-Token: $CIRCLE_TOKEN" \
  --header "content-type: application/json" \
  --data {
  "definition_id": "<pipeline-definition-id>",
  "config": {"branch": "<your-branch-name>"},
  "checkout": {"branch": "<your-branch-name>"},
  "parameters": {"run-storybook-tests": "true"}
  }
```

**Operators**

The operators you can use for expression-based job filters are described in the following table. You can also group sub-expressions with parentheses `(`, `)` as in the examples above.

<table><thead><tr><th>Operator type</th><th>Operators</th><th>Description</th></tr></thead><tbody><tr><td>Logical</td><td><code>and</code>, <code>or</code></td><td>These are short-circuiting boolean operators.</td></tr><tr><td>Equality</td><td><code>==</code>, <code>!=</code></td><td>String, numeric, and boolean equality. If the operands are of different types then <code>==</code> will evaluate <code>false</code>, and <code>!=</code> will evaluate <code>true</code>.</td></tr><tr><td>Equality</td><td><code>starts-with</code></td><td>String prefix equality, <code>"hello world" starts-with "hello"</code> evaluates as <code>true</code>. It is an error to use a non-string type as an operand.</td></tr><tr><td>Equality</td><td><code>matches</code></td><td>String pattern matching, <code>"hello world" matches /hello.*/</code> evaluates as <code>true</code>. It is an error to use a non-string type as an operand.</td></tr><tr><td>Numeric comparison</td><td><code>&gt;=</code>, <code>&gt;</code>, <code>⇐</code>, <code>&lt;</code></td><td>Numeric comparisons. It is an error to use a non-numeric type as an operand.</td></tr><tr><td>Negation</td><td><code>not</code></td><td><div><div><p>Boolean negation.</p></div><div><p>Note that <code>not</code> has very high precedence and so binds very tightly. Use sub-expressions to apply <code>not</code> to more complex expressions. For example, with <code>foo</code> being <code>true</code> and <code>bar</code> being <code>false</code>:</p></div><div><ul><li><p><code>not foo and bar</code> evaluates to <code>false</code></p></li><li><p><code>not (foo and bar)</code> evaluates to <code>true</code></p></li></ul></div></div></td></tr></tbody></table>

* * *

#### **`filters`**

Job filters are deprecated. Use expression-based job filters instead. See [Expression-based job filters](#expression-based-job-filters) for more information.

Filter job execution within a workflow based on the following:

*   Branch
    
*   Tag
    
*   Expression-based condition
    

Job filters can have the keys `branches` or `tags`.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `filters` | N | Map | A map or string to define rules for job execution. Branch and tag filters require a map. Expression-based filters require a string. |

The following is an example of how the CircleCI documentation project uses a regular expression to filter running a job in a workflow only on a specific branch:

```yaml
# ...
workflows:
  build-deploy:
    jobs:
      - js_build
      - build_server_pdfs: # << the job to conditionally run based on the filter-by-branch-name.
          filters: pipeline.git.branch starts-with "server/" # only run on branches starting with server/
```

You can read more about using regular expressions in your config in the [Using Workflows to Schedule Jobs](https://circleci.com/docs/guides/orchestrate/workflows/#using-regular-expressions-to-filter-tags-and-branches) page.

* * *

#### **`branches`**

Job filters are deprecated. Use expression-based job filters instead. See [Expression-based job filters](#expression-based-job-filters) for more information.

The branches filter can have the keys `only` and `ignore`, which map to a single string naming a branch. You may also use regular expressions to match against branches by enclosing them with slashes, or map to a list of such strings. Regular expressions must match the **entire** string.

*   Any branches that match `only` run the job.
    
*   Any branches that match `ignore` do not run the job.
    
*   If you specify neither `only` nor `ignore`, the job runs on all branches.
    
*   If you specify both `only` and `ignore`, CircleCI checks `only` before `ignore`.
    

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `branches` | N | Map | A map defining rules for execution on specific branches. |
| `only` | N | String, or list of strings | Either a single branch specifier, or a list of branch specifiers. |
| `ignore` | N | String, or list of strings | Either a single branch specifier, or a list of branch specifiers. |

```yaml
workflows:
  dev_stage_pre-prod:
    jobs:
      - test_dev:
          filters:  # using regex filters requires the entire branch to match
            branches:
              only:  # only branches matching the below regex filters will run
                - dev
                - /user-.*/
      - test_stage:
          filters:
            branches:
              only: stage
      - test_pre-prod:
          filters:
            branches:
              only: /pre-prod(?:-.+)?$/
```

* * *

#### **`tags`**

Job filters are deprecated. Use expression-based job filters instead. See [Expression-based job filters](#expression-based-job-filters) for more information.

CircleCI does not run workflows for tags unless you explicitly specify tag filters. If a job requires any other jobs (directly or indirectly), you must specify tag filters for those jobs.

Tags can have the keys `only` and `ignore`. You may also use regular expressions to match against tags by enclosing them with slashes, or map to a list of such strings. Regular expressions must match the **entire** string. Both lightweight and annotated tags are supported.

*   Any tags that match `only` runs the job.
    
*   Any tags that match `ignore` do not run the job.
    
*   If neither `only` nor `ignore` are specified then the job is skipped for all tags.
    
*   If both `only` and `ignore` are specified the `only` is considered before `ignore`.
    

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `tags` | N | Map | A map defining rules for execution on specific tags |
| `only` | N | String, or List of Strings | Either a single tag specifier, or a list of tag specifiers |
| `ignore` | N | String, or List of Strings | Either a single tag specifier, or a list of tag specifiers |

For more information, see the [Executing Workflows for a Git Tag](https://circleci.com/docs/guides/orchestrate/workflows/#executing-workflows-for-a-git-tag) section of the Workflows page.

```yaml
workflows:
  untagged-build:
    jobs:
      - build
  tagged-build:
    jobs:
      - build:
          filters:
            tags:
              only: /^v.*/
```

* * *

#### **`matrix`**

The `matrix` key is supported in `version: 2.1` configuration

The `matrix` stanza allows you to run a parameterized job multiple times with different arguments. For more information see the how-to guide on [Using Matrix Jobs](https://circleci.com/docs/guides/orchestrate/using-matrix-jobs/). In order to use the `matrix` stanza, you must use parameterized jobs.

| Key | Required | Type | Description |
| --- | --- | --- | --- |
| `parameters` | Y | Map | A map of parameter names to every value the job is called with |
| `exclude` | N | List | A list of argument maps to exclude from the matrix |
| `alias` | N | String | An alias for the matrix, usable from another job’s `requires` stanza. Defaults to the name of the job being executed |

**Example:**

Basic example of using matrix jobs which creates nine different `build` jobs

```yaml
workflows:
  workflow:
    jobs:
      - build:
          matrix:
            parameters:
              version: ["0.1", "0.2", "0.3"]
              platform: ["macos", "windows", "linux"]
```

Equivalent configuration without using matrix jobs

```yaml
workflows:
  workflow:
    jobs:
      - build:
          name: build-macos-0.1
          version: "0.1"
          platform: macos
      - build:
          name: build-macos-0.2
          version: "0.2"
          platform: macos
      - build:
          name: build-macos-0.3
          version: "0.3"
          platform: macos
      - build:
          name: build-windows-0.1
          version: "0.1"
          platform: windows
      - ...
```

* * *

#### Excluding sets of parameters from a matrix

Sometimes you may wish to run a job with every combination of arguments _except_ some value or values. You can use an `exclude` stanza to achieve this:

```yaml
workflows:
  workflow:
    jobs:
      - build:
          matrix:
            parameters:
              a: [1, 2, 3]
              b: [4, 5, 6]
            exclude:
              - a: 3
                b: 5
```

The matrix above would expand into 8 jobs: every combination of the parameters `a` and `b`, excluding `{a: 3, b: 5}`

* * *

#### Dependencies and matrix jobs

To require an entire matrix (every job within the matrix), use its `alias`. The `alias` defaults to the name of the job being invoked.

```yaml
workflows:
  workflow:
    jobs:
      - deploy:
          matrix:
            parameters:
              version: ["0.1", "0.2"]
      - another-job:
          requires:
            - deploy
```

This means that `another-job` will require both deploy jobs in the matrix to finish before it runs.

Matrix jobs expose their parameter values via `<< matrix.* >>` which can be used to generate more complex workflows. For example, here is a `deploy` matrix where each job waits for its respective `build` job in another matrix.

```yaml
workflows:
  workflow:
    jobs:
      - build:
          name: build-v<< matrix.version >>
          matrix:
            parameters:
              version: ["0.1", "0.2"]
      - deploy:
          name: deploy-v<< matrix.version >>
          matrix:
            parameters:
              version: ["0.1", "0.2"]
          requires:
            - build-v<< matrix.version >>
```

This workflow expands to:

```yaml
workflows:
  workflow:
    jobs:
      - build:
          name: build-v0.1
          version: "0.1"
      - build:
          name: build-v0.2
          version: "0.2"
      - deploy:
          name: deploy-v0.1
          version: "0.1"
          requires:
            - build-v0.1
      - deploy:
          name: deploy-v0.2
          version: "0.2"
          requires:
            - build-v0.2
```

* * *

#### **`pre-steps`** and **`post-steps`**

Pre-steps and post-steps are supported in `version: 2.1` configuration

Every job invocation in a workflow may optionally accept two special arguments: `pre-steps` and `post-steps`.

Steps under `pre-steps` are executed before any of the other steps in the job. The steps under `post-steps` are executed after all of the other steps.

Pre and post steps allow you to execute steps in a given job without modifying the job. Pre and post steps are useful, for example, to run custom setup steps before job execution.

```yaml
version: 2.1

jobs:
  bar:
    machine:
      image: ubuntu-2604:current
    steps:
      - checkout
      - run:
          command: echo "building"
      - run:
          command: echo "testing"

workflows:
  build:
    jobs:
      - bar:
          pre-steps: # steps to run before steps defined in the job bar
            - run:
                command: echo "install custom dependency"
          post-steps: # steps to run after steps defined in the job bar
            - run:
                command: echo "upload artifact to s3"
```

* * *

## Using expressions in your configuration

CircleCI configuration supports expressions for dynamic value evaluation. Expressions can include pipeline values, pipeline parameters, literals, and operators such as `and`, `or`, and comparison operators.

### Expressions in configuration fields

Configuration fields accept expressions either directly or as string values. When you provide a string value, you can use `<< >>` delimiters to mark a section of the string to be interpreted as an expression.

You can write the expression in a configuration field as shown in the following example:

Use expression to determine parallelism for a job

```yaml
jobs:
  test:
    docker:
      - image: cimg/base:current
    parallelism: << pipeline.git.branch == "main" and 10 or 1 >>
    steps:
      - checkout
      - run: run_tests
```

In this example, `parallelism` is set to `10` when running on the `main` branch, and `1` on all other branches.

Use direct expressions in job filters and using `when` or `unless` in your workflows. For example:

Direct expression in a job filter

```yaml
workflows:
  my-workflow:
    jobs:
      - build:
          filters: pipeline.git.branch == "main" or pipeline.git.branch starts-with "release/"
```

Workflow `when` expression

```yaml
workflows:
  deploy-workflow:
    when: pipeline.git.tag starts-with "v" and pipeline.trigger_source == "webhook"
    jobs:
      - deploy
```

For all other configuration fields, you must use the `<< >>` delimiters to mark the expression as an expression, as shown in other examples in this section.

### Expressions within strings

When you need to include an expression within a larger string value, use `<< >>` delimiters to mark the expression:

```yaml
- run:
    name: Print branch info
    command: |
      echo "Running on << pipeline.git.branch or "unknown branch" >>"
```

In this example, the `<< >>` delimiters mark `pipeline.git.branch or "unknown branch"` as an expression. If `pipeline.git.branch` is null (for example, when the pipeline is triggered for a tag rather than a branch), the `or` operator provides the fallback value "unknown branch".

### Conditional logic example

You can combine `and` and `or` to implement if-then-else style logic:

```yaml
parallelism: << pipeline.git.branch == "main" and 10 or 1 >>
```

*   If the condition `pipeline.git.branch == "main"` is true, the `and` expression evaluates to its second operand `10`.
    
*   If the condition is false, the `and` expression evaluates to false, and the `or` expression returns the fallback value `1`.
    

### Expression operators

The operators you can use for expressions are described in the following table. You can also group sub-expressions with parentheses `(`, `)`.

<table><thead><tr><th>Operator type</th><th>Operators</th><th>Description</th></tr></thead><tbody><tr><td>Logical</td><td><code>and</code>, <code>or</code></td><td>These are short-circuiting boolean operators.</td></tr><tr><td>Equality</td><td><code>==</code>, <code>!=</code></td><td>String, numeric, and boolean equality. If the operands are of different types then <code>==</code> will evaluate <code>false</code>, and <code>!=</code> will evaluate <code>true</code>.</td></tr><tr><td>Equality</td><td><code>starts-with</code></td><td>String prefix equality, <code>"hello world" starts-with "hello"</code> evaluates as <code>true</code>. It is an error to use a non-string type as an operand.</td></tr><tr><td>Equality</td><td><code>matches</code></td><td>String pattern matching, <code>"hello world" matches /hello.*/</code> evaluates as <code>true</code>. It is an error to use a non-string type as an operand.</td></tr><tr><td>Numeric comparison</td><td><code>&gt;=</code>, <code>&gt;</code>, <code>⇐</code>, <code>&lt;</code></td><td>Numeric comparisons. It is an error to use a non-numeric type as an operand.</td></tr><tr><td>Negation</td><td><code>not</code></td><td><div><div><p>Boolean negation.</p></div><div><p>Note that <code>not</code> has very high precedence and so binds very tightly. Use sub-expressions to apply <code>not</code> to more complex expressions. For example, with <code>foo</code> being <code>true</code> and <code>bar</code> being <code>false</code>:</p></div><div><ul><li><p><code>not foo and bar</code> evaluates to <code>false</code></p></li><li><p><code>not (foo and bar)</code> evaluates to <code>true</code></p></li></ul></div></div></td></tr></tbody></table>

### Valid parameter names

To use a pipeline parameter in an expression, the parameter name must follow these rules:

*   Start with a letter.
    
*   Can contain upper-case letters (`A`\-`Z`) and lower-case letters (`a`\-`z`).
    
*   Can contain digits (`0`\-`9`).
    
*   Can contain hyphens (`-`), underscores (`_`), and periods (`.`).
    
*   Cannot contain consecutive periods (`..`).
    

If a pipeline parameter has a name that does not follow these rules, CircleCI performs string replacement instead of evaluating an expression.

### Expression examples

You can find usage examples on the [Orchestration Cookbook](https://circleci.com/docs/guides/orchestrate/orchestration-cookbook/) page.

* * *

## Logic statement syntax

CircleCI recommends using [Expressions](#using-expressions-in-your-configuration) for conditional logic in your configuration. Expressions can reference pipeline values and pipeline parameters and use comparison and logic operators.

Certain dynamic configuration features accept logic statements as arguments. Logic statements are evaluated to boolean values at configuration compilation time, that is, before the workflow is run. The group of logic statements includes:

| Type | Arguments | `true` if | Example |
| --- | --- | --- | --- |
| YAML literal | None | is truthy | `true`/`42`/`"a string"` |
| [Pipeline Value](https://circleci.com/docs/guides/orchestrate/pipeline-variables/#pipeline-values) | None | resolves to a truthy value | `<< pipeline.git.branch >>` |
| [Pipeline Parameter](https://circleci.com/docs/guides/orchestrate/pipeline-variables/#pipeline-parameters-in-configuration) | None | resolves to a truthy value | `<< pipeline.parameters.my-parameter >>` |
| `and` | N logic statements | all arguments are truthy | `and: [ true, true, false ]` |
| `or` | N logic statements | any argument is truthy | `or: [ false, true, false ]` |
| `not` | 1 logic statement | the argument is not truthy | `not: true` |
| `equal` | N values | all arguments evaluate to equal values | `equal: [ 42, << pipeline.number >>]` |
| `matches` | `pattern` and `value` | `value` matches the `pattern` | `matches: { pattern: "^feature-.$", value: << pipeline.git.branch >> }+` |

The following logic values are considered falsy:

*   false.
    
*   null.
    
*   0
    
*   NaN
    
*   empty strings ("").
    
*   statements with no arguments.
    

All other values are truthy. Also note that using logic with an empty list will cause a validation error.

Logic statements always evaluate to a boolean value at the top level, and coerce as necessary. They can be nested in an arbitrary fashion, according to their argument specifications, and to a maximum depth of 100 levels.

`matches` uses [Java regular expressions](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html) for its `pattern`. A full match pattern must be provided, prefix matching is not an option. Though, it is recommended to enclose a pattern in `^` and `$` to avoid accidental partial matches.

When using logic statements at the workflow level, do not include the `condition:` key (the `condition` key is only needed for `job` level logic statements).

### Logic statement example

```yaml
workflows:
  my-workflow:
    when:
      or:
        - equal: [ main, << pipeline.git.branch >> ]
        - equal: [ staging, << pipeline.git.branch >> ]
```

Compare this with the expression syntax equivalent:

```yaml
workflows:
  my-workflow:
    when: pipeline.git.branch == "main" or pipeline.git.branch == "staging"
```

## Example full configuration

**Using Docker?** Authenticating Docker pulls from image registries is recommended when using the Docker execution environment. Authenticated pulls allow access to private Docker images, and may also grant higher rate limits, depending on your registry provider. For further information, see [Using Docker Authenticated Pulls](https://circleci.com/docs/guides/execution-managed/private-images/).

```yaml
version: 2.1
jobs:
  build:
    docker:
      - image: ubuntu:23.04

      - image: mongo:6.0.14
        command: [mongod, --smallfiles]

      - image: postgres:14.12
        # some containers require setting environment variables
        environment:
          POSTGRES_USER: user

      - image: redis@sha256:54057dd7e125ca41afe526a877e8bd35ec2cdd33b9217e022ed37bdcf7d09673

      - image: rabbitmq:3.12.12

    environment:
      TEST_REPORTS: /tmp/test-reports

    working_directory: ~/my-project

    steps:
      - checkout

      - run:
          command: echo 127.0.0.1 devhost | sudo tee -a /etc/hosts

      # Create Postgres users and database
      # Note the YAML heredoc '|' for nicer formatting
      - run: |
          sudo -u root createuser -h localhost --superuser ubuntu &&
          sudo createdb -h localhost test_db

      - restore_cache:
          keys:
            - v1-my-project-{{ checksum "project.clj" }}
            - v1-my-project-

      - run:
          environment:
            SSH_TARGET: "localhost"
            TEST_ENV: "linux"
          command: |
            set -xu
            mkdir -p ${TEST_REPORTS}
            run-tests.sh
            cp out/tests/*.xml ${TEST_REPORTS}

      - run: |
          set -xu
          mkdir -p /tmp/artifacts
          create_jars.sh << pipeline.number >>
          cp *.jar /tmp/artifacts

      - save_cache:
          key: v1-my-project-{{ checksum "project.clj" }}
          paths:
            - ~/.m2

      # Save artifacts
      - store_artifacts:
          path: /tmp/artifacts
          destination: build

      # Upload test results
      - store_test_results:
          path: /tmp/test-reports

  deploy-stage:
    docker:
      - image: ubuntu:23.04
    working_directory: /tmp/my-project
    steps:
      - run:
          name: Deploy if tests pass and branch is Staging
          command: ansible-playbook site.yml -i staging

  deploy-prod:
    docker:
      - image: ubuntu:23.04
    working_directory: /tmp/my-project
    steps:
      - run:
          name: Deploy if tests pass and branch is Main
          command: ansible-playbook site.yml -i production

workflows:
  build-deploy:
    jobs:
      - build:
          filters: pipeline.git.branch != "develop" and not (pipeline.git.branch matches /feature-.*/) # only run the build job on branches other than develop and any branch starting with feature-
      - deploy-stage:
          requires:
            - build
          filters: pipeline.git.branch == "staging" # only run the deploy-stage job on the staging branch
      - deploy-prod:
          requires:
            - build
          filters: pipeline.git.branch == "main" # only run the deploy-prod job on the main branch
```