macOS setup for software development

I’ve been using Linux as my daily-driver OS for professional software development since 2019.

In 2021 I had a short, company-mandated stint with macOS, and it went badly enough that I swore I’d never touch it again. Looking back, most of it was self-inflicted: I tried to force my Linux workflow and keyboard shortcuts into macOS, used an external keyboard whose layout was not Mac-compatible and then made it worse by remapping keys like Cmd and Ctrl in an attempt to bring some familiarity back. I also really, really missed a tiling window manager. Unsurprisingly the whole thing didn’t work and I switched back to Linux as soon as I could.

By the beginning of 2025, a few things had changed:

  • I stopped caring about using a tiling window manager. My setup made context-switching too easy: one shortcut to change workspaces and suddenly I’m “taking a quick look” on slack whenever something gets hard or boring.
  • The performance difference between my laptop and the Macbooks was very noticeable: running a linter on my company’s main monorepo was taking 2-3x more time than on my colleagues’ Macbooks.
  • I missed the ecosystem: my AirPods never quite worked on Linux (to be fair, I didn’t fight it much), some apps like Slack or Spotify were clearly second class on Linux
  • LLMs were clearly an industry changing technology and apps like ChatGPT or Claude did not exist on Linux. Although in retrospect these apps weren’t that important I really didn’t want to miss out on the bleeding edge of the industry and Linux was clearly not being treated as a first class target of app developers.

So I switched to a MacBook Pro M4. And, annoyingly for my past self, it’s been great: everything is fast, the screen is so good that I ditched my external monitor, and the keyboard + trackpad combo is excellent.

The biggest difference this time is that I didn’t try to “fix” macOS into Linux. No key remaps, no forcing it. I just learned the shortcuts and everything clicked right away.

As the saying goes: never say never.

Setup

  • Install Ghostty terminal emulator.
  • Install Xcode Command Line Tools with xcode-select --install
  • Install Homebrew
  • Disable Spotlight hotkey. Install Raycast.
  • Install ohmyzsh to manage zsh (default macOS shell)
  • Install zsh-peco-history to improve shell history search using Ctrl+R [1]
  • Install mise to manage different versions of tooling (node, python, ruby, etc)
  • Install Jetbrain’s toolbox app to manage all IDE’s I use
  • Install claude code.
  • Setup zsh aliases [2]
  • Setup ssh for Github and create a GPG signing key
  • Setup macOS keyboard with the help of https://mac-key-repeat.zaymon.dev/
    • defaults write -g InitialKeyRepeat -int 12
    • defaults write -g KeyRepeat -int 1
  • Change Finder settings
    • chflags nohidden ~/Library to show Library folder
    • defaults write com.apple.finder AppleShowAllFiles -boolean true to show hidden files
    • defaults write com.apple.finder ShowPathbar -bool true to show path bar

Footnotes

1. zsh-peco-history config ↩︎

# .zshrc

HISTSIZE=10000000
SAVEHIST=10000000

setopt EXTENDED_HISTORY          # Write the history file in the ":start:elapsed;command" format.
setopt INC_APPEND_HISTORY        # Write to the history file immediately, not when the shell exits.
setopt SHARE_HISTORY             # Share history between all sessions.
setopt HIST_EXPIRE_DUPS_FIRST    # Expire duplicate entries first when trimming history.
setopt HIST_IGNORE_DUPS          # Don't record an entry that was just recorded again.
setopt HIST_IGNORE_ALL_DUPS      # Delete old recorded entry if new entry is a duplicate.
setopt HIST_FIND_NO_DUPS         # Do not display a line previously found.
setopt HIST_IGNORE_SPACE         # Don't record an entry starting with a space.
setopt HIST_SAVE_NO_DUPS         # Don't write duplicate entries in the history file.
setopt HIST_REDUCE_BLANKS        # Remove superfluous blanks before recording entry.

2. Aliases ↩︎

I make heavy use of aliases on my ~/.zshrc file to help me navigate to common directories or open projects on the appropriate IDE. Some examples:

export EDITOR='vim'

# .zshrc
alias ezshrc="$EDITOR $HOME/.zshrc"
alias szshrc="source $HOME/.zshrc"

# projects
export PROJECTS_HOME="$HOME/projects"
export AOC="$PROJECTS_HOME/aoc-2022"

alias aoc="cd $AOC"
alias iaoc="launch_rubymine $AOC"

# functions
launch_rubymine() {
        nohup $HOME/bin/rubymine $1 > /dev/null 2>&1 &
}

I can type ezshrc from anywhere in my terminal to edit my zsh config file and then szshrc to source it.