Skip to content
Getting Started

Kache resolves settings in this order:

  1. environment variable
  2. config file
  3. built-in default

KACHE_DISABLED, KACHE_CONFIG, KACHE_SOCKET_PATH, logging controls, progress controls, and credentials are operational settings. They do not all have TOML equivalents.

Config file

Open the editor:

kache config

Or edit TOML directly. Kache chooses the first file in this order:

  1. KACHE_CONFIG
  2. the nearest .kache.toml, walking up from the current directory
  3. $XDG_CONFIG_HOME/kache/config.toml or ~/.config/kache/config.toml

The editor covers common fields and preserves advanced tables it does not expose.

[cache]
cache_executables = true

[cache.remote]
type = "s3"
bucket = "my-build-cache"
region = "us-east-1"

Use type = "filesystem" with path = "/mnt/kache" for a shared filesystem remote. Only s3 and filesystem are compiled remote backends.

Core settings

EnvironmentTOML keyDefaultPurpose
KACHE_CACHE_DIRcache.local_storeOS cache directoryPersistent store
KACHE_RUNTIME_DIRcache.runtime_dirlocal storeSocket, locks, logs, state, and session markers
nonecache.volumesunsetVolume-local store shards, e.g. [cache.volumes] "D:" = "D:/kache-store". Builds on a mapped volume share inodes there instead of copying across mounts. Unmapped volumes use the main store.
KACHE_SOCKET_PATHnone<runtime_dir>/daemon.sockAbsolute daemon endpoint override
KACHE_MAX_SIZEcache.local_max_size5% of the cache disk, floored at 5GiB and capped at 100GiBRegistered blob bytes allowed before GC. An explicit size always wins. none is not allowed.
KACHE_AUTO_GCcache.auto_gctrueSpawn throttled background GC under size pressure
KACHE_GC_MAX_AGE_HOURScache.gc_max_age_hours0Automatic age retention; 0 disables it
KACHE_GC_EVICT_SHAREDcache.gc_evict_sharedfalseRestore namespace-first GC for entries retained by build outputs
KACHE_MIN_STORE_COMPILE_MScache.min_store_compile_ms0Skip local retention for faster compiles; 0 stores all eligible results
KACHE_COMPRESSION_LEVELcache.compression_level3Zstd level, clamped to 1 through 22
nonecache.event_log_max_size10MiBRotate the event log after this size
nonecache.event_log_keep_lines1000Lines retained when the event log rotates
KACHE_DISABLEDnonefalsePass all compiler work through when set to 1 or true
KACHE_LOCAL_ONLYcache.local_onlyfalseIgnore all remote and planner configuration while keeping local caching
KACHE_REMOTE_READONLYcache.remote_readonlyfalseAllow remote reads but suppress remote writes. Untrusted CI (pull requests, tags, unprotected branches) also forces this on; =0 does not turn that off.
KACHE_SCHEDULERcache.schedulertruePace real compiler processes across concurrent builds after a miss. Hits and passthroughs never wait. 0 or false turns it off.

On macOS the default store is ~/Library/Caches/kache; on Linux it is $XDG_CACHE_HOME/kache or ~/.cache/kache; on Windows it is under %LOCALAPPDATA%.

GC and shared build outputs

cache.local_max_size measures blob bytes registered in Kache's store. A Cargo target directory can hardlink or block-clone those blobs. In that case the store name and the build output refer to the same disk blocks.

By default, GC keeps an entry when removing its last store name would reclaim zero bytes. This preserves a usable cache hit. It also means the registered store size can remain above local_max_size until the target output is removed. kache gc reports these entries as unreclaimable and separates store bytes removed from disk bytes reclaimed.

To reclaim the blocks, remove the retaining build output. For known stale targets, preview Kache's machine-local registry before deleting anything:

kache clean --tracked --stale 14d --dry-run
kache clean --tracked --stale 14d --yes

If enforcing the store namespace limit matters more than retaining hits, restore the older policy:

[cache]
gc_evict_shared = true

The equivalent environment setting is KACHE_GC_EVICT_SHARED=1. With this option, GC can drop an entry even though target files still hold all its blocks. The registered store size falls, but disk usage does not. A later build must compile or download that entry again. Explicit purge and repair operations remain unconditional regardless of this setting.

Compiler policy

