v1.0 — Now available for macOS · Press ⌘ Space to launch
← Back to blog

Why `git checkout` triggers a Spotlight storm (and how to stop it for good)

CmdSpace Team·

You run git checkout main. Three seconds later, your fan spins up. Activity Monitor shows mdworkershared at 280% CPU. Your battery icon turns yellow. The build you wanted to start is now waiting on the indexer to settle.

You run git checkout main. Three seconds later, your fan spins up. Activity Monitor shows mdworker_shared at 280% CPU. Your battery icon turns yellow. The build you wanted to start is now waiting on the indexer to settle.

This is the Spotlight storm. It is one of the most well-documented friction points for developers on macOS — and it is mechanically predictable once you understand how Spotlight reacts to a git checkout. This post explains the mechanism, walks through the safe long-term fix, and shows you how to verify the storm is gone.

Why a branch switch storms the indexer

git checkout does two things at the filesystem level when you switch branches:

  1. Removes files that exist on the current branch but not on the target.
  2. Writes files that exist on the target branch but not on the current.

For a typical web project, switching between two feature branches can rewrite 50,000 files in node_modules, .next, dist, and the source tree itself — in well under a second. From the filesystem's perspective, this is a flood of file-create and file-modify events.

Spotlight's indexer (mds_stores, mdworker_shared) subscribes to those events via FSEvents. When a flood arrives, it queues every changed file for re-indexing. Each file gets opened, parsed for metadata (filename, modification date, content-type), and the index is updated. For 50,000 files this takes anywhere from 30 seconds on an M3 with a cold cache to several minutes on an older Intel Mac.

The CPU and battery cost is visible. The disk write cost is less obvious but real — the SSD takes wear from a workload that produces zero user-visible benefit, because nobody will ever search for a transpiled chunk of react-dom by filename.

This is not a bug. Spotlight is doing exactly what it was designed to do: keep the index fresh. The bug is that Spotlight does not know node_modules and dist are disposable.

How to confirm it on your machine

Before fixing, verify the storm is actually happening. Open Terminal in one window and run:

sudo fs_usage -w -f filesystem mdworker_shared

In another terminal, run a git checkout between two branches that have meaningful differences. Within seconds, the first terminal will show mdworker_shared opening files in node_modules, .next, dist, and so on. That is the storm.

To see the impact on CPU:

top -o cpu -stats pid,command,cpu,time

During a storm, mdworker_shared and mds_stores will sit at the top of that list for the duration of the indexing pass. Once they drop off, the storm is over.

The fix: tell Spotlight to ignore the folders that don't matter

The robust fix is to exclude the directories that produce storms from Spotlight's index. There are three credible methods, ranked by how durably they survive macOS updates.

Method 1: Per-folder .metadata_never_index file (most reliable)

Drop a sentinel file named .metadata_never_index in any folder, and Spotlight will skip it on the next index pass. This is the method npm install itself uses inside node_modules for .bin-adjacent directories.

# In a single repo
touch node_modules/.metadata_never_index

# At the home directory, for all current and future node_modules
find ~/code -type d -name node_modules -exec touch '{}/.metadata_never_index' \;

The trick: npm install recreates node_modules on the next install, which removes the sentinel. You need either:

  • A post-install hook that re-touches the file, or
  • A volume-level rule (see Method 3), or
  • A periodic cron/launchd job that re-touches the sentinel across all your dev folders weekly.

For most developers, the post-install hook is the right tradeoff. A one-liner in your ~/.npmrc or in a postinstall script handles it.

Method 2: System Settings Spotlight Privacy

Apple's official UI: System Settings → Spotlight → Search Privacy → drag in folders you want excluded.

This works for stable folders (e.g., ~/code) but is fragile for two reasons:

  • The exclusion lives in a .plist that can be reset by macOS updates.
  • Exclusions disappear when a folder is deleted and recreated (e.g., rm -rf node_modules && npm install).

It is the right method for excluding an entire dev tree (~/code, ~/Projects) once. It is the wrong method for excluding node_modules directories because of the recreation problem.

