macOS ships without a package manager, which makes setting up a developer machine a manual slog — download this DMG, drag that app, configure this PATH. Homebrew fixes that. It’s the de-facto standard package manager for macOS, and once you understand its model (formulae vs. casks, taps, and Brewfiles), maintaining a reproducible dev environment becomes straightforward. Let’s cover everything you actually need.

Installing Homebrew

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

The installer will prompt for your password, install Xcode Command Line Tools if needed, and set up Homebrew at /opt/homebrew on Apple Silicon or /usr/local on Intel Macs.

After installation, follow the on-screen instructions to add Homebrew to your PATH. For Apple Silicon:

$ echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
$ eval "$(/opt/homebrew/bin/brew shellenv)"

Verify it works:

$ brew --version
Homebrew 4.3.1

Formulae vs. Casks

Homebrew has two types of packages:

  • Formulae — command-line tools and libraries (git, node, postgresql, ffmpeg). Installed to /opt/homebrew/bin.
  • Casks — macOS GUI applications (--cask flag). Installed to /Applications like a normal app.
$ brew install git          # formula — installs the git CLI
$ brew install --cask iterm2  # cask — installs the iTerm2.app GUI

Daily Commands

$ brew search <term>        # search available packages
$ brew install <name>       # install a package
$ brew uninstall <name>     # remove a package
$ brew upgrade              # upgrade all outdated packages
$ brew upgrade <name>       # upgrade a specific package
$ brew list                 # list installed formulae
$ brew list --cask          # list installed casks
$ brew info <name>          # show package details and dependencies
$ brew doctor               # diagnose common Homebrew issues
$ brew cleanup              # remove old versions to free disk space

Seeing What’s Outdated

$ brew outdated
git (2.43.0) < 2.46.0
node (20.11.0) < 22.4.0
postgresql@16 (16.2) < 16.4
$ brew upgrade
==> Upgrading 3 outdated packages:
git 2.43.0 -> 2.46.0
node 20.11.0 -> 22.4.0
postgresql@16 16.2 -> 16.4

Installing Multiple Versions with @

Some formulae support pinned versions via the @ convention:

$ brew install node@20          # install Node.js 20 LTS
$ brew install python@3.11      # install Python 3.11 specifically
$ brew install postgresql@16    # PostgreSQL 16

To switch between versions, unlink one and link another:

$ brew unlink node@22
$ brew link node@20 --force

Taps — Third-Party Repositories

Homebrew’s built-in repository (called homebrew/core) covers thousands of packages, but some tools are distributed via their own taps:

$ brew tap hashicorp/tap
$ brew install hashicorp/tap/terraform

$ brew tap mongodb/brew
$ brew install mongodb/brew/mongodb-community

$ brew tap homebrew/cask-fonts
$ brew install --cask font-jetbrains-mono

A tap is just a GitHub repository with a specific file layout. brew tap <user>/<repo> clones it to $(brew --repository)/Library/Taps/.

Brewfile — Reproducible Environments

The Brewfile is Homebrew’s equivalent of a package.json — a declarative file listing all your packages. This is how you set up a new machine in minutes instead of hours.

Create one interactively from your current installation:

$ brew bundle dump --file=~/Brewfile

A typical Brewfile looks like:

tap "homebrew/bundle"
tap "homebrew/cask-fonts"
tap "hashicorp/tap"

brew "git"
brew "node"
brew "python@3.12"
brew "postgresql@16"
brew "redis"
brew "ffmpeg"
brew "jq"
brew "ripgrep"
brew "tmux"
brew "gh"

cask "iterm2"
cask "visual-studio-code"
cask "docker"
cask "rectangle"
cask "font-jetbrains-mono"

To restore from a Brewfile on a new machine:

$ brew bundle install --file=~/Brewfile
Installing git... done
Installing node... done
Installing python@3.12... done
...
Homebrew Bundle complete! 14 Brewfile dependencies now installed.

Keep your Brewfile in a dotfiles git repository. It’s the fastest way to get a new Mac developer-ready.

Services — Running Background Processes

Many developer tools (PostgreSQL, Redis, nginx) need to run as background services. Homebrew wraps macOS’s launchctl so you don’t have to:

$ brew services start postgresql@16
==> Successfully started postgresql@16 (label: homebrew.mxcl.postgresql@16)

$ brew services stop redis
$ brew services restart nginx

$ brew services list
Name            Status  User         File
nginx           started mukulkadel   ~/Library/LaunchAgents/homebrew.mxcl.nginx.plist
postgresql@16   started mukulkadel   ~/Library/LaunchAgents/homebrew.mxcl.postgresql@16.plist
redis           none

Services started this way survive reboots automatically.

Troubleshooting Common Issues

brew doctor Warnings

Run brew doctor when things feel off. Most warnings come with instructions:

$ brew doctor
Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. Most probably won't cause any issues.

Warning: Unbrewed dylibs were found in /usr/local/lib

Package Conflicts

If a package conflicts with a system tool or another Homebrew package:

$ brew link --overwrite <name>    # force linking
$ brew unlink <name>              # unlink to resolve a conflict

Stale Lock Files

If a brew upgrade dies mid-run and leaves Homebrew locked:

$ rm -rf $(brew --prefix)/var/homebrew/locks/*

Conclusion

Homebrew is the starting point for any macOS developer environment. The core workflow — brew install, brew upgrade, brew services — covers 90% of daily use. The Brewfile is where the real leverage is: commit it to your dotfiles repo and you can rebuild a complete dev environment on a new machine with a single command. Run brew doctor periodically to catch drift before it becomes a problem.