The mem0 post mentioned that oMLX serves chat and embedding models on this machine. What it left out: none of those models live on the internal disk. The whole model library sits on an external SSD, and a second drive takes hourly backups of it. This post covers both halves.
Why an external SSD
The Mac mini doing the serving has a 1 TB internal disk, and MLX models add up fast — a single 27B 4-bit model is ~15 GB. My library is at 36 GB and growing:
/Volumes/Mate_Mini/omlx/base/models/
├── Youssofal/Qwen3.8-27B-MTPLX-Optimized-Speed
└── mlx-community/
├── bge-m3-mlx-8bit
├── gemma-4-e2b-it-4bit
└── Kokoro-82M-bf16
Model loading from a Thunderbolt-attached SSD is effectively indistinguishable from internal storage — the weights stream into unified memory once, then inference is compute-bound anyway. What the internal disk gains (free space, less wear from multi-GB downloads) outweighs a load time I never notice.
Pointing oMLX at the SSD
oMLX keeps everything — models, HF cache, logs, settings, usage stats — under one base path. Relocating it is a single setting in the app, which persists the choice to a bootstrap file:
$ cat ~/Library/Application\ Support/oMLX/base-path
/Volumes/Mate_Mini/omlx/base
The Homebrew-installed omlx CLI is just a shim that reads that file and exports it before handing off to the real binary inside the app bundle:
BOOTSTRAP="$HOME/Library/Application Support/oMLX/base-path"
if [ -r "$BOOTSTRAP" ]; then
IFS= read -r OMLX_BASE_PATH < "$BOOTSTRAP" || OMLX_BASE_PATH=""
if [ -n "$OMLX_BASE_PATH" ]; then
export OMLX_BASE_PATH
fi
fi
exec '/Applications/oMLX.app/Contents/MacOS/omlx-cli' "$@"
The one file that matters inside the base path is settings.json, which records the model directory explicitly:
{
"model": {
"model_dirs": ["/Volumes/Mate_Mini/omlx/base/models"]
}
}
Restart the server (omlx restart) and it serves from the SSD. launch_at_login is on, and on a desktop mini the drive is always attached — if yours isn’t, see the gotchas below.
Why back up re-downloadable files at all
Model weights are public — you can always re-download them. But 36 GB over a slow or metered connection is hours of waiting, and the directory is more than weights: settings.json, per-model tuning in model_settings.json, hf_download_tasks.json, and a usage.sqlite3 with serving statistics are not re-downloadable. The goal isn’t disaster-proofing Hugging Face’s catalog; it’s making “restore directory, restart server” a five-minute operation.
Kopia does the backups
Kopia is a deduplicating, encrypted, content-addressed backup tool — think restic with a friendlier scheduler. I run KopiaUI on the mini, with the repository on a second external drive (a 9 TB spinning disk), because a backup on the same device as the source is a copy, not a backup:
Source: /Volumes/Mate_Mini/omlx (3 TB SSD)
Repository: /Volumes/Getea/VM-backups/mate_mini_backups (9 TB HDD)
The repository is password-encrypted at rest, as every Kopia repository is. It also holds three other directories off the same SSD (VMs, voice models, container data) — Kopia deduplicates across all of them.
The policy for the oMLX directory, as configured in the UI:
- Schedule: snapshot every hour
- Retention: 5 latest, 24 hourly, 12 daily, 4 weekly, 24 monthly, 3 annual
- Compression:
zstd-fastest
The CLI equivalent, using the binary bundled inside KopiaUI:
KOPIA="/Applications/KopiaUI.app/Contents/Resources/server/kopia"
"$KOPIA" policy set /Volumes/Mate_Mini/omlx \
--snapshot-interval=1h \
--keep-latest=5 --keep-hourly=24 --keep-daily=12 \
--keep-weekly=4 --keep-monthly=24 --keep-annual=3 \
--compression=zstd-fastest
Model libraries are Kopia’s best case
Snapshots of a model directory are nearly free, because model weights are immutable: once bge-m3-mlx-8bit is downloaded, those gigabytes never change again. Kopia chunks and content-addresses everything, so after the first snapshot, hourly runs upload almost nothing. The actual snapshot list shows it:
2026-10-04 07:01 38.4 GB files:1091 (daily-4) ← Qwen3.8-27B landed
2026-10-04 23:02 38.4 GB files:1099 (hourly-19..24, daily-3, weekly-2)
+ 7 identical snapshots until 2026-10-05 19:02
2026-10-05 20:02 38.4 GB files:1099 (latest-1..5, hourly-1..18, ...)
+ 17 identical snapshots until 2026-10-06 13:00
Thirty snapshots deep, and the “identical” runs cost a few KB of metadata each. The jump from 13.1 GB to 38.4 GB in early October was the 27B model arriving — one incremental upload of the new blobs, then back to silence. This is the ideal backup profile: aggressive schedule, generous retention, negligible incremental cost.
Compression choice deserves a note: 4-bit quantized safetensors are already dense, so no compressor will shrink them meaningfully. zstd-fastest is cheap insurance for the JSON/SQLite/text files in the directory without burning CPU on the weights.
Gotchas
- Mount order at login. oMLX has
launch_at_loginenabled. If the SSD isn’t mounted when the server starts, the base path won’t resolve. On a desktop mini with permanently attached drives this never happens; on a laptop, either disable launch-at-login or accept that oMLX only works when the drive is in. - KopiaUI schedules only while it’s running. The hourly interval is executed by the app, not a system daemon. KopiaUI lives in the menu bar and starts at login, which covers it; if you quit the app, snapshots stop. For a headless setup, run
kopia server startunder launchd instead. - The backup crosses two physical devices. Source on the SSD, repository on the HDD. If you back up to the same drive, a dead drive takes both copies — the most common way “I have backups” turns out to be false.
- Everything gets snapshotted, including
cache/andlogs/. A.kopiaignorein the source directory could exclude them. At this scale I don’t bother — dedup makes the noise free, andignore_cache_directoriesin the global policy already skips OS-flagged caches. - Live snapshots are safe here. oMLX writes
usage.sqlite3and logs while serving, but weights are static. The worst case is a slightly stale stats database in the snapshot, which no restore scenario cares about.
Checking it works
KOPIA="/Applications/KopiaUI.app/Contents/Resources/server/kopia"
"$KOPIA" snapshot list /Volumes/Mate_Mini/omlx \
--config-file ~/Library/Application\ Support/kopia/repository.config
And the restore drill that actually matters: mount a snapshot (kopia mount), or kopia snapshot restore <id> /tmp/omlx-test, then point oMLX’s base path at the restored directory and confirm the models load. A backup you’ve never restored from is a hypothesis.