Method 3: Disable indexing per-volume

If your dev work lives on a separate APFS volume, you can disable indexing for the entire volume:

sudo mdutil -i off /Volumes/Dev
sudo mdutil -E /Volumes/Dev    # erase existing index

This is the heaviest hammer and the most durable. Spotlight will not index anything on /Volumes/Dev, including your editor's recent files. The trade-off is that Spotlight will no longer find files there from the GUI — which is fine if you have already migrated to a developer launcher and fd/rg for code search.

The detailed safety rules are in How to disable Spotlight indexing safely.

A recommended setup

For a developer with a typical web stack on macOS Tahoe 26 in 2026, the setup I run and recommend:

  1. Drop .metadata_never_index into every node_modules. Add the touch step to your global postinstall so it survives reinstalls.
# ~/.npmrc
ignore-scripts=false

# in your global postinstall (yarn / pnpm / npm scripts, or a git hook)
find . -type d -name node_modules -exec touch '{}/.metadata_never_index' \;
  1. Add ~/code (or wherever your repos live) to Spotlight Privacy as a belt-and-suspenders measure. This catches .next, dist, target, and other build directories without per-folder sentinels.

  2. Verify after the next OS update. Macros, plists, and Privacy lists can get reset across major updates. A quick fs_usage check after each macOS upgrade catches regressions early.

  3. Replace Spotlight as your file-finding tool. With node_modules excluded, Spotlight's index of your code is now permanently incomplete — which is fine if you already use a launcher's file search or fd for code. Full reasoning in Why Spotlight is hostile to developers.

This setup eliminates the storm without breaking anything you actually use Spotlight for (Mail, Documents, photos).

What you should not do

A few "fixes" that show up in blog posts and forum threads but cause more problems than they solve:

  • sudo mdutil -i off / — disables indexing for the entire system. Breaks Mail search, Messages search, and Photos search. Reversible, but the cost is not worth it.
  • Killing mds_stores repeatedlylaunchd will just restart it. You burn battery on the restart cycle.
  • Deleting /.Spotlight-V100 — sometimes recommended; it forces a full reindex, which is usually the opposite of what you want. Use it only when fixing a broken index, not when avoiding storms.
  • Disabling Spotlight via a third-party "tweak" app — these typically just toggle the same mdutil flags but persist the setting in ways that can break after a macOS update. Use Apple's official paths.

How to know the storm is gone

After applying the fix, repeat the fs_usage test:

sudo fs_usage -w -f filesystem mdworker_shared

Switch branches with git checkout. The previous flood of node_modules paths should be replaced with a much smaller list — only source files that genuinely changed. CPU on mdworker_shared should peak briefly and settle within a second or two.

If you still see thousands of indexer events on a branch switch, you missed an exclusion. The most common cause is a node_modules that was recreated without a sentinel. Re-run the global find ... -exec touch and try again.

Why this is not Spotlight's fault, exactly

It is tempting to call this a Spotlight bug. It is not, technically. Spotlight is doing the job it was designed to do: keep your search index fresh as files change. The mismatch is that developer file trees behave very differently from the personal photo libraries and document folders Spotlight was tuned for.

That said, Apple has had two decades to ship a default exclusion for node_modules, target, vendor, .venv, and the rest of the universally-disposable directory names. They have not. The official answer remains "tweak it yourself, every time." For developers, that answer has worn thin, and the fix above is the closest thing to a permanent escape hatch.

A side-effect worth knowing

Once node_modules and friends are excluded, Spotlight's GUI search will start returning fewer false positives in your code tree. The downside is that it will also miss legitimate code matches. If you have not already, this is the moment to move code search to fd and rg — see Searching files from the command line on macOS — and reserve Spotlight (or your launcher's file search) for non-code files like Markdown notes, PDFs, and Documents.

The net result for most developers is a cleaner Spotlight that finds the things Spotlight is good at finding, paired with fd/rg for the things Spotlight was never good at. The branch-switch storm goes away as a side effect.

Related reading