EnvironmentTOML keyDefaultPurpose
KACHE_CACHE_EXECUTABLEScache.cache_executablesLinux/macOS: true; Windows: falseCache eligible Rust bins and test executables
KACHE_CLEAN_INCREMENTALcache.clean_incrementaltrueRemove tracked incremental directories during cleanup
KACHE_ADAPTIVE_INCREMENTALcache.adaptive_incrementaltrueLearn rapidly changing Cargo units and give them isolated incremental state
KACHE_PRESERVE_INCREMENTALcache.preserve_incrementalfalseForce eligible Cargo units onto isolated incremental state
KACHE_INCREMENTAL_CRATEScache.incremental_crates[]Force listed rustc crate names onto that incremental path
KACHE_MODIFIED_INPUT_GUARDcache.modified_input_guardfalseDo not store a result when a keyed input changed at or after build start
KACHE_INPUT_PREDICTIONScache.input_predictionsfalseRemember the source closure each crate's dep-info pass discovers
KACHE_FALLBACKcache.fallbacknoneWrapper used for ordinary Kache passthroughs
nonecache.exclude[]Source-path globs that bypass Kache
nonecache.bypass_crates[]Exact rustc crate names that bypass Kache
nonecache.bypass_argv[]Argument substrings that bypass Kache
nonecache.bypass_env[]NAME or NAME=VALUE rules that bypass Kache
KACHE_CC_EXTRA_ALLOWLIST_FLAGScc.extra_allowlist_flags[]Exact C/C++ flag spellings accepted in addition to the built-in model

Bypass rules can only reduce caching:

[cache]
exclude = ["vendor/problematic/**"]
bypass_crates = ["generated_bindings"]
bypass_argv = ["--cfg", "uncacheable_mode"]
bypass_env = ["SPECIAL_BUILD=1"]

Cache-key controls

EnvironmentTOML keyDefaultPurpose
KACHE_KEY_SALTcache.key_saltnoneOpaque value folded into every key
KACHE_BASE_DIRnonenoneOne extra path prefix normalized as <BASE_DIR>
nonepaths.base_dirs[]Additional absolute prefixes with distinct stable sentinels
KACHE_PATH_ONLY_ENV_VARScache.path_only_env_vars[]Path locator variables eligible for safe normalization
KACHE_KEY_ENV_VARScache.key_env_vars[]Environment read by proc macros but not reported by rustc
KACHE_VERIFY_RESTORESnoneoffRe-hash sampled or always before restoring
KACHE_VERIFYnoneoffRecompile each rustc cache hit and compare it to the restored files

KACHE_VERIFY is qualification for cache-key changes. Set it to 1 or true to recompile every rustc cache hit into a staging directory and diff those artifacts against the files just restored. Leave it unset (or 0 / false) in ordinary builds: each hit pays a full compile. There is no kache build command for this.

Path and debug-info bytes that differ only as embedded absolute paths are reported as path-debug and do not fail the build. Remaining byte differences are content. In both cases the restored files stay in place so the build continues; the wrapper records the class on the hit event as verify_compare (and in tracing when logging is on).

KACHE_VERIFY_RESTORES still only re-hashes stored blobs before restore. It does not recompile.

Use a key salt when an unobserved toolchain component changes output:

[cache]
key_salt = "sysroot-2026-08"

Keep paths.base_dirs narrow. Normalizing unrelated roots to stable sentinels can make different inputs appear equal.

key_env_vars accepts exact names and trailing-star prefix patterns:

[cache]
key_env_vars = ["BOLTFFI_*"]

Values are hashed exactly and are not written to event logs. A changing value such as a job ID will destroy hit rate.

Hidden compile-time inputs

Some macros read files that rustc does not report. Put kache.toml without a leading dot next to the crate manifest:

extra_inputs = [
  ".sqlx/**/*.json",
  "migrations/**/*.sql",
]

Matches are relative to that crate. Kache folds their paths and contents into its key and adds bounded watches to Cargo dep-info. Invalid or unreadable declarations fail closed.

For a workspace-root input used by a provider package and its direct consumers:

[[workspace.extra_inputs]]
crates = ["query-macros"]
inputs = [".sqlx/**/*.json"]
propagate_to_dependents = true

Workspace rules are accepted only from the .kache.toml beside the active Cargo workspace manifest. After adding a declaration to a target Cargo already considers fresh, rebuild that package once.

Remote settings

EnvironmentTOML keyDefaultPurpose
nonecache.remote.typeinferred as S3 for legacy configs3 or filesystem
KACHE_S3_BUCKETcache.remote.bucketnoneS3 bucket
KACHE_S3_ENDPOINTcache.remote.endpointAWSCustom S3-compatible endpoint
KACHE_S3_REGIONcache.remote.regionus-east-1Region
KACHE_S3_PREFIXcache.remote.prefixartifactsObject prefix
KACHE_S3_PROFILEcache.remote.profilecredential-chain defaultAWS profile
KACHE_S3_USER_AGENTcache.remote.user_agentnoneCustom HTTP User-Agent
nonecache.remote.pathnoneFilesystem remote root
nonecache.remote.atomic_write_dir<path>/.kache-tmpSame-filesystem staging directory
KACHE_S3_CONCURRENCYcache.s3_concurrency16Concurrent operations for either backend
KACHE_S3_POOL_IDLE_SECScache.s3_pool_idle_secs300S3 connection pool idle time
KACHE_REMOTE_RESTORE_TIMEOUT_SECScache.remote_restore_timeout_secs300Daemon operation deadline; wrapper demand remains capped at three seconds
KACHE_REMOTE_NEGATIVE_TTL_SECScache.remote_negative_ttl_secs60Cache definitive remote 404 results

