Table of Contents
- Table of Contents
- Introduction
- Installing Zsh and Oh My Zsh
- Theme: Powerlevel10k
- Plugins
- Shell Settings
- Aliases
- Key Bindings
- The Full Config
- Wrapping Up
Introduction
I spend most of my day in the terminal. Over time I’ve put together a Zsh setup that I’m pretty happy with - it’s fast, gives me the info I need at a glance, and has a few plugins that I genuinely miss when I’m on a machine that doesn’t have them.
This article goes through the whole thing from scratch. If you want to copy it exactly, you can grab the config files at the bottom. Or just cherry-pick the parts you like.
Installing Zsh and Oh My Zsh
Most Linux distros come with Bash. Zsh is basically a superset of it - better tab completion, better globbing, and a massive plugin ecosystem.
Install it:
sudo apt install zsh
Set it as your default shell and log out and back in:
chsh -s $(which zsh)
Next, install Oh My Zsh. It’s a framework that manages your Zsh config, themes, and plugins:
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
This drops a ~/.oh-my-zsh directory with themes and plugins, and generates a starter ~/.zshrc that we’ll be replacing throughout this guide.
Note:On macOS, Zsh is already the default shell - skip
chshand go straight to Oh My Zsh.
Theme: Powerlevel10k
Powerlevel10k is the prompt theme I use. It’s fast, shows the current directory, git branch, last command’s exit code, execution time - all the stuff you’d want to see at a glance.
Clone it into Oh My Zsh’s custom themes directory:
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git \
${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
Set the theme in ~/.zshrc:
ZSH_THEME="powerlevel10k/powerlevel10k"
After restarting your terminal, the p10k configuration wizard launches automatically and walks you through the style options. You can always re-run it with:
p10k configure
The wizard writes everything to ~/.p10k.zsh. My config uses lean style, two lines, disconnected segments, transient prompt (old commands collapse to just ❯), and 24-hour time. I’ve included my .p10k.zsh for download, but honestly - just run the wizard. It’s more fun to pick your own.
Fonts:You’ll want a Nerd Font for the icons in the prompt. MesloLGS NF is the go-to -
p10k configurewill offer to install it for you.
Plugins
Adding plugins in Oh My Zsh means cloning a repo into the custom plugins directory and adding the name to the plugins array. Here are the five I use.
git
Built into Oh My Zsh, no clone needed. Gives you a bunch of aliases (gst for git status, gco for git checkout, etc.) and better git completions. I mostly use it for the completions.
zsh-autosuggestions
This is the one I miss the most on other machines. It shows ghost-text suggestions as you type, pulled from your history. Right arrow to accept, or just keep typing to ignore it.
git clone https://github.com/zsh-users/zsh-autosuggestions \
${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
zsh-history-substring-search
Type part of a command, press up arrow, and it cycles through history entries that contain what you typed. Way better than the default behavior which only matches from the start of the line.
git clone https://github.com/zsh-users/zsh-history-substring-search \
${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-history-substring-search
zsh-autopair
Auto-closes brackets, quotes, and other paired characters. Type ( and you get () with the cursor in between. Small thing, but you notice when it’s gone.
git clone https://github.com/hlissner/zsh-autopair \
${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autopair
zsh-syntax-highlighting
Colors commands as you type - valid commands in green, errors in red, quoted strings highlighted. You catch typos before you hit enter.
git clone https://github.com/zsh-users/zsh-syntax-highlighting \
${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
Important:
zsh-syntax-highlightingmust be last in thepluginsarray. It needs to load after everything else to highlight correctly.
Once all plugins are cloned, add them to the plugins array in ~/.zshrc:
plugins=(
git
zsh-autosuggestions
zsh-history-substring-search
zsh-autopair
zsh-syntax-highlighting # must be last
)
Then source Oh My Zsh to load everything:
source "$ZSH/oh-my-zsh.sh"
Shell Settings
A few shell-level settings that I’ve found worth having.
Editor
I use Neovim, but not every machine has it, so this falls back to Vim:
if command -v nvim >/dev/null 2>&1; then
export EDITOR="nvim"
else
export EDITOR="vim"
fi
export VISUAL="$EDITOR"
History
A generous history with deduplication and cross-session sharing:
HISTFILE="$HOME/.zsh_history"
HISTSIZE=200000
SAVEHIST=200000
setopt HIST_IGNORE_ALL_DUPS HIST_REDUCE_BLANKS INC_APPEND_HISTORY SHARE_HISTORY EXTENDED_GLOB
What the setopt flags do:
HIST_IGNORE_ALL_DUPS- If a command already exists in history, the old entry is removed. Keeps things clean.HIST_REDUCE_BLANKS- Strips extra whitespace before saving.INC_APPEND_HISTORY- Writes each command to the history file immediately instead of waiting for the shell to exit. No more losing history when a terminal crashes.SHARE_HISTORY- All terminal sessions share the same history. Run something in one tab, press up in another.EXTENDED_GLOB- Enables advanced globbing with^,~, and#.
Safety
Two settings that have saved me from myself more than once:
set -o noclobber
set -o pipefail
noclobber- Prevents>from overwriting existing files. Ifimportant.txtexists,echo "oops" > important.txtwill be refused. Use>|when you actually mean it.pipefail- Makes a pipeline fail if any command in it fails, not just the last one. Without this,bad-cmd | grep foosilently swallows the error frombad-cmd.
Aliases
Nothing groundbreaking here, just stuff I got tired of typing:
# Colorized output
alias ls='ls --color=auto'
alias grep='grep --color=auto'
# Quick clear
alias cls="clear"
# Nuclear Docker cleanup - removes all images, containers, and volumes
alias docker-purge="docker system prune -a --volumes -f"
# System update in one shot
alias update-all="sudo apt-get update -y && sudo apt-get upgrade -y && sudo apt-get autoremove -y"
cls is muscle memory from years of Windows. docker-purge is the “nuke everything and start fresh” button for when Docker has eaten half your disk. update-all is just the apt update + upgrade + autoremove dance in one command.
Key Bindings
The history-substring-search plugin doesn’t bind to the arrow keys on its own, so you need to wire it up:
bindkey '^[[A' history-substring-search-up
bindkey '^[[B' history-substring-search-down
^[[A and ^[[B are the escape sequences for up/down arrows. With this, you type docker, press up, and it cycles through only the history entries containing “docker” instead of your entire history.
The Full Config
Both config files are here if you want to grab them:
Back up what you have, drop these in, and source:
cp ~/.zshrc ~/.zshrc.bak
cp ~/.p10k.zsh ~/.p10k.zsh.bak
curl -o ~/.zshrc https://nubpaws.dev/articles/2026-03-13-my-zsh-setup/.zshrc
curl -o ~/.p10k.zsh https://nubpaws.dev/articles/2026-03-13-my-zsh-setup/.p10k.zsh
source ~/.zshrc
You’ll need Oh My Zsh, Powerlevel10k, and all the plugins installed first - the .zshrc references them and will complain if they’re missing.
Wrapping Up
That’s the whole thing. Zsh, Oh My Zsh, Powerlevel10k, and five plugins. Takes maybe ten minutes to set up from scratch on a new machine, and it’s been my go-to setup for a while now.
If you end up using any of this, I hope it serves you well. Happy hacking!