> ## Documentation Index
> Fetch the complete documentation index at: https://codspeed.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuring GitHub Actions for CodSpeed

> Learn how to configure GitHub Actions to run benchmarks with CodSpeed.

export const CIWorkflow = ({minimal = false, enableWorkflowDispatch = true, runsOn = "ubuntu-latest", highlight = [], mode, modes, submodules = false, preSteps = [], buildSteps = ["# ...", "# Setup your environment here:", "#  - Configure your Python/Rust/Node version", "#  - Install your dependencies", "#  - Build your benchmarks (if using a compiled language)", "# ..."], benchmarkCommand = ["<Insert your benchmark command here>"], jobName = "Run benchmarks", env = {}}) => {
  const modeList = modes || (mode ? [mode] : undefined);
  if (!modeList || modeList.length === 0) {
    throw new Error("mode or modes is required");
  }
  const indent = (lines, depth) => {
    const reindentedLines = lines.map(l => l.length === 0 ? l : (" ").repeat(depth) + l);
    return reindentedLines.join("\n");
  };
  const workflowDispatchSection = enableWorkflowDispatch ? "  # `workflow_dispatch` allows CodSpeed to trigger backtest\n" + "  # performance analysis in order to generate initial data.\n" + "  workflow_dispatch:\n" : "";
  let yaml = "";
  if (!minimal) {
    yaml += `
name: CodSpeed Benchmarks

on:
  push:
    branches:
      - "main" # or "master"
  pull_request:
`;
    yaml += workflowDispatchSection;
  }
  yaml += `
jobs:
  benchmarks:
    name: ${jobName}
    runs-on: ${runsOn}`;
  if (!minimal) {
    yaml += `
    permissions: # optional for public repositories
      contents: read # required for actions/checkout
      id-token: write # required for OIDC authentication with CodSpeed`;
  }
  if (preSteps.length > 0) yaml += "\n" + indent(preSteps, 4);
  yaml += `
    steps:
      - uses: actions/checkout@v5`;
  if (submodules) {
    const value = typeof submodules === "string" ? submodules : "true";
    yaml += `\n        with:\n          submodules: ${value}`;
  }
  yaml += "\n" + indent(buildSteps, 6);
  const modeValue = modeList.join(",");
  yaml += `
      - name: Run the benchmarks
        uses: CodSpeedHQ/action@v4
        with:
          mode: ${modeValue}`;
  if (benchmarkCommand.length > 0) {
    const indentedBenchCommand = benchmarkCommand.length > 1 ? benchmarkCommand[0] + "\n" + indent(benchmarkCommand.slice(1), 12) : benchmarkCommand;
    const runLine = indent(["run: "], 10) + indentedBenchCommand;
    yaml += `\n${runLine}`;
  }
  const envEntries = Object.entries(env);
  if (envEntries.length > 0) {
    const envLines = ["env:", ...envEntries.map(([k, v]) => `  ${k}: ${v}`)];
    yaml += "\n" + indent(envLines, 8);
  }
  return <CodeBlock language="yaml" highlight={JSON.stringify(highlight)} {...minimal || ({
    filename: ".github/workflows/codspeed.yml",
    icon: "github"
  })}>
      {yaml}
    </CodeBlock>;
};

## Authentication

CodSpeed needs to validate the authenticity of the benchmark results being
uploaded.

In order to upload benchmark results to CodSpeed, the GitHub Actions workflow
needs to authenticate with CodSpeed. There are three supported methods for
authentication:

* OIDC: recommended way for both private and public repositories
* Static CodSpeed tokens (legacy)
* Tokenless uploads (public repositories only)

### OIDC (Recommended)

CodSpeed recommends using
[OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/) for
authentication.

Using this method, a token is generated on-the-fly during the workflow run. This
token is then used to authenticate securely with CodSpeed without needing to
store long-lived credentials, but grants no additional permissions to the
workflow.

To enable OIDC, scope the `permissions` block to the benchmark job:

```yaml icon="github" .github/workflows/codspeed.yml highlight={10-12} theme={null}
name: Benchmarks

on:
  push: { branches: [main] }
  pull_request:

jobs:
  benchmarks:
    runs-on: ubuntu-latest
    permissions:
      contents: read # required for actions/checkout
      id-token: write # required for OIDC authentication with CodSpeed
    steps:
      - uses: actions/checkout@v4
      - uses: CodSpeedHQ/action@v4
        with:
          run: npm run bench
```

<Note>
  Scoping `id-token: write` to the benchmark job, rather than the whole workflow,
  follows GitHub's least-privilege guidance for OIDC. Since GitHub's OIDC
  permission is not restricted by audience, keeping it on the benchmark job avoids
  granting unrelated jobs the ability to request tokens for other services. See
  GitHub's
  [OIDC with reusable workflows](https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/using-openid-connect-with-reusable-workflows)
  documentation for further reading.
</Note>

For more information, see the GitHub Actions OIDC documentation:

