← purge

How to free up disk space on a Mac: a developer's guide

A developer's Mac fills up differently from anyone else's. The photos and the downloads folder are rarely the problem. The problem is that every project you have ever built left several gigabytes behind, every package manager kept a copy of everything it downloaded, and every application on the machine has been writing to its own cache folder for years. Almost all of it regenerates. Very little of it needs to be there.

Where the space actually goes

Before deleting anything, it helps to know which categories are worth your attention. These are the ones that reliably run to gigabytes, and what each one costs you if you remove it:

WhatWhy it existsHow it comes back
DerivedDataXcode build intermediates, indexes, module cachesRegenerated on the next build
node_modulesInstalled dependencies, one copy per projectnpm install
.next / .turbo / distFramework and bundler build outputNext build
targetRust compilation artifacts, per cratecargo build
~/.npm/_cacacheEvery package tarball npm has downloadedRe-fetched from the registry
~/Library/CachesOne folder per installed app, decades deepRebuilt by each app on demand
ms-playwrightA full browser set per Playwright versionRe-downloaded on next install
~/Library/LogsPer-app log folders that nothing rotatesWritten fresh

The pattern is consistent: everything on that list is a cache or a build product. None of it is your work, and none of it is irreplaceable — the only cost of deleting it is time, paid once, the next time you build or install.

Finding it without guessing

macOS gives you About This Mac → Storage, which is close to useless for this: it buckets almost everything a developer cares about into “System Data” and offers no way to look inside. The usual next step is a manual tour with du -sh *, which works but takes an afternoon and misses anything outside the directory you happened to be standing in.

The alternative is a tool that already knows where these things live. purge is a command-line scanner for exactly this: one pass over your home directory, everything grouped and sized, nothing deleted until you say so.

brew install soummyaanon/tap/purge   # Homebrew — brings its own Node
npm i -g purge-cli                   # or npm, Node 22.18+
purge                                # or: purge-cli

# or, no install — always the newest version:
npx purge-cli@latest

It requires macOS. The Homebrew install brings its own Node; the npm install needs Node 22.18 or later. Either way it has zero runtime dependencies, makes no network calls, and sends no telemetry. The scan itself is read-only — you get a full picture of what is reclaimable before any decision is required.

What is safe to delete, and what is not

Safe, in almost every case

Not safe, whatever a cleaner tells you

This distinction is the whole reason purge exists as a review screen rather than a single command. It refuses to delete the second list outright, and shows the genuinely ambiguous cases — git-tracked, cloud-synced, ML model caches, agent history — unchecked with a warning next to them, so the default action is always the conservative one.

Clearing it in one pass

Running purge with no arguments scans everything and drops you into a keyboard checklist. Rows are grouped, sized and sorted, and the footer keeps a running total of what you have selected:

To look at one category only, name the groups: purge builds xcode. To get machine-readable output instead of the review screen, use purge --json.

Keeping directories permanently off-limits

Client work, a directory you never want a cleaner to see, a build cache you are deliberately keeping warm — put a glob in ~/.purgerc and it is never shown and never deleted:

{
  "keep": ["**/work/**", "~/Developer/client-project/**"],
  "staleDays": 90,
  "minSize": 25,
  "trash": true
}

staleDays sets how long a build directory must sit untouched before it is offered at all, and minSize is the megabyte floor below which items are not listed — both exist to keep the review screen short enough to actually read.

Undo, and a record

Run with --trash (or set "trash": true in ~/.purgerc) and nothing is deleted: every item is moved into ~/.Trash, instantly and unchanged. Empty the Trash when you are sure; run purge undo if you were not, and the last trash run goes back where it came from. Undo never overwrites a path that exists again and never moves anything that is not inside the Trash.

A plain run deletes for real, and purge writes a manifest of every run to ~/.purge/runs/: every path, its size, when it went and — for trash runs — where it went. If something you expected is missing a week later, purge history tells you whether it was this tool that took it.

Frequently asked questions

How do I free up disk space on a Mac as a developer?

