(Breaking change) Sunsetting Configuration Version 2.0

IMPORTANT: :warning: This post has been superseded. This breaking change has been consolidated with two others into a single post, and the effective date is now July 17, 2026. Please refer to the updated Discuss post for the up to date details. The information below is retained for reference only.

Old discuss post

CircleCI will end support for configuration version: 2 | 2.0 on June 27, 2026. After this date, all pipelines must use version: 2.1. This post explains what’s changing, how to migrate, and how to resolve common issues.

Background

CircleCI has supported two config versions for several years: v2 (legacy) and v2.1 (current). Version 2.1 introduced orbs, pipeline parameters, reusable commands, reusable executors, and a well-defined schema with strict validation. As we build next-generation config tooling, we are consolidating onto v2.1 as the single supported configuration format.

How to migrate

Step 1: Update the version key

Change the first line of your config from:

version: 2 | 2.0

to:

version: 2.1

Step 2: Validate your config

Use one of the following methods to check that your config compiles successfully under version 2.1:

Using the CircleCI CLI (Recommended):

circleci config validate <path-to-config.yml>

If you don’t have the CLI installed, see the CLI installation docs.

Using the in-app config editor:

Navigate to your project in the CircleCI web app and open the configuration file editor. The editor will automatically validate your config and surface any errors.

Step 3: Fix any validation errors

If validation fails, your config likely uses patterns that were accepted by v2 but are not part of the v2.1 specification. See the common issues section below.

Common issues and how to fix them

HEREDOC syntax (\`<<\`)

Symptom: Error about unresolved pipeline expressions in run: steps.

Cause: Version 2.1 interprets << as a pipeline parameter expression. If your shell scripts use heredocs (e.g., cat <<EOF), the compiler will try to evaluate them.

Fix: Escape the << with a backslash:

# Before
- run:
    command: |
      cat <<EOF
      some content
      EOF

# After
- run:
    command: |
      cat \<<EOF
      some content
      EOF
Illegal characters in job names

Symptom: Error about invalid job name.

Cause: Version 2.1 requires job names to contain only letters, numbers, spaces, hyphens, and underscores. Characters like colons, parentheses, and commas are not allowed.

Fix: Rename any affected jobs.

# Before
jobs:
  build (linux):
    ...

# After
jobs:
  build-linux:
    ...
Unrecognized keys on job definitions

Symptom: Error about unexpected keys on a job.

Cause: Version 2.1 has a stricter schema and will reject keys that are not part of the job configuration reference.

Fix: Remove any keys from your job definitions that are not documented in the configuration reference. If a custom key was being used by external tooling that reads your config, consider moving that data to environment variables or a separate file.

\`branches:\` on job definitions

Symptom: Error about branches not being a valid key on a job.

Cause: Job-level branch filtering was replaced by workflow-level filters in v2.1.

Fix: Move branch filtering into your workflow configuration:

# Before (v2)
jobs:
  deploy:
    branches:
      only:
        - main

# After (v2.1)
workflows:
  build-and-deploy:
    jobs:
      - deploy:
          filters: pipeline.git.branch == "main"
Unsupported keys on Docker image definitions

Symptom: Error about unexpected keys on a Docker image definition.

Cause: Version 2.1 has a stricter schema for Docker image entries and will reject keys that are not part of the specification. If your config includes extra keys on secondary containers, they will need to be removed.

Fix: Remove any unsupported keys from your Docker image definitions. Refer to the Docker executor reference for the supported set of keys.

# Before
jobs:
  build:
    docker:
      - image: cimg/node:20.0
      - image: postgres:15
        environment:
          POSTGRES_DB: mydb
        ports:
          - "5432:5432"

# After
jobs:
  build:
    docker:
      - image: cimg/node:20.0
      - image: postgres:15
        environment:
          POSTGRES_DB: mydb
\`working-directory\` vs \`working_directory\`

Symptom: Job runs in the wrong directory or error about an unknown key.

Cause: The correct key is working_directory (with an underscore). The kebab-case form working-directory was silently ignored by v2, meaning it was never actually applied.

Fix: Use working_directory (underscore).

\`resource_class\` inside \`machine:\` executor

Symptom: Error about resource_class being in the wrong location.

Cause: In v2.1, resource_class must be a top-level key on the job, not nested inside the machine: block.

Fix:

# Before
jobs:
  build:
    machine:
      image: ubuntu-2404:current
      resource_class: large

# After
jobs:
  build:
    machine:
      image: ubuntu-2404:current
    resource_class: large
Pipeline parameter syntax

Symptom: Error about an undeclared pipeline parameter.

Cause: Expressions like << pipeline.parameters.x >> are treated as live expressions in v2.1 and must be declared. In v2, they were passed through as plain text.

Fix: Either declare the parameters in a parameters: block at the top of your config, or remove the expressions if they were not intended to be dynamic.

\`name:\` key on jobs

Symptom: Error about name not being a valid job key.

Cause: The name: key is not supported directly on job definitions in v2.1.

Fix: Remove the name: key from job definitions. To give a job a display name, set it in the workflow entry instead:

workflows:
  build:
    jobs:
      - my-job:
          name: "My Custom Name"
`CIRCLE_COMPARE_URL` not available in v2.1

Symptom: The environment variable CIRCLE_COMPARE_URL is empty or undefined.

Cause: CIRCLE_COMPARE_URL is only available in v2 configs and is not carried over to v2.1.

Fix: Use pipeline values to construct the compare URL yourself:

# Before (v2) — CIRCLE_COMPARE_URL was automatically available
- run: echo $CIRCLE_COMPARE_URL

# After (v2.1) — define it yourself using pipeline values
jobs:
  my-job:
    environment:
      CIRCLE_COMPARE_URL: << pipeline.project.git_url >>/compare/<< pipeline.git.base_revision >>..<<pipeline.git.revision>>
    steps:
      - run: echo $CIRCLE_COMPARE_URL

Need help?

If you have questions or run into issues migrating, reply to this thread or open a support ticket. You can also consult the configuration reference for the full v2.1 schema.

1 Like