My homebrew installation of Postgres is always there when I need it. 😍 I can be
confident that even just after login, my database is only a
Homebrew 🍺 (everyone’s favorite missing package manager for MacOS) not only
manages installation and cleanup of
the stuff we need that Apple doesn’t provide,
but provides an abstraction over managing background processes with the native
cron wasn’t the only tool replaced but also
init. Launchctl was created to serve as a single
performant native API to replace those UNIX tools.
Launchctl can handle running programs at certain times, like
cron, but also in
response to other triggers like login or file changes, and can relaunch
programs if they crash.
Starting a process on login without
brew services means writing (or copying, or
symlinking) a plist file to
~/Library/LaunchAgents for a single user and
/Library/LaunchDaemons for all
The plist, which stands for “property list”, acts as instructions to launchctl about how, when, and what to do with the application.
Here is a snippet of a plist from my homebrew managed Postgres installation:
If the app was updated or uninstalled, choosing to manage the file means remembering to update or delete the plist ourselves.
brew services handles all that for us.
When we run
brew services start postgresql@14 we’re telling homebrew to copy
the necessary plist to the correct folder and manage it. If we remove postgres
(😱), homebrew removes the plist.
Apple made a change in MacOS 13 that provides a new scheme for these launchctl plist files.
“Rather than apps installing their own helpers and property lists, MacOS 13 (Ventura) introduces a new scheme where those are provided within the app” – The Eclectic Light Company
It should make this process more seamless for users, but not every program will
or has taken advantage of this yet, so
brew services isn’t going away.
That’s right! Previously we would need to “tap” (install) the services package
before using it with
brew tap homebrew/services, but it will now install
itself the first time we run the command.
Because services is the preferred way to manage launch items installed via
homebrew, messaging after installing applications no longer directs us to
symlink plist files to
*/Library, but instead to use
There are only a few commands commonly needed to manage loading processes with homebrew.
brew services start xyz and
brew services stop xyz will start and stop an
application, but will also remove or add the plist file instructing
to run the program at login.
If a running application needs to be turned off and on again (as we all do
brew services restart xyz will do that for us.
That’s usually the extent of it, but also handy are these—
brew services run xyz and
brew services kill xyz will start and stop an
application without changing anything with regards to
Should we want to see what processes are running via
launchctl, some of which
might not be managed by homebrew, we can run
brew services list. This is what
mine currently looks like–
postgresql@14 started aji ~/Library/LaunchAgentsemail@example.com
redis started aji ~/Library/LaunchAgents/homebrew.mxcl.redis.plist
Apple wants us to know what is happening in the background of our computer, and rightly so! Security is always in tension with convenience, and in this tradeoff, our notification centers will have to pay the price.