Building the Ultimate Developer Shell
Modern development workflows increasingly live inside the terminal. With the right tooling, your shell becomes a fast, expressive, and deeply ergonomic environment—far beyond what the default macOS setup provides.
In this guide, we’ll build a state-of-the-art developer shell on macOS using the following tools:
- fish – User-friendly, smart, interactive shell
- oh-my-posh – Beautiful, information-rich prompts
- zoxide – Smarter
cdnavigation - fzf – Lightning-fast fuzzy finder
- eza – Modern replacement for
ls - bat – Syntax-highlighting
catalternative - lazygit – Terminal-native Git UI
- yazi – Ultra-fast terminal file manager
- LazyVim – Neovim preconfigured as a full-fledged IDE
- Ghostty – GPU-accelerated terminal for macOS (and Linux)
By the end of this post, you’ll have an extremely productive terminal environment optimized for coding, navigation, version control, and file management.
1. Base Setup: Ghostty Terminal + Fish Shell
Ghostty is a modern terminal emulator that is fast, GPU-accelerated, and highly configurable. It pairs beautifully with fish, which provides smart defaults, autosuggestions, and a much smoother user experience than bash or zsh.
Install fish
brew install fish
Add fish to valid shells:
echo /opt/homebrew/bin/fish | sudo tee -a /etc/shells
chsh -s /opt/homebrew/bin/fish
Enable fish for Ghostty
Ghostty will automatically pick up your default shell.
Optionally configure font, themes, and keybindings in:
~/Library/Application Support/com.mitchellh.ghostty/config
2. Add a Powerful Prompt with Oh My Posh
A meaningful prompt surfaces context: Git branch, Kubernetes context, execution time, error codes, etc. Oh My Posh is cross-platform and beautifully customizable.
Install:
brew install jandedobbeleer/oh-my-posh/oh-my-posh
Activate in fish:
Add to ~/.config/fish/config.fish:
oh-my-posh init fish --config ~/.poshthemes/yourtheme.json | source
Pick a theme:
oh-my-posh get themes
I recommend starting with jandedobbeleer, paradox, or bubbletea.
3. Smarter Navigation with Zoxide
zoxide replaces cd by learning which directories you visit most often and jumping there instantly.
Install:
brew install zoxide
Fish integration:
zoxide init fish | source
Now navigation becomes:
z myproject
z src
z ~/dev/ai
Zoxide also integrates with fzf:
zi # interactive directory jump
4. Fuzzy Finding Everything with FZF
fzf adds fuzzy search to directory jumping, Git history, command history, file navigation, and more.
Install:
brew install fzf
Run setup:
$(brew --prefix)/opt/fzf/install
Useful keybindings (fish)
Add to config.fish:
# CTRL+R: fuzzy search command history
bind \cr '__fzf_history'
You now have frictionless interactive search everywhere.
5. Modern CLI Replacements: eza and bat
eza (ls replacement)
brew install eza
Define useful aliases:
alias ls="eza --icons auto"
alias ll="eza -l --git --icons"
alias lt="eza --tree --icons"
bat (cat on steroids)
brew install bat
bat brings syntax highlighting, paging, line numbers, and Git integration.
Combine it with fzf:
fzf --preview 'bat --style=numbers --color=always {}'
6. Terminal File Manager: Yazi
Yazi is a blazing-fast, TUI-based file manager with previews, tabs, and excellent navigation.
brew install yazi
Launch it from anywhere:
y
For fish convenience:
alias yy="yazi"
Yazi integrates nicely with zoxide and fzf indirectly, giving you instant exploration of deep directory structures.
7. Git Superpowers with Lazygit
Lazygit is one of the most impactful CLI tools for developers. It gives you a mouse-free UI for:
- staging/unstaging
- resolving merge conflicts
- browsing logs
- managing branches
- viewing diffs
Install:
brew install lazygit
Run:
lazygit
Add an alias:
alias lg="lazygit"
8. Neovim as a Full IDE with LazyVim
LazyVim turns Neovim into a powerful IDE with:
- LSP (TypeScript, Go, Rust, Python, etc.)
- Treesitter
- Git signs
- Debug adapters
- File explorer
- Telescope fuzzy search
- Beautiful UI
Installation
brew install neovim
Backup existing config:
mv ~/.config/nvim ~/.config/nvim.bak
Install LazyVim starter:
git clone https://github.com/LazyVim/starter ~/.config/nvim
cd ~/.config/nvim && rm -rf .git
Start Neovim:
nvim
LazyVim will install all plugins automatically.
Integrate with the ecosystem
- Telescope uses fzf for fuzzy finding
- LazyVim shortcuts align well with yazi + zoxide navigation
- Lazygit integrates via plugins like
kdheepak/lazygit.nvim
Your terminal becomes a complete development cockpit.
9. Putting It All Together
At this point, your developer shell includes:
- Ghostty: fast, GPU-accelerated terminal
- fish: smart, interactive shell
- oh-my-posh: information-dense prompt
- zoxide: intelligent directory jumping
- fzf: fuzzy searching everywhere
- eza + bat: modern file and content tools
- yazi: fast file manager
- lazygit: powerful Git UI
- LazyVim: a full development IDE inside the terminal
A typical workflow becomes:
z project # instantly jump to a repo
yy # inspect directories with yazi
nvim . # open repo in LazyVim
lg # manage Git with lazygit
or:
fzf # find any file
bat file.txt # preview contents
lt # browse structure with eza tree view
Every part of the stack is designed for speed, clarity, and minimal friction.
Absolutely — here’s a clean, production-ready dotfiles section plus a complete config.fish tailored to the toolchain you’re using (fish, zoxide, fzf, oh-my-posh, bat, eza, yazi, lazygit, LazyVim).
Everything is macOS + Ghostty friendly.
10. Dotfile Snippets for the Developer Shell
These snippets can be dropped into your dotfiles repository (e.g., ~/.config/fish/config.fish, ~/.config/ghostty/config, ~/.config/nvim/init.lua, etc.) or symlinked using GNU stow and stored in Github which I highly recommend.
fish configuration — ~/.config/fish/config.fish
Full file is provided below in section “Complete config.fish”.
It includes:
- oh-my-posh prompt init
- fzf keybindings
- zoxide integration
- aliases for eza, bat, lazygit, yazi
- environment improvements
- Neovim defaults
Ghostty Config — ~/Library/Application Support/com.mitchellh.ghostty/config
Example:
font-family = "JetBrainsMono Nerd Font"
font-size = 13.0
theme = "TokyoNight"
cursor-style = "block"
background-opacity = 0.92
keybind = ["ctrl+shift+t=new_tab", "ctrl+shift+w=close_tab"]
Ghostty reloads configs automatically.
Yazi Config — ~/.config/yazi/yazi.toml
[preview]
wrap = true
tab_size = 2
max_size = 5_000_000
[manager]
show_hidden = true
bat Config — ~/.config/bat/config
--theme="TwoDark"
--style="numbers,changes,header"
eza aliases — placed in fish config or ~/.config/fish/conf.d/eza.fish
alias ls="eza --icons"
alias ll="eza -l --git --icons"
alias la="eza -la --git --icons"
alias lt="eza --tree --icons --git"
lazygit Config — ~/Library/Application Support/lazygit/config.yml
git:
paging:
colorArg: always
pager: delta --dark --paging=never
(Requires brew install git-delta)
Zoxide + FZF directory jumper — optional helper script
~/.config/fish/functions/cd.fish:
function cd
if test (count $argv) -eq 0
z
else
z $argv
end
end
This makes cd behave like z.
11. Complete config.fish — Ready to Use
Below is a fully structured, clean, and portable config.fish tailored around your stack.
You can copy/paste it as-is.
~/.config/fish/config.fish
# -----------------------------------------------------------
# Fish Shell Configuration — The Ultimate Dev Shell
# macOS + Ghostty + LazyVim + yazi + lazygit
# -----------------------------------------------------------
# ----- PATH Setup -----------------------------------------------------------
set -Ux PATH /opt/homebrew/bin $PATH
set -Ux PATH ~/.local/bin $PATH
# ----- Oh My Posh Prompt ----------------------------------------------------
if type -q oh-my-posh
oh-my-posh init fish --config ~/.poshthemes/jandedobbeleer.omp.json | source
end
# ----- Zoxide (smarter cd) --------------------------------------------------
if type -q zoxide
zoxide init fish | source
end
# ----- FZF Integration ------------------------------------------------------
if type -q fzf
# History search: CTRL+R
bind \cr '__fzf_history'
end
# FZF Defaults (ripgrep + bat)
set -Ux FZF_DEFAULT_COMMAND "rg --files --hidden --follow --glob '!.git/*'"
set -Ux FZF_CTRL_T_COMMAND $FZF_DEFAULT_COMMAND
set -Ux FZF_DEFAULT_OPTS "--height=80% --layout=reverse --border"
set -Ux FZF_PREVIEW_COMMAND "bat --color=always --style=numbers --line-range=:200 {}"
# ----- eza aliases (modern ls) ---------------------------------------------
if type -q eza
alias ls="eza --icons"
alias ll="eza -l --git --icons"
alias la="eza -la --git --icons"
alias lt="eza --tree --icons --git"
end
# ----- bat alias (modern cat) ----------------------------------------------
if type -q bat
alias cat="bat"
end
# ----- lazygit alias --------------------------------------------------------
if type -q lazygit
alias lg="lazygit"
end
# ----- yazi alias -----------------------------------------------------------
if type -q yazi
alias yy="yazi"
end
# ----- Neovim as default editor --------------------------------------------
set -Ux EDITOR nvim
set -Ux VISUAL nvim
alias vi="nvim"
alias vim="nvim"
# ----- macOS Specifics ------------------------------------------------------
# Fix Homebrew issues with fish
fish_add_path /opt/homebrew/bin
fish_add_path /opt/homebrew/sbin
# Enable colored man pages (via bat)
if type -q bat
set -gx MANPAGER "sh -c 'col -bx | bat -l man -p'"
end
# ----- Git quality-of-life --------------------------------------------------
set -gx GIT_EDITOR nvim
# ----- Helpful functions ----------------------------------------------------
function mkcd
mkdir -p $argv[1]
cd $argv[1]
end
function fzf-open
set file (fzf --preview "bat --style=numbers --color=always {}")
if test -n "$file"
nvim "$file"
end
end
# -----------------------------------------------------------
# End of config
# -----------------------------------------------------------
12. Final Thoughts
Building a highly productive terminal environment isn’t about adding random tools—it’s about making your CLI feel natural, fluid, and joyful to use. With this setup on macOS using Ghostty, you get a modern, unified experience that dramatically improves navigation, coding, file exploration, Git workflows, and shell interaction.
This is the kind of terminal setup that grows with you over time and becomes an essential part of your developer workflow.