Setting Up Your Mac

Updated May 26, 2024
Created June 8, 2020

A guide to mac setup with a focus on enhancing existing/normal workflows. Tooling and setup has a focus on ease of setup and keeping an experience that isn't too far from OS defaults. This could potentially be scripted, but has been left as a set of manual tasks so that engineers can pick, choose, and understand what they're doing.

What this means

Professional engineers need to ensure a consistent system for development and running applications. Running systems often use containers for ensuring consistency, but for local development containers and virtualisation isn't always a desired or efficient option.

The Problem

It’s likely you’ll have to work on different projects which use different versions of tools. For example you might be working on a Terraform 0.11 project today and a Terraform 0.13 project tomorrow. To make things worse, that Terraform 0.11 project might need Terragrunt 0.21, while the Terraform 0.13 project might need Terragrunt 0.26 (contrived example, I know).

There are a few ways to handle this. You could version the tools themselves (e.g. terraform0.11.. You can set up symlinks and have a script which flips them around. You can have a env file in each project you source. You could also use something like direnv.

There are tools like tfenv which set up Terraform on a per directory basis which can partially solve this. There are also tools like rbenv and pyenv which solve for Ruby and Python respectively. One problem is they all require separate set up and configuration, which can get old. Some don’t even have automatic switching mechanisms, and require more tools.

A Solution: asdf

asdf is a meta version manager, it manages other version managers (tools like pyenv).

I like it because you install and configure it once and from then on you can use .tool-versions files in your projects to automatically switch (and optionally install) tool versions.

Tools like Homebrew for desktop and terminal applications and asdf for managing runtimes, enables professionals this consistency and reproducibility.


Manage multiple runtime versions with a single CLI tool, extendable via plugins - docs at asdf is a CLI tool that can manage multiple language runtime versions on a per-project basis. It is like gvm, nvm, rbenv & pyenv (and more) all in one! Simply install your language's plugin!


Homebrew is the easiest and most flexible way to install the UNIX tools Apple didn’t include with macOS. It can also install software not packaged for your Linux distribution to your home directory without requiring sudo.

As a general rule of thumb, if available in asdf and homebrew prefer to install package from asdf. Database engines should be run locally via Docker.

  1. Open the terminal app - we'll install iterm shortly.

  2. Install Homebrew

    From Homebrew - make sure to follow any additional instructions in the console.

    /bin/bash -c "$(curl -fsSL"
  3. Add to profile

    export BREW_LOC=$(which brew)
    echo "eval \"\$($BREW_LOC shellenv)\"" >> ~/.zprofile
    eval "$BREW_LOC shellenv" || echo 'Test if `brew --version` works. If not, restart the your terminal and continue.'
  4. Install git, ZSH tools, and shell completions

    brew install wget zsh-completions git vim direnv \
      && brew install --cask iterm2
  5. Setup direnv

    mkdir -p ~/.config/direnv
    echo "[global]
    load_dotenv = true
    " > ~/.config/direnv/direnv.toml
  6. Setup git

    It is fine to use your personal github, but use your company email and link it to your account.

    git config --global "... ..."
    git config --global "...@..."
    git config --global pull.rebase false
    git config --global init.defaultBranch main
  7. Git alias' are setup by default with zsh, but this is a handy graph display of commits you may want to setup

    echo "alias git-graph=\"git log --oneline --graph --decorate\"" >> ~/.zshrc
  8. Setup Rosetta

    This is for compatibility of existing x86 applications with the M1 chipset.

    if [[ `sysctl -n machdep.cpu.brand_string` == *'Apple M1'* ]]; then
    # Mac M1s different arch workaround.
      softwareupdate --install-rosetta
  9. Install oh-my-zsh

    Allows installing plugins for zsh terminals such as type completion.

    sh -c "$(curl -fsSL"
  10. Close all all terminals and open iterm

    Iterm is more feature rich than the standard mac terminal app.

  11. Apply keybindings for iterm and increase window memory

    • Open iTerm2

    • Open iTerm2 > Preferences or "⌘" + ","

    • Profiles > Terminal > Scrollback Lines: 10,000

    • Profiles > Keys > Key Mappings > Presets > Natural Text Editing > "Remove"

  12. Change oh-my-zsh to include full path

    Default oh-my-zsh would show the directory /usr/my-name/projects/client/app path as app. The below will backup the default themeand then setup to show the path as ~/projects/client/app.

    cp ~/.oh-my-zsh/themes/robbyrussell.zsh-theme $ZSH_THEME
    find $ZSH_THEME -type f -exec sed -i '' -e 's|%c%|%~%|g' {} \;
    find ~/.zshrc -type f -exec sed -i '' -e 's|ZSH_THEME="robbyrussell"|ZSH_THEME="ollyrussell"|g' {} \;
  13. Setup nodejs with asdf for runtime management. Also setup compatibility with nvm for easy migrations (Note #1), and yarn, ipsum and ni to auto-install alongside new node installations (Note #2)

    brew install gnupg asdf
    find ~/.zshrc -type f -exec sed -i '' -e 's|plugins=(|plugins=(asdf |g' {} \; # Add asdf-vm shell completions
    . ~/.zshrc # Source the new additions
    asdf plugin-add nodejs # Add nodejs
    echo "\n# Disable asdf nodejs signature check\nNODEJS_CHECK_SIGNATURES=no\n" >> ~/.zshrc
    # See note #1 above
    echo "legacy_version_file = yes" > ~/.asdfrc
    # See note #2 above
    echo "yarn\nipsum-cli\n@antfu/ni\nzx" > ~/.default-npm-packages
    asdf install nodejs lts
    asdf global nodejs $(asdf list nodejs | grep -e "\d.*" | tail -1)

    If you're on an M1 - take a look at this guide for working with older versions of node.

  14. Install recommended packages (feel free to delete as required)

    Application brew info link
    Visual Studio Code
     brew install --cask \
       chromium \
       cyberduck \
       docker \
       firefox \
       google-chrome \
       itsycal \
       libreoffice \
       ngrok \
       obsidian \
       opera \
       insomnia \
       rectangle \
       slack \
       switchhosts \
       transmission \
       visual-studio-code \

    Note you'll need to approve most of the above apps from unidentified developers

  15. Create a projects and personal directory

    This allows us to pair and reason about each others systems easily.

    mkdir \
     -p ~/projects/prototypes \
    Directory Description Structure
    projects Client work and prototypes projects/<github organisation/client name>/<code-repo>
    personal Personal and non-company work. personal/<code-repo>

    The repo radically-digital/prismic-circleci-webhook would be ~/projects/radically-digital/prismic-circleci-webhook in all employee systems.

    The repo olmesm/ohmybuck would be ~/personal/ohmybuck in my system.

  16. Add projects and personal to your favourites

    open ~
    • Drag and drop the projects and personal directories into the left hand favourites pane of the finder window.
  17. For a quickly accessible calendar and clock, setup itsycal (depends on itsycal being installed as above)

    • Open itsycal
    • Open Preferences or "⌘" + ","
    • General > Launch at login
    • Preferences > Appearance > E d MMM
    • Hide icon
    • Hide the system date
  18. Install Lastpass in the browser

  19. Setup Authy on your mobile device for MFA - do not install this on your laptop.

  20. Setup Lastpass on your mobile device.

  21. Setup Slack on your mobile device.