Welcome to my periodically updated guide to setting up the best terminal development environment for any platform, starting with macOS for now. This guide have overlapping concepts, but all in all it will be tailored for each platform as much as possible.

macOS

Interface

Over the years I've frequently flip flopped between the stock Terminal.app and iTerm2. Depending on your desire for features, Terminal.app will be just fine to start with. After customizing it a bit and wanting to take your personalization and features to the next level, my recommendation is iTerm2.

iTerm2 handles just about any type of configuration with ease and I'll go over a few benefits that make it a bit more useful than the stock Terminal.app.

Color Schemes

Yes, I know, not a feature, but who doesn't like to customize their terminal with a pleasing theme. Over at mbadolato's Color Schemes Repo you can find a ton of schemes that you can import directly and select your favorite.

Colored Host Schemes

This feature is one of my favorites for working in production environments. When I ssh into a production server to fix or deploy something, it is very important to know which window is that server. There is a quick right click option to Edit Session to display background text.

Toolbelt

The Toolbelt is something I do not have enabled all the time, but it is worth mentioning and showcasing a couple things. I typically keep the jobs tab open to show which processes spawn and what exactly is running. Another couple of useful tools are the Command History and the Paste History as shown below. I mainly wanted to show its potential usefulness because the stock Terminal.app does not have anything like this built in.

  • Much More

There are plenty of other features that I haven't listed, but these are a couple to start you off in iTerm2.

Managing Packages & Utilities

HomeBrew

When starting off customizing your Mac's terminal, choosing the right command-line utilities can make the experience much better. The very first utility you should install is HomeBrew or brew in your terminal. HomeBrew is the unofficial package manager that every macOS terminal enthusiast should have. Since it's your package manager, let it manage anything else whenever possible. HomeBrew makes installing and updating utilities as easy as brew install git. You can download it from their site, brew.sh or use the quick command below.

Quick Install

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

One overlooked tip that I always suggest is to leverage brew doctor. This command will solve and help manage your installed packages. It is highly recommended to check this after any macOS update in case folder permissions, symlinks, or dependencies change. You're all good when you see Your system is ready to brew.

If you haven't installed Xcode, run xcode-select --install to download the relevant developer utilities. This is typically suggested with brew doctor but is often cluttered with other warnings. This typically resolves most of those.

Finally, occasionally update packages with brew upgrade.

Packages

Bundled Tools

  • These are preinstalled tools bundled with macOS but reinstalling it with HomeBrew allows for faster updates and patches you normally wouldn't get until another macOS update.
  • zsh, brew install zsh, optional but if you want to use Oh-My-Zsh, it's good to update here.
  • git, brew install git, bundled with the Xcode Tools, but it is important to link it with HomeBrew for various security patches.
  • bash, brew install bash, macOS bundles an out of date version and updating it will give more compatibility with Bash scripts made for Linux.

Personal Favorites

  • NeoVim, brew install neovim, my favorite cross platform text editor. It is very similar to vim but has a few added features that I prefer. I will get into those a bit later.
  • ack, brew install ack, a faster and more efficient grep search tool
  • neofetch, brew install neofetch, generates a cool looking system and terminal color overview page. It's just a neat little package.
  • tree, brew install tree, super handy utility to visualize folder structures in the terminal.

Setting Up Your Shell

Opening up the Terminal on a fresh install of macOS brings you directly into the Bash shell (Bourne-again shell). I personally have nothing against Bash, I just love the practical feature enhancements of Zsh (Z shell). This article won't be getting into the exact differences, but Zsh includes more features as well as plugins. By default, macOS includes Zsh out of the box, but we're going to make it even more useful.

The first thing I recommend is to make sure HomeBrew has installed its version instead of the standard macOS version included with the OS like mentioned above. You will also have to change the path of the macOS login shell in the User's settings panel.

"System Preferences" -> "Users & Groups" -> Right click on user, "Advanced Options"

Quickly copy the current path of HomeBrew's Zsh, and paste into the "Login Shell"

which zsh | pbcopy

Oh-My-Zsh

This will be a long section full of plenty of useful tips and tweaks to fully understand the complexities of using Zsh's plugin system with the added tweaks of Oh-My-Zsh. Basically, Oh-My-Zsh sits on top of zsh and adds even more quality of life features. I'll list out just a few before we dive in.

  • Tab completion of folder and file names
  • Auto capitalization matching
  • No more typing cd Folder, just folder will get you there
  • Much, much more

