Databases & services
Beyond serving PHP sites, Butler manages the backing services your projects need — databases, caches, a mail catcher, search and object storage. A fresh install ships none of these; you add exactly the ones you want.
Components vs. services
Section titled “Components vs. services”Butler draws a small but useful distinction:
- A component is an installed binary — for example the MySQL engine or the Redis server. Installing a component downloads and verifies the binary but doesn’t run anything.
- A service is a running instance of a component — an actual MySQL server listening on a port, with its own data directory. You can run more than one instance of the same component (say, two MySQL versions) as separate services.
The menu bar app mirrors this: a Components section for what’s installed and a Services section for what’s running.
Install a component
Section titled “Install a component”butler install mysqlbutler install redisbutler install mailpitSee what you have installed:
butler componentsButler’s catalog includes databases (MySQL, PostgreSQL, MariaDB, MongoDB), caches (Redis, Valkey), mail (Mailpit), search (Typesense) and S3-compatible storage — installed on demand as verified static binaries.
Manage a running service
Section titled “Manage a running service”Once a component is installed, manage instances of it with butler service:
butler service add mysql # create + start an instance (on a unix socket)butler service add mysql --tcp # …or listen on 127.0.0.1:3306 insteadbutler service status mysqlbutler service stop mysqlbutler service restart mysqlBy default an instance listens on a unix socket; pass --tcp (or --port)
to bind a loopback TCP port instead. See
Connecting to databases for the details.
For everyday start/stop across everything, the top-level commands are quickest:
butler start # start Butler's servicesbutler stop # stop thembutler restart mysql # restart one by nameRun butler start with no arguments in a terminal and it confirms before
starting everything.
Upgrading a service
Section titled “Upgrading a service”Butler treats a minor/patch upgrade and a major upgrade very differently, because a database’s on-disk format only stays compatible within a major version.
In place (minor or patch)
Section titled “In place (minor or patch)”Staying on the same major version — say MySQL 8.4.9 → 8.4.10 — is an in-place
upgrade. Butler downloads the new component, snapshots the data directory, repoints
the instance and restarts it, rolling back automatically if the new version fails
to start:
butler service upgrade mysql-default # latest compatible minor/patchbutler service upgrade mysql-default @8.4.10 # a specific versionIn the menu bar app, the same upgrade appears as an Update available card on the service’s detail panel.
Across a major version (migration)
Section titled “Across a major version (migration)”Crossing a major — for example MySQL 8.4 → 9.x — is not an in-place
upgrade. The newer engine would run a one-way conversion of your data directory on
first start, with no path back, so Butler refuses it and asks you to migrate
instead.
The safe path is a logical migration: dump from the old instance and load into a fresh instance on the new version, side by side, then cut over.
# 1. Install the new major and add a fresh instance for itbutler install mysql@9.7butler service add mysql --name v97 # → instance "mysql-v97"
# 2. Dump from the old instance, load into the new one.# Each instance's socket lives under Butler's Run directory.RUN="$HOME/Library/Application Support/Butler/Run"BIN="$HOME/Library/Application Support/Butler/Components/mysql"
"$BIN"/8.4.*/bin/mysqldump --socket="$RUN/mysql-default.sock" -u root \ --all-databases --routines --events --single-transaction > /tmp/mysql-8.4.sql
"$BIN"/9.7.*/bin/mysql --socket="$RUN/mysql-v97.sock" -u root < /tmp/mysql-8.4.sql
# 3. Point your apps at mysql-v97, verify, then retire the old instance.# Removing an instance keeps its data directory as a safety net.butler service remove mysql-defaultA logical dump/restore leaves the old data directory untouched, so if anything looks wrong you can point your app back at the original instance.
The equivalent flow for PostgreSQL uses pg_dumpall/psql, and MongoDB
uses mongodump/mongorestore — the shape is the same: dump from the old
instance’s socket, restore into a fresh instance on the new version.
Databases
Section titled “Databases”Install a database engine, add a service instance, and connect your app to it on
127.0.0.1 with the default port for that engine — see
Connecting to databases for the exact
hosts, ports and credentials. You can also have Butler create
a database and wire it up when you link a project — set it in the project’s
butler.yml:
database: type: mysql name: my_app_local createOnLink: trueInstall Mailpit to catch outgoing mail locally. Point your app’s SMTP settings at Mailpit’s local port and every message your app sends lands in Mailpit’s inbox instead of a real recipient — ideal for testing password resets, receipts and the like.
One Mailpit serves every project: it accepts any SMTP credentials and tags each
message with the username it was sent with, so setting MAIL_USERNAME per app
(MAIL_USERNAME="${APP_NAME}" in Laravel) makes the inbox filterable by app.
Every service writes to a log you can tail:
butler log mysqlThe app’s Logs section shows the same output live for any process.
Remove what you don’t need
Section titled “Remove what you don’t need”butler service remove mysql # remove a running instancebutler component remove mysql # remove the installed binaryButler guards against removing a component that a service still depends on, so you won’t accidentally pull the binary out from under a running instance.