Homebrew Uses Too Much Disk Space: How to Clean Up and Prevent Bloat
Homebrew can consume 10GB+ of disk space with old versions, caches, and the git repository. Here's how to clean up — and how stout stays lean.
Open Disk Utility on a Mac that has been running Homebrew for a year or two and you might be surprised: Homebrew and its packages can easily occupy 10-20GB of disk space. On a 256GB MacBook Air, that’s 4-8% of your total storage consumed by a package manager.
Here’s where all that space goes, how to reclaim it, and how to prevent the bloat from returning.
Where the disk space goes
Homebrew stores data in several locations. Let’s audit each one:
# Check total Homebrew disk usage (this may take a moment)
du -sh /opt/homebrew 2>/dev/null || du -sh /usr/local/Homebrew
du -sh "$(brew --cache)"
du -sh "$(brew --repository)/Library/Taps"
Here’s a typical breakdown on a machine with ~50 installed packages:
| Location | Contents | Typical Size |
|---|---|---|
$(brew --cellar) | Installed packages (current + old versions) | 3-8 GB |
$(brew --cache) | Downloaded bottles and source archives | 2-5 GB |
Library/Taps/homebrew/homebrew-core/.git | Git objects for formula repository | 500-700 MB |
Library/Taps/homebrew/homebrew-cask/.git | Git objects for cask repository | 200-400 MB |
Linked files in bin/, lib/, include/ | Symlinks (negligible) | < 1 MB |
The biggest offenders are old package versions and the download cache.
Old package versions
When you run brew upgrade, Homebrew downloads and installs the new version but keeps the old one. This is a safety feature — if the upgrade breaks something, you can switch back. But it means every package you’ve ever upgraded has multiple versions sitting in the Cellar:
# List all installed packages with their versions
brew list --versions
# Example output:
# node 20.11.0 20.10.0 20.9.0 21.6.1
# [email protected] 3.12.1 3.12.0
# openssl@3 3.2.0 3.1.4 3.1.3
Each version of node is 70-100MB. Three old versions of Node alone waste 200-300MB.
The download cache
Every bottle Homebrew downloads is cached in ~/Library/Caches/Homebrew (macOS) or ~/.cache/Homebrew (Linux). This cache persists indefinitely. If you’ve been using Homebrew for a year, it may contain hundreds of outdated .tar.gz and .bottle.tar.gz files:
ls "$(brew --cache)" | wc -l
# Often 200+ files
du -sh "$(brew --cache)"
# Often 2-5 GB
The git repositories
The homebrew-core git repository alone occupies 500-700MB. If you have homebrew-cask and additional taps, the total git data can reach 1GB+:
du -sh "$(brew --repository)/Library/Taps/"
This is pure metadata — none of it is actual package content. It’s the accumulated history of every formula change since 2009.
How to clean up
Step 1: Remove old package versions
brew cleanup
This removes all but the latest version of each installed package and clears outdated downloads from the cache. Run it with -n first to preview what will be removed:
brew cleanup -n
# Shows what would be removed without actually removing it
To be more aggressive and also remove the download cache:
brew cleanup -s
The -s flag scrubs the download cache, removing even the bottles for currently installed versions (they can always be re-downloaded).
Step 2: Clear the download cache entirely
If brew cleanup -s doesn’t free enough space, you can delete the entire cache:
rm -rf "$(brew --cache)"
This is safe — Homebrew will re-download bottles as needed. The only cost is re-downloading a package if you reinstall it.
Step 3: Remove unused dependencies
Packages that were installed as dependencies but are no longer needed by any installed formula can be removed:
brew autoremove
This identifies “orphaned” dependencies and removes them. It’s common to find 5-10 orphaned packages after uninstalling a few top-level formulae.
Step 4: Prune dead symlinks
brew cleanup --prune=all
This removes broken symlinks and stale lock files from the Homebrew prefix.
Step 5: Audit for large packages
Find your biggest installed packages to decide if you still need them:
# List packages sorted by disk usage (largest first)
brew list --formula | xargs -I{} sh -c 'du -sh "$(brew --cellar)/{}" 2>/dev/null' | sort -rh | head -20
Common space hogs include gcc (1-2GB), llvm (1-3GB), qt (500MB-1GB), rust (500MB+), and texlive (3-5GB). If you installed one of these as a dependency and no longer need it, removing it can free gigabytes.
Preventing future bloat
Enable auto-cleanup
Set Homebrew to clean up old versions automatically after every install:
export HOMEBREW_CLEANUP_MAX_AGE_DAYS=30
export HOMEBREW_CLEANUP_PERIODIC_FULL_DAYS=7
Or run brew cleanup on a schedule. Add to your crontab:
# Clean up weekly
0 3 * * 0 /opt/homebrew/bin/brew cleanup -s >/dev/null 2>&1
Limit cache retention
export HOMEBREW_CLEANUP_MAX_AGE_DAYS=14
This tells brew cleanup to remove cached downloads older than 14 days.
Be selective about what you install
Before installing a package, check its dependency tree:
brew deps --tree <formula>
A single brew install imagemagick can pull in 30+ dependencies. Consider whether a lighter alternative exists (e.g., libvips instead of ImageMagick, jq instead of a full Python environment for JSON processing).
How stout stays lean
stout is designed to minimize disk usage from the ground up:
3MB index vs 700MB git repo. The entire package metadata database is a single 3MB SQLite file. There are no git objects, no commit history, no working tree copies of formula files. This alone saves 700MB+ compared to Homebrew’s default configuration.
No download cache by default. stout doesn’t cache downloaded bottles after installation. Once a package is extracted and installed, the bottle archive is deleted. If you need to reinstall, stout re-downloads the bottle — which takes seconds with a modern connection. You can opt into caching with stout config set cache.bottles true if you prefer the tradeoff.
Automatic cleanup on upgrade. When stout upgrades a package, it removes the old version by default. There’s no accumulation of stale versions in the Cellar. If you want to keep old versions (for rollback), you can enable it explicitly with stout config set cleanup.keep_old true.
Space reporting. stout provides built-in disk usage reporting:
stout status --disk
# Installed packages: 2.4 GB (47 formulae)
# Index: 3.1 MB
# Cache: 0 B
# Total: 2.4 GB
Compare this to the typical Homebrew installation where you need to cobble together multiple du commands to understand your total footprint.
A realistic before/after
On a test machine with 50 common development packages installed:
| Component | Homebrew | stout |
|---|---|---|
| Package metadata | 720 MB | 3 MB |
| Installed packages | 4.2 GB | 4.2 GB |
| Download cache | 2.8 GB | 0 B |
| Old versions | 1.1 GB | 0 B |
| Total | 8.8 GB | 4.2 GB |
The installed packages are identical — same bottles, same binaries. The difference is entirely metadata overhead, cached downloads, and accumulated old versions. stout saves over 4GB of disk space while maintaining the same installed packages.
If you’re running low on disk space on your Mac, start with brew cleanup -s and brew autoremove. Those two commands alone can reclaim several gigabytes. For a permanent solution, a package manager that’s lean by default eliminates the need for periodic cleanup altogether.
Need Rust performance engineering or AI agent expertise?
Neul Labs — the team behind stout — consults on Rust development, performance optimization, CLI tool design, and AI agent infrastructure. We build fast, reliable systems that ship.