Open-source project
kunobi-ninja/kache avatar
kunobi-ninja/kache

Kache: a content-addressed build cache that hardlinks instead of copying

Zero-copy, content-addressed Rust build cache for Rust, C/C++ and more. No copies, no wasted disk — just hardlinks locally and S3 for sharing.

853 stars46 forksRustApache-2.0

At a glance

What is it?
Kache is a local-first compiler cache for Rust and C/C++ that stores build outputs by content and shares them across worktrees through reflinks or hardlinks, with S3-compatible and filesystem remotes for CI. It is a fit for teams running many Cargo targets against the same source tree; it is the wrong tool if you need a cache that is transparent to build systems other than rustc and the C/C++ compilers it shims.
Who is it for?
Adopt Kache if your CI or local workflow repeatedly builds the same crates across multiple worktrees or machines and you want the second build to cost disk space proportional to what changed rather than what was compiled. Do not adopt it if your build is dominated by non-rustc, non-C/C++ steps, or if you run on a filesystem without reflink or hardlink support and cannot tolerate the fallback.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The disk-space problem Kache targets

A normal compiler cache trades CPU time for disk space. sccache and similar tools keep a store of compiled artifacts, and when a build reuses an artifact they write a fresh copy into the target directory. On a repository the size of Firefox, where a single build produces tens of gigabytes of object files and rlibs, the second worktree pays for the whole thing again. The README's own storage chart makes the shape of this concrete: on APFS, the second Firefox worktree added about 3 GB of new data under Kache, which reflinks the other 13.5 GB, against 16.7 GB for sccache, which writes an independent copy. The benchmark is labeled Firefox 151 with Kache 0.7.0 on macOS/APFS, so it is a specific measurement on a specific filesystem, not a general claim. The mechanism behind that number is the part worth understanding: Kache stores outputs by content and then links them into place rather than copying them, so the marginal cost of a reused artifact is metadata, not bytes.

Content addressing, hardlinks, and where the bytes actually live

Kache is a content-addressed store. A cache key derived from the compiler invocation and its inputs maps to an entry, and that entry is the compiled output. When a build requests an entry that is already present, Kache links the stored file into the target directory instead of writing a new one. On a filesystem that supports reflinks the link shares extents; on one that supports hardlinks it shares the inode. The README's diagram shows four Firefox worktrees sharing cached build outputs through reflinks, which is the intended shape of the workflow: separate target directories, one backing store, shared blocks. This is also why the default local cache path matters. On Linux it is $XDG_CACHE_HOME/kache or ~/.cache/kache, on macOS ~/Library/Caches/kache, and on Windows %LOCALAPPDATA%\kache. If that path lives on a different filesystem from your target directory, the link cannot be made and the zero-copy property does not hold for that build. The README does not spell out the fallback behavior in the excerpt, so treat cross-filesystem setups as something to verify rather than assume.

Rust setup: rustc-wrapper, not a new build command

The Rust integration is deliberately thin. kache init sets rustc-wrapper in Cargo's config, which means Cargo itself calls Kache for every rustc invocation and your existing cargo build commands are unchanged. The README states that on Unix kache init also adds the [env] keys for build-script C and C++, and that kache init --no-service gives persistent Cargo configuration without an OS service. The install sequence is three lines: cargo install kache, then kache init --check to print the proposed changes, then kache init to apply them. That --check step is the one to actually use, because the command edits your Cargo configuration and you want to see the diff before it lands. For Rust executables the README notes support on Linux and macOS, disabled by default on Windows. Rust libraries and build scripts are listed as supported. If you would rather not touch Cargo config at all, RUSTC_WRAPPER=kache is the equivalent environment-variable route.

C and C++ through PATH shims, with pass-through for the rest

The C/C++ story is different because there is no single wrapper hook equivalent to rustc-wrapper that Make, CMake, and autotools all honor. Kache's answer is compiler-name shims: kache install-shims writes a directory of executables named gcc, g++, and so on, and you put that directory first in PATH. Build systems that call gcc by name then route through Kache without a CC= edit or a shell wrapper. The README gives the exact two commands: kache install-shims, then export PATH="$HOME/.local/lib/kache/shims:$PATH". Distribution packages place the same layout at /usr/lib/kache, and the Nix package exposes symlinks under ${kache}/shims and ${kache}/lib/kache. Two caveats are stated plainly. First, kache init can create the user farm but does not change PATH, so for makepkg you must put the same assignment in ~/.makepkg.conf. Second, Kache inspects the real compiler invocation and passes through unsupported or unsafe invocations. That pass-through is the safety valve, and it is also the limit: if your build uses a compiler flag combination Kache does not model, you get a correct build and no cache hit, not a wrong build.

Remotes: S3-compatible and filesystem, with bounded restore memory

