3.7 KiB
disk-reclaim — find reclaimable disk space
disk-reclaim scans a directory tree for generated/cache directories that
regenerate from source — node_modules, target, __pycache__, build
outputs, IDE state — and reports them sorted by size. Read-only by design;
it names paths, it never deletes.
The intended workflow is: run it, scan the list for entries you don't
need actively built, rm -rf those yourself. The script stays out of the
deletion decision because the right answer is project-by-project (a
target/ you'll need to recompile in 10 minutes is different from one on a
project you haven't touched in a year).
Usage
disk-reclaim # scan $HOME, default --min 100M
disk-reclaim ~/Code # scope to a subtree
disk-reclaim --min 1G # only the worst offenders
disk-reclaim --all # no minimum filter
disk-reclaim --no-summary # skip the per-category totals
Sample output (first real run on this machine, ~/Code --min 500M):
scanning /Users/natalie/Code (min size: 500M)...
SIZE PATH
---- ----
15.7G /Users/natalie/Code/@projects/@magic-civilization/src/simulator/target
5.6G /Users/natalie/Code/@projects/@magic-civilization/.local/build
1.2G /Users/natalie/Code/@projects/@lilith/lilith-platform.live/node_modules
top-level cache roots:
1.5G /Users/natalie/.npm
868M /Users/natalie/Library/Caches
579M /Users/natalie/.cargo/registry
totals by category:
15.7G target
5.6G build
1.2G node_modules
What it scans
Project-scoped patterns (via find ... -prune):
| Ecosystem | Patterns |
|---|---|
| JS/TS | node_modules, .next, .nuxt, .turbo, .vite, .parcel-cache, .svelte-kit, .astro, .cache, dist, build, out |
| Python | __pycache__, .pytest_cache, .mypy_cache, .ruff_cache, .tox, .venv |
| Rust | target |
| Other | _build, Pods, DerivedData, .gradle, .android |
-prune matters: once a node_modules is matched, find doesn't descend
into it looking for nested matches. Otherwise scans are slow and
double-count nested build dirs.
Top-level cache roots (checked once each, not via find):
~/Library/Caches,~/Library/Developer/Xcode/DerivedData(macOS)~/.cache(XDG)~/.npm,~/.pnpm-store,~/.yarn/cache~/.cargo/registry,~/.cargo/git
These are the cache root for their tool — including them in the find
sweep would be wrong (the script would find every nested .cache inside
them).
What it deliberately does NOT scan
| Pattern | Why excluded |
|---|---|
vendor/ |
Usually committed (Go) or required at runtime (PHP). Not generated. |
.git |
User data. Never delete. |
Top-level tmp, Downloads, Movies |
User-created content, not regenerable from source. |
| Docker images/volumes | Use docker system prune instead — separate workflow with its own safety story. |
Caveats before rm -rf
| Pattern | Cost to rebuild |
|---|---|
node_modules |
pnpm install / npm install — seconds to minutes depending on cache |
target (Rust) |
Full cargo build — minutes |
.venv |
uv sync / pip install -r requirements.txt — depends on wheel availability |
.next, .nuxt, dist, build |
Single build command — usually fast |
DerivedData, .gradle |
First build after deletion is slow; subsequent builds fine |
The script prints this warning at the bottom of every run. Cache roots
(~/.npm, ~/.cargo/registry, etc.) are safe to nuke — they're pure
caches that get repopulated lazily on next install.
Files
| Path | Role |
|---|---|
bin/disk-reclaim |
The script |
Related
- lan-power-ctrl — when apricot's disk fills and it wedges,
power-cycle apricotis the recovery path