Starting and Stopping Background Services with Homebrew

Gabe Berke-Williams
Edited by Aji Slater

editor’s note (August 4, 2023): New versions of MacOS and homebrew means the information in this article is no longer current.

If you are on a version of MacOS Ventura or later, see this post for further information. If your version of MacOS is pre-Ventura…read on!

I love Homebrew, but sometimes it really gets me down, you know? Especially when I have to deal with launchctl.

launchctl loads and unloads services that start at login. In OS X, these services are represented by files ending with .plist (which stands for “property list”). These plists are usually stored in either ~/Library/LaunchAgents or /Library/LaunchAgents. You load them (i.e. tell them to start at login) with launchctl load $PATH_TO_LIST and unload them with launchctl unload $PATH_TO_LIST. Loading a plist tells the program it represents (e.g. redis) to start at login, while unloading it tells the program not to start at login.

This post-install message from Homebrew may look familiar:

To have launchd start mysql at login:
    ln -sfv /usr/local/opt/mysql/*.plist ~/Library/LaunchAgents
Then to load mysql now:
    launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist
Or, if you don't want/need launchctl, you can just run:
    mysql.server start

Doing all that takes too long, and I can never remember where Homebrew plists are. Fortunately, Homebrew includes a lovely interface for managing this without using ln, launchctl or knowing where plists are.

brew services

First, install brew services by tapping homebrew/services (one time):

brew tap homebrew/services

Here’s an example usage:

$ brew services start mysql
==> Successfully started `mysql` (label: homebrew.mxcl.mysql)

Behind the scenes, brew services start is doing everything in the post-install message above. First it runs ln -sfv ... for you. Then it runs launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist. It Just Works.

Let’s say MySQL’s acting funky. We can easily restart it:

brew services restart mysql
Stopping `mysql`... (might take a while)
==> Successfully stopped `mysql` (label: homebrew.mxcl.mysql)
==> Successfully started `mysql` (label: homebrew.mxcl.mysql)

Now let’s see everything we’ve loaded:

$ brew services list
redis      started      442 /Users/gabe/Library/LaunchAgents/homebrew.mxcl.redis.plist
postgresql started      443 /Users/gabe/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
mongodb    started      444 /Users/gabe/Library/LaunchAgents/homebrew.mxcl.mongodb.plist
memcached  started      445 /Users/gabe/Library/LaunchAgents/homebrew.mxcl.memcached.plist
mysql      started    87538 /Users/gabe/Library/LaunchAgents/homebrew.mxcl.mysql.plist

Note that the list of services includes services you started with launchctl load, not just services you loaded with brew services.

Let’s say we uninstalled MySQL and Homebrew didn’t remove the plist for some reason (it usually removes it for you). There’s a command for you:

$ brew services cleanup
Removing unused plist /Users/gabe/Library/LaunchAgents/homebrew.mxcl.mysql.plist

Kachow.

Hidden Homebrew commands

Homebrew ships with a whole bunch of commands that don’t show up in brew --help. You can see a list of them in the Homebrew git repo. Each file is named like brew-COMMAND, and you run them with brew command. I recommend brew beer.

What’s next

If you liked this, I recommend reading through Homebrew’s Tips and Tricks. You can also try out another Homebrew extension for installing Mac apps: homebrew-cask.