If you're a developer on macOS, you've probably noticed that your machine feels different than it did a year ago. You brew install something to try it out. You npm install -g a CLI for a side project. You drag a Mac app into /Applications to test an integration. A few weeks later you've moved on, but the installs haven't.
The problem isn't that any one tool is misbehaving. It's that your dev environment has no single source of truth. Your installed software is spread across at least three independent ecosystems — Homebrew, npm globals, and macOS application bundles — and none of them naturally tells you what's still being used versus what's just sitting there. Over months, the orphaned dependencies accumulate: stale Homebrew dependencies, npm CLIs you used once and forgot, app support files for software you uninstalled a year ago. To know what's actually on your machine, you have to audit each ecosystem separately.
Where the Orphans Live
Let's get specific about where dev installs leave traces on macOS.
Mac applications. When you remove an app from /Applications, the binary is gone but its support files stay. Typical paths to inspect:
~/Library/Application Support/— app data, databases, configuration~/Library/Caches/— cached assets that can be surprisingly large~/Library/Preferences/— plist files with old settings~/Library/Containers/— sandboxed app data~/Library/LaunchAgents/— background processes that may still be scheduled
Homebrew. When you uninstall a formula, its dependencies don't automatically go with it. brew autoremove catches some of them, but old versions linger in the Cellar, and config files in $(brew --prefix)/etc tend to stick around. brew leaves shows you top-level formulae you've explicitly installed, and brew deps --installed can give you the full dependency graph — between those two, you can manually identify orphans, but it takes time.
npm globals. Globally installed packages live wherever your npm prefix points (commonly /usr/local/lib/node_modules or, more recently, ~/.npm-global/lib/node_modules if you've configured that). Their binaries are symlinked into the corresponding bin directory. npm list -g --depth=0 shows your global install list, but it doesn't tell you which packages you've actually invoked recently.
The Audit Options
So how do you actually get visibility into all of this? A few approaches with different trade-offs.
Manual auditing with built-in CLIs. brew leaves, brew autoremove --dry-run, npm list -g --depth=0, plus a poke around ~/Library with ls and du -sh. This works, technically. It's free. But it requires you to mentally cross-reference outputs from three different tools, and you'd have to repeat the exercise periodically to keep a current picture. Most developers do this exactly once, get bored, and never come back.
Custom scripts. A motivated developer can write a script that aggregates brew output, npm list, and a directory walk of ~/Library, then identifies orphans by cross-referencing what's installed against what's on disk. This is genuinely the right shape of solution, and if you enjoy writing this kind of script, more power to you. The tedious part isn't writing it — it's keeping it working when Homebrew changes its prefix conventions, npm changes its install paths, or a new macOS release moves things around.
StrayFiles. StrayFiles is a focused dev-environment audit tool for macOS. It inspects your Homebrew formulae, npm globals, and macOS app installs in a single pane, cross-references each ecosystem's installed list against what's actually on disk, and surfaces orphaned dependencies with size and last-modified information. Removal is optional — the primary value is the visibility. When you do choose to remove something, StrayFiles invokes the official package manager commands (brew uninstall, npm uninstall -g) rather than touching files directly, so the package managers stay consistent with their own state. It's $9.99 one-time, no subscription.
Why the Three-in-One View Matters
You can audit any of these ecosystems individually. What you can't easily do — without writing the script yourself — is see them together. A globally installed npm CLI you forgot about looks identical to one you actively use, until you compare it to your shell history or your project repos. A Homebrew dependency you assume is being used by something might actually be orphaned. A folder in ~/Library/Application Support may belong to an app you removed three years ago. The value of a single pane is recognizing patterns across the three sources you couldn't see when looking at each one in isolation.
This is also the reason general-purpose Mac utilities don't fit well here. They were designed for a different problem — managing space on a non-developer's Mac — and they don't understand brew or npm. For a developer's machine, the audit needs to be aware of how developer tooling actually installs software, which means knowing about formula dependency graphs, npm prefix conventions, and the difference between an app's bundle and its support files.
Want to see what's actually installed?
StrayFiles audits your npm globals, Homebrew formulae, and macOS app installs in a single view.
Learn More About StrayFiles