A high-performance local compiler cache daemon
Project description
zccache
A blazing fast compiler cache for C/C++ and Rust
Inspired by sccache, but optimized for local-first use with aggressive file metadata caching and filesystem watching.
Quick Install
curl -LsSf https://github.com/zackees/zccache/releases/latest/download/install.sh | sh
powershell -ExecutionPolicy Bypass -c "irm https://github.com/zackees/zccache/releases/latest/download/install.ps1 | iex"
Verify:
zccache --version
Performance
50 files per benchmark, median of 5 trials. Run it yourself: ./perf
Cache Hit (warm cache)
| Benchmark | Bare Compiler | sccache | zccache | vs sccache | vs bare |
|---|---|---|---|---|---|
| C++ single-file | 11.705s | 1.576s | 0.050s | 32x | 236x |
| C++ multi-file | 11.553s | 11.530s | 0.017s | 695x | 696x |
| C++ response-file (single) | 12.540s | 1.558s | 0.047s | 33x | 267x |
| C++ response-file (multi) | 12.049s | 12.434s | 0.019s | 669x | 648x |
| Rust build | 6.592s | 8.604s | 0.045s | 193x | 148x |
| Rust check | 3.716s | 5.922s | 0.049s | 121x | 76x |
Cache Miss (cold compile)
| Benchmark | Bare Compiler | sccache | zccache | vs sccache | vs bare |
|---|---|---|---|---|---|
| C++ single-file | 12.641s | 20.632s | 13.430s | 1.5x | 0.9x |
| C++ multi-file | 11.358s | 11.759s | 12.867s | 0.9x | 0.9x |
| C++ response-file (single) | 12.063s | 20.607s | 14.087s | 1.5x | 0.9x |
| C++ response-file (multi) | 13.030s | 25.303s | 13.975s | 1.8x | 0.9x |
| Rust build | 7.119s | 10.023s | 8.507s | 1.2x | 0.8x |
| Rust check | 4.289s | 7.056s | 5.060s | 1.4x | 0.8x |
Benchmark details
- Single-file = 50 sequential
clang++ -c unit.cppinvocations - Multi-file = one
clang++ -c *.cppinvocation (sccache cannot cache these — its "warm" time is a full recompile) - Response-file = args via nested
.rspfiles: 200-Ddefines + 50-Ipaths + 30 warning flags (~283 expanded args) - Rust build =
--emit=dep-info,metadata,link(cargo build) - Rust check =
--emit=dep-info,metadata(cargo check) - Cold = first compile (empty cache). Warm = median of 5 subsequent runs.
- sccache gets cache hits but each hit still costs ~170ms subprocess overhead. zccache serves hits in ~1ms via in-process IPC.
Why is zccache so much faster on warm hits?
The difference comes from architecture, not better caching:
| sccache | zccache | |
|---|---|---|
| IPC model | Subprocess per invocation (fork + exec + connect) | Persistent daemon, single IPC message per compile |
| Cache lookup | Client hashes inputs, sends to server, server checks disk | Daemon has inputs in memory (file watcher + metadata cache) |
| On hit | Server reads artifact from disk, sends back via IPC | Daemon hardlinks cached file to output path (1 syscall) |
| Multi-file | Compiles every file (no multi-file cache support) | Parallel per-file cache lookups, only misses go to the compiler |
| Per-hit cost | ~170ms (process spawn + hash + disk I/O + IPC) | ~1ms (in-memory lookup + hardlink) |
Architecture enhancements that make the difference:
- Filesystem watcher — a background
notifywatcher tracks file changes in real time, so the daemon already knows whether inputs are dirty before you even invoke a compile. No redundant stat/hash work on hit. - In-memory metadata cache — file sizes, mtimes, and content hashes live in a lock-free
DashMap. Cache key computation is a memory lookup, not disk I/O. - Single-roundtrip IPC — each compile is one length-prefixed bincode message over a Unix socket (or named pipe on Windows). No subprocess spawning, no repeated handshakes.
- Hardlink delivery — cache hits are served by hardlinking the cached artifact to the output path — a single syscall instead of reading + writing the file contents.
- Multi-file fast path — when a build system passes N source files in one invocation, zccache checks all N against the cache in parallel, serves hits immediately, and batches only the misses into a single compiler process.
Broader tool coverage — zccache supports modes that other compiler caches don't:
| Mode | Description |
|---|---|
| Multi-file compilation | clang++ -c a.cpp b.cpp c.cpp — per-file caching with parallel lookups |
| Response files | Nested .rsp files with hundreds of flags — fully expanded and cached |
| clang-tidy | Static analysis results cached and replayed |
| include-what-you-use | IWYU output cached per translation unit |
| Emscripten (emcc/em++) | WebAssembly compilation cached end-to-end |
| wasm-ld | WebAssembly linking cached |
| rustfmt | Formatting results cached |
| clippy | Lint results cached |
| Rust check & build | cargo check and cargo build with extern crate content hashing |
Install
curl -LsSf https://github.com/zackees/zccache/releases/latest/download/install.sh | sh
powershell -ExecutionPolicy Bypass -c "irm https://github.com/zackees/zccache/releases/latest/download/install.ps1 | iex"
This installs the standalone native Rust binaries (zccache, zccache-daemon,
and zccache-fp) directly from GitHub Releases.
Default install locations:
- Linux/macOS user install:
~/.local/bin - Linux/macOS global install:
/usr/local/bin - Windows user install:
%USERPROFILE%\.local\bin - Windows global install:
%ProgramFiles%\zccache\bin
Global install examples:
curl -LsSf https://github.com/zackees/zccache/releases/latest/download/install.sh | sudo sh -s -- --global
powershell -ExecutionPolicy Bypass -c "$env:ZCCACHE_INSTALL_MODE='global'; irm https://github.com/zackees/zccache/releases/latest/download/install.ps1 | iex"
Each GitHub release also publishes standalone per-platform archives:
- Linux:
zccache-vX.Y.Z-x86_64-unknown-linux-musl.tar.gz,zccache-vX.Y.Z-aarch64-unknown-linux-musl.tar.gz - macOS:
zccache-vX.Y.Z-x86_64-apple-darwin.tar.gz,zccache-vX.Y.Z-aarch64-apple-darwin.tar.gz - Windows:
zccache-vX.Y.Z-x86_64-pc-windows-msvc.zip,zccache-vX.Y.Z-aarch64-pc-windows-msvc.zip
PyPI remains available if you prefer pip install zccache; those wheels also install
the native binaries directly onto your PATH. Pre-built wheels are available for:
| Platform | Architecture |
|---|---|
| Linux | x86_64, aarch64 |
| macOS | x86_64, Apple Silicon |
| Windows | x86_64 |
Verify the install:
zccache --version
Rust crates are also published on crates.io. The main installable/runtime crates are:
zccache-clizccache-daemonzccache-corezccache-hashzccache-protocolzccache-fscachezccache-artifact
Use it as a drop-in replacement for sccache — just substitute zccache:
Integration Summary
RUSTC_WRAPPER=zccache cargo build
export CC="zccache clang"
export CXX="zccache clang++"
- Rust: set
RUSTC_WRAPPER=zccacheor addrustc-wrapper = "zccache"to.cargo/config.toml. - Bash: export
RUSTC_WRAPPER,CC, andCXXonce in your shell or CI environment. - Python: pass
RUSTC_WRAPPER,CC, andCXXthroughsubprocessenv when invokingcargoorclang. - First commands to check:
zccache --version,zccache start,zccache status.
Rust zccache integration
Use zccache as Cargo's compiler wrapper:
# one-off invocation
RUSTC_WRAPPER=zccache cargo build
RUSTC_WRAPPER=zccache cargo check
# optional: start the daemon explicitly
zccache start
Add to .cargo/config.toml for automatic use:
[build]
rustc-wrapper = "zccache"
Recommended project-local config:
[build]
rustc-wrapper = "zccache"
[env]
ZCCACHE_DIR = { value = "/tmp/.zccache", force = false }
Supports --emit=metadata (cargo check), --emit=dep-info,metadata,link (cargo build),
extern crate content hashing, and cacheable crate types such as lib, rlib,
and staticlib. Proc-macro and binary crates are passed through without caching,
matching the usual sccache behavior.
Useful Rust workflow commands:
# inspect status
zccache status
# clear local cache
zccache clear
# validate wrapper is active
RUSTC_WRAPPER=zccache cargo clean
RUSTC_WRAPPER=zccache cargo check
zccache status
Bash integration
For shell-driven builds, export the wrapper once in your session or CI step:
export RUSTC_WRAPPER=zccache
export CC="zccache clang"
export CXX="zccache clang++"
zccache start
cargo build
ninja
If you want this active in interactive shells, add it to ~/.bashrc:
export RUSTC_WRAPPER=zccache
export PATH="$HOME/.local/bin:$PATH"
For per-build stats in Bash:
eval "$(zccache session-start --stats)"
cargo build
zccache session-end "$ZCCACHE_SESSION_ID"
Python integration
Python projects can use zccache when invoking Rust or C/C++ toolchains through
subprocess, build backends, or extension-module builds.
import os
import subprocess
env = os.environ.copy()
env["RUSTC_WRAPPER"] = "zccache"
env["CC"] = "zccache clang"
env["CXX"] = "zccache clang++"
subprocess.run(["cargo", "build", "--release"], check=True, env=env)
This is useful for:
setuptools-rustmaturinscikit-build-core- custom Python build/test harnesses that shell out to
cargo,clang, orclang++
Example with maturin:
RUSTC_WRAPPER=zccache maturin build
Example with Python driving cargo check:
subprocess.run(["cargo", "check"], check=True, env=env)
C/C++ build system integration (ninja, meson, cmake, make)
zccache is a drop-in compiler wrapper. Point your build system's compiler
at zccache <real-compiler> and it handles the rest:
# meson native file
[binaries]
c = ['zccache', '/usr/bin/clang']
cpp = ['zccache', '/usr/bin/clang++']
# CMake
set(CMAKE_C_COMPILER_LAUNCHER zccache)
set(CMAKE_CXX_COMPILER_LAUNCHER zccache)
The first build (cold cache) runs at near-bare speed. Subsequent rebuilds
(ninja -t clean && ninja, or touching source files) serve cached artifacts
via hardlinks in under a second.
Single-roundtrip IPC: In drop-in mode, zccache sends a single
CompileEphemeral message that combines session creation, compilation, and
session teardown — eliminating 2 of 3 IPC roundtrips per invocation.
Session stats: Track hit rates per-build with --stats:
eval $(zccache session-start --stats --log build.log)
export ZCCACHE_SESSION_ID=...
# ... build runs ...
zccache session-stats $ZCCACHE_SESSION_ID # query mid-build
zccache session-end $ZCCACHE_SESSION_ID # final stats
Persistent cache: Artifacts are stored in ~/.zccache/artifacts/
and survive daemon restarts. No need to re-warm the cache after a reboot.
Compile journal (build replay): Every compile and link command is recorded
to ~/.zccache/logs/compile_journal.jsonl as a JSONL file with enough
detail to replay the entire build:
{"ts":"2026-03-17T10:30:00.123Z","outcome":"hit","compiler":"/usr/bin/clang++","args":["-c","foo.cpp","-o","foo.o"],"cwd":"/project/build","env":[["CC","clang"]],"exit_code":0,"session_id":"uuid","latency_ns":1234567}
Fields: ts (ISO 8601 UTC), outcome (hit/miss/error/link_hit/link_miss),
compiler (full path), args (full argument list), cwd, env (omitted when
inheriting daemon env), exit_code, session_id (null for ephemeral),
latency_ns (wall-clock nanoseconds). One JSON object per line — pipe through
jq to filter, or replay builds by extracting compiler + args + cwd.
Per-session compile journal: Pass --journal <path> to session-start to
write a dedicated JSONL log containing only the commands from that session.
The path must end in .jsonl:
result=$(zccache session-start --journal build.jsonl)
session_id=$(echo "$result" | jq -r .session_id)
export ZCCACHE_SESSION_ID=$session_id
# ... build runs ...
# Inspect this session's commands only (no noise from other sessions)
jq . build.jsonl
zccache session-end $session_id
The session journal uses the same JSONL schema as the global journal. Entries
are written to both the global and session journals simultaneously. The session
file handle is released when session-end is called.
Multi-file compilation (fast path)
When a build system passes multiple source files to a single compiler invocation
(e.g. gcc -c a.cpp b.cpp c.cpp -o ...), zccache treats this as a fast path:
- Each source file is checked against the cache in parallel.
- Cache hits are served immediately — their
.ofiles are written from the cache. - Remaining cache misses are batched into a single compiler process, preserving the compiler's own process-reuse and memory-sharing benefits.
- The outputs of the batched compilation are cached individually for future hits.
This hybrid approach means the first build populates the cache per-file, and subsequent builds serve as many files as possible from cache while still letting the compiler handle misses efficiently in bulk.
Recommendation: Configure your build system to pass multiple source files per compiler invocation whenever possible. This gives zccache the best opportunity to parallelize cache lookups and minimize compiler launches.
Concurrency
The daemon uses lock-free concurrent data structures (DashMap) for artifact and metadata lookups, so parallel compilation requests from multiple build workers never serialize on a global lock.
Status
Early development — architecture and scaffolding phase.
Goals
- Extremely fast on local machines (daemon keeps caches warm)
- Portable across Linux, macOS, and Windows
- Correct under heavy parallel compilation (no stale cache hits)
- Simple deployment (single binary)
Tool Compatibility
zccache works as a drop-in wrapper for these compilers and tools:
- Clang Toolchain: clang, clang-tidy, IWYU
- Emscripten / WebAssembly: emcc, wasm-ld
- Rust Toolchain: rustc, rustfmt, clippy
Architecture
See docs/ARCHITECTURE.md for the full system design.
Key components
| Crate | Purpose |
|---|---|
zccache-cli |
Command-line interface (zccache binary) |
zccache-daemon |
Daemon process (IPC server, orchestration) |
zccache-core |
Shared types, errors, config, path utilities |
zccache-protocol |
IPC message types and serialization |
zccache-ipc |
Transport layer (Unix sockets / named pipes) |
zccache-hash |
blake3 hashing and cache key computation |
zccache-fscache |
In-memory file metadata cache |
zccache-artifact |
Disk-backed artifact store with redb index |
zccache-watcher |
File watcher abstraction (notify backend) |
zccache-compiler |
Compiler detection and argument parsing |
zccache-test-support |
Test utilities and fixtures |
Building
cargo build --workspace
Testing
cargo test --workspace
Documentation
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zccache-1.1.19-py3-none-win_arm64.whl.
File metadata
- Download URL: zccache-1.1.19-py3-none-win_arm64.whl
- Upload date:
- Size: 4.3 MB
- Tags: Python 3, Windows ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b16f033088200035e3b74e5404f8acaab40d2c78f8eda3c6b8c6ae634aa7470c
|
|
| MD5 |
ccaf44323978e8a344a29d37e51d8a4b
|
|
| BLAKE2b-256 |
82e4a1a21a0cd6769bf418c8698739432c5e2ffb128f54dabe661dd68f147122
|
File details
Details for the file zccache-1.1.19-py3-none-win_amd64.whl.
File metadata
- Download URL: zccache-1.1.19-py3-none-win_amd64.whl
- Upload date:
- Size: 4.6 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b08a083acabecafd8402a47f3415cc0024706ba114ca6a9d02b1f2a68dd95997
|
|
| MD5 |
3fbcb92c0d44c1679630aacf2988c6cc
|
|
| BLAKE2b-256 |
4deeb91ca7e340eec0b8cae48b0a4d2778f6002b8bb124963429674a5a1f4d9a
|
File details
Details for the file zccache-1.1.19-py3-none-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: zccache-1.1.19-py3-none-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 5.5 MB
- Tags: Python 3, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f19907c1d1e9c9afe3a9d40ea63cbac1c9af3bd7f0f0f56f17598082ffe821b
|
|
| MD5 |
abda252269221261838f76e6330a821f
|
|
| BLAKE2b-256 |
70985d504d4e1f429fcd38aaaf700861ff1180b48030648f86e2b6759c18262a
|
File details
Details for the file zccache-1.1.19-py3-none-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: zccache-1.1.19-py3-none-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 5.0 MB
- Tags: Python 3, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
211dfcd7dd5f8aee5fa80bcc08b0000ece336e3392582bae76e2e7707f0129ae
|
|
| MD5 |
5010b865d0e8dd74dc81e8951f771642
|
|
| BLAKE2b-256 |
d2078adf0ce9d048c5e5984ba09b159eb99b0d2b544c007785d0c08996419948
|
File details
Details for the file zccache-1.1.19-py3-none-manylinux_2_17_x86_64.whl.
File metadata
- Download URL: zccache-1.1.19-py3-none-manylinux_2_17_x86_64.whl
- Upload date:
- Size: 5.3 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c6b892522612c83fb23e7e6708d84ef3cd47a5b0dae1625280fa02ac3af5c30
|
|
| MD5 |
8f70f7ee7aeb914a2bb229ace2884aa1
|
|
| BLAKE2b-256 |
dd0109742dade548b7d096ae16ca6652735dd86823a3ffe8e240224ab07af565
|
File details
Details for the file zccache-1.1.19-py3-none-manylinux_2_17_aarch64.whl.
File metadata
- Download URL: zccache-1.1.19-py3-none-manylinux_2_17_aarch64.whl
- Upload date:
- Size: 4.9 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d516317d367359d10ab723aa20d2e6cd5bcd968ecd3aab506b92dd3c1b4c25d
|
|
| MD5 |
8149452bf9139a2beac0da314f33d08e
|
|
| BLAKE2b-256 |
ab98362f1461d16f562972f6587c81e8b0a5befb0535233e22ca3754fdf10eec
|
File details
Details for the file zccache-1.1.19-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: zccache-1.1.19-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.6 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
038962a7cbec49c3d5992e73cb373e30c3e3f69ac50174a5705dd228d3946d48
|
|
| MD5 |
3c37d0fbdcf598f89d8c688727140fb9
|
|
| BLAKE2b-256 |
1d74a4633ef94936cb0831d9041f69b65f25682a4f6e9768ed48e334281c2f22
|
File details
Details for the file zccache-1.1.19-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: zccache-1.1.19-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 4.8 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80d0833fb2ddef6a611986c7ec6f67a609fc1e1db02de42c8bc3ff3710eb6fba
|
|
| MD5 |
bbb7a161f381ade27973dc591a1a7449
|
|
| BLAKE2b-256 |
40df1cabb54926893e23ba76b682cc6c0d05a26791f70621e0ebe5dc63fd7688
|