---
title: "Using the Docker execution environment"
description: "Learn how to configure your jobs to run in the Docker execution environment"
platform: "Cloud, Server"
doc_version: "unversioned"
last_updated: "2026-10-15"
cloud_plans: "Free, Performance, Scale"
version_control: "All supported providers"
---

> For current CircleCI product defaults, deprecated patterns, and Cloud/Server differences, see [AGENTS.md](https://circleci.com/docs/AGENTS.md).
>
> For the complete documentation index and site structure, see [llms.txt](https://circleci.com/docs/llms.txt).

# Using the Docker execution environment

**Cloud plans:** Free, Performance, Scale

**Version control:** [All supported providers](https://circleci.com/docs/guides/integration/version-control-system-integration-overview/)

You can use the Docker execution environment to run your [Jobs](https://circleci.com/docs/guides/orchestrate/jobs-steps/) in Docker containers. You access the Docker execution environment using the [Docker executor](https://circleci.com/docs/reference/configuration-reference/#docker). Using Docker increases performance because it builds only what your application requires.

Specify a Docker image in your [`.circleci/config.yml`](https://circleci.com/docs/reference/configuration-reference/) file to spin up a container. All steps in your job run in this container.

**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/execute/private-images/).

```yaml
jobs:
  my-job:
    docker:
      - image: cimg/node:lts
```

A container is an instance of a specified Docker image. CircleCI refers to the first image listed in your configuration for a job as the _primary_ container image, and this is where all steps in the job run. You can also specify _secondary_ containers to run alongside the primary container for services such as databases.

For an introduction to Docker concepts, see the [Docker Overview documentation](https://docs.docker.com/engine/docker-overview/).

CircleCI maintains convenience images on Docker Hub for popular languages. See [the CircleCI Developer Hub](https://circleci.com/developer/images) for a complete list of image names and tags.

If you need a Docker image that installs Docker and has Git, consider using `cimg/base:current`.

## Specifying Docker images

You can specify Docker images in two ways:

*   By the image name and version tag on Docker Hub.
    
*   By using the URL to an image in a registry.
    

CircleCI supports nearly all public images on Docker Hub and other Docker registries by default when you specify the `docker:` key in your `config.yml` file. If you want to work with private images/registries, refer to [Using Docker Authenticated Pulls](https://circleci.com/docs/guides/execute/private-images/).

The following examples show how you can use public images from various sources:

### CircleCI’s public convenience images on Docker Hub

*   `name:tag`
    
    *   `cimg/node:14.17-browsers`
        
    
*   `name@digest`
    
    *   `cimg/node@sha256:aa6d08a04d13dd8a...`
        
    

### Public images on Docker Hub

*   `name:tag`
    
    *   `alpine:3.13`
        
    
*   `name@digest`
    
    *   `alpine@sha256:e15947432b813e8f...`
        
    

### Public images on Docker registries

*   `image_full_url:tag`
    
    *   `gcr.io/google-containers/busybox:1.24`
        
    
*   `image_full_url@digest`
    
    *   `gcr.io/google-containers/busybox@sha256:4bdd623e848417d9612...`
        
    

## Available Docker resource classes

The [`resource_class`](https://circleci.com/docs/reference/configuration-reference/#resourceclass) key allows you to configure CPU and RAM resources for each job.

Specify a resource class using the `resource_class` key, as follows:

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

### x86

For the Docker execution environment, the following resource classes are available for the x86 architecture:

#### Gen1

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** |

#### 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** |

### Arm

The following resource classes are available for Arm with Docker:

#### Gen1

**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** |

#### Gen2 Beta

**Arm gen2 for Docker is currently in beta.** Performance and pricing are tentative and may change when this feature becomes generally available.

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 |
| --- | --- | --- | --- | --- |
| `arm.medium.gen2` | 2 | 8 GB | **Yes** | **No** |
| `arm.large.gen2` | 4 | 16 GB | **Yes** | **No** |
| `arm.xlarge.gen2` | 8 | 32 GB | **Yes** | **No** |
| `arm.2xlarge.gen2` | 16 | 64 GB | **Yes** | **No** |

### View resource usage

To view the compute resource usage for the duration of a job in the CircleCI web app:

1.  In the [CircleCI web app](https://app.circleci.com), select your org from the org cards on your user homepage.
    
2.  Select **Pipelines** from the sidebar and locate your pipeline from the list. You can use the project, branch, date, and status search options to help.
    
3.  Select the job you want to access by selecting the job name.
    
4.  Select the **Resources** tab to view CPU and RAM usage for the duration of the job.
    

You can use these insights to decide whether to make changes to the job’s configured resource class.

> **Image:** Resources tab

Figure 1. Resources tab in web app for a job

## Docker gen2

Resource classes running on gen2 infrastructure offer significant performance and cost improvements over their gen1 equivalents.

### Performance improvements

Using more modern compute, gen2 instances deliver significant performance improvements compared to gen1 equivalents, based on benchmarks measured during the beta period:

*   x86 gen2: up to 71% faster.
    
*   Arm gen2: up to 94% faster.
    

Actual performance gains depend on your specific workloads.

x86 gen2 resources have a higher cost in credits per minute than their gen1 equivalents. See our [Pricing Page](https://circleci.com/pricing/price-list/) for details.

### Using gen2

To use a gen2 resource class, specify a `large.gen2` or equivalent class in your job configuration. For Arm, use the equivalent `arm.*.gen2` class, for example `arm.large.gen2`:

```yaml
version: 2.1
jobs:
  my-job:
    docker:
      - image: cimg/base:current
    resource_class: large.gen2
    steps:
      # ... steps for your job
```

## Docker benefits and limitations

Docker also has built-in image caching and enables you to build, run, and publish Docker images via [Remote Docker](https://circleci.com/docs/guides/execute/building-docker-images/). Consider the requirements of your application as well. If the following are true for your application, Docker may be the right choice:

*   Your application is self-contained.
    
*   Your application requires additional services for testing.
    
*   You distribute your application as a Docker image (requires using [Remote Docker](https://circleci.com/docs/guides/execute/building-docker-images/)).
    
*   You want to use `docker compose` (requires using [Remote Docker](https://circleci.com/docs/guides/execute/building-docker-images/)).
    

Choosing Docker limits your runs to what is possible from within a Docker container (including our [Remote Docker](https://circleci.com/docs/guides/execute/building-docker-images/) feature). For instance, if you require low-level access to the network or need to mount external volumes, consider using `machine`.

The table below shows tradeoffs between using a `docker` image versus an Ubuntu-based `machine` image as the environment for the container:

| Capability | `docker` | `machine` |
| --- | --- | --- |
| Start time | Instant | Instant for most (1) |
| Clean environment | Yes | Yes |
| Custom images | Yes (2) | No |
| Build Docker images | Yes (3) | Yes |
| Full control over job environment | No | Yes |
| Full root access | No | Yes |
| Run multiple databases | Yes (4) | Yes |
| Run multiple versions of the same software | No | Yes |
| [Docker Layer Caching](https://circleci.com/docs/guides/optimize/docker-layer-caching/) | Yes | Yes |
| Run privileged containers | No | Yes |
| Use Docker compose with volumes | No | Yes |
| [Configurable Resources](https://circleci.com/docs/reference/configuration-reference/#resourceclass) | Yes | Yes |

(1) Some less commonly used execution environments may see up to 90 seconds of start time.

(2) See [Using Custom Docker Images](https://circleci.com/docs/guides/execute/custom-images/).

(3) Requires using [Remote Docker](https://circleci.com/docs/guides/execute/building-docker-images/).

(4) While you can run multiple databases with Docker, all images (primary and secondary) share the underlying resource limits. Performance in this regard depends on the compute capacities of your plan.

For more information on `machine`, see the next section below.

## Docker image best practices

*   If you encounter problems with rate limits imposed by your registry provider, using [Authenticated Docker Pulls](https://circleci.com/docs/guides/execute/private-images/) may grant higher limits.
    
*   CircleCI has partnered with Docker to ensure that our users can continue to access Docker Hub without rate limits. You are not impacted by rate limits when pulling images from Docker Hub through CircleCI. We encourage you to [Add Docker Hub Authentication](https://circleci.com/docs/guides/execute/private-images/) to your CircleCI configuration and consider upgrading your Docker Hub plan, as appropriate, to prevent any impact from rate limits.
    
*   Avoid using mutable tags like `latest` or `1` as the image version in your `config.yml` file. It is best practice to use precise image versions or digests, like `redis:3.2.7` or `redis@sha256:95f0c9434f37db0a4f...` as shown in the examples. Mutable tags often lead to unexpected changes in your job environment. CircleCI cannot guarantee that mutable tags return an up-to-date version of an image. You may specify `alpine:latest` and actually get a stale cache from a month ago.
    
*   If you experience increases in your run times due to installing additional tools during execution, consider creating and using a custom-built image that comes with those tools pre-installed. See the [Using Custom-Built Docker Images](https://circleci.com/docs/guides/execute/custom-images/) page for more information.
    
*   When you use [AWS ECR](https://circleci.com/docs/guides/execute/private-images/#aws-ecr) images, it is best practice to use `us-east-1` region. Our job execution infrastructure is in `us-east-1` region, so having your image on the same region reduces the image download time.
    
*   If your pipelines fail despite little to no changes in your project, you may need to investigate upstream issues with the Docker images you use.
    

More details on the Docker executor are available on the [Configuration Reference](https://circleci.com/docs/reference/configuration-reference/) page.

## Using multiple Docker images

You can specify multiple images for your job. Each image spins up a separate container.

Using multiple containers for a job is useful if you need a database for your tests, or another required service.

When using a multi-container job setup, all containers run in a common network, and every exposed port is available on `localhost`. All containers can communicate with one another. You can also change this hostname using the `name` key. For a full list of options, see the [Configuration Reference](https://circleci.com/docs/reference/configuration-reference/#docker).

**In a multi-image configuration job, the container created by the first image listed executes all steps**.

```yaml
jobs:
  build:
    docker:
    # Primary container image where all steps run.
     - image: cimg/base:current
    # Service container image on common network.
     - image: cimg/mariadb:10.6

    steps:
      # command will execute in an Ubuntu-based container
      # and can access MariaDB on localhost
      - run: sleep 5 && nc -vz localhost 3306
```

## RAM disks

A RAM disk is available at `/mnt/ramdisk` that offers a [temporary file storage paradigm](https://en.wikipedia.org/wiki/Tmpfs), like `/dev/shm`. Using the RAM disk can help speed up your build. Ensure your `resource_class` has enough memory to fit the entire project contents (all files checked out from git, dependencies, assets generated, etc.).

The simplest way to use this RAM disk is to configure the `working_directory` of a job to be `/mnt/ramdisk`:

```yaml
jobs:
  build:
    docker:
     - image: alpine

    working_directory: /mnt/ramdisk

    steps:
      - run: |
          echo '#!/bin/sh' > run.sh
          echo 'echo Hello world!' >> run.sh
          chmod +x run.sh
      - run: ./run.sh
```

## Caching Docker images

This section discusses caching the Docker images used to spin up a Docker execution environment. It does not apply to [Docker Layer Caching](https://circleci.com/docs/guides/optimize/docker-layer-caching/), which is a feature used to speed up building Docker images in your projects.

The time it takes to spin up a Docker container to run a job can vary based on several factors. These include the size of the image and whether some, or all, of the layers are already cached on the underlying Docker host machine.

If you are using a more popular image, such as CircleCI convenience images, then cache hits are more frequent across a larger number of layers. Most of the popular CircleCI images use the same base image. The majority of the base layers are the same between images, so you have a greater chance of having a cache hit.

The environment has to spin up for every job, regardless of whether it is in the same workflow or if it is a re-run/subsequent run. (CircleCI never reuses containers, for security reasons.) Once the job finishes, CircleCI destroys the container. Jobs, even in the same workflow, are not guaranteed to run on the same Docker host machine. This implies that the cache status may differ.

In all cases, cache hits are not guaranteed, but are a bonus convenience when available. With this in mind, account for a worst-case scenario of a full image pull in all jobs.

You cannot control caching availability via settings or configuration. Choosing a popular image, such as [CircleCI convenience images](https://circleci.com/developer/images), increases the chances of hitting cached layers in the "Spin Up Environment" step.

## Next steps

Find out more about using [Convenience Images](https://circleci.com/docs/guides/execute/circleci-images/) with the Docker executor.