Recipes
Working commands, grouped by what you are trying to achieve. Every recipe
that can delete is shown in its --dry-run form first. Drop --dry-run once
the preview looks right — the rest of the command stays identical.
Substitute npx macleanup, macleanup or ./macleanup.sh freely; the
flags are the same.
Find out where the space went
# Full read-only audit — writes .txt files you can read at leisure
macleanup --profile audit --dry-run
open ~/.macleanup/reports/
# Per-directory usage for $HOME and ~/Library
macleanup --only 26
# Every file ≥ 500 MB under $HOME, with no age filter
macleanup --only 18
# System health and what is currently running
macleanup --only 0
Start here. Knowing which directory holds 40 GB usually beats running a cleanup blind.
Reclaim developer disk space
# Preview the whole developer bundle
macleanup --profile dev --dry-run
# Developer caches and Docker prune; Docker volume deletion has a separate prompt
macleanup --only "1,2,3,4" --dry-run
# Xcode alone: DerivedData, DeviceSupport, simulator leftovers
macleanup --only 1 --dry-run
# Package-manager caches with a tighter age threshold
macleanup --only 3 --cache-age-days 30 --dry-run
# Docker: containers, images and build cache; volumes require a separate interactive yes
macleanup --only 4 --dry-run
Sweep stale build directories
Section 23 deletes permanently. Preview, protect what matters, then run.
# Every node_modules-shaped dir untouched for 90+ days
macleanup --only 23 --stale-build-days 90 --dry-run
# Point it at your real project roots
macleanup --only 23 --scan-roots "$HOME/repos:$HOME/code" --dry-run
# Protect specific trees — the flag is repeatable
macleanup --only 23 \
--exclude-path "$HOME/Code/active-client" \
--exclude-path "$HOME/Code/side-project" \
--stale-build-days 120 --dry-run
A deleted node_modules comes back only while the lockfile resolves and the
registry still serves those versions. For a repo you are actively shipping,
protect it with --exclude-path.
Find big dormant files
# 2 GB+, untouched for 180 days
macleanup --only 24 --large-file-size-gb 2 --large-file-days 180 --dry-run
# 5 GB+, untouched for a year
macleanup --only 24 --large-file-size-gb 5 --large-file-days 365 --dry-run
Section 24 requires both atime and mtime to be older than the threshold. A file you opened recently is not flagged even if you have not edited it in years. If a file you expected is missing from the list, lower the threshold or use section 18, which has no age filter.
Selected files go to the Trash, so they are recoverable until you empty it.
Uninstall apps you no longer use
# Which apps have been idle for 60+ days?
macleanup --only 21 --threshold 60 --dry-run
# A year or more
macleanup --only 21 --threshold 365 --dry-run
# Review and choose interactively (recommended)
macleanup --only 21 --threshold 180
The interactive run supports multi-select — all, 1,3,5-7,12, or none.
Apps and their companion data move to the Trash.
macleanup --only 21 --yes --i-understand-deep moves every idle app to
the Trash with no further prompt. Preview first, always.
Clear caches without losing settings
# Every cache layer
macleanup --profile cache-only --dry-run
# Browser caches only — history, logins and bookmarks are untouched
macleanup --only 19
# User caches, skipping everything that needs sudo
macleanup --only 5 --no-sudo
Pre-flight before reinstalling Xcode
macleanup --only "1,17" --dry-run
Section 1 clears DerivedData and simulator leftovers; section 17 offers Xcode archives for review.
Deleting the archive for a build you already shipped means its crash reports can no longer be symbolicated. Keep the archives for live releases.
Audit login items
macleanup --only 25
Finds LaunchAgents and LaunchDaemons whose target no longer exists — a common
cause of slow logins and mysterious background processes. Sudo is only needed
if you choose to remove something under /Library/.
In batch mode, the command above reports candidates without removing them.
Removing them unattended requires both --yes and --i-understand-deep and
selects every candidate, so preview with --dry-run first.
Automate a routine sweep
Validate the exact command with --dry-run before it ever runs unattended.
# Step 1 — verify
macleanup --all --dry-run
# Step 2 — automate the verified command
macleanup --all --yes --quiet --notify
A launchd weekly job, using the global install:
# ~/Library/LaunchAgents/com.aoneahsan.macleanup.plist runs this:
/usr/local/bin/macleanup --all --yes --quiet --no-reports
--all is the safe batch only, and it never includes the deep sections — which
is exactly what you want from an unattended job.
Scripting with JSON
# Just the number of KB freed
macleanup --all --yes --json | jq .freed_kb
# Freed space plus which sections ran
macleanup --only 3,5 --yes --json | jq '{freed: .freed_kb, sections: .sections_done}'
# Fail a CI step if nothing was reclaimed
test "$(macleanup --all --yes --json | jq .freed_kb)" -gt 0
--json implies --quiet and puts everything except the single JSON object on
stderr, so stdout stays clean for a pipe.
Save a preview for review
macleanup --profile deep --dry-run --no-color > ~/Desktop/macleanup-preview.txt
--no-color strips ANSI escapes so the file is readable in any editor.
Housekeeping
macleanup --stats # what is in ~/.macleanup
macleanup --prune-history 30 --dry-run # preview a 30-day prune
macleanup --prune-history 30 # prune
macleanup --uninstall-data # remove ~/.macleanup entirely
macleanup --check-update # is a newer version published?
The heavy monthly clean
# 1. Snapshot first
tmutil snapshot
# 2. Preview
macleanup --profile deep --dry-run
# 3. Run it, minus the sections you want to keep control of
macleanup --profile deep --exclude 17,23 --yes
Next
- CLI reference — every flag used above.
- The 28 sections — what each number does.
- Profiles — the bundles behind
--profile.