I needed to update some CLI tools. Here’s the quick Homebrew reference.

Update Homebrew itself:

brew update

Upgrade all packages:

brew upgrade

Upgrade a specific package:

brew upgrade gh

See what’s outdated:

brew outdated

Install a cask (GUI app):

brew install --cask iterm2

List installed packages:

brew list

Search for a package:

brew search redis

Clean up old versions:

brew cleanup

The difference between update and upgrade: update fetches the latest package definitions, upgrade actually installs newer versions.

How often I upgrade Link to heading

I run brew upgrade roughly once a week, usually on a Monday morning when I’m having my first coffee. It’s a good background task whilst I’m catching up on emails.

I don’t do it more frequently because:

  1. Most updates are minor and not urgent
  2. It’s a good chunk of download time (can be 500MB+ if lots has changed)
  3. Breaking changes occasionally happen

I don’t do it less frequently because:

  1. Security updates are important
  2. The longer you wait, the more likely something will break
  3. It’s easier to debug issues if you upgrade weekly vs monthly

For production servers, I’m more careful and test upgrades in staging first. But for my local dev machine, I’m fairly relaxed about it.

Dealing with breaking changes Link to heading

Breaking changes happen, but they’re rare. When they do:

Check what’s changed first:

brew outdated

If you see a major version bump (e.g., postgres@14 to postgres@15), read the release notes before upgrading.

Pin a version if needed:

brew pin postgres@14

This prevents brew upgrade from touching that package. Useful if you need to stay on a specific version for compatibility.

Unpin when ready:

brew unpin postgres@14

Roll back if something breaks:

Brew keeps old versions around for a while. You can check what’s available:

brew info postgres

If you need to downgrade:

brew uninstall postgres
brew install postgres@14

I’ve only had to roll back a handful of times in years of using Homebrew. The most common issue is Python packages breaking when Python itself upgrades, but that’s more of a general Python problem than a Homebrew problem.

brew cleanup and disk space Link to heading

Homebrew keeps old versions around by default. Over time this adds up:

brew cleanup -n  # Dry run - see what would be deleted
brew cleanup     # Actually clean up old versions

I run brew cleanup every month or so. On my machine it usually frees 2-3 GB. Not critical, but nice to reclaim the space.

You can also configure automatic cleanup:

export HOMEBREW_INSTALL_CLEANUP=1

Add that to your .zshrc or .bashrc and Homebrew will clean up automatically after every upgrade.

Homebrew vs other package managers Link to heading

I’ve used a few different package managers over the years:

apt/yum (Linux) - Rock solid, huge repositories, but tied to specific distributions. These work well on servers but aren’t ideal for a dev machine.

MacPorts (macOS) - I used this before Homebrew existed. It works fine but feels more “Linux-y” with its /opt/local prefix. Homebrew’s /usr/local (or /opt/homebrew on Apple Silicon) feels more native to macOS. Homebrew also has better cask support for GUI apps.

Nix - I tried Nix for a few months. It’s conceptually brilliant (reproducible builds, multiple versions side-by-side, atomic upgrades) but the learning curve is steep and the documentation isn’t great. If you’re willing to invest the time, Nix is probably the “right” way to do package management. But for most people, Homebrew is more pragmatic.

asdf / mise - These are great for managing language runtimes (Python, Node, Ruby, etc.) but they’re complementary to Homebrew, not a replacement. The recommended approach is Homebrew for system tools and asdf for language versions.

My honest opinion: Homebrew is good enough. It’s not perfect - upgrades can be slow, it occasionally breaks things, and there’s no built-in way to pin your entire environment for reproducibility. But it’s pragmatic, well-maintained, and has excellent community support. For a dev machine on macOS, I wouldn’t use anything else.

If I was building production infrastructure, I’d use Docker or Nix for reproducibility. But for local dev? Homebrew is fine.