Start with regenerable data rather than your own files. On a working developer Mac the largest reclaimable items are almost always Xcode DerivedData, node_modules directories in projects you are no longer building, framework build output such as .next, .turbo and dist, and package-manager caches for npm, bun, Homebrew and Playwright. Install purge with `brew install soummyaanon/tap/purge` (or `npm i -g purge-cli`) and run `purge`: it finds all of them in one scan, shows each one's size, and deletes only the rows you leave checked.

Is it safe to delete node_modules?

Yes, when the project has a lockfile committed. node_modules is entirely reproducible from package.json and your lockfile — `npm install` rebuilds it byte for byte. The only cost is the reinstall time the next time you work on that project, which is why purge flags directories by how long they have been idle instead of deleting them blindly.

Is it safe to delete Xcode DerivedData?

Yes. DerivedData holds intermediate build products, indexes and module caches that Xcode regenerates on the next build. Deleting it is a standard fix for stale-build problems, and it is frequently the single largest folder on an iOS developer's machine. Xcode Archives are a different thing — those are your shipped builds, and purge never deletes them.

Does purge have an undo?

Yes, when you run it in trash mode. `purge --trash` (or "trash": true in ~/.purgerc) moves every item into ~/.Trash instead of deleting it — instant, same volume, files unchanged — and `purge undo` moves the last trash run back where it came from, refusing to overwrite anything that exists again. A plain `purge` deletes for real and cannot be undone. Either way every run writes a manifest to ~/.purge/runs/ listing every path, its size, when it went and, for trash runs, where it went; read it back with `purge history`, or `purge history --last --json` to pipe it somewhere.

How do I stop a cleaner from touching a specific directory?

Create ~/.purgerc and add a glob to its keep array — for example {"keep": ["**/work/**"]}. Anything matching is never shown in the review screen and never deleted. The same file sets staleDays, which controls how long a build directory must sit untouched before it is offered, and minSize, the megabyte floor below which items are not listed at all.

Is it safe to delete the npm cache?

Yes. ~/.npm/_cacache is a download cache: clearing it means the next install re-fetches packages from the registry rather than reading them locally. It commonly runs to several gigabytes on a machine that has been installing packages for a year or two. The same reasoning applies to Homebrew, bun, Playwright browsers and Electron distributions.

Why does `purge` say "Unable to purge disk buffers: Operation not permitted"?

That message comes from macOS's own /usr/sbin/purge, a built-in utility that flushes disk buffers and needs sudo — not from this tool. It means your shell found the system binary before npm's, usually because npm's global bin directory sits after /usr/sbin in PATH or the install wasn't global. Run `purge-cli` instead (it is the same tool under a name that never collides), or install with Homebrew — `brew install soummyaanon/tap/purge` — whose bin directory comes before /usr/sbin, so plain `purge` resolves to this tool.

How do I update purge to the latest version?

Run `brew upgrade purge` if you installed with Homebrew, or `npm i -g purge-cli@latest` with npm. A global install stays at whatever version you installed — purge never phones home to check for updates, because it makes no network calls at all, by design — so updating is always an explicit step. If you would rather never think about versions, skip the install entirely: `npx purge-cli@latest` downloads and runs the newest release every time. (Plain `npx purge-cli` is not enough — npx happily reuses a stale cached copy.) After updating, run `hash -r` or open a new terminal so your shell forgets where it last found the command.

What should you never delete when cleaning a Mac?

Anything that is not regenerable: application settings and credentials, browser profiles containing passwords, bookmarks and history, installed editor extensions, coding-agent session history, Xcode Archives, and anything living inside iCloud Drive, Dropbox, Google Drive or OneDrive — deleting there propagates the deletion to your other machines. purge refuses to delete credentials, profiles and Archives outright, and shows everything ambiguous unchecked with a visible warning. Non-regenerable data you may still legitimately want gone — an uninstalled app's leftover settings, an old iOS backup, Docker's disk image — is never pre-checked and never swept up by select-all: since v0.7.0 you can delete such a row, but only by checking it yourself, past a warning naming exactly what the loss is.

Try it

brew install soummyaanon/tap/purge   # or: npm i -g purge-cli, or: npx purge-cli@latest
purge                                # or: purge-cli

MIT-licensed and open source — the source is on GitHub, the package is on npm and in a Homebrew tap, and the landing page shows the review screen in action.