Skip to content
Documentation

Docs / GitHub Actions

GitHub Actions

Bring local BoringCache settings into GitHub Actions with short-lived workload identity, or choose separate scoped credentials when OIDC is unavailable.

Configure cache and build outputs

Start with boringcache onboard locally when you can. In GitHub Actions, reuse that repo config through a short-lived Machine connection when OIDC is available. BoringBuild supplies that connection before the job, and boringcache/one uses it automatically without a BoringCache token.

Choose CI authentication

Prefer a Machine connection. Approve the repository-to-Workspace connection once through Connect CI. On a standard GitHub-hosted runner, the Action starts and renews that connection from GitHub OIDC. On BoringBuild, it reuses the runner-provided connection. No reusable BoringCache secret is stored in either workflow, and a failed OIDC session never falls back to one.

GitHub Actions with workload identity (preferred)
permissions:
  contents: read
  id-token: write

steps:
  - uses: boringcache/one@f0fb9b2d926a32b10c543e92093ba00c5a291b79 # v1.33.0
    with:
      trust-policy: auto
      mode: archive
      cache-profiles: ci

  - run: YOUR_BUILD_COMMAND

Use explicit scoped credentials when a Machine connection is unavailable. In that path, keep the capability split simple: every job gets a restore token, candidate-producing jobs get a stage token, and only trusted publishing jobs get a save token.

Scoped credential alternative
env:
  BORINGCACHE_RESTORE_TOKEN: ${{ secrets.BORINGCACHE_RESTORE_TOKEN }}
  BORINGCACHE_STAGE_TOKEN: ${{ secrets.BORINGCACHE_STAGE_TOKEN }}
  BORINGCACHE_SAVE_TOKEN: ${{ github.event_name != 'pull_request' && secrets.BORINGCACHE_SAVE_TOKEN || '' }}

Restore token: read-only. Use it on pull requests and other low-trust jobs.

Stage token: restore + immutable candidate creation. It cannot move published tags.

Save token: restore + save. Use it on trusted jobs that should publish cache updates.

One policy: trust-policy: auto keeps pull_request jobs restore-only. Use stage in a separately trusted candidate job and publish only in a trusted publishing job.

Exact handoff: a stage job exposes authenticated candidate receipts as cache-candidates. Pass that job output unchanged to an explicit CLI restore or promotion command in the later trusted job.

Adapter modes: Bazel, Cargo, ccache, Gradle, Maven, Nix, Nx, Turbo, Go, GHA Cache v2, sccache, and Xcode restore without publishing when only a restore token is present.

Docker cache writes: restore-only pull requests can read through the managed BuildKit backend. A save-capable token is required to publish updates.

Migrate an existing cache step

Run boringcache onboard --apply in the repository and choose y when prompted to opt in to workflow updates. It can move one simple actions/cache step with literal paths into .boringcache.toml, then update the workflow to use it. Split restore/save steps, dynamic paths, and multiple cache steps need an explicit profile setup.

GitHub cache keys and stored objects are not imported. Local and CI runs share the cache in your BoringCache workspace.

boringcache/one

Use one Action for archive caching, Docker builds, and native tool adapters. Run boringcache onboard first, commit .boringcache.toml, and bring the cache settings you tested locally into CI.

The version comment beside the immutable SHA identifies the Action release. It is not the CLI version: Action v1.33.0 installs CLI v1.33.0 by default, and cli-version is an independent override.

The mode examples below use the workload-identity permission shown above. Add scoped credential environment variables only when that preferred path is unavailable.

Reuse your repo setup

Run onboard once, commit `.boringcache.toml`, and use the same cache names, commands, and settings locally and in CI.

Bridge the GitHub lifecycle

The Action installs the CLI when needed, runs or starts its selected cache lifecycle, passes planned settings to later steps, and cleans up after the job.

Restore safely, publish deliberately

Machine connections follow signed job trust. With scoped credentials, pull requests restore and trusted jobs with a save token publish.

Adapter modes

With CLI and Action v1.32.0 or later, an active Machine connection supplies its approved workspace for archive, Cargo, sccache, Docker, GHA compatibility, and direct CLI commands. An explicit workspace must match that connection or the command fails. Without a Machine connection, local and scoped-token runs use the workspace in .boringcache.toml; an explicit workspace can override it.

Every non-archive mode matches the CLI command name and reads its cache tag from [adapters.<mode>].tag in .boringcache.toml; the Action has no tag input. Open the adapter guide for its native protocol, local setup, Action shape, benchmarks, and limits.

Archive caching

.github/workflows/ci.yml
- uses: boringcache/one@f0fb9b2d926a32b10c543e92093ba00c5a291b79 # v1.33.0
  with:
    trust-policy: auto
    mode: archive
    cache-profiles: ci

Keep workspace, archive entries, tags, paths, exclusions, and scope in .boringcache.toml. Archive transport is an opaque, SHA-verified tar round trip for regular files, directories, symlinks, hard links, and sparse files. The tar extractor restores those entries; BoringCache verifies the decoded tar and reports the result without inspecting individual files.

Docker build with cache

.github/workflows/ci.yml
- uses: boringcache/one@f0fb9b2d926a32b10c543e92093ba00c5a291b79 # v1.33.0
  with:
    trust-policy: auto
    mode: docker

Rust with remote sccache

.github/workflows/ci.yml
- uses: boringcache/one@f0fb9b2d926a32b10c543e92093ba00c5a291b79 # v1.33.0
  with:
    trust-policy: auto
    mode: sccache

Complete Cargo build cache

With CLI and Action 1.31.0 or later, omit [adapters.cargo].command to cache several Cargo steps: the Action restores before them and publishes in its post step. A committed command runs the complete lifecycle inside the Action step. Keep the compiler-cache choice under [adapters.cargo] and the shared compiler tag under [adapters.sccache]. Use compiler-cache = "none" for target caching without sccache. Use only one Cargo Action step per job.

.github/workflows/ci.yml
- uses: boringcache/one@f0fb9b2d926a32b10c543e92093ba00c5a291b79 # v1.33.0
  with:
    trust-policy: auto
    mode: cargo

- run: cargo check --locked
- run: cargo test --locked

Post-step publication defaults to save: on-success. Choose save: always to save the state reached after failed steps, or save: never to disable publication. Trust and credentials still limit writes. See the Cargo guide for direct CLI phases and local worktree snapshots.

Nix binary cache

Install Nix first. The Action adds the loopback substituter and bounded post-build publication hook. Global Nix signature checks remain enabled.

.github/workflows/ci.yml
- uses: boringcache/one@f0fb9b2d926a32b10c543e92093ba00c5a291b79 # v1.33.0
  with:
    trust-policy: auto
    mode: nix

Runner-integrated GitHub compatibility

On a runner integrated with BoringCache GHA, keep existing cache and artifact actions unchanged. The runner starts boringcache gha before the job, so cache actions keep keys and restore keys while upload/download-artifact keep names, paths, and retention.

.github/workflows/ci.yml
- uses: actions/upload-artifact@v4
  with:
    name: test-results
    path: test-results/

- uses: actions/download-artifact@v4
  with:
    name: test-results
    path: restored-results/

A mode: gha setup step does not redirect later provider actions on a standard GitHub-hosted runner. GitHub Runner supplies its own endpoint when each action launches, so those artifacts and caches remain GitHub-backed.

C and C++ with remote ccache

Keep the compiler launcher already configured by your project, such as CMAKE_C_COMPILER_LAUNCHER=ccache. The Action adds remote storage, safe read and write behavior, and ccache statistics.

.github/workflows/ci.yml
- uses: boringcache/one@f0fb9b2d926a32b10c543e92093ba00c5a291b79 # v1.33.0
  with:
    trust-policy: auto
    mode: ccache

Xcode compilation cache

On a macOS runner, install the BoringCache Xcode CAS companion from the same CLI release first. The Action validates it, prepares Xcode's native compilation-cache bridge, and exports a stable DerivedData path. Keep the existing workspace, scheme, and build command.

.github/workflows/ci.yml
- uses: boringcache/one@f0fb9b2d926a32b10c543e92093ba00c5a291b79 # v1.33.0
  with:
    trust-policy: auto
    mode: xcode

