kache 1.2.0

Compiler cache for Rust, C/C++ and CUDA, with S3, GCS, shared-filesystem and OCI remotes.
---
title: Kache or sccache?
description: Choose a compiler cache based on the workflow you need
---

Kache and [sccache](https://github.com/mozilla/sccache#readme) both avoid repeated compiler work. This page explains the differences for teams moving to Kache or deciding whether it covers their build today.

It describes both projects as they are today and does not rank their speed. Test the same repository, toolchain, runner, and remote before deciding.

## Main differences

| Question | Kache | sccache |
| --- | --- | --- |
| Primary workflow | Local-first cache; an optional remote is read after a local miss and written in the background | Client-server compiler cache with local and remote storage |
| Rust setup | `kache init` | `RUSTC_WRAPPER=sccache` |
| C/C++ setup | `kache init` (PATH compiler-name shims on Unix) or `CC="kache cc"` | Prefix wrapper (`sccache gcc`); no ccache-style PATH farm |
| Remote backends | S3-compatible storage, GCS, filesystem paths, and OCI registries | S3, Redis, Memcached, GCS, Azure, GitHub Actions, WebDAV, and others listed by sccache |
| Inspection | `monitor`, `stats`, `explain`, `list`, and `doctor` | `--show-stats`, logs, and server commands |
| Remote transfer | On-demand restore plus `sync`, manifests, and prefetch | Remote access is part of normal server operation |
| Rust executables | Cacheable by default on Linux and macOS | Rust crates that invoke the system linker are not cached, according to the sccache README |
| Incremental Rust builds | Kache disables or isolates incremental state according to its configured policy | Incrementally compiled Rust crates are not cached, according to the sccache README |
| Fallback | Passes invocations it does not cache to another wrapper, such as sccache | No Kache-specific handoff needed |

## Choose Kache when

- You want cache entries shared across local worktrees without a remote.
- You want to inspect individual events and ask why a compile missed.
- You want explicit pull and push steps in CI (`kache sync --pull`, `kache sync --push`) and prefetch you can tune or turn off.
- Caching eligible Rust executable and linker outputs matters to your workload.
- You want one `PATH` change to cache Make/CMake/PKGBUILD object compiles without wrapping `CC` in a shell.

## Gaps sccache can fill

If you need a compiler Kache does not cache yet, [use sccache as a fallback](#use-sccache-as-a-fallback). Kache caches what it supports and passes the rest to sccache, so one build can use both.

If a missing compiler, backend, or workflow still blocks you, [open a feature request](https://github.com/kunobi-ninja/kache/issues/new?template=feature_request.md). Include the build command and the compiler or backend. Concrete workloads help us prioritize support.

## Measure your own build

Compare cold, local-hit, and remote-hit cases separately. Keep these fixed:

- repository revision and lockfile
- compiler and linker versions
- target triple and build profile
- machine or CI runner class
- remote region and credentials

Run several samples after one warm-up and compare medians. A count-based hit rate does not show how much compile time was avoided, so record wall time as well.

Kache can generate benchmark artifacts with `kache stats --full` and the repository benchmark harness. See [Benchmarks](/docs/benchmarks).

## Use sccache as a fallback

Put Kache in front of sccache. After `kache init`, add the fallback to your Kache config:

```toml title="~/.config/kache/config.toml"
[cache]
fallback = "sccache"
```

Kache still caches everything it supports. Compiler invocations it passes through go to sccache instead of the bare compiler. `KACHE_FALLBACK=sccache` sets the same option for a single build.

If the fallback fails to start or exits unsuccessfully, Kache warns and retries once
with the direct compiler. The direct compiler's result determines the build result.
Interrupts and termination requests (including shell statuses 130 and 143) do not trigger a retry.
Both attempts keep their diagnostics; the warning marks the transition to the direct
compiler. A genuine source error can therefore be reported twice.

On macOS, Kache also checks the output access of an identifiable local sccache TCP
server. A confirmed sandbox denial skips the fallback before compilation. This
optional check respects `SCCACHE_SERVER_PORT`. With a Unix socket, an unidentified
server, or no sandbox query available, Kache runs the fallback as usual and retries
with the direct compiler if it fails. Kache does not start, stop, or change the
server during this check. A server that starts after the check can still inherit
its launcher's sandbox, so the retry is still needed. Use `KACHE_FALLBACK=off` to disable the fallback for a build.

Build events and JSON report bypass details include `fallback_attempt` with
`wrapper`, `outcome`, `exit_code`, and `detail`. In the JSON report, the bypass
detail's `route` (`fallback` or `direct`) and `exit_code` show whether direct
compilation followed and whether it succeeded. A build event carries
`fallback: true` when Kache kept the wrapper's result, and its `exit_code` is
the final status.

Invocations that read standard input or write standard output, preprocessor-only
runs (`-E`, `-M`, `-MM`, `/E`, `/EP`), and invocations with an unexpanded
response file (`@file`) go directly to the compiler, and Kache prints the same
warning for them. This prevents a failed fallback from consuming input or
leaving partial output that cannot be replayed safely.

A Rust compile whose Kache key holds inputs the fallback does not know also
goes directly to the compiler when Kache does not cache it: a crate with
[extra inputs](/docs/getting-started/configuration#hidden-compile-time-inputs),
and a unit of a workspace or path package whose build script declares a path
or a variable (see
[Build scripts](/docs/how-it-works/build-scripts#declared-inputs-in-the-rust-key)).
The fallback could otherwise restore an artifact built from older inputs.