Skip to content

Understanding System Data

Guilherme Selig edited this page Oct 21, 2026 · 1 revision

Understanding System Data

System Data is not a category

System Settings > General > Storage sorts files into Applications, Documents, Photos, Music, Developer, macOS and other lines. System Data is the remainder: whatever the classifier did not put in another line. There is no folder called "System Data" on disk.

To explain N GB of System Data you have to measure the whole Data volume and account for what Settings already placed elsewhere. There is no shortcut.

In practice, most of it is ~/Library. In the audit that started this project (about 166 GB of System Data), ~/Library alone was about 153 GB, with the rest in /private/var, /opt/homebrew, /Library and /usr/local.

How Settings arrives at the number

  • macOS in Settings is the sum of the separate system volumes in the same APFS container (System, Preboot, Recovery, Update, VM). They are not inside System Data. SDTally reads them with diskutil and DiskArbitration (containers in the JSON).
  • System Data is computed by Apple's StorageManagementService and written to the system log while the Storage pane is open. SDTally reads that log line (settings_screen) and also reproduces the screen from the pane's own "Sum of categories" line. The log keeps it for less than about 21 hours.
  • Available in Settings is free space plus purgeable space: caches macOS can remove on its own (CacheDelete). Tools such as df do not count purgeable as free.

SDTally also reproduces 15 of the Settings categories from what it measures (system_data.reproduced), each graded A (rule read in Apple's code) or B (hypothesis or approximation), and compares them with the screen when the pane's log is available.

What usually lives in System Data

Where What it is Notes
~/Library/Mobile Documents iCloud Drive data Real user data, synced across devices. Not a cache
~/Library/Application Support App state Mixed: real data and regenerable data
~/Library/Caches Caches Usually regenerable, with exceptions (for example a cache in use by an active upload)
~/Library/Containers, ~/Library/Group Containers Data of sandboxed apps Mixed. Messaging apps keep real media here
~/Library/Preferences Settings files Should be kilobytes. Gigabytes here are an anomaly
~/Library/CloudStorage Google Drive, Dropbox, OneDrive and others Mostly placeholders
Dotfolders in your home (~/.npm, ~/.ollama, ...) Developer tool caches and models Often missed by tools that skip hidden files
Local snapshots Time Machine and other snapshots Hold blocks of files you already deleted
Swap, sleep image Virtual memory On the VM volume
Open-but-deleted files Files deleted while an app still has them open Space returns when the app closes them
APFS metadata The file system's own trees Not a file anywhere

Measurement pitfalls

Four ways a disk misreports its own size, all observed in the audit. A tool that ignores any of them produces a wrong report. SDTally handles each one.

1. Sparse files

A sparse file declares a large size but only allocates the blocks that were written. VM disks are the classic case: one observed disk declared 100 GB and occupied 2.66 GB.

  • Wrong: stat st_size, du --apparent-size, Finder's "Size".
  • Right: allocated blocks (st_blocks, stat -f %b). Plain du already uses them.
  • SDTally: counts allocated size only.

2. Dataless files (cloud placeholders)

iCloud Drive, OneDrive and Google Drive keep files "online only": the file appears with its full size, but the content is not on disk. macOS marks these with the SF_DATALESS flag. In the audit, two copies of one video in two OneDrive folders appeared as 72 GB; the folders actually occupied under 2 GB.

The worse trap: reading a dataless file downloads it. A duplicate finder that hashes everything can download hundreds of gigabytes and fill the disk it was meant to clean.

  • SDTally: sets its process policy so dataless files are never materialized, never descends into dataless folders, reports them separately (informational.dataless, apparent size) and counts them as 0 on disk.

3. APFS clones

clonefile(2) creates a new file that shares blocks with the original (copy on write). Both report their full size and du counts both, but the blocks exist once. Deleting one copy may free nothing.

  • SDTally: reads each file's physical extents (F_LOG2PHYS_EXT) and counts each shared block once in the tree. For each row it reports private bytes ("freed if deleted"): what deleting it would actually return. Repeated clones are listed under informational.repeated_full_clones and repeated_shared_blocks.

4. Dotfiles

Shell globbing (du -sh ~/*) skips names that start with a dot. On a developer's Mac that hides caches like ~/.ollama, ~/.npm, ~/.colima, ~/.rustup: about 21 GB in the audit.

  • SDTally: the traversal includes hidden entries.

Also handled

  • Hard links and firmlinks: deduplicated by device and inode, so /Applications and similar firmlinked paths do not count twice.
  • Graft roots: skipped, because their blocks are already counted.
  • Mount points: the traversal does not cross into other volumes.
  • Folders the traversal cannot open: counted through APFS directory statistics when APFS keeps them (protected_folders), otherwise listed in protected_without_size.
  • Large extended attributes: measured with listxattr (large_xattrs).
  • Access times: the process disables atime updates, so measuring does not write metadata.
  • GB vs GiB: Settings uses GB (10^9). du and df use GiB (2^30), about 7 percent different. SDTally uses GB by default and labels it; --binary switches to GiB.

The account

SDTally adds up only parts that do not overlap:

used (Data volume) = tree + large_xattrs + snapshots + deleted_open + protected_folders + apfs_metadata + unexplained

Everything else (purgeable, repeated clones, cloud-only files, Trash age, Time Machine state) is informational: either already inside one of the terms or a different kind of measure. The text output keeps the two apart, and the JSON puts them under informational.

unexplained is what is left: the space macOS would not let SDTally see (without root or Full Disk Access) plus anything not measured. Running as root with Full Disk Access makes it small. In the text output it is labeled "Blocked by macOS".

Why space may not come back

Deleting something does not always return its size. SDTally lists only causes it measured at 1 GB or more:

Cause Why
Local snapshots A snapshot still holds the deleted file's blocks until the snapshot is removed. macOS removes Time Machine snapshots on its own when space runs low
Open-but-deleted files The app that has the file open keeps the space until it closes it. Quitting the app or restarting returns it
APFS clones Blocks shared with another file stay until the last copy is gone
Cloud-only files They were not taking disk space to begin with
Purgeable Settings already counts it as available; df does not count it as free until macOS releases it
Trash Space returns only when the Trash is emptied

What SDTally recommends, and what it never does

Recommendations come from fixed rules over measured rows. Each has a level:

Level Meaning
measurement Measure better first (for example grant Full Disk Access or measure as administrator)
system_handles macOS manages this on its own
safe Regenerates or is disposable; no loss of function
cost Regenerates, but you pay in time or bandwidth (rebuilds, re-downloads, reindexing)
check_first Depends on state that must be checked first (active sync, app open)
anomaly Unusual; explained for a human to judge
do_not_touch Real data or system data

Recommended steps go through Finder, the owning app, System Settings, or an official command from a fixed list (with its dry-run form). SDTally never recommends touching /System, disabling SIP, or deleting local snapshots other than through tmutil, and it never runs any of these steps itself.

Further reading in the repository (Portuguese): storage model, measurement pitfalls, target catalog.

Clone this wiki locally