---
title: Filesystem setup
description: Configure a shared filesystem as the kache remote cache.
---
# Filesystem setup
A filesystem remote stores the same versioned cache objects as S3 in a shared
directory. It is useful when every builder can mount the same NFS, SMB, or other
shared filesystem and no object-storage service is needed.
## Minimal configuration
```toml title="~/.config/kache/config.toml"
[cache.remote]
type = "filesystem"
path = "/mnt/shared-kache"
prefix = "artifacts"
```
Use an absolute `path` so the wrapper, daemon, and `kache sync` resolve the same
directory regardless of their working directory. Every machine that reads or
writes the remote must mount that directory and have suitable permissions.
Treat every writer to the shared directory as trusted. A filesystem remote is
not a security boundary: a peer that can replace cache paths or create symlinks
can influence what other machines read or overwrite. Use S3 with access controls
when writers are not mutually trusted.
<Callout type="info">
kache currently compiles the `s3` and `filesystem` remote types. Other
OpenDAL services are not included in the binary.
</Callout>
## Atomic writes
Writes are staged in a temporary directory and atomically renamed into their
final location, so readers never observe a partially written pack or manifest.
By default, the staging directory is `<path>/.kache-tmp`.
Override it only when the default is unsuitable:
```toml title="~/.config/kache/config.toml"
[cache.remote]
type = "filesystem"
path = "/mnt/shared-kache"
prefix = "artifacts"
atomic_write_dir = "/mnt/shared-kache/.staging"
```
<Callout type="warn">
`atomic_write_dir` and `path` must be on the same filesystem. The final
rename cannot be atomic across filesystems and will fail with a cross-device
error. In particular, do not use the machine's `/tmp` unless it is on the
same filesystem as the shared cache. kache checks this when it connects and
refuses the remote with an explicit message rather than failing every write.
It must also sit outside the object tree (`<prefix>/v3/...`); otherwise
in-progress staging files are listed as if they were cached objects. The
default `<path>/.kache-tmp` already satisfies both rules.
</Callout>
<Callout type="info">
A shared cache directory that other users can write is a trust boundary. kache
verifies that each write resolves inside the configured `path`, so a symlink
planted under the cache cannot redirect writes elsewhere, and it rejects keys
whose components end in a dot or space (Windows strips those, which would make
two distinct keys collide). This is defense in depth: provision the directory
with restrictive permissions rather than relying on it.
</Callout>
## Directory layout
With the minimal configuration, the shared directory contains:
```text
/mnt/shared-kache/
├── .kache-tmp/
└── artifacts/
├── v3/
│ ├── manifests/{crate_name}/{cache_key}.json
│ └── packs/{crate_name}/{cache_key}.tar.zst
└── _manifests/
```
`prefix` keeps kache's objects in their own subtree. The logical layout and
`kache sync` behavior are the same for S3 and filesystem remotes. Filesystem
prefixes cannot contain `:` so the same config cannot become a Windows drive
path or alternate data stream.
Keep `KACHE_CACHE_DIR` on fast local storage for each machine. Only
`cache.remote.path` should point at the shared mount; the local store is not
safe to share between machines.