---
title: "Use a GitHub Actions workflow file as your pipeline configuration"
description: "Set up a CircleCI pipeline that runs an existing GitHub Actions workflow file, and check which GitHub Actions features are supported."
doc_version: "unversioned"
last_updated: "2026-09-22"
---

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

# Use a GitHub Actions workflow file as your pipeline configuration Preview

**GitHub Actions workflow support is in Preview.** This feature is in its early stages and you may encounter bugs, unexpected behavior, or incomplete features. Post all feedback to [The CircleCI ideas board](https://circleci.canny.io/cloud-feature-requests/p/github-actions-support-now-available-on-circleci).

A CircleCI pipeline is generally defined by a CircleCI configuration file. You can instead use an existing GitHub Actions workflow file as your pipeline configuration. CircleCI runs your GitHub Actions workflow on CircleCI compute. Your workflow file stays where it is, in `.github/workflows/`, and you do not need to translate it into CircleCI syntax.

Running your GitHub Actions workflow as it is helps when you want to move work onto CircleCI without rewriting your configuration first. It also lets you compare the two platforms using the same workflow. A subset of GitHub Actions features is supported. Before you start, check the [GitHub Actions Feature Support](#github-actions-feature-support) section to confirm your workflow uses supported features.

If you would rather convert your workflow into CircleCI syntax, see the [Migrate From GitHub Actions](https://circleci.com/docs/guides/migrate/migrating-from-github/) page and the [CircleCI configuration translator](https://circleci.com/developer/tools/configTranslator).

## Prerequisites

*   A CircleCI Cloud organization integrated with GitHub using the CircleCI GitHub App.
    
*   A GitHub repository with a GitHub Actions workflow file.
    
*   A workflow that runs on Linux. CircleCI does not support macOS or Windows for GitHub Actions workflows. For macOS and Windows builds you can migrate to use CircleCI YAML config. See the [Migrate From GitHub Actions](https://circleci.com/docs/guides/migrate/migrating-from-github/) page for more information.
    

To use the CircleCI CLI steps on this page, you also need the following:

*   CircleCI CLI v1.0 or later, authenticated with `circleci auth login`. Run `circleci auth me` to confirm. See the [CircleCI CLI](https://circleci.com/docs/guides/toolkit/circleci-cli/) page.
    
*   The GitHub CLI (`gh`), used to look up your repository ID. Any other method of finding the repository ID works too.
    

## Set up a new project with a GitHub Actions workflow file

To set up a new project with a GitHub Actions workflow file, follow the steps in the web app or the CircleCI CLI.

<Tabs>
<Tab title="Web app">

When you create a project, CircleCI asks where to get build instructions for your repository. Choose your existing GitHub Actions workflow file at that point.

1.  In the [CircleCI web app](https://app.circleci.com/home), select **Home** in the sidebar.
    
2.  Select **Create Project** at the top of the page, or anywhere in the **Create a project** card if this is your first project.
    
3.  Give your project a descriptive name and then select **Next: Set up a pipeline**.
    
    **Project names** must meet the following requirements:
    
    *   Begin with a letter.
        
    *   Be 3-40 characters long.
        
    *   Contain only letters, numbers, or the following characters: `" - _ . : ! & + [ ] " ;`.
        
    
4.  Next, set up your first pipeline for your project. Pipelines define the executable commands and scripts for your CI/CD processes. The first step is to name your pipeline. Use a name that describes the purpose of the pipeline, for example, `build-and-test`. Then select **Next: Choose a repo**.
    
5.  Choose a repo for your pipeline. CircleCI checks out the code from this repo when your pipeline runs.
    
    If you **already have a connection**, select your repo from the list. To connect an additional provider, select **\+ Add** and then choose its tile.
    
    If you have **no connection** yet, select your provider’s tile and follow that provider’s instructions. Granting access applies to any project in your organization, and you can update repo access at any time.
    
    Select the **GitHub Cloud** tile if you do not already have a connection. CircleCI redirects you to GitHub, where you install and authorize the CircleCI GitHub App. Installing the app is a one-time step.
    
6.  On the **Select your config source** step, select **Use existing GitHub Actions workflow file**, enter the path to the GitHub Actions workflow file, then select **Continue**.
    
7.  Set up the triggers for your pipeline. CircleCI adds one trigger by default, to build your project on every commit. You can [Add More Triggers](https://circleci.com/docs/guides/orchestrate/set-up-triggers/) at this point. Select **Next: review and finish setup**
    
8.  Review what you have set up, then select **Finish setup**.
    

Your pipelines page opens. The next time your trigger fires, CircleCI runs the jobs from your GitHub Actions workflow file.

</Tab>
<Tab title="CircleCI CLI">

Run these commands from your repository directory. Every command below resolves your project from the git remote, so you do not need to pass a project slug.

1.  Create the project. CircleCI names it after the current repository.
    
    ```shell
    circleci project create --json
    ```
    
    If you belong to more than one organization, add `--org <org-slug>`. Run `circleci org list` to find it, then use `gh/<org-name>` for a GitHub organization or `circleci/<org-id>` for a `circleci` type organization.
    
2.  Find the numeric ID of your GitHub repository. You need this ID for both the pipeline definition and the trigger.
    
    ```shell
    gh api /repos/<owner>/<repo> --jq .id
    ```
    
3.  Create the pipeline definition, pointing it at your workflow file.
    
    ```shell
    circleci pipeline create \
      --name "github-actions-ci" \
      --config-provider github_app \
      --config-repo-id <github-repo-id> \
      --config-file .github/workflows/ci.yml \
      --config-file-type github-actions \
      --checkout-provider github_app \
      --checkout-repo-id <github-repo-id> \
      --json
    ```
    
    `--config-file-type github-actions` is the flag that makes this work, and it is simple to miss when following a general onboarding flow.
    
    Leave it out and CircleCI reads your workflow file as CircleCI configuration syntax. The failure is confusing rather than obvious, and looks similar to the following:
    
    ```shell
    jobs referenced in workflows that have not been defined: build
    ```
    
    Note the pipeline definition ID returned by this command. You need it in the next two steps.
    
4.  Follow the project, so that it appears on your dashboard. This step is required for OAuth organizations, with slugs beginning `gh/` or `bb/`, and is worth doing for any organization.
    
    ```shell
    circleci project follow
    ```
    
5.  Add a trigger to connect your pipeline definition to a Git event.
    
    ```shell
    circleci project trigger create \
      --pipeline-definition-id <definition-id> \
      --repo-id <github-repo-id> \
      --event-preset all-pushes \
      --json
    ```
    
    Other presets include `only-open-prs` and `default-branch-pushes`. Run `circleci help triggers` for the full list, or see the [GitHub Trigger Event Options](https://circleci.com/docs/guides/orchestrate/github-trigger-event-options/) page.
    
6.  Trigger a run to check your setup. Targeting the definition directly bypasses the trigger, so you do not need to push a commit.
    
    ```shell
    circleci pipeline run --definition-id <definition-id> --branch main --json
    circleci run watch <run-id> --failfast
    ```
    

**Check what actually ran, rather than trusting a green result.** Because some GitHub Actions features are accepted without taking effect, a passing run does not prove that every step did what your workflow file asks for. Use `circleci run get <run-id> --json` to list workflow and job IDs, `circleci job get <job-id> --json` to list steps, and `circleci job output get <job-id> --step-num <n> --strip-ansi` to read the raw step output.

</Tab>
</Tabs>

## Add a GitHub Actions pipeline to an existing project

A project can have more than one pipeline, so you can add a GitHub Actions pipeline alongside pipelines that use CircleCI configuration.

<Tabs>
<Tab title="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 **Projects** from the sidebar and locate your project from the list. You can use the search to help.
    
3.  Select the ellipsis next to your project and select **Project Settings**.
    
    You can also access project settings from each project overview page using the **Settings** button.
    
4.  Select **Project Setup** in the sidebar.
    
5.  Select **Add Pipeline**, or select the pencil icon () next to an existing pipeline to change it.
    
6.  Give your pipeline a descriptive name, for example `github-actions-ci`.
    
7.  Under **Config source**, select the repository that holds your GitHub Actions workflow file.
    
8.  Under **Config filepath**, select the **GitHub Actions workflow file** checkbox, then enter the path to your workflow file, for example `.github/workflows/ci.yml`.
    
9.  Under **Checkout source**, select the repository to check out when your workflow runs. For most projects this is the same repository you selected as the config source.
    
10.  Select **Save**.
     

Connect your new pipeline to a trigger before it can run. See the [Set Up Triggers](https://circleci.com/docs/guides/orchestrate/set-up-triggers/) page.

</Tab>
<Tab title="CircleCI CLI">

Run these commands from your repository directory, so your project resolves from the git remote.

1.  Find the numeric ID of your GitHub repository.
    
    ```shell
    gh api /repos/<owner>/<repo> --jq .id
    ```
    
2.  Create the pipeline definition in your existing project, pointing it at your workflow file. Include `--config-file-type github-actions`, or CircleCI reads your workflow file as CircleCI configuration syntax and the run fails.
    
    ```shell
    circleci pipeline create \
      --name "github-actions-ci" \
      --config-provider github_app \
      --config-repo-id <github-repo-id> \
      --config-file .github/workflows/ci.yml \
      --config-file-type github-actions \
      --checkout-provider github_app \
      --checkout-repo-id <github-repo-id> \
      --json
    ```
    
    Note the pipeline definition ID returned by this command.
    
3.  Add a trigger to connect your new pipeline definition to a Git event.
    
    ```shell
    circleci project trigger create \
      --pipeline-definition-id <definition-id> \
      --repo-id <github-repo-id> \
      --event-preset all-pushes \
      --json
    ```
    
4.  Trigger a run to check your setup.
    
    ```shell
    circleci pipeline run --definition-id <definition-id> --branch main --json
    circleci run watch <run-id> --failfast
    ```
    

**The CLI cannot tear these down.** The CLI has no command to delete a project or a pipeline definition, and no command to delete or disable a trigger. Check your flags before you create anything, and remove unwanted pipelines and triggers in the web app.

</Tab>
</Tabs>

## How it works

When you set up a pipeline to use a GitHub Actions workflow file, CircleCI does the following:

1.  **CircleCI reads your workflow file** from the config source repository, at the path you gave the pipeline.
    
2.  **CircleCI translates the workflow into a CircleCI workflow.** Each GitHub Actions job becomes a CircleCI job, and `needs:` relationships become `requires:` relationships, so your workflow graph is preserved.
    
3.  **CircleCI runs your GitHub Actions jobs.** Your steps run with GitHub Actions semantics. This covers `run:` and `uses:` steps, `${{ }}` expression evaluation, step and job outputs, and secret masking.
    

Your workflow file is never rewritten, and you do not maintain a CircleCI configuration file alongside it. You get CircleCI compute and the pipelines dashboard, running the workflow definition you already have.

CircleCI implements GitHub Actions semantics rather than calling GitHub, so only a subset of features is available. See [GitHub Actions Feature Support](#github-actions-feature-support).

### How CircleCI triggers your workflow

Your CircleCI trigger decides whether the pipeline runs. You configure it in CircleCI, in the same way as any other pipeline. See the [Set Up Triggers](https://circleci.com/docs/guides/orchestrate/set-up-triggers/) page.

**The filters under `on:` are not applied.** CircleCI does not read `on.<event>.branches`, `paths`, or `types`, and it does not evaluate `on.schedule.cron`.

A workflow with `on.push.branches: [main]` still runs on every branch if its CircleCI trigger fires on all pushes. Use your CircleCI trigger, or a job-level or step-level `if:` condition, to limit when work runs. For the trigger options, see the [GitHub Trigger Event Options](https://circleci.com/docs/guides/orchestrate/github-trigger-event-options/) page.

CircleCI does read `on:` for two things: the inputs declared under `on.workflow_dispatch.inputs`, and the interface declared under `on.workflow_call`. A workflow that declares only unsupported events is skipped.

The following table shows how CircleCI translates its own events into the `github.event_name` your workflow sees. It describes the value in the GitHub Actions context rather than a second gate on whether the workflow runs.

| GitHub Actions event | CircleCI event | Notes |
| --- | --- | --- |
| `push` | Push | CircleCI builds a partial event payload from the pipeline values. |
| `pull_request` | Pull request | The payload includes the base and head SHA, and the branch. |
| `schedule` | Schedule | Set the schedule on your CircleCI trigger. The `cron` value in your workflow file is not evaluated. |
| `workflow_dispatch` | API | The `inputs.*` context is fully populated from the inputs declared in your workflow file. |
| `workflow_call` | Not applicable | Defines a reusable workflow interface for other local workflows to call. |
| `repository_dispatch` | Custom webhook | The event name is mapped, but the event payload is not populated. |
| Any other event | Not applicable | Not mapped. A workflow that declares only unsupported events is skipped. |

## What to expect when your workflow runs on CircleCI

Your workflow runs on CircleCI compute, so some values your workflow reads at runtime differ from the values GitHub would report.

*   Jobs run on Linux x86-64. The `runner.os` context reports `Linux`, `runner.arch` reports `X64`, and `runner.environment` reports `self-hosted`.
    
*   All standard `GITHUB_*` and `RUNNER_*` environment variables are set, with the exception of `ACTIONS_RUNTIME_TOKEN`.
    
*   OIDC tokens are issued by CircleCI. See [OIDC Tokens](#oidc-tokens).
    
*   Set the secrets your workflow reads as project environment variables, rather than as GitHub repository secrets. See the [Set an Environment Variable in a Project](https://circleci.com/docs/guides/security/set-environment-variable/#set-an-environment-variable-in-a-project) page.
    

## Next steps

*   [Set Up Triggers](https://circleci.com/docs/guides/orchestrate/set-up-triggers/)
    
*   [Pipelines Overview and Setup](https://circleci.com/docs/guides/orchestrate/pipelines/)
    
*   [Migrate From GitHub Actions](https://circleci.com/docs/guides/migrate/migrating-from-github/)
    
*   [Version Control Systems, Pipeline Types, and Feature Support](https://circleci.com/docs/guides/integration/version-control-system-integration-overview/)
    

## GitHub Actions feature support

If a feature does not appear in this section, treat it as unsupported.

### Support levels

| Level | Meaning |
| --- | --- |
| **Supported** | Works as it does on GitHub Actions. |
| **Partial** | Works within the limits described in the table. |
| **No effect** | The syntax is accepted and your workflow still runs, but the feature does nothing. Read these rows carefully. A workflow that depends on one of these features for correctness or safety behaves differently on CircleCI. |
| **Not supported** | Rejected, or outside the supported set. |

### Workflow and job structure

| Feature | Support | What to know |
| --- | --- | --- |
| Jobs, `needs`, and outputs | **Supported** | Static job dependencies, matrix fan-out and fan-in, job results, and job outputs all work. Dependency graphs can be up to 20 levels deep. |
| `runs-on` | **Partial** | Use `ubuntu-latest`, `ubuntu-24.04`, `ubuntu-22.04`, `ubuntu-20.04`, or `self-hosted`. All other labels are rejected, including all macOS and Windows labels. |
| `name` | **Supported** | Retained at workflow and job level. Job names can use matrix values. |
| `continue-on-error` | **Supported** | Accepts literal booleans and expressions, at job and step level. |
| `timeout-minutes` | **Partial** | Enforced at job and step level, defaulting to 360 minutes. A warning in the build output may state that this key has no effect. That warning is wrong, and the timeout is enforced. |
| `env` and `defaults.run` | **Partial** | Workflow, job, and step values use normal precedence, so the most specific value wins. `NODE_OPTIONS` cannot be set through `GITHUB_ENV`. |
| `concurrency` | **No effect** | CircleCI emits a warning. Concurrent runs are not serialized, so a workflow that relies on a concurrency group to prevent overlapping deploys is not protected. |
| `environment` | **Partial** | CircleCI inserts an approval job before any job that declares `environment:`, so the job waits for approval in the CircleCI web app. See [Environment Approval Gates](#environment-approval-gates) for what the gate does and does not enforce. |
| `container:` at job level | **Partial** | CircleCI starts a long-lived container and runs your `run:` steps inside it, using `docker exec`. The `image`, `env`, `ports`, `volumes`, `options`, and `credentials` keys work. Your workspace is mounted at `/github/workspace`, and the temporary directory is `/github/home`. JavaScript actions and `docker://` action steps run on the host rather than in the container. |

### Matrix strategies

| Feature | Support | What to know |
| --- | --- | --- |
| `matrix` with static values | **Supported** | Up to 256 instances per job. |
| `include` and `exclude` | **Partial** | Literal combinations work. An `include` entry whose value is an expression that cannot be resolved when the workflow is parsed is skipped without an error. |
| `fail-fast` | **No effect** | A failing matrix instance does not cancel its siblings. |
| `max-parallel` | **No effect** | Use CircleCI concurrency controls instead. |
| `strategy.*` context | **Not supported** | The context is not populated and resolves to null. Use `matrix.*` instead. |

### Steps, shells, and expressions

| Feature | Support | What to know |
| --- | --- | --- |
| `run` steps | **Partial** | Use `bash`, `sh`, `python`, `pwsh`, or a custom shell template. Linux only. |
| Operators and comparisons | **Supported** | The full set of GitHub Actions operators is available in conditions and in string interpolation. |
| `startsWith()`, `contains()`, `endsWith()`, `format()`, `join()`, `toJSON()`, and `fromJSON()` | **Supported** | Available in conditions and in string interpolation. |
| `always()`, `success()`, `failure()`, and `cancelled()` | **Partial** | Available in conditions, without arguments. Not available in string interpolation. |
| `hashFiles()` | **Partial** | Available in step conditions and workflow steps, not in job conditions. |
| `case()` | **Supported** | Available in conditions and in string interpolation. Takes predicate and value pairs followed by a fallback, as in `case(pred1, val1, pred2, val2, default)`. CircleCI accepts an odd number of arguments, from three to 255. Any other number of arguments evaluates to an empty string rather than raising an error. |
| Environment files | **Supported** | `GITHUB_OUTPUT`, `GITHUB_ENV`, `GITHUB_PATH`, `GITHUB_STATE`, and `GITHUB_STEP_SUMMARY` all work, including multiline Heredoc values. |
| Log grouping and annotations | **Supported** | The `group`, `endgroup`, `warning`, `error`, `notice`, `debug`, `echo`, and `add-mask` workflow commands work. |
| `set-env` and `add-path` workflow commands | **Not supported** | Disabled for security reasons, following [CVE-2020-15228](https://github.com/advisories/GHSA-mfq2-61fr-9j23). CircleCI logs a warning and does not apply the value. Use the `GITHUB_ENV` and `GITHUB_PATH` environment files instead. See [Actions That Set the Path](#actions-that-set-the-path) for the effect this has on some common actions. |
| `set-output` and `save-state` workflow commands | **No effect** | Deprecated by GitHub, and silently consumed here. Use `GITHUB_OUTPUT` and `GITHUB_STATE`. |
| `add-matcher` and `remove-matcher` workflow commands | **No effect** | Silently consumed. |
| `background:`, `wait:`, `wait-all:`, `cancel:`, and `parallel:` | **Not supported** | Not implemented. |

For the contexts available in job conditions and step conditions, see [Available Contexts](#available-contexts).

### Actions

| Feature | Support | What to know |
| --- | --- | --- |
| Local actions (`./path`) | **Partial** | Resolved relative to the workspace, or relative to the path of the composite action calling them. |
| Public actions (`owner/repo@ref`) | **Partial** | Downloaded from GitHub and cached on disk. |
| Private actions | **Not supported** | Private action sources cannot be reached. |
| JavaScript actions | **Supported** | The `node16`, `node20`, and `node24` runtimes are supported. |
| Composite actions | **Partial** | Nesting is limited to 10 levels. Secrets are not available inside composite action children. |
| Docker actions | **Partial** | Linux only. A Dockerfile is built before the action runs. Prebuilt images are pulled anonymously, so private images are not available. |
| `uses: docker://` as a workflow step | **Partial** | Accepted as a direct step, as on GitHub Actions. |
| Pre and post steps | **Supported** | The `pre-if` and `post-if` conditions work, and post steps run in reverse order. |

#### Environment approval gates

When a job declares `environment:`, CircleCI inserts an approval job before it. Someone must approve the job in the CircleCI web app before the gated job starts.

The gate is a hold on the pipeline rather than a reproduction of GitHub’s environment protection rules. Read these limits before you rely on it:

*   **Reviewer identity is not checked.** Any project member with write access to the CircleCI project can approve. Named reviewers, team restrictions, and self-approval prevention are not enforced.
    
*   **Every environment is gated.** An environment with no protection rules in GitHub still holds the pipeline until someone approves it.
    
*   **A false `if:` condition still holds the pipeline.** The gated job runs once approved and then reports as skipped, so the pipeline waits for input either way.
    
*   **A matrix job gets one gate.** A single approval covers the whole fan-out.
    
*   **The object form needs a name.** An `environment:` block that sets only `url:` has no environment name to gate on, so CircleCI emits a warning and inserts no approval job.
    
*   **`wait_timer` and `deployment_branch_policy` are not translated.** Neither are deployment status URLs.
    

Environment-scoped secrets and variables are not resolved separately from your other secrets and variables.

#### Actions that set the path

Some widely used setup actions, including `actions/setup-python`, put a tool on the path by calling the `add-path` workflow command. That command is disabled, so the action itself succeeds, but later `run:` steps do not pick up the version it installed and fall back to whatever is already on the path.

That silent difference is the most common way a workflow passes on CircleCI while doing something other than what you expect. If your workflow pins a tool version through a setup action, add the tool to `GITHUB_PATH` yourself, or set the full path in the steps that need it.

### Checkout, artifacts, and caching

CircleCI intercepts these actions and handles them natively, so they work without needing GitHub’s storage services.

| Action | Support | What to know |
| --- | --- | --- |
| `actions/upload-artifact` | **Partial** | All versions are intercepted. The `overwrite` and `include-hidden-files` inputs are rejected. The `retention-days` and `compression-level` inputs are accepted and ignored. |
| `actions/download-artifact` | **Partial** | The `name` input is required. The `pattern` and `merge-multiple` inputs are not supported, and downloading every artifact at once is not supported. |
| `actions/cache` | **Partial** | Restoring and saving both work. The `cache-hit` output always returns `false`, so a step that branches on `cache-hit` always takes the cache-miss path. The `fail-on-cache-miss`, `lookup-only`, and `enableCrossOsArchive` inputs are rejected. |
| `actions/cache/restore` and `actions/cache/save` | **Partial** | Subject to the same limits as `actions/cache`. |

`ACTIONS_RUNTIME_TOKEN` is not set. An action that expects this variable, such as the upstream JavaScript client behind `actions/cache`, does not find it.

### Reusable workflows

| Feature | Support | What to know |
| --- | --- | --- |
| Local calls (`./.github/workflows/…​`) | **Supported** | Resolved from your repository. |
| Public calls (`owner/repo/.github/workflows/ci.yml@ref`) | **Partial** | Resolved from GitHub when the workflow runs. |
| Inputs | **Supported** | Static `boolean`, `number`, and `string` inputs work, and the `inputs.*` context is populated. |
| Call outputs | **Not supported** | A called workflow cannot return outputs to its caller. A workflow that declares call outputs is rejected when it is parsed. |
| `secrets: inherit` | **Not supported** | Pass secrets explicitly instead. |
| Private reusable workflows | **Not supported** | Only local paths and public references are resolved. |
| Dynamic workflow paths | **Not supported** | The path to a called workflow must be static. |

### Secrets, variables, and tokens

| Feature | Support | What to know |
| --- | --- | --- |
| `secrets.*` | **Partial** | Resolved from the job environment, matching names without regard to case. Set these values as project environment variables, as described in [Set an Environment Variable in a Project](https://circleci.com/docs/guides/security/set-environment-variable/#set-an-environment-variable-in-a-project). Contexts are not used yet, because the translation cannot tell which context holds a given secret. Secrets are not available in `if:` conditions, or inside composite action children. |
| `vars.*` | **Partial** | Resolved from a single flat set of values. The organization, repository, and environment scoping that GitHub applies is not reproduced. |
| `GITHUB_TOKEN` | **Partial** | A GitHub App installation token, scoped to the job. Injected when `permissions:` is omitted, when `permissions.contents` has any value other than `none`, or when the global `*` scope has any non-zero value. Set `permissions: {}` or `permissions.contents: none` to withhold it. |
| `permissions` scopes | **Partial** | Only `contents` and `id-token` change behavior. Other scopes, such as `issues`, `pull-requests`, and `checks`, are accepted, but the token scope is not narrowed to match. |
| GitHub Packages, Releases, Checks, and Deployments | **Not supported** | These GitHub services are not emulated. |

### OIDC tokens

A job that declares `permissions: id-token: write`, or `permissions: write-all`, can request an OIDC token.

**The tokens are issued by CircleCI, not by GitHub.** A trust policy that trusts GitHub’s issuer rejects them. Migrate the OIDC trust relationship on your cloud provider, whether that is AWS IAM, Google Cloud Workload Identity, or Microsoft Entra ID.

For the token format and the claims to trust, see the [Using OpenID Connect Tokens in Jobs](https://circleci.com/docs/guides/permissions-authentication/openid-connect-tokens/) page.

OIDC tokens are not available to Docker action steps, or to any job that sets a job-level `container:` key. In both cases the step runs in a container that cannot reach the token endpoint on the host.

### Service containers

Service containers work as they do on GitHub Actions. CircleCI starts them on a per-job Docker network before your steps run.

| Feature | Support | What to know |
| --- | --- | --- |
| `services:` | **Supported** | The `image`, `credentials`, `env`, `ports`, `volumes`, `options`, `command`, and `entrypoint` keys all work. |
| Health checks | **Supported** | A service with a Docker health check must report healthy before your steps run. |
| Port mapping | **Supported** | Published ports are available through the `job.services.<id>.ports[<port>]` context. |
| Registry credentials | **Supported** | CircleCI logs in to your registry before pulling the image. |

### Available contexts

Contexts are available in different places depending on whether you use them in a job condition or a step condition. The table below shows where each context can be used, not how completely it is populated. The `github` and `github.event` contexts are both partial, so read [GitHub Context Values](#the-github-context) and [Event Payload Values](#the-github-event-context) before relying on a specific key.

| Context | Job `if` | Step `if` |
| --- | --- | --- |
| `github.*` | **Yes** | **Yes** |
| `github.event.*` | **Yes** | **Yes** |
| `runner.os`, `runner.arch`, `runner.name`, and `runner.temp` | **Yes** | **Yes** |
| `needs.<job>.result` and `needs.<job>.outputs.<name>` | **Yes** | **Yes** |
| `matrix.<name>` | **Yes** | **Yes** |
| `vars.<name>` | **Yes** | **Yes** |
| `inputs.<name>` | **Yes** | **Yes** |
| `job.status` | **Yes** | **Yes** |
| `steps.<id>.outcome`, `steps.<id>.conclusion`, and `steps.<id>.outputs.<name>` | **No** | **Yes** |
| `env.<name>` | **No** | **Yes** |
| `job.services.<service>.ports[<port>]` | **No** | **Yes** |
| `strategy.*` | **No** | **No** |
| `secrets.*` | **No** | **No** |

#### GitHub context values

CircleCI derives the `github` context from your pipeline, so most keys hold the value you would expect and a few differ.

| Key | Value |
| --- | --- |
| `github.repository`, `github.repository_owner`, `github.repository_id` | Your repository, its owner, and its ID. |
| `github.repositoryUrl` | The `git://github.com/<owner>/<repo>.git` form, matching GitHub. |
| `github.sha` | The full 40-character SHA of the commit CircleCI checked out. |
| `github.ref`, `github.ref_name`, `github.ref_type` | The tag when the pipeline was triggered by a tag, and the branch otherwise. |
| `github.base_ref`, `github.head_ref` | The base and head branches. Populated for pull request events only. |
| `github.actor`, `github.triggering_actor` | The GitHub user who triggered the pipeline. Both hold the same value. |
| `github.event_name` | The translated event name. See [How CircleCI Triggers Your Workflow](#how-circleci-triggers-your-workflow). |
| `github.workflow` | The `name` from your workflow file. |
| `github.run_id`, `github.run_number` | The CircleCI pipeline ID and pipeline number. |
| `github.server_url`, `github.api_url`, `github.graphql_url` | Always the `github.com` values. |
| `github.token` | The `GITHUB_TOKEN` for the job, when the permission gate allows one. |

The following keys have no CircleCI equivalent and keep their default values: `github.actor_id`, `github.repository_owner_id`, `github.ref_protected`, `github.run_attempt`, and `github.secret_source`. `github.retention_days` is always `90`.

Four differences can change how a workflow behaves:

*   **`github.event_name` can be empty.** CircleCI does not guess an event name it cannot translate, so a condition such as `if: github.event_name == 'push'` is false rather than wrongly true on those pipelines. Handle the empty value if your workflow branches on the trigger.
    
*   **`github.run_id` is a UUID, not a number.** CircleCI’s pipeline ID is a UUID and has no numeric equivalent, so a workflow that does arithmetic on `github.run_id` does not work here.
    
*   **On a pull request, the refs describe the head branch.** GitHub sets `github.ref` to `refs/pull/<number>/merge` and `github.sha` to an ephemeral merge commit. CircleCI checks out the head branch instead, so `github.ref` is `refs/heads/<head-branch>` and `github.sha` is the head SHA. Use `github.event_name == 'pull_request'` with `github.base_ref` and `github.head_ref` rather than testing for `refs/pull/`.
    
*   **The GitHub URLs are always `github.com`.** GitHub Enterprise Server is not supported.
    

#### Event payload values

For push and pull request pipelines, CircleCI builds a partial event payload and writes it to the path in `GITHUB_EVENT_PATH`. Both `${{ github.event.* }}` expressions and shell steps that read the file see real values. For schedule, API, and custom webhook pipelines there is no payload, and `github.event.*` returns an empty string.

*   **Push events** populate `ref`, `after`, and `sender.login`.
    
*   **Pull request events** populate `action`, `number`, `sender.login`, and `pull_request.number`, `.title`, `.url`, `.draft`, `.head.ref`, `.head.sha`, `.base.ref`, and `.base.sha`.
    

A field whose value is absent is left out of the payload rather than set to an empty value. A condition such as `if: github.event.pull_request.draft == false` therefore works on a pull request that does not supply the field.

Everything else is unavailable. That includes `commits`, `head_commit`, `before`, and `pusher` on a push, and `body`, `state`, `labels`, `user.login`, `mergeable`, `requested_reviewers`, and the `repository` sub-objects on a pull request.

### Limits

| Item | Limit |
| --- | --- |
| Matrix instances per job | 256 |
| Jobs in a workflow | 255 |
| Steps per job | 256 |
| Nested composite action depth | 10 levels |
| Job dependency graph depth | 20 levels |
| Job or step timeout | 360 minutes |
| Expression length | 21,000 characters |
| Expression depth | 50 nodes |

