kache 0.4.1

Zero-copy, content-addressed Rust build cache. No copies, no wasted disk — just hardlinks locally and S3 for sharing.
---
title: Configuration
description: Config file, environment variables, and the TUI editor.
---

# Configuration

kache reads configuration from three places, in order of priority:

1. **Environment variables** — always win, useful for CI overrides
2. **Config file** — selected from the config file priority below
3. **Defaults** — sensible values that work without any configuration

## Config file

The config file is TOML. You can edit it directly or use the TUI editor:

```sh
kache config
```

The TUI editor shows all fields with their current values, marks which ones are coming from env vars, and lets you toggle or edit them interactively.

Config file priority:

1. `KACHE_CONFIG`, when set
2. The nearest project-local `.kache.toml`, walking up from the current directory
3. User config at `~/.config/kache/config.toml`, respecting `XDG_CONFIG_HOME`

A minimal config that enables a remote cache looks like this:

```toml title="~/.config/kache/config.toml"
[cache.remote]
type = "s3"
bucket = "my-build-cache"
endpoint = "https://s3.example.com"   # omit for AWS S3
profile = "my-aws-profile"            # omit to use the default credential chain
```

## All settings

| Environment variable | Config key | Default | Description |
|---|---|---|---|
| `KACHE_CACHE_DIR` | `cache.local_store` | `~/Library/Caches/kache` on macOS, `~/.cache/kache` on Linux | Local cache directory |
| `KACHE_MAX_SIZE` | `cache.local_max_size` | `50GiB` | Maximum local store size |
| `KACHE_CONFIG` | — | XDG config path | Explicit config file path |
| `KACHE_S3_BUCKET` | `cache.remote.bucket` | — | S3 bucket name |
| `KACHE_S3_ENDPOINT` | `cache.remote.endpoint` | — | S3 endpoint URL (required for Ceph, MinIO, R2) |
| `KACHE_S3_REGION` | `cache.remote.region` | `us-east-1` | AWS region |
| `KACHE_S3_PREFIX` | `cache.remote.prefix` | `artifacts` | Key prefix inside the bucket |
| `KACHE_S3_PROFILE` | `cache.remote.profile` | — | AWS credentials profile |
| `KACHE_S3_ACCESS_KEY` | — | — | Explicit S3 access key |
| `KACHE_S3_SECRET_KEY` | — | — | Explicit S3 secret key |
| `KACHE_CACHE_EXECUTABLES` | `cache.cache_executables` | `false` | Cache bin/dylib/cdylib/proc-macro outputs |
| `KACHE_CLEAN_INCREMENTAL` | `cache.clean_incremental` | `true` | Auto-clean tracked incremental dirs during GC; active builds also remove the current crate's incremental dir eagerly |
| — | `cache.exclude` | `[]` | Source-path glob patterns that bypass kache and compile normally without lookup, store, or upload |
| `KACHE_COMPRESSION_LEVEL` | `cache.compression_level` | `3` | Zstd compression level (1–22) |
| `KACHE_S3_CONCURRENCY` | `cache.s3_concurrency` | `16` | Max concurrent S3 operations |
| `KACHE_S3_POOL_IDLE_SECS` | `cache.s3_pool_idle_secs` | `300` | How long an idle S3 connection is kept in the HTTP pool. Higher values reuse warm TLS sessions across build phases; lower this if you sit behind a load balancer that drops idle connections aggressively |
| `KACHE_DAEMON_IDLE_TIMEOUT` | `cache.daemon_idle_timeout_secs` | `600` | Idle daemon shutdown timeout in seconds (`0` disables auto-shutdown) |
| `KACHE_DISABLED` | — | `0` | Disable caching entirely (pass-through to rustc) |
| `KACHE_LOG` | — | `kache=warn` | Log level for stderr output |
| `KACHE_LOG_FILE` | — | `kache=info` | Log level for the file log |
| `KACHE_PROGRESS` | — | `auto` | CI progress lines: `always`, `never`, or `auto` |

`KACHE_PROGRESS=auto` (the default) prints per-crate progress lines to stderr when stderr is not a terminal. In CI this is usually the right behavior without any configuration.

## Excluding Sources

Use `cache.exclude` when a source file should compile normally but never use kache:

```toml title=".kache.toml"
[cache]
exclude = [
  "crates/problematic-rust-crate/**",
  "vendor/problematic-c-lib/**",
  "$CARGO_HOME/registry/src/**/some-crate-*/**",
]
```

Patterns are globs matched against the compiler's primary source path. Relative patterns are matched relative to the current build directory and, when kache can infer it, the Cargo workspace root. Excluded invocations bypass local lookup, remote lookup, store, and upload.

Exclude patterns support `~`, `$VAR`, and `${VAR}` expansion. `$CARGO_HOME` falls back to Cargo's default `~/.cargo` when the environment variable is not set, so registry-source exclusions work on default Cargo installs.

## Credential resolution order

Remote S3 credentials are resolved in this order:

1. `KACHE_S3_ACCESS_KEY` + `KACHE_S3_SECRET_KEY`
2. AWS profile from `cache.remote.profile` or `KACHE_S3_PROFILE`
3. AWS default chain, such as `AWS_ACCESS_KEY_ID`, `~/.aws/credentials [default]`, or IAM roles

For Ceph, MinIO, or R2, set `cache.remote.endpoint` or `KACHE_S3_ENDPOINT`.

```toml title="Ceph example"
[cache.remote]
type = "s3"
bucket = "build-cache"
endpoint = "https://s3.example.com"
profile = "ceph"
```

## Size values

Size fields (`KACHE_MAX_SIZE`, `cache.local_max_size`) accept human-friendly strings:

```
50GiB   10GB   512MiB   1024MB
```

## Log levels

`KACHE_LOG` follows the `tracing` subscriber syntax:

```sh
KACHE_LOG=kache=debug   # verbose, useful when diagnosing cache misses
KACHE_LOG=kache=info    # operational detail
KACHE_LOG=kache=warn    # default — only surface real problems
```

The file log is written to `~/Library/Logs/kache/kache.log` on macOS and `~/.cache/kache/kache.log` elsewhere. It rotates automatically when it exceeds 5 MB.

## Local store layout

```
~/.cache/kache/           # Linux example
├── index.db          # SQLite index (WAL mode)
├── events.jsonl      # build event log
├── daemon.sock       # daemon unix socket
└── store/            # content-addressed blobs
    ├── ab/
    │   └── abcdef...  # blake3 hash-named files
    └── ...
```

The store directory is excluded from Time Machine and Spotlight on macOS automatically.