On macOS, you edit an application's preferences .plist file in ~/Library/Preferences by hand while the app is running, and your change disappears. Why, and what is the supported way to set that preference?
answer
- a daemon owns the file, not you
- reads and writes are both cached
- the plist is a backing store
- cfprefsd flushes over your edit
- defaults write, then restart the consumer
basics
~20 sThe preferences daemon cfprefsd owns those files, caches each domain in memory, and flushes its own copy back to disk — overwriting a hand edit. Use the defaults command (or the CFPreferences API), which goes through cfprefsd, then restart the app that reads the setting.
solid answer
~50 smacOS preferences are not plain config files you own; they are a **domain database** fronted by `cfprefsd`, the per-user and per-root preferences daemon. When a process reads or writes a preference through CFPreferences, `cfprefsd` serves it from an in-memory cache and lazily writes the domain back to `~/Library/Preferences/<domain>.plist`. Editing that file directly races the daemon: it may never notice your change, and when it next flushes it writes its cached copy over you. The supported path is `defaults write com.apple.dock autohide -bool true`, which talks to `cfprefsd` so the daemon's cache and the file agree. Two extras matter. Reading is also cached, so a running app usually needs a restart — `killall Dock` for the Dock — before it picks the value up. And sandboxed apps keep preferences under `~/Library/Containers/<bundle-id>/Data/Library/Preferences`, so the top-level path may not be the file being read at all.
code
bash · 11 lines# Read, write and verify through the daemon, then restart the consumer
defaults read com.apple.finder AppleShowAllFiles 2>/dev/null || echo "not set"
defaults write com.apple.finder AppleShowAllFiles -bool true
defaults read com.apple.finder AppleShowAllFiles
killall Finder
# Inspect a plist that is stored in binary form, without modifying it
plutil -convert xml1 -o - ~/Library/Preferences/com.apple.finder.plist | head -20
# Check whether a profile is managing the same domain
ls /Library/Managed\ Preferences/go deeper
Be ready to say that macOS preferences are changed with the defaults command, and that the app usually has to be restarted before the new value shows up.
Explain the mechanism: cfprefsd mediates the domain, caches it in memory, and can flush its cache over a hand-edited file, which is why the supported interface is the API rather than the file.
Demonstrate the debugging path for a preference that will not stick — managed preferences from a profile shadowing the user domain, sandbox containers, ByHost settings, and when restarting the daemon is justified.
Own the fleet question: settings that must be enforced belong in a configuration profile as managed preferences, not in login scripts running defaults write, because scripted user-domain writes are advisory and drift the moment a user changes them back.
## Preferences are a database, not a file On Linux you edit a config file and the daemon rereads it. macOS does not work that way. A preference lives in a **domain** — usually a reverse-DNS bundle identifier like `com.apple.dock` — and the domain is mediated by `cfprefsd`, a daemon that runs once per user session and once as root. Applications call the CFPreferences / `NSUserDefaults` APIs; those APIs talk to `cfprefsd` over XPC; `cfprefsd` maintains the in-memory state and decides when to persist it to a property-list file. The `.plist` file under `~/Library/Preferences` is therefore the daemon's **backing store**, not the interface. Treating it as the interface produces exactly the symptom in the question: you write valid XML, the daemon has never been told, and the next flush of its cached domain replaces the file wholesale. There is a second, dumber trap in the same directory: modern preference files are usually **binary property lists**, not XML. A text editor either refuses them or corrupts them. `plutil -convert xml1 -o - file.plist` prints a readable version, and `plutil -lint` validates one, but converting the on-disk file still does not tell `cfprefsd` anything. ## The supported interface `defaults` is a thin command-line client of the same API the apps use: ```bash defaults read com.apple.dock autohide defaults write com.apple.dock autohide -bool true defaults delete com.apple.dock autohide defaults domains # every domain in the user's search list ``` Because it goes through `cfprefsd`, the daemon's cache and the file stay consistent. Types are explicit — `-bool`, `-int`, `-float`, `-string`, `-array`, `-dict`, `-data` — and getting the type wrong is a real failure: an app reading a boolean will not accept the string `"true"`. Nested values are reachable with `defaults write <domain> <key> -dict-add <subkey> <value>`. A `defaults write` affects the *current* user's domain. Running it under `sudo` writes root's preferences, which is almost never what a support script intended; to set a preference for another user you run `defaults` as that user, and to set a machine-wide default you write a domain under `/Library/Preferences`. ## Why the app still shows the old value Reads are cached too. A running application asked `cfprefsd` for the domain once, got the values, and holds them. Setting the preference underneath it changes nothing visible until the app rereads. That is why every macOS tweak recipe ends with a restart of the consumer: ```bash defaults write com.apple.finder AppleShowAllFiles -bool true killall Finder ``` When even `defaults read` seems to return stale data — which happens if something *did* edit the file behind the daemon's back — `killall cfprefsd` forces the daemon to restart and reload from disk. It is a recovery step, not a normal part of setting a preference. ## The two other locations that catch people out **Sandboxed applications** (anything from the App Store, and many others) do not use `~/Library/Preferences/<domain>.plist`. Their preferences live inside their container at `~/Library/Containers/<bundle-id>/Data/Library/Preferences/<domain>.plist`. Confusingly, `defaults write com.example.app key value` still usually works, because the sandbox redirects the domain — but a script that hunts for the file path will be looking in the wrong place. **Per-host preferences** — settings that should not follow a user to another machine — live in `~/Library/Preferences/ByHost/` and are addressed with `defaults -currentHost read <domain>`. Reading the plain domain for a ByHost setting returns nothing, which looks like the setting does not exist. ## Managed preferences win On a managed Mac there is a fourth layer: preferences delivered by a configuration profile land in `/Library/Managed Preferences/` and take precedence in the CFPreferences search order. A user-level `defaults write` for the same key appears to succeed and then has no effect, because the managed value shadows it. When a preference "will not stick" on a corporate laptop, checking for a managed domain is the fast diagnosis. ## The shape of a good answer Say that preferences are daemon-mediated, name `cfprefsd`, explain that direct file edits race its cache, give `defaults` as the interface plus the consumer restart, and mention at least one of the location traps — sandbox containers, ByHost, or managed preferences. That sequence shows you have actually debugged a preference that would not stick rather than copied a one-liner from a blog.
- You run defaults write for a setting on a corporate laptop, it reports no error, and the setting does not change. What do you check?Whether the domain is managed. Configuration-profile-delivered preferences land in `/Library/Managed Preferences/` and outrank the user domain in the CFPreferences search order, so your write lands but is shadowed. Check for the domain there and look at the installed profiles. If it is not managed, check whether the app is sandboxed (its real store is inside `~/Library/Containers/`), whether the setting is per-host, and whether the consumer simply needs restarting.
- When is killall cfprefsd appropriate, and why is it not part of a normal preference change?It is a recovery step for when the daemon's cache and the on-disk file have diverged — usually because something wrote the plist directly. Restarting the daemon makes it reload from disk. In a normal change you never need it: `defaults write` goes through the daemon, so cache and file already agree, and the only thing left is restarting the app that reads the value.
- Why does the type flag on defaults write matter?Because the property list stores typed values and the reading app expects a specific type. `defaults write com.example.app enabled true` stores the string `"true"`, which a boolean read will not interpret as true; `-bool true` stores a real boolean. The same applies to `-int` versus a numeric string. Type mismatches are a frequent cause of a written preference that the app silently ignores.
saying these in an interview costs you the question
- Treating ~/Library/Preferences plists as ordinary editable config files
- Thinking a preference change takes effect without restarting the reader
- Running defaults write under sudo to change a user's setting
- Assuming every app's plist sits at the top-level Preferences path
- Editing a binary plist in a text editor and corrupting it