A 70B Q4 GGUF is 42 GB. A 405B Q4 is 230 GB. If you have ever benchmarked a model, found a smaller one that won, and then left the loser sitting in ~/.lmstudio/models/ for six months, you already know the shape of the problem. The audit at brtkwr.com puts it plainly: "After the initial Docker/cache cleanup freed 150GB, going back and asking 'what else?' found another 75GB." Part of that 75 GB was LLM model files, kept because deleting them felt expensive and copying them felt vague. There is a middle move.
Why do LLM models deserve an archive, not a delete?
A ~/Library/Caches folder is a cache. Delete it and the app rebuilds it in seconds. A GGUF file is not a cache. It is a multi-gigabyte snapshot of weights that took an hour of bandwidth to fetch the first time, and that may or may not still be available on Hugging Face the day you need it back. Repos vanish. Quantisations get rerolled. A Bartowski Q4_K_M from January is not byte-identical to the same name uploaded in June.
Local LLM weights are state-bearing assets, the same category as a screen recording or an old Xcode archive. You do not delete state. You decide where it lives.
The three tools producing most of this state on a developer Mac are Ollama, LM Studio, and the Hugging Face hub cache. None of them dedupe across each other, which means the same 42 GB 70B can sit in three places at once. Before you archive anything you need to know how much you have and where.
How much LLM data is on my Mac right now?
A read-only audit takes one paste. No sudo, no helper app, no installer.
# Ollama models (blob store under ~/.ollama or $OLLAMA_MODELS)
du -sh "${OLLAMA_MODELS:-$HOME/.ollama/models}" 2>/dev/null
# LM Studio models (per-publisher GGUF tree)
du -sh ~/.lmstudio/models 2>/dev/null
du -sh ~/.lmstudio/models/*/ 2>/dev/null | sort -h | tail -10
# Hugging Face hub cache (per-revision snapshots)
du -sh ~/.cache/huggingface/hub 2>/dev/null
du -sh ~/.cache/huggingface/hub/models--*/ 2>/dev/null | sort -h | tail -10
# Any GGUF or safetensors over 4 GB anywhere in $HOME, with mtime
find ~ -type f \( -name "*.gguf" -o -name "*.safetensors" \) -size +4G \
-exec stat -f "%Sm %z %N" -t "%Y-%m-%d" {} \; 2>/dev/null \
| sort
The last command is the receipt. Read it the way you would read a fridge audit. Anything older than ninety days and never opened since is a candidate for archive. Anything you cannot remember pulling is a candidate for delete-after-archive.
What does the right archive layout look like?
Pick one external volume and one folder tree. Mirror the upstream Hugging Face shape so the path itself tells you where the file came from. A layout that has served me well on a 2 TB Samsung T9:
/Volumes/LLMArchive/
by-tool/
ollama/ # ollama blob store snapshot
manifests/
blobs/
lmstudio/ # mirrors ~/.lmstudio/models/
bartowski/
Meta-Llama-3-70B-Instruct-GGUF/
Meta-Llama-3-70B-Instruct-Q4_K_M.gguf
Meta-Llama-3-70B-Instruct-Q4_K_M.gguf.sha256
huggingface/ # mirrors ~/.cache/huggingface/hub/
models--meta-llama--Meta-Llama-3-70B-Instruct/
notes.md # one line per model: when archived, why
The by-tool/ split matters because Ollama's blob store is content-addressed and unreadable as bare files, LM Studio's tree is human-readable, and the Hugging Face hub uses revision symlinks. Mixing them loses information you need to restore later.
The .sha256 next to each weight file is the cheapest insurance you will ever buy. Compute it once when you archive, recompute it any time you suspect the drive, diff the two. If they match, the bytes survived. If not, redownload that one model rather than restoring corrupted state.
How do I actually move models to the archive?
The mechanics depend on which tool produced the model, but the order is always the same: quit the app, mv the files, write a checksum, point the app at the new location, verify one load, then move the originals to Trash.
Ollama: archive via OLLAMA_MODELS
Ollama reads its model store from the OLLAMA_MODELS environment variable, defaulting to ~/.ollama/models. The store contains a manifests/ tree (small JSON) and a blobs/ tree (the actual weight bytes). You move both together.
# 1. Quit the Ollama app and any ollama serve process.
pkill -x ollama 2>/dev/null
osascript -e 'tell application "Ollama" to quit' 2>/dev/null
# 2. Move the whole store to the external drive.
mv ~/.ollama/models /Volumes/LLMArchive/by-tool/ollama
# 3. Write per-blob checksums (the long step, kicks off in background).
cd /Volumes/LLMArchive/by-tool/ollama/blobs
for f in sha256-*; do
shasum -a 256 "$f" > "$f.sha256"
done
# 4. Tell Ollama where the new store lives.
echo 'export OLLAMA_MODELS=/Volumes/LLMArchive/by-tool/ollama' >> ~/.zshrc
# 5. Open a new shell, start Ollama, list models.
exec zsh
ollama list
ollama run llama3:8b "say hi"
The ollama list output is the receipt. If the model names you expected appear, the archive is live. The first ollama run confirms the weights are readable from the external drive.
LM Studio: archive via in-app settings
LM Studio stores models at ~/.lmstudio/models/ by default, organised as publisher/repo/file.gguf. The migration is a mv plus a Settings change.
# 1. Quit LM Studio.
osascript -e 'tell application "LM Studio" to quit' 2>/dev/null
# 2. Move the model tree to the external drive.
mv ~/.lmstudio/models /Volumes/LLMArchive/by-tool/lmstudio
# 3. Write a checksum next to every GGUF.
find /Volumes/LLMArchive/by-tool/lmstudio -name "*.gguf" \
-exec sh -c 'shasum -a 256 "$1" > "$1.sha256"' _ {} \;
# 4. Open LM Studio, Settings -> Models Directory ->
# /Volumes/LLMArchive/by-tool/lmstudio
# 5. Load the smallest model in the list. Confirm a one-token reply.
I usually add a belt-and-braces symlink at the old path as well: ln -s /Volumes/LLMArchive/by-tool/lmstudio ~/.lmstudio/models. Any older script that still references the old path then resolves correctly.
Hugging Face hub: archive via HF_HOME
The Hugging Face hub cache uses per-revision snapshots and symlinks under ~/.cache/huggingface/hub. It is the most likely to break if you delete pieces of it. The right move is to relocate the whole huggingface directory and point HF_HOME at the new root.
# 1. Move the cache as a unit.
mv ~/.cache/huggingface /Volumes/LLMArchive/by-tool/huggingface
# 2. Export HF_HOME so future transformers and huggingface_hub calls
# use the new path.
echo 'export HF_HOME=/Volumes/LLMArchive/by-tool/huggingface' >> ~/.zshrc
# 3. Sanity-check by listing one model's snapshots.
ls /Volumes/LLMArchive/by-tool/huggingface/hub/models--meta-llama--Meta-Llama-3-70B-Instruct/snapshots/
The same HF_HOME covers the datasets cache, which lives at $HF_HOME/datasets. The deeper layout story is covered in Hugging Face cache location on Mac and Hugging Face triple cache explained.
Which tool archives the cleanest?
The answer tells you where to start. A tool with a human-readable layout and a single env var to redirect it is cheap to archive. One with content-addressed blobs and no relocation switch is expensive.
| Tool | Default path | How to relocate | Layout shape | Archive complexity |
|---|---|---|---|---|
| LM Studio | ~/.lmstudio/models/ |
Settings UI | publisher/repo/file.gguf |
Low |
| Ollama | ~/.ollama/models/ |
OLLAMA_MODELS env var |
manifests/ plus blobs/ content-addressed |
Medium |
| Hugging Face hub | ~/.cache/huggingface/hub/ |
HF_HOME env var |
models--*/snapshots/* with symlinks |
Medium |
| GPT4All | ~/Library/Application Support/nomic.ai/GPT4All/ |
App settings | Flat | Low |
| llama.cpp manual | wherever you cloned | mv + path argument |
Whatever you set up | Trivial |
If you have a one-day budget, do LM Studio first (highest visible reclaim per minute of work), then Ollama, then Hugging Face. The hub cache tends to be the smallest of the three because transformers users typically pull a handful of models, not the dozen-plus that LM Studio testers accumulate.
How do I prove the archive worked before I delete the original?
This is the step almost every "I freed 200 GB" story skips, and it is the one that keeps you out of a 2 AM Hugging Face redownload. Three checks, in order:
- Checksum match.
shasum -a 256 -c file.sha256on the archived copy. If it errors, do not delete the original. - Load test. Open the app pointed at the new path. Load the model. Generate at least one token. If it errors, do not delete the original.
- Trash, do not
rm -rf. Move the original folder to the Finder Trash withmv ~/.lmstudio/models ~/.Trash/lmstudio-models-pre-archive-$(date +%Y%m%d)so the rollback is a drag-and-drop, not a redownload.
Only after seven days of real work against the archive do you empty Trash. The same Trash-first floor that protects DerivedData and Docker volumes is the right one for model weights, as laid out in Move to Trash vs rm -rf.
What about cross-machine sync?
Skip cloud drive sync. iCloud and Dropbox try to "optimise" multi-GB files by paging them in and out, the opposite of what you want for weights. The patterns that work are a USB-C external SSD passed between machines, or a wired 10GbE NAS. Wi-Fi 6 maxes out around 1 Gbps in real conditions, slow enough that a Hugging Face redownload is competitive.
Closing: archive is the third option
The default frame is binary: keep the model on your SSD or delete it and redownload. Archive is the third option, and it is the right one for most weight files older than ninety days. Pick an external drive, mirror the per-tool layout, write checksums, point the apps at the new path, then Trash the originals after a week of verification.
If you want a single screen that shows every GGUF and safetensor on your Mac with size, last-modified, owning tool, and a tickbox to move it to Trash, CleanMyDev is the $9.99 lifetime tool that gives you that receipt before it deletes anything. Move-to-Trash by default, no admin password, no subscription, no surprises.