Mac Terminal — iTerm2 vs WezTerm vs Ghostty + zsh + Starship
Three options to replace the default Terminal.app, plus the fastest path to a stable zsh + Starship setup.
macOS's built-in Terminal.app works, but it falls behind the alternatives on splits, search, rendering, and configurability. This guide compares iTerm2 · WezTerm · Ghostty and builds the fastest stable environment (WezTerm + zsh + Starship + four modules).
TL;DR
| Option | Strengths | Weaknesses | Best for |
|---|---|---|---|
| WezTerm (recommended) | Lua config / GPU acceleration / cross-platform | Lua learning curve | Solo devs who like configs as code |
| iTerm2 | Most mature / strong search/split/sessions | Settings GUI maze | Prioritizes feature richness |
| Ghostty | Fast / simple / 1.0 stable | Newer, some features missing | Minimalists / latest-first |
1. Options Compared
iTerm2
The oldest macOS-only terminal. Splits (⌘D), instant replay, search, triggers (text-match actions), session auto-restore — rich feature set.
WezTerm
Written in Rust, configured in Lua, GPU-accelerated, cross-platform (Mac/Linux/Win). Keybindings, themes, multiplexing — all in one Lua file. Reproducible.
Ghostty
1.0 stable in 2024. Fast, GPU-accelerated, minimal config. Fewer features than iTerm2/WezTerm but enough for daily use.
Recommendation: WezTerm
For "manage config as code, restore on a new machine in one shot" scenarios, WezTerm wins decisively. Integrates naturally with dotfiles management. This guide is WezTerm-based.
2. Install WezTerm
brew install --cask weztermFirst launch → default shell is zsh (macOS default). If the screen renders, you're good.
3. WezTerm Config — ~/.config/wezterm/wezterm.lua
mkdir -p ~/.config/wezterm && nvim ~/.config/wezterm/wezterm.lua:
local wezterm = require 'wezterm'
local config = wezterm.config_builder()
-- Fonts
config.font = wezterm.font_with_fallback({
'JetBrainsMono Nerd Font',
'Hiragino Sans', -- Korean / Japanese fallback
})
config.font_size = 13.0
-- Color scheme
config.color_scheme = 'Catppuccin Mocha' -- or 'Tokyo Night', 'Dracula'
-- Window
config.window_decorations = 'RESIZE' -- hide titlebar, keep resizable
config.window_padding = { left = 8, right = 8, top = 8, bottom = 8 }
config.window_background_opacity = 0.95
config.macos_window_background_blur = 20
-- Tabs
config.use_fancy_tab_bar = false
config.tab_bar_at_bottom = true
config.hide_tab_bar_if_only_one_tab = true
-- Shell
config.default_prog = { '/opt/homebrew/bin/zsh', '-l' } -- brew zsh (newer than macOS default)
-- Keybindings
config.keys = {
-- Splits
{ key = 'd', mods = 'CMD', action = wezterm.action.SplitHorizontal { domain = 'CurrentPaneDomain' } },
{ key = 'D', mods = 'CMD|SHIFT', action = wezterm.action.SplitVertical { domain = 'CurrentPaneDomain' } },
-- Pane navigation
{ key = 'LeftArrow', mods = 'CMD|OPT', action = wezterm.action.ActivatePaneDirection 'Left' },
{ key = 'RightArrow', mods = 'CMD|OPT', action = wezterm.action.ActivatePaneDirection 'Right' },
{ key = 'UpArrow', mods = 'CMD|OPT', action = wezterm.action.ActivatePaneDirection 'Up' },
{ key = 'DownArrow', mods = 'CMD|OPT', action = wezterm.action.ActivatePaneDirection 'Down' },
-- Close pane
{ key = 'w', mods = 'CMD', action = wezterm.action.CloseCurrentPane { confirm = true } },
}
return configWezTerm auto-reloads on save. Try ⌘D to confirm splits work.
4. Upgrade zsh
macOS ships an older zsh. brew has newer:
brew install zsh
which -a zsh
# /opt/homebrew/bin/zsh
# /bin/zsh
# Change default shell
sudo sh -c "echo /opt/homebrew/bin/zsh >> /etc/shells"
chsh -s /opt/homebrew/bin/zshNew terminal → echo $ZSH_VERSION → 5.9+ confirms.
5. Starship Prompt
Lighter and faster than oh-my-zsh. Rust single binary:
brew install starshipAppend to ~/.zshrc:
eval "$(starship init zsh)"~/.config/starship.toml:
# Snappy default activation
add_newline = true
format = """
$directory\
$git_branch\
$git_status\
$nodejs\
$python\
$rust\
$cmd_duration\
$line_break\
$character"""
[directory]
truncation_length = 3
truncate_to_repo = true
[git_status]
disabled = false
ahead = "↑${count} "
behind = "↓${count} "
[cmd_duration]
min_time = 2000 # only show for commands >2 seconds
[character]
success_symbol = "[➜](bold green)"
error_symbol = "[➜](bold red)"Reload with . ~/.zshrc or open a new terminal.
6. Four zsh Modules
6.1 zsh-autosuggestions
History-based gray suggestion:
brew install zsh-autosuggestions~/.zshrc:
source /opt/homebrew/share/zsh-autosuggestions/zsh-autosuggestions.zshAccept with →.
6.2 zsh-syntax-highlighting
Color commands (invalid = red):
brew install zsh-syntax-highlightingsource /opt/homebrew/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh⚠️ Source syntax-highlighting last in
.zshrcfor correct behavior.
6.3 fzf — fuzzy finder
brew install fzf
$(brew --prefix)/opt/fzf/install
# yes to all promptsIn a new terminal:
Ctrl+R— history searchCtrl+T— file searchAlt+C— directory jump
6.4 zoxide — smarter cd
brew install zoxide~/.zshrc:
eval "$(zoxide init zsh)"z proj # jump to a frequently visited project path
zi # interactive picker7. Full .zshrc Example
# History
HISTFILE=~/.zsh_history
HISTSIZE=10000
SAVEHIST=10000
setopt SHARE_HISTORY HIST_IGNORE_DUPS HIST_IGNORE_SPACE
# Completion
autoload -Uz compinit && compinit
# Brew
eval "$(/opt/homebrew/bin/brew shellenv)"
# Modules
source /opt/homebrew/share/zsh-autosuggestions/zsh-autosuggestions.zsh
eval "$(zoxide init zsh)"
# Aliases
alias ll='ls -lah'
alias gs='git status -sb'
alias gd='git diff'
alias ..='cd ..'
# Tools
eval "$(starship init zsh)"
# (Must be last)
source /opt/homebrew/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh8. iTerm2 Quick Setup (Alternative)
If you prefer iTerm2 over WezTerm:
brew install --cask iterm2- Preferences → Profiles → Default → Text → Font = JetBrainsMono Nerd Font 13pt
- Window → Transparency 5%, Blur on
- Keys → Hotkey window — bind a global shortcut like
⌥ Spacefor floating
iTerm2's killer feature is the Hotkey Window (floating terminal toggle from anywhere). WezTerm can be configured to behave similarly, but iTerm2 gives it out of the box.
Verification
- New terminal → Starship prompt shows (with colored cwd / git branch)
Ctrl+R→ fzf interactive history searchls→ zsh-syntax-highlighting colors the command- Type part of a previous command → gray autosuggestion → press
→ z proj→ jump to a previously visited project folder- WezTerm
⌘D→ split pane →⌘⌥←to navigate
Troubleshooting
Syntax highlighting shows no color
- Not sourced last in
.zshrc(must come after other modules) - WezTerm color_scheme below 256 colors — unlikely; prefer Catppuccin / Tokyo Night
Garbled glyphs in Starship
Nerd Font missing. Check WezTerm's font config + actually install the font (brew install --cask font-jetbrains-mono-nerd-font).
z does nothing
- zoxide init missing from
.zshrc, or.zshrcnot reloaded - Database is empty at first — do a few
cds to train it
WezTerm opens at $HOME by default
Set in config: config.default_cwd = wezterm.home_dir .. '/work', or alias cd to your folder.
chsh didn't change the shell
- The new shell wasn't added to
/etc/shells→ chsh fails - Log out / log back in, or reboot
References
- Mac initial setup — Homebrew prerequisites
- Dotfiles management — recommend storing
.zshrc,wezterm.lua,starship.tomlin chezmoi - WezTerm (official)
- Starship config
- iTerm2
- Ghostty
Changelog
- 2026-05-12: First draft. Three terminals compared + WezTerm + zsh + Starship + four modules + five troubleshooting cases.