#macOS dotfiles should not go in ~/Library/Application Support
One of my pet peeves is when command-line tools look for user configuration
files in ~/Library/Application Support
when running on macOS. In addition to
offering poor ergonomics for users, I believe this behavior is incorrect
according to the documentation which is cited to justify it. Instead,
command-line tools should implement the XDG Base Directory Specification
and look for configuration files in $XDG_CONFIG_HOME
, which defaults to
~/.config
.
Usually, when a program looks for configuration files in ~/Library/Application Support
, it’s not because of an intentional design decision. Instead, the
author delegated that decision to a library, and several popular libraries for
determining platform-specific configuration directories use
~/Library/Application Support
as the default configuration directory on
macOS, including Python’s platformdirs
package (242
million downloads / month), JavaScript’s
env-paths
(95 million downloads / month), Rust’s dirs
crate (4.8 million downloads / month), and Go’s adrg/xdg
package (used in 913 packages). While ~/Library/Application Support
may be the correct configuration directory for GUI apps which manage their
configuration files for the user automatically, the vast majority of
applications using these libraries are command-line utilities whose
configuration belongs in ~/.config
.
The main reason I dislike programs looking for dotfiles in
~/Library/Application Support
is that it’s unexpected. As Ashlin Eldridge
explained on GitHub:
As a new user, it’s extremely surprising to me to that a modern tool like
nu
would put config files under Application Support on macOS. It’s even more surprising to see that some people are actively against adopting the XDG standard.The origins of XDG no longer matter at this point. No one really cares what the X, D, and G stand for. The fact is that hundreds of tools support it (including Git, Emacs, Neovim, Tmux) and users have come to expect support for it. It’s the closest thing we have to a standard that allows users to control the placement of their config files (which facilitates users’ ability to source control their files) and it also includes support for files that shouldn’t be source controlled such as cache and data files.
If a user explains that they found a program’s behavior surprising, many engineers will respond by telling the user that their expectations were wrong. However, I find that the reason users form an incorrect mental model of a program’s behavior is usually because the program’s design violated an established convention from some broader context. In accordance with the Principle of Least Astonishment, I prefer to change the program to behave how users expect rather than futilely attempt to change what users expect.
Users expect macOS CLI tools to look for configuration files in ~/.config
is
because that’s what almost every other program does. Your program should
probably not disagree with Bash and Vim and Git about where configuration files
are supposed to go!
These conventions help us explore unfamiliar systems by letting us apply knowledge about one part of the system to other parts of the system. Consistency is predictability. When every tool works the same except for a small handful, users get justifiably annoyed at the exceptions for wasting their time.
#What do dotfile managers do?
Many engineers use (or maintain) some sort of dotfile manager to handle
tracking these configuration files. If configuration files are really supposed
to go in ~/Library/Application Support
, we would expect dotfile managers to
put configuration files there by default when running on macOS. After all, the
whole point of a dotfile manager is to simplify managing configuration files
across multiple machines and platforms. Let’s take a quick survey to see how
some popular dotfile managers behave on macOS:
- chezmoi (14.3k stars) makes no effort to link
configuration to
~/Library/Application Support
, despite including documentation for using chezmoi on macOS specifically. - dotbot (7.3k stars) ignores
~/Library/Application Support
. Despite including macOS-specific configuration files in the examples, the README shows a configuration for VS Code that will be completely ignored on macOS. - yadm (5.5k stars) makes no effort to
support
~/Library/Application Support
. The example configurations include macOS-specific portions but also do not reference~/Library/Application Support
. - rcm (3.2k stars) makes no effort to
support
~/Library/Application Support
. - GNU Stow makes (unsurprisingly) no
effort to support
~/Library/Application Support
.
Most of these tools are able to link configuration files to
~/Library/Application Support
if you ask them to explicitly (although macOS
will regularly replace your symlinks with copies of the destination files), but
the fact that they don’t bother to do so by default is revealing. Users only
want this behavior for specific misbehaving programs.
#An appeal to logic
Perhaps “consistency” isn’t a good enough reason for you to place your
program’s configuration files in ~/.config
like everybody else. Maybe you
think that programs should follow the platform guidelines, even if they don’t
match developer expectations. @soc on GitHub phrases it like this:
As a general advice for macOS devs: If you are developing on their platform, do what the platform owners tell you. They are the lords, you are the share-croppers.
Elsewhere, Reilly Wood rebukes a user asking if there would “be any
downside to just not using Application Support
ever” by saying that “[Nushell
would] no longer be following the macOS Standard Directories
guidelines.”
We’ll read through those guidelines in a minute, but it’s not entirely clear to
me that they’re relevant in the first place. The XDG Base Directory
Specification mentions Unix a few times but lists no carveouts for macOS
or any other operating system. If ~/.config
is accepted as the standard
location for configuration files on Unix-like operating systems, then surely it
would be the standard location on macOS as well, given that macOS is a Unix by
way of BSD.
But suppose we accept that the XDG specification only applies to some Unix operating systems, despite making no mention of this. The macOS Standard Directories documentation starts by stating that “[w]hether provided by the system or created by your app, every file has its place in macOS”, and honestly we could stop reading right there, because a command-line tool is not the system or an app.
While this might seem like a pedantic nitpick, in reality it’s critical to
correctly interpreting this documentation! I suspect that many of the
developers who cite these guidelines do not know very much about macOS and
think that “app” is just what macOS calls executables, but that’s not true. A
couple screens down, the same page says that /bin
“[c]ontains essential
command-line binaries”, so we can be sure the authors aren’t conflating apps
and command-line tools. Apps on macOS are installed in /Applications
and are
subject to a number of additional requirements, from a bundle ID
(a unique reverse-DNS identifier for an app, like com.apple.Preview
for
Preview.app
) to application icons, launch screens, code signing,
notarization, app sandboxing, and runtime hardening. Needless to say, none of
the developers shipping command-line utilities are following any of these
guidelines.
Moving on, the documentation for ~/Library/Application Support
says that it:
Contains all app-specific data and support files. These are the files that your app creates and manages on behalf of the user and can include files that contain user data.
Again, command-line tools do not have any app-specific data because they are not apps. Further, dotfiles are usually written by hand and not managed on behalf of the user.
The next paragraph makes it very clear that ~/Library/Application Support
is
for apps only:
By convention, all of these items should be put in a subdirectory whose name matches the bundle identifier of the app. For example, if your app is named
MyApp
and has the bundle identifiercom.example.MyApp
, you would put your app’s user-specific data files and resources in the~/Library/Application Support/com.example.MyApp/
directory. Your app is responsible for creating this directory as needed.
Command-line tools do not have a bundle identifier, including many command-line
tools shipped with macOS by Apple (such as ls
or vim
). And even though
Apple feels very comfortable shipping command-line tools that behave in a
subtly different manner from their equivalents on other modern Unix-descendent
operating systems, the macOS variants of bash
, zsh
, git
, and
vim
all look for their configuration files in the same place: ~/.config
.
Unless your tool is installed in /Applications
, there’s no reason for its
configuration to live in ~/Library/Application Support
.
#When should you use ~/Library/Application Support
With the guidelines and conventions listed above in mind, your application
should store its configuration files in ~/Library/Application Support
instead
of $XDG_CONFIG_HOME
if both of the following conditions apply:
- It is a GUI application installed in
/Applications
or~/Applications
. - It manages its configuration files automatically on behalf of the user, rather than expecting the user to write their configuration in a text file themself.
#TL;DR
Users do not expect command-line tools to look for configuration files in
~/Library/Application Support
on macOS. Dotfile managers do not place
configuration files in ~/Library/Application Support
on macOS. The most
commonly-cited justifications for placing configuration files in
~/Library/Application Support
are not meant to apply to command-line tools at
all. Even command-line tools like bash
and git
shipped by Apple look for
their configuration files in ~/.config
.
Please, please, please just use the XDG Base Directory Specification.