* [Overview of OIDC on GitHub](https://docs.github.com/en/actions/concepts/security/openid-connect)
* [How to configure OpenID Connect in GitHub Actions](https://docs.github.com/en/actions/reference/security/oidc#workflow-permissions-for-the-requesting-the-oidc-token)

### CodSpeed token (Legacy)

While we recommend using OpenID Connect (OIDC) for improved security, you can
use a static CodSpeed token for authentication.

Retrieve your CodSpeed token from your repository settings page:

<img src="https://mintcdn.com/codspeed/jKaxX6yy-Kzw1C-0/assets/upload-token.png?fit=max&auto=format&n=jKaxX6yy-Kzw1C-0&q=85&s=84e746ad14c38862e9e72776ee7b1f38" className="rounded-xl w-full max-w-xl mx-auto" alt="Upload Token from the settings page" width="1442" height="426" data-path="assets/upload-token.png" />

<Note>
  **Token Scope**: Be mindful that a token is scoped to a specific repository.
  Make sure that you are on the correct repository settings page when copying the
  token.
</Note>

Then, create a new
[encrypted secret](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository)
in your repository with the name `CODSPEED_TOKEN` and the value of your token.

Then pass the token explicitly to the action using the `with` key:

```yaml highlight={5} theme={null}
- name: Run benchmarks
  uses: CodSpeedHQ/action@v4
  with:
    mode: simulation
    token: ${{ secrets.CODSPEED_TOKEN }}
```

### Tokenless

CodSpeed allows tokenless uploads for public repositories, allowing runs to be
triggered from public forks directly. However, we still recommend using OIDC for
improved security.

To use tokenless uploads on public repositories, you can simply omit the `token`
input and the whole `permissions` section when
[creating the benchmarks workflow](#1-create-the-benchmarks-workflow).

## Advanced

### Defining environment variables

You can define environment variables for your benchmarks by using the `env` key
in the section of the action:

```yaml theme={null}
- name: Run benchmarks
  uses: CodSpeedHQ/action@v4
  env:
    MY_ENV_VAR: "my-value"
  with:
    mode: simulation
```

### Running benchmarks in parallel CI jobs

With Github Actions, you can leverage matrix jobs to improve the performance of
your benchmarks.

For example, using `pytest`:

<CIWorkflow
  mode="simulation"
  highlight={[19, 20, 21, 33]}
  preSteps={["strategy:", "  matrix:", "    shard: [1, 2, 3, 4]"]}
  jobName="Run benchmarks (Shard #\${{ matrix.shard }})"
  buildSteps={[
"- name: Install required-version defined in uv.toml",
"  uses: astral-sh/setup-uv@v7",
"- uses: actions/setup-python@v6",
"  with:",
"    python-version: 3.12.8",
]}
  benchmarkCommand={[
"uv run pytest tests/benchmarks/ --codspeed --test-group=${{ matrix.shard }} --test-group-count=4",
]}
/>

<Info>
  CodSpeed will only supports emitting results from your benchmarks if you split
  them within a single CI workflow.

  If you run benchmarks in multiple CI workflows, CodSpeed will not be able to
  aggregate the results correctly, and you may see incomplete or missing data in
  your CodSpeed reports.
</Info>

<Warning>
  When running benchmarks across multiple jobs, all jobs **must use the same
  authentication method** (either all OIDC, all static tokens, or all tokenless).
  Mixing authentication methods will prevent CodSpeed from aggregating the results
  correctly.
</Warning>

<Warning>
  CodSpeed does not yet support running the same benchmarks multiple times. If
  your matrix has several dimensions (e.g. a runtime version), please ensure that
  each benchmark will only run once.

  If the same benchmark is run multiple times, you will receive the following
  comment on your pull request:

  <img src="https://mintcdn.com/codspeed/jKaxX6yy-Kzw1C-0/assets/parallel-benchmarks-variations-warning.png?fit=max&auto=format&n=jKaxX6yy-Kzw1C-0&q=85&s=f5e87d3fecc76f2fe3ce7f302e7f9a93" className="rounded-xl w-full max-w-lg mx-auto" alt="Multiple Benchmark Variations Error Message" width="1832" height="568" data-path="assets/parallel-benchmarks-variations-warning.png" />
</Warning>

Learn more about
[benchmark sharding and how to integrate with your CI provider](/features/sharded-benchmarks).

### Running multiple instruments serially

If you want to measure multiple aspects of performance, you can run multiple
instruments in a single CI step by passing a comma-separated list to the `mode`
input.\
Please note that for compiled languages, you will need to have built your
benchmarks with support for all the instruments you are trying to run
beforehand.

For example, to run both the `simulation` and `memory` instruments:

<CIWorkflow minimal modes={["simulation", "memory"]} highlight={[18]} />

<Warning>
  Walltime needs a dedicated runner (`codspeed-macro`) for reliable results. Do
  not run walltime serially on default runners as they are shared with other
  users and introduce lots of noise. See the [macro runner
  documentation](/features/macro-runners) for more information.
</Warning>

<Note>
  Support for running multiple instruments serially was added in CodSpeed v4.12.0.
</Note>

### Using container images

When running benchmarks in a container (such as `ubuntu:latest` or other base
images), git is typically not installed by default. Without git in the path,
`actions/checkout` falls back to downloading a tarball of your code, which does
not setup a local git repository.

CodSpeed relies on git to determine the current commit hash and other metadata,
so it's important to have git installed and the repository checked out.

```yaml theme={null}
jobs:
  benchmarks-in-container:
    runs-on: ubuntu-latest
    container:
      image: ubuntu:latest
    steps:
      - name: Install git before fetching repository
        run: |
          apt-get update
          apt-get install -y git
          git config --global --add safe.directory $GITHUB_WORKSPACE
      - name: Checkout code
        uses: actions/checkout@v4
```

<Note>
  The `git config --global --add safe.directory` command is required to prevent
  git from triggering file system permission errors when accessing the repository.
  More details can be found in this
  [GitHub Issue](https://github.com/actions/checkout/issues/766)
</Note>

### Compatibility

For now, only the following OS and versions are supported on the runners:

* Ubuntu 22.04 and later
* Debian 12 and later