Credentials resolve from explicit KACHE_S3_ACCESS_KEY and KACHE_S3_SECRET_KEY, standard AWS variables, the selected AWS profile, web identity, container credentials, then instance credentials.

See S3 setup or filesystem setup.

Prefetch and planner

EnvironmentTOML keyDefaultPurpose
KACHE_PREFETCH_ENABLEDcache.prefetch_enabledtrueEnable speculative manifest and planner prefetch
KACHE_REMOTE_KEY_CACHE_REFRESH_SECScache.remote_key_cache_refresh_secs60Refresh the fallback planner's remote key index; 0 means initial load only
KACHE_PREFETCH_MAX_KEYScache.prefetch_max_keys2000Entries allowed per plan; 0 is unlimited
KACHE_PREFETCH_MAX_BYTEScache.prefetch_max_bytes2GiBCompressed bytes allowed per plan; in-flight downloads may finish
KACHE_PREFETCH_DEADLINE_SECScache.prefetch_deadline_secs300Time during which a plan may start downloads; 0 disables the deadline
KACHE_PLANNER_ENDPOINTcache.planner.endpointnonePlanner service URL
KACHE_PLANNER_TIMEOUT_MScache.planner.timeout_ms750Planner request timeout
KACHE_PLANNER_TOKENcache.planner.tokennoneBearer token
KACHE_NAMESPACEnonenoneShard namespace used by manifest upload and prefetch

On a long-lived runner with a warm local store, speculative prefetch may be unnecessary:

[cache]
prefetch_enabled = false

Exact remote lookup and background upload continue to work.

Telemetry

Kache does not push metrics to a collector. It writes OTLP JSON files that Kartero imports from CI artifacts, the same way nightly benches already work.

Two signals, never mixed:

  • kache.bench.* — one-shot bench gauges (duration, speedup, verdict) from kache-scenario
  • kache.cache.* — cache counters (uploads, prefetch, store size) from kache telemetry write
kache telemetry write ./cache-otlp --scenario bench-firefox --phase warm

That writes metrics.otlp.json and schema_version in the directory. --scenario must match kache.bench.project. --phase distinguishes cold from warm: the bench stops the daemon between phases, so counters are per daemon lifetime. The rustc wrapper does not write these files. The planner service still exposes Prometheus /metrics for cluster scrape.

Daemon, events, and diagnostics

EnvironmentTOML keyDefaultPurpose
KACHE_DAEMON_IDLE_TIMEOUTcache.daemon_idle_timeout_secs0Stop after idle seconds; 0 keeps it running
KACHE_LOCAL_HIT_DAEMONcache.local_hit_daemonfalseExperimental daemon-assisted local lookup with local fallback
KACHE_HEARTBEAT_SECScache.heartbeat_secs30Event heartbeat cadence for long miss compiles; 0 disables it
KACHE_EXPLAIN_MISScache.explain_missfalseRecord changed key groups on repeat misses
KACHE_STORAGE_LAYOUT_ADVICEcache.storage_layout_advicetrueWarn when storage layout forces copies
KACHE_WINDOWS_HARDLINKcache.windows_hardlinkfalseUnsafe opt-in hardlink restores on non-CoW Windows volumes
KACHE_PROGRESSnoneoffhits or verbose compiler progress
KACHE_LOGnoneCLI: kache=warn; wrapper: offStderr tracing filter
KACHE_LOG_FILEnoneCLI/daemon: kache=info; wrapper: offFile tracing filter and wrapper opt-in
KACHE_EVENT_ROOTnonedetectedRoot attached to events for report filtering
KACHE_PAGERnoneplatform pagerPager command for kache list

Pin file-backed settings

Set cache.ignore_env in a controlled project config to ignore environment overrides for settings that also exist in TOML:

[cache]
ignore_env = true

It does not suppress KACHE_DISABLED, KACHE_CONFIG, KACHE_SOCKET_PATH, credentials, logging, progress, or other environment-only controls. Kache warns when it ignores a set variable.

The daemon reads configuration at startup and watches the active config file. File changes trigger a graceful restart. Environment changes require starting a new daemon from that environment; an installed service uses its service definition, not your current shell.

Available for:
Apple macOS logomacOSMicrosoft Windows logoWindowsLinux logoLinux
Download Kunobi