macos · level 6

defaults & plists

Tweaking macOS through the preference database — and reloading so it sticks.

150 XP

defaults & plists

Every preference on macOS — every checkbox in System Settings, every Dock autohide toggle, every app preference pane — is stored in a plist file. The defaults command is the universal interface for reading and writing them. Learn it once and you stop needing to chase "how do I configure X" articles.

Analogy

Picture the electrical panel in the utility closet of a house. The decorative wall switches in the living room — lamp, ceiling fan, dimmer — are the System Settings pane: easy, curated, fine for everyday use. But behind that is the breaker panel with hundreds of labelled toggles for circuits the builder never exposed: the porch light's daylight sensor, the garbage disposal interlock, the heated-floor thermostat. defaults is the flashlight and the breaker panel together. Each domain (com.apple.finder, NSGlobalDomain) is one circuit section; each key is one breaker; the type flag is whether the breaker takes an integer amperage, a boolean on/off, or a named setting. And because some appliances only read their circuit at startup, you have to flick them off and on — that's killall Finder.

How the database is laid out

Two locations you care about:

  • ~/Library/Preferences/ — per-user preferences
  • /Library/Preferences/ — system-wide preferences

Each file is named after its domain: com.apple.dock.plist, com.apple.finder.plist, com.apple.screencapture.plist. The domain is the reverse-DNS identifier the app uses; third-party apps follow the same convention (com.spotify.client.plist).

There's also a catch-all: NSGlobalDomain (aka .GlobalPreferences), which is inherited by every Cocoa app. Keyboard repeat, window animations, system accent colour — these live here.

Reading

defaults read                     # every key in every domain, huge dump
defaults read com.apple.dock      # one domain's whole plist
defaults read com.apple.dock autohide    # a single key
defaults read-type com.apple.dock autohide   # just the type

Before you tweak anything, defaults read the domain and pipe it to a file. That's your rollback plan.

Writing

The write syntax:

defaults write <domain> <key> <type> <value>

The type flag matters. If you defaults write an integer key with -string "1", the value has the wrong type and the owning app will ignore it. Common flags:

Flag Example value
-string "jpg"
-int 30
-bool true / false
-float 0.5
-array value1 value2 value3
-dict key1 value1 key2 value2

Screenshots to JPG:

defaults write com.apple.screencapture type -string "jpg"

Faster keyboard repeat (below the UI slider's floor):

defaults write NSGlobalDomain KeyRepeat -int 2
defaults write NSGlobalDomain InitialKeyRepeat -int 15

Show hidden files in Finder:

defaults write com.apple.finder AppleShowAllFiles -bool true

The killall pattern

Preferences are cached in memory by the owning process. A defaults write changes the plist on disk, but Finder won't pick up the change until it restarts. The idiom:

defaults write com.apple.finder AppleShowAllFiles -bool true
killall Finder

killall <name> sends SIGTERM to every process with that name; the process restarts and re-reads the plist. The common targets:

Writing to... killall target
com.apple.finder Finder
com.apple.dock Dock
com.apple.screencapture SystemUIServer
NSGlobalDomain (varies) Often SystemUIServer, or log out/in

Some changes only take effect after a full logout — NSGlobalDomain AppleInterfaceStyle (light/dark), for example.

Undoing a tweak

defaults delete com.apple.dock autohide-time-modifier
killall Dock

delete removes the key; the app reverts to its compiled-in default. You can also write the opposite value; for booleans, writing false undoes true.

Finding the right key

The discovery workflow:

  1. Close the app you want to configure.
  2. defaults read com.apple.dock > /tmp/before.plist
  3. Open the app, flip one setting, close it.
  4. defaults read com.apple.dock > /tmp/after.plist
  5. diff /tmp/before.plist /tmp/after.plist

The diff is the key and value you just flipped. This is how every "dotfiles .macos" on GitHub was written.

plutil — for non-preference plists

Preferences go through defaults. Random plist files — Info.plist in an app bundle, a launchd agent plist — use plutil:

plutil -lint path/to.plist              # validate XML
plutil -p path/to.plist                 # pretty-print
plutil -convert xml1 path/to.plist      # convert binary plist to XML for editing
plutil -convert binary1 path/to.plist   # back to binary (what launchd wants)

Modern plists are stored in a binary format for size. plutil -convert xml1 -o - path/to.plist is the quickest way to view one.

Why this matters

macOS has a thousand UI toggles and ten thousand that never made it to a UI. Every one of them is a defaults write away. Dotfiles-style tweaks scripts — .macos in a dotfiles repo — scale to hundreds of preferences applied in seconds on a new machine. Learn this one command and you control your Mac; ignore it and you spend the next decade clicking through System Settings.