Sharing beyond one machine is configured in TOML. A minimal S3-compatible remote is three keys under [cache.remote]: type = "s3", bucket, and region. Credentials come from the standard AWS environment variables or credential chain, so Kache does not introduce its own secret store. The README names AWS S3, MinIO, and Cloudflare R2 as in scope, and also lists a filesystem remote type for shared disks and CI volumes. The filesystem remote is the more interesting option for on-prem CI, because it needs no object-store account and the shared disk is already the thing your runners mount. Release v0.19.0 is titled bounded memory for remote restores, which tells you that remote restore memory was a real constraint at some point; if you pull large artifacts into constrained CI containers, that release note is the one to read before pinning an older version. The kache sync command pulls from and pushes to the configured remote, and kache gc enforces cache limits.

Diagnostics are the part most caches skip

The command surface is where Kache separates itself from a minimal wrapper. kache monitor gives live build and cache activity; kache stats is the non-interactive summary; kache doctor runs setup and integrity checks. The one that matters most for adoption is kache why-miss <crate>, which explains the latest miss. Release v0.18.0 is titled understand each build's cache misses, so this is a deliberate design priority rather than an afterthought. A cache you cannot debug is a cache you eventually disable, because a 40 percent hit rate with no explanation is indistinguishable from a misconfiguration. kache list inspects cached entries, and kache daemon status inspects the background service. The daemon is worth noting as an architectural fact: Kache runs a background service, and kache init --no-service exists precisely because some environments do not want one. The README links a daemon lifecycle doc, so the service has a defined state machine rather than being fire-and-forget.

Where Kache is the wrong choice

Three limits are visible in the material. First, workload coverage. The support table lists Rust libraries and build scripts, Rust executables on Linux and macOS, and C/C++ object files. Build systems outside rustc and the C/C++ compilers it shims are not in the table, so a project whose build time is dominated by code generation, protobuf compilation, or a language toolchain that is not C/C++ will see little benefit. Second, platform asymmetry. Rust executables are disabled by default on Windows, which means a Windows CI matrix gets partial coverage unless you change that. Third, filesystem dependence. The zero-copy claim rests on reflinks or hardlinks, and the README's headline storage number is an APFS measurement. On a filesystem or mount arrangement where the cache directory and the target directory are not on the same device, the linking optimization does not apply. The README excerpt does not state what Kache does in that case, so this is a configuration to test with kache doctor rather than assume. A fourth, softer limit: Kache is at 0.x. The release cadence shown is three versions in three days in September 2026, which is fast-moving for a tool that sits in the critical path of every compile.

How it differs from sccache

sccache is the obvious comparison and the README links a dedicated page for it. The architectural difference is what happens on a hit. sccache keeps a store and writes a fresh copy of the artifact into the target directory on reuse; Kache links the stored file into place. That single choice is the origin of the storage chart, and it is also the origin of the filesystem constraint: copying works anywhere, linking does not. The second difference is diagnostic surface. sccache's model is largely a hit/miss counter; Kache ships why-miss, monitor, and doctor as first-class commands, and devotes a release to understanding misses. If your problem is "we have a cache and I do not know why it is not helping," that difference is the whole argument. If your problem is "we need a cache that works identically on every filesystem and every platform we build on," sccache's copy-based model is more portable by construction.

Maintenance, licence, and what to check before rollout

Kache is Apache-2.0, which permits commercial and closed-source use and includes an explicit patent grant. That is a permissive licence and imposes no copyleft obligation on your build outputs; it is not legal advice, and if your organization has a licence policy you should route it through that policy. The maintenance surface is small in one sense and non-trivial in another. Configuration is a TOML file you can edit directly or through kache config, and the state is a content-addressed store with garbage collection via kache gc. But there is a background daemon, a local store, and optionally a remote, and each has its own failure mode. The upgrade path is the part to plan: because the store is content-addressed, a version that changes cache key derivation can invalidate entries wholesale, and the README points to a dedicated page on how cache keys work. The repository runs a scheduled benchmark workflow against Firefox, LLVM, Substrate, SurrealDB, Lance, OpenDAL, and eza, and the README instructs readers to treat timing or hit-rate numbers as evidence only when the individual job succeeds and its benchmark verdict is ok. That is an unusually honest framing, and it is the standard you should apply to your own measurements: run kache stats before and after, and use kache why-miss to confirm that misses are what you think they are.

Editorial conclusion

Adopt Kache if your CI or local workflow repeatedly builds the same crates across multiple worktrees or machines and you want the second build to cost disk space proportional to what changed rather than what was compiled. Do not adopt it if your build is dominated by non-rustc, non-C/C++ steps, or if you run on a filesystem without reflink or hardlink support and cannot tolerate the fallback. Before committing, run kache init --check to see the proposed Cargo config edits, run kache doctor to confirm the daemon and store are healthy, and verify with kache why-miss on a real miss that the cache key is keyed on what you expect.

Official sources

  1. kunobi-ninja/kache on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Community notes

Community notes