Journal · Developer workflow

Mac storage for developers: a cleanup workflow

A development machine accumulates several kinds of storage that look alike in a disk scan: generated output, downloaded dependencies, test data, and work that exists nowhere else. A useful cleanup begins by separating those categories.

01 Start with an inventory

Find the large directories before choosing commands. Scan your projects and user Library, or inspect them with Finder and read-only disk usage tools. Note which tool owns each large area and whether that tool is actively writing to it.

CategoryExamplesBefore removal
Generated dataBuild intermediates, indexes, reproducible outputConfirm the inputs and build process are available.
Downloaded dataPackages, toolchains, simulator runtimesConfirm you can retrieve the required version again.
Working dataSource changes, simulator fixtures, local databasesBack up or export what you need.
Release recordsDistributed binaries, archives, matching debug symbolsVerify a retained copy for future support.

A directory called “cache” is worth inspecting. A directory called “data” needs a more specific explanation. Neither a large size nor an old modification date makes the decision for you.

02 Xcode: separate build output from releases

DerivedData is a common source of generated storage. Stop builds and remove only the project data you intend to regenerate. Manage unused simulator runtimes in Xcode's Components settings instead of deleting files inside the runtime installation. Apple documents the component controls.

Preserve release archives and their matching debug symbols. Simulator devices may also contain test cases you cannot recreate from a fresh install. Our Xcode cleanup guide covers these boundaries in detail.

03 Docker: inspect the engine before the disk image

Start with Docker's own storage report:

docker system df -v

The report separates images, containers, local volumes, and build cache, including shared image data. It gives better context than treating Docker's entire disk image as a single disposable file. Docker explains each field.

If you choose to run docker system prune, read its confirmation carefully. It removes stopped containers, unused networks, dangling images, and unused build cache. A stopped container may contain uncommitted work in its writable layer. The -a and --volumes options expand the scope; do not add them by habit. Review the prune reference.

04 JavaScript: inspect projects and the package cache separately

An inactive project's node_modules may be reproducible from its manifest and lockfile, provided the dependencies remain available. Check for local patches, linked packages, and generated artifacts before removing it. Keep source files, lockfiles, local configuration, and any data you need to restore the project.

For the npm cache, first locate and verify it:

npm config get cache
npm cache verify

npm describes its cache as self-healing. Verification checks integrity and garbage-collects unneeded data. Forcing the entire cache to clear is not a routine fix for every dependency problem and can require new downloads. Read npm's cache documentation.

05 Homebrew: preview the cleanup

Homebrew can report its planned cleanup before changing anything:

brew cleanup --dry-run

Review the output. If it matches your intention, brew cleanup removes the items selected by Homebrew's cleanup policy. Use that supported behavior instead of manually emptying broad installation directories. The Homebrew manual explains the options.

Apply the same approach to other ecosystems: locate the actual cache, check the tool's documentation, and distinguish downloaded artifacts from configuration or locally published packages.

Work through a cleanup review

Suppose a disk map highlights an old web project, Docker storage, and a release archive. This is an illustrative review, not a measured cleanup. The largest region is where the investigation starts; it does not decide which data to remove.

CandidateEvidence to collectNext action
An inactive project's dependenciesManifest, lockfile, package access, and any local patches or linked packages.Confirm the project is reproducible before removing its installed dependencies.
A large Docker imageIts shared size, unique size, and container references from docker system df -v.Review the owning project's use; image size alone is not exclusive disk use.
A stopped database container or volumeWhether needed records exist only in its writable layer or volume.Export and verify the data before considering any removal.
An old release archiveWhich shipped version it matches and where its verified backup lives.Keep the archive and symbols for supported releases.

For each candidate, write down the full path or tool identifier, its owner, what can recreate it, the backup location if needed, and the proposed action. Leave the action undecided when any of those answers is missing. This turns a large-folder list into a review you can repeat or share without exposing project contents.

Read Docker's shared-size columns correctly

In an illustrative report, image A has 4 GB shared and 1 GB unique, while image B has the same 4 GB shared and 2 GB unique. Their displayed sizes add to 11 GB, but the distinct image data in this simplified model totals 7 GB. Removing A while B remains does not make their shared 4 GB disposable. Container references and build cache add further constraints. Docker defines the shared, unique, and total columns; use your actual report before deciding.

06 Confirm the result and the next build

Recheck available space on the same volume after the cleanup. Open the affected project, restore the dependencies you need, and run the build or workflow that matters. A cleanup is complete when the workspace still works and you understand what was removed.

APFS shared blocks and snapshots can make the recovered space differ from directory totals. Docker's internal accounting can also differ from the host disk image's apparent size. Understand the measurements before chasing a mismatch.

07 Use a disk map to decide where to focus

Delve helps you compare project folders, build output, and tool storage in one visual view. Start with the largest relevant area, inspect its path, then return to the owning tool for data it manages itself.

This workflow is a useful reason to choose a disk analyzer instead of relying only on automatic cleanup categories. You keep the project context that a generic removal rule cannot supply.

Common questions

What developer files are usually regenerable?

Build intermediates, indexes, and downloaded dependencies are often regenerable when their original inputs and required versions remain available. Confirm the project configuration before removing them.

Is docker system prune safe for every project?

No. It can remove stopped containers and build cache you still need. Review its scope, preserve writable-layer data, and back up persistent data before pruning.

Should I force-clear the npm cache?

Start with npm cache verify. npm documents the cache as self-healing, so blanket clearing is usually unnecessary for troubleshooting.

Keep exploring

← All journal