IAnswerable

A Clean Mac Developer Setup

15 Apr 2026

A fresh Mac is faster to set up right the first time than to fix six months in once you’ve accumulated three package managers and no idea which one owns what. Here’s the order that avoids the common conflicts.

1. Xcode Command Line Tools, before anything else

xcode-select --install

This gets you git, clang, and the headers most compiled dependencies need. Homebrew and most language installers assume this is already present and fail in confusing ways if it isn’t.

2. Homebrew

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

On Apple Silicon it installs to /opt/homebrew, not /usr/local. Add it to your PATH — the installer prints the exact line, usually:

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

Skip this step and brew-installed tools silently won’t be found by your shell, which looks like a broken install when it’s actually a missing PATH entry.

3. Pick one version manager per language, not three

The most common mess on a dev machine is Node installed via Homebrew, nvm, and the official installer, all fighting over which node runs. Pick one per language:

Language Recommended
Node mise or nvm — not brew install node
Python mise or pyenv — not system Python, not brew install python
Ruby mise or rbenv

mise (formerly rtx) handles all three from one tool and one config file (.tool-versions or mise.toml) per project, which is the actual reason to prefer it over juggling nvm + pyenv + rbenv separately:

brew install mise
echo 'eval "$(mise activate zsh)"' >> ~/.zshrc
mise use --global node@lts python@3.12

4. Git config, before you clone anything

git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
git config --global pull.rebase false

Set pull.rebase explicitly — the unset default prints a warning on every pull with a fast-forward-able history, and it’s one less thing to see and ignore a hundred times.

5. SSH key for git remotes

ssh-keygen -t ed25519 -C "you@example.com"
eval "$(ssh-agent -s)"
ssh-add --apple-use-keychain ~/.ssh/id_ed25519

--apple-use-keychain stores the passphrase in macOS Keychain so you’re not retyping it every terminal session. Add the public key (~/.ssh/id_ed25519.pub) to GitHub/GitLab before your first clone.

6. Terminal and shell

Default Terminal.app works. If you’re going to spend eight hours a day in it, iTerm2 or Ghostty (both brew install --cask) add real scrollback search and split panes that the built-in terminal lacks.

For the shell itself, zsh ships default on macOS. Add oh-my-zsh or a minimal prompt like starship if you want git branch/status in your prompt without hand-rolling it.

7. A Brewfile so the next machine takes five minutes, not an afternoon

brew bundle dump --file=~/Brewfile

Captures every formula, cask, and Mac App Store app you have installed into one file. On the next machine:

brew bundle install --file=~/Brewfile

Keep this file in your dotfiles repo. This is the difference between reconstructing your setup from memory and running one command.

What to skip

Don’t install Docker Desktop by default if you don’t already know you need containers — it runs a background VM that eats RAM whether you’re using it or not. Same for a database GUI, a full IDE beyond your editor of choice, or any “might need it later” tool. Install it when a project actually requires it; a fresh machine with 20 unused apps is the thing you’re trying to avoid rebuilding from.