Installation

Installing Oh-My-Zsh, is quite simple. Follow the installation on their GiHub or copy and paste from below.

sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

Folder Structure & Relevant Files

After installing Oh-My-Zsh, a new folder and file will be in your home directory. Running ls -a ~ in the terminal will list out all the dot files in your home directory. The two entries we'll be working with is ~/.oh-my-zsh/ and ~/.zshrc. The first is strictly a Git directory of the Oh-My-Zsh project. You really won't have to touch this directory unless you want to build your own custom theme or plugin. The other file, ~/.zshrc deserves its own section due to its depth of customization.

.zshrc

In this section, I’ll go over the default .zshrc file and show you how to customize it. I’ll also go over some of the useful functions and aliases that I’ve set up. You can find my full public .zshrc file in my dotfiles repository.

Below is the default ~/.zshrc file, with some comments and properties removed for conciseness.

# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH

# Path to your oh-my-zsh installation.
export ZSH=$HOME/.oh-my-zsh

ZSH_THEME="robbyrussell"

# _ and - will be interchangeable.
# HYPHEN_INSENSITIVE="true"

# Uncomment the following line to disable bi-weekly auto-update checks.
# DISABLE_AUTO_UPDATE="true"

# Uncomment the following line to change how often to auto-update (in days).
# export UPDATE_ZSH_DAYS=13

# Uncomment the following line to disable colors in ls.
# DISABLE_LS_COLORS="true"

# Uncomment the following line to disable auto-setting terminal title.
# DISABLE_AUTO_TITLE="true"

# Uncomment the following line to enable command auto-correction.
# ENABLE_CORRECTION="true"

# Uncomment the following line to display red dots whilst waiting for completion.
# COMPLETION_WAITING_DOTS="true"

# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*)
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(
  git
)

source $ZSH/oh-my-zsh.sh

# User configuration

# Compilation flags
# export ARCHFLAGS="-arch x86_64"

# ssh
# export SSH_KEY_PATH="~/.ssh/rsa_id"

# Example aliases
# alias zshconfig="mate ~/.zshrc"
# alias ohmyzsh="mate ~/.oh-my-zsh"

As you can see, the default ~/.zshrc file has a lot of various flags and features that a user can toggle or set up. I'll go over the more popular parts of this file below and explain how to customize it.

PATH

# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH

The PATH variable is incredibly useful for a developer. Setting this variable to look into other folders tremendously eases running arbitrary executables. My first time leveraging this came from installing the Android Dev Tools. This installation places some common tools like adb in a folder deep in their installation directory. Well, adding that tools directory to this PATH variable allowed me to run adb from anywhere instead of cding into that deep directory.

ZSH_THEME

The ZSH_THEME is one of the main reasons some people recommend  Oh-My-Zsh. This allows you to completely change the look and add useful bits of information to your shell. You can find a complete list with picture on their GitHub Repo. After finding a theme you like, simply replace the string and restart you shell, exec zsh.

plugins

Plugins give a lot of quality of life enhancements to the shell. My personal favorite and the one I could not live without now is the git plugin. It gives a tremendous amount of aliases to manage git repositories.  Some examples include: typing gl for git pull, gco -b for git checkout -b, or gp to push. I recommend reviewing the list in the repo and adding the ones for your dev environment.

Startup Speed

One of the warnings in the plugin section was regarding the speed at which your shell will open by adding more plugins. I personally did not find a slowdown for that, but this needs to be brought up before customizing further. Over time, some utilities will want you to add to your zsh profile. In doing so, I found some utilities to cause a significant slowdown when starting my shell. One example is nvm. I found that adding the auto load script caused startup times to hit > 1 second. The solution I found that worked best was to load this when needed and not every startup. When I am working in a node project, I simply call loadnvm and everything gets set up. I'll include a little snippet on how to add in a call like that below.

# Logic to call when needed
load-function() {
  # Some long process
}

# Helper alias if other scripts need to be loaded
alias loadnvm='[ -s "$NVM_DIR/nvm.sh" ] && load-function'

There are also really great blog posts that detail Oh-My-Zsh startup speed and how to debug which components are taking too long to load. My favorite was htr3n's post.

Interface

NeoVim

Tools

Shell Tweaks