The user friendly way to change an application preferences (aka settings) in macOS is to use the UI menu as Application Name
> Preferences...
or by typing the shortcut ⌘+, from the given application.
Though, this user interface based method doesn’t allow you to version control your preferences with git
or programmatically set your applications preferences from a shell script. This is where the macOS command line tool defaults
comes handy. defaults
lets you read, write, and delete user preferences from the command line.
This post covers:
What is the defaults command line?
defaults
access the Mac OS X user defaults system, i.e. preferences. All Mac OS X application use the defaults
system to record user preferences and other informations that must be maintained when the applications are not running.
It is worth noting that you can often access more options through the defaults
command line than when using the user interface. Also, keep in mind that if you change the settings of a running application, the application may not see the change until it get restarted and/or may overwrite the change.
User defaults belong to domains which generally represented a unique domain for each application. Each domain will be represented a dictionary of key/value; for example, “Default Font” = “Arial”. Keys are always strings but the values may be complex data structures comprising arrays, dictionaries, strings, and binary data. Those data structures are stored as XML Property Lists and are known as plist
.
How to use the defaults command line?
defaults
comes with a few available commands to read, write, and delete user applications preferences from the command line.
read | prints the user’s settings to standard output |
read-type | prints the plist type for a given key |
write | write a value for the given key |
rename | rename a key |
import | import a plist to a given domain |
export | export a domain and all the keys as a plist |
delete | delete a given key or a domain / all keys for a given domain |
domains | prints the name of all domains |
find | search all domains, keys, and values for a given word |
Make sure to take a look at the man defaults
for the full details or simply run the command line without any argument as defaults
to get the basic help message.
Examples
Find Out the Domains of Installed Applications
If you simply use defaults domains
you may end-up with a long list of comma separated domains that is not necessary easy to read.
[…] com.apple.Spotlight, com.apple.SystemProfiler, com.apple.TelephonyUtilities, com.apple.Terminal, com.apple.TextEdit, com.apple.UIKit, com.apple.UserAccountUpdater, com.apple.WebKit.WebContent, com.apple.accounts […]
You can easily make that list output prettier by using tr
with something like defaults domains | tr ',' '\n'
.
[…]
com.apple.Terminal
com.apple.TextEdit
[…]
You will still end-up with hundreds of lines and you may have to grep your way through if you are unsure which domains you are looking for.
Find The Domain And Read a Key
Lets say you want to programmatically enable the Check grammar with spelling in TextEdit. To find the domain, we will first use the above command defaults domains
and grep
for the application name.
[me@me-macOS: ~]$ defaults domains | tr ',' '\n' | grep -i textedit
com.apple.TextEdit
Then we can simply read the existing defaults for TextEdit with defaults read <domain>
. You won’t see anything fancy there as the option we are interested in won’t be present yet.
[me@me-macOS: ~]$ defaults read com.apple.TextEdit
{
NSNavPanelExpandedSizeForOpenMode = "{799, 448}";
"NSWindow Frame NSNavPanelAutosaveName" = "320 334 799 390 0 0 1440 877 ";
}
In order to find out the option name, we do have to go in the TextEdit UI and edit the preference manually. Use ⌘+, then in New Document
check the box named Check grammar with spelling
. Close the preference pane.
Now, if you run again the defaults
command above, your new output should look like as below and include the CheckGrammarWithSpelling
key.
[me@me-macOS: ~]$ defaults read com.apple.TextEdit
{
CheckGrammarWithSpelling = 1;
NSNavLastRootDirectory = "~/Library/Mobile Documents/com~apple~TextEdit/Documents";
NSNavPanelExpandedSizeForOpenMode = "{799, 448}";
"NSWindow Frame NSNavPanelAutosaveName" = "320 334 799 390 0 0 1440 877 ";
}
So, we now know that the key we want to use in our script is CheckGrammarWithSpelling
and the domain is com.apple.TextEdit
.
This method works fine for simple options but in some case you may have to resort to using diff
on the full export of the defaults read
file in order to easily find domain and keys impacted.
Write a new Value to a given Key
In order to write a new value to a key, you need to first know what is the value’s type. This is where the command defaults read-type
becomes necessary. The key must exist in the defaults in order to return successfully. From our previous TextEdit example, the CheckGrammarWithSpelling
key expect a Boolean value.
[me@me-macOS: ~]$ defaults read-type com.apple.TextEdit CheckGrammarWithSpelling
Type is boolean
Once you know that, you can easily write your new settings using the defaults write
command.
[me@me-macOS: ~]$ defaults write com.apple.TextEdit CheckGrammarWithSpelling -bool true
[me@me-macOS: ~]$ defaults read com.apple.TextEdit
{
CheckGrammarWithSpelling = 1;
NSNavLastRootDirectory = "~/Library/Mobile Documents/com~apple~TextEdit/Documents";
NSNavPanelExpandedSizeForOpenMode = "{799, 448}";
"NSWindow Frame NSNavPanelAutosaveName" = "320 334 799 390 0 0 1440 877 ";
}
Note that, in this case, because of the boolean, using an integer would also work; for example: defaults write com.apple.TextEdit CheckGrammarWithSpelling 1
.
Delete a Given Key
In the event you want to reset completely the defaults
configuration of an application or remove a change you made, then you may want to delete a key or a domain. Though, I would recommend instead to overwrite the preference key with a new value instead as it is less destructive.
In our previous example, if we want to restore our TextEdit preference to its default we can simply run defaults delete
on the given key.
[me@me-macOS: ~]$ defaults delete com.apple.TextEdit CheckGrammarWithSpelling
[me@me-macOS: ~]$ defaults read com.apple.TextEdit
{
NSNavLastRootDirectory = "~/Library/Mobile Documents/com~apple~TextEdit/Documents";
NSNavPanelExpandedSizeForOpenMode = "{799, 448}";
"NSWindow Frame NSNavPanelAutosaveName" = "320 334 799 390 0 0 1440 877 ";
}
If you completely delete a domain then, the next time you read that domain will fail.
[me@me-macOS: ~]$ defaults delete com.apple.TextEdit
[me@me-macOS: ~]$ defaults read com.apple.TextEdit
2020-05-03 21:38:44.129 defaults[28419:688204]
Domain /Users/me/Library/Containers/com.apple.TextEdit/Data/Library/Preferences/com.apple.TextEdit does not exist
The preference would shows up again the next time you start the application as it will write a new set of defaults.
Going Further
Some people have been going quite far on how to customize their macOS working environment with a fully scripted customization of their various apps, including the Finder
itself. A nice example to check is the config from
Mathias Bynens and also a great inventory of various peoples dotFiles curated by
Wilson Mar.