Skip to content
Remote cache

GitHub Actions

The official action installs Kache, configures the Rust wrapper, and can persist the local store through GitHub's cache service:

steps:
  - uses: actions/checkout@v4
  - uses: dtolnay/rust-toolchain@stable
  - uses: kunobi-ninja/kache-action@v1
  - run: cargo build --locked

See the kache-action repository for its current input reference and release notes.

For S3-compatible storage:

- uses: kunobi-ninja/kache-action@v1
  with:
    s3-bucket: my-build-cache
    s3-region: eu-west-1
    s3-access-key-id: ${{ secrets.S3_ACCESS_KEY_ID }}
    s3-secret-access-key: ${{ secrets.S3_SECRET_ACCESS_KEY }}

Add s3-endpoint for R2, Ceph, or MinIO. Prefer workload identity or IAM roles over long-lived access keys when the runner supports them.

Who may write

A write credential for an S3 or filesystem remote can overwrite or delete objects.

On GitHub Actions and GitLab CI, Kache suppresses remote writes unless the job is a push to a protected branch. Pull requests, merge requests, tags, unprotected branches, workflow_dispatch, and scheduled runs are read-only even if the job has a write credential. KACHE_REMOTE_READONLY=0 does not turn that off.

A laptop or other non-CI process is left as configured, so kache sync --push still works locally. Set KACHE_REMOTE_READONLY=1 (or cache.remote_readonly) there when you want reads without writes.

# Optional: make the read-only intent explicit in pull-request jobs.
env:
  KACHE_REMOTE_READONLY: "1"

GitHub withholds secrets and OIDC tokens from fork pull-request jobs, so those runs cannot publish unless you also pass a write credential another way. Same-repository pull requests do receive secrets; the CI policy above is what stops them writing.

Pull-request jobs can still restore entries a trusted branch already published.

C and C++ objects publish through the same remote as Rust. A daemon-backed compile restores them on miss; kache sync --pull --all also warms them in the local store. clang-cl debug objects stay on the machine and are not published.

Other CI systems

Install Kache, then provide wrapper and remote configuration:

export RUSTC_WRAPPER=kache
export KACHE_S3_BUCKET=my-build-cache
export KACHE_S3_REGION=eu-west-1

kache sync --pull
cargo build --locked
kache sync --push

Set credentials through the runner's secret store or standard cloud identity chain. Use --allow-partial only when cache failure must not fail the job.

Ephemeral and persistent runners

Speculative prefetch is intended for empty runners. A persistent self-hosted runner may already have the needed entries locally. Measure both modes and disable speculation when it adds work:

[cache]
prefetch_enabled = false

This keeps exact remote reads and uploads.

Concurrent jobs may share a persistent local store, but each job should have a distinct KACHE_RUNTIME_DIR for sockets, locks, event logs, and session state.

Progress and reports

Kache is quiet in compiler-wrapper mode by default because Cargo can retain wrapper stderr as compiler diagnostics.

env:
  KACHE_PROGRESS: hits       # hits only
  # KACHE_PROGRESS: verbose # hits, dups, misses, and long-compile heartbeats

Create a machine-readable summary after the build:

kache report --format json --output kache-report.json
kache stats

Coverage and uncached steps

Coverage instrumentation uses separate, path-local keys. If you do not want coverage artifacts in Kache:

- run: cargo llvm-cov
  env:
    KACHE_DISABLED: "1"

Unset KACHE_DISABLED to enable caching again. Only 1 and true disable it.

Available for:
Apple macOS logomacOSMicrosoft Windows logoWindowsLinux logoLinux
Download Kunobi