- run: >-
    xcodebuild -workspace App.xcworkspace -scheme App
    -derivedDataPath "$BORINGCACHE_XCODE_DERIVED_DATA_PATH" build

Xcode 26 reuse is scoped by real checkout and DerivedData paths. Keep those paths stable across runners; treat each benchmark as project-specific rather than a universal speed claim.

Bazel remote cache

mode: bazel connects Bazel's native remote cache to BoringCache. Keep benchmark-only local-state archives out of the normal setup.

.github/workflows/ci.yml
- uses: boringcache/one@f0fb9b2d926a32b10c543e92093ba00c5a291b79 # v1.33.0
  with:
    trust-policy: auto
    mode: bazel

Diagnostics

.github/workflows/ci.yml
- uses: boringcache/one@f0fb9b2d926a32b10c543e92093ba00c5a291b79 # v1.33.0
  with:
    trust-policy: auto
    mode: bazel
    diagnostics: summary

Start with the summary: diagnostics: summary reports the resolved lifecycle without dumping proxy logs. Use verbose only for bounded troubleshooting output.

Keep session labels in repo config: shared and adapter metadata hints belong in .boringcache.toml, beside the cache plan they describe.

Pin publisher trust outside the repository: when [trust] is configured, supply trust-policy-sha256 from protected workflow or organization configuration. Publishing also requires id-token: write. The CI supervisor passes GitHub's OIDC request capability only to the bundled Sigstore provider invocation, which requests and holds the identity token.

Core Inputs

trust-policy Choose auto, restore, stage, or publish for this job.
trust-policy-sha256 Optional protected sha256:... pin for the exact .boringcache.toml bytes used by publisher verification.
mode archive, artifact, docker, buildkit, bazel, cargo, ccache, go, gradle, gha, maven, nix, nx, sccache, turbo, and xcode. Default: archive.
working-directory Project root used for repo config and relative paths.
cli-version BoringCache CLI version. runner requires the CLI preinstalled in the runner image; skip disables installation and requires boringcache on PATH.
cli-platform Exact release asset platform override for unusual runners; omit it normally.
diagnostics Choose auto (default, follows ACTIONS_STEP_DEBUG), off, summary, or verbose diagnostics with bounded proxy logs.
save Post-step publication: on-success (default), always after failed steps, or never. Trust and credentials still limit writes.
save-always Alias for save: always. If both are set, the stricter policy wins. A failed embedded CLI command does not publish through the post step.

Archive Inputs

cache-profiles Named profiles from .boringcache.toml; the maintained archive interface.
fail-on-cache-miss Fail if restore misses.
lookup-only Check for a hit without downloading.
fail-on-cache-error Fail when cache setup, restore, publication, or cleanup fails.

Mode-Specific Inputs

proxy-port Optional one-run port override. Omit it normally; the shared default is 22243.
gradle-home Gradle user home, exported as GRADLE_USER_HOME for later steps. Relative paths use working-directory. Omit it to use the CLI plan.

Outputs

cache-hit Whether a restore hit was found.
evidence-path Versioned redacted lifecycle evidence.
cache-candidates, cache-candidate-digests Exact staged cache identity for a later job or explicit promotion.
proxy-port Runner-local port for a process used by later steps.
restore-duration-seconds, restore-transferred-bytes Cargo restore duration and transferred bytes.
publish-duration-seconds, publish-transferred-bytes, publish-logical-bytes, snapshot-duration-seconds Cargo publication duration, transferred and logical bytes, and snapshot duration. Metrics stay unset when the selected CLI does not report them.

Install tools first: use the project's dedicated runtime and build-tool setup actions before boringcache/one. The BoringCache Action installs only its CLI and fails before starting cache infrastructure when a CLI-planned runner prerequisite is missing or incompatible. Docker tool-cache clients belong in the image stage that uses them.

Use one mode per step: Bazel plus Gradle, or a native adapter plus an archive profile, use separate steps with the same workspace and cache settings.

Need help or found something unclear? Open an issue or browse the CLI repo.