A friend recently watched me jump between projects - and asked, "Wait, how did you do that so fast?".
That moment made me realize just how much of my workflow is powered by my customized .zshrc (and Alfred 🎩, but that's a topic for another article).
Below, you'll find an overview of tools, plugins, and custom scripts I use to make my development workflow more efficient.
Whether you're setting up your terminal for the first time or an experienced developer looking for inspiration, this guide has something for you.
⚡️ Best of all: each section is modular and easy to follow - jump in wherever you're curious and skip what you don't need.
🧭 Note: This guide is written for macOS and other Unix-like environments. Some parts may not work as-is on Windows without WSL or similar tools.
📚 Table of Contents
- 🔧 What is .zshrc and Why Do We Need It?
- ⚙️ Terminal Framework: Oh My Zsh
- 🎨 Theme: Powerlevel10k
- 🔌 Plugins
- ⚡️ Aliases
- 💻 Custom Scripts
- 📝 Final Notes
🔧 What is .zshrc and Why Do We Need It?
zsh
is short for Z Shell: a powerful, highly customizable Unix shell that helps you interact with your operating system.
The .zshrc
file is your main zsh
configuration file. It runs every time you start a new terminal session.
It defines the environment, sets up shortcuts, loads plugins, and controls how your terminal behaves.
A well-configured .zshrc
makes your terminal more powerful and easier to use, but most importantly - more fun!
So without further ado - let's dive in 💪🏼.
⚙️ Terminal Framework: Oh My Zsh
I use Oh My Zsh to manage my Zsh configuration. It makes Zsh far more powerful and customizable than the default setup, thanks to its plugin system and theming capabilities.
Installation
Just run this command in your terminal:
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
This will download and install Oh My Zsh in your home directory (~
).
It will also create a new .zshrc
file under ~/.zshrc
, backing up any old .zshrc
you might have had into a file called .zshrc.pre-oh-my-zsh
.
💾 Backup Your .zshrc Before You Start
Before making any changes to your .zshrc, it's a good idea to create a backup. That way, if anything goes wrong or you just want to roll back to your original configuration, you can easily restore it.
You can run this command to create a backup:
cp ~/.zshrc ~/.zshrc.backup.$(date +%Y%m%d%H%M%S)
This will create a timestamped backup file, like ~/.zshrc.backup.20250604123045
, so you can always go back to a specific version.
How to Edit .zshrc
💡 Important Note: Throughout this guide we will need to edit our
.zshrc file
. We can open it in any editor we like (for example - VS Code, Cursor, Sublime Text, etc.).
To open it in VS Code, run:
code ~/.zshrc
No VS Code? You can use the default macOS editor:
open ~/.zshrc
After saving changes, apply them with:
source ~/.zshrc
Alternatively, close and reopen your terminal to reload the config.
Now we're ready to start with the customizations 😎🛠️.
🎨 Theme: Powerlevel10k
The default Oh My Zsh theme is robbyrussell
, which is decent.
But I really like Powerlevel10k, as it offers much more customization.
Installation
First - clone the Powerlevel10k repository by running this command:
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git "${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k"
Now open ~/.zshrc
, find the line that sets ZSH_THEME
, and change its value to "powerlevel10k/powerlevel10k"
.
The configuration wizard should start immediately, but if not - you can run this command to manually trigger it:
p10k configure
You can now follow the wizard in order to customize the theme to your preferences.
You can go wild here, as you can always run p10k configure
again and select different options.
The wizard is pretty straightforward, but let me know if you'd like to see an in-depth tutorial on it.
🔌 Plugins
Plugins are small add-ons that extend Zsh's functionality - they can
add helpful aliases, improve autocomplete, enhance Git integration,
and more.
In order to install plugins we usually need to do 2 things:
- Clone the plugin repository.
- Add the plugin to the
plugins
line in our.zshrc
file.
You can view a huge list of Oh My Zsh plugins in their docs.
Let's go over some of my favorite plugins that I use every day.
Git
The git plugin provides many useful aliases and functions.
Some aliases I use are:
-
gl
=git pull
-
ga
=git add
-
gcm
=git checkout $(git_main_branch)
(which is likegit checkout master
orgit checkout main
, depending on your repo's settings) -
gc
=git commit --verbose
-
gp
=git push
You can view the entire list of aliases and functions here.
In order for it to work - find the plugins
line in your .zshrc
file and add git to it (if it weren't already there).
Your plugins line should now look like this:
plugins=(git)
zsh-autosuggestions
Always dreamt of auto-complete in your terminal? Well, now it's not a dream anymore.
As you type commands in your terminal - zsh-autosuggestions will suggest completions based on your usage history, and can also be customized to suggest using a completion engine.
When pressing the →
(right arrow) key - the suggestion will be accepted, replacing the contents of the command line buffer with the suggestion.
You can view the suggestion strategy (and other customization options) in their docs.
Installation
-
Clone this repository into
$ZSH_CUSTOM/plugins
(by default~/.oh-my-zsh/custom/plugins
):
git clone [https://github.com/zsh-users/zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
-
Add the plugin to the list of plugins for Oh My Zsh to load (inside
~/.zshrc
):
plugins=( # other plugins... zsh-autosuggestions )
-
(Optional) In order to customize
zsh-autosuggestions
to auto complete based on a completion engine if it didn't find a match in your history - add this line above the plugins line:
ZSH_AUTOSUGGEST_STRATEGY=(history completion)
-
Don't forget to source your
.zshrc
file:
source ~/.zshrc
zsh-syntax-highlighting
zsh-syntax-highlighting provides, well, syntax highlighting in your terminal.
Installation
-
As usual - clone this repository into
$ZSH_CUSTOM/plugins
(by default~/.oh-my-zsh/custom/plugins
):
git clone [https://github.com/zsh-users/zsh-syntax-highlighting.git](https://github.com/zsh-users/zsh-syntax-highlighting.git) ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
-
Add the plugin to the list of plugins for Oh My Zsh to load (inside
~/.zshrc
):
plugins=( # other plugins... zsh-syntax-highlighting )
-
(Optional) We can add more highlighters (and even implement our own). The default highlighter is
main
. I also addedbrackets
to highlight brackets. You can see the available highlighters in the docs. To add highlighters - add this line above the plugins line:
ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets)
-
Don't forget to source your
.zshrc
file:
source ~/.zshrc
fzf and fzf-tab
fzf is an interactive filter program that implements a "fuzzy" matching algorithm. This means you can quickly type in patterns with omitted characters and still get the results you want.
We need to install it in order to use fzf-tab
.
fzf-tab is replacing zsh's default completion selection menu (that shows up when pressing tab
) with fzf
!
This is what it looks like before using fzf-tab
:
And this is how it looks after using fzf-tab
:
We can even set it to have directory previews, as shown above.
Installation
-
Install
fzf
by running this command:
brew install fzf
-
Now install
fzf-tab
by cloning the repo like we did before:
git clone [https://github.com/Aloxaf/fzf-tab](https://github.com/Aloxaf/fzf-tab) ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/fzf-tab
-
Add the plugin to the list of plugins for Oh My Zsh to load (inside
~/.zshrc
):
plugins=( # other plugins... fzf-tab )
-
(Optional) We can config
fzf-tab
for some added functionality. I added case-insensitivity, tolerance to separators and directory previews. In order to add these configurations - add these lines above yourplugins
line:
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}' 'r:|[._-]=** r:|=**' zstyle ':fzf-tab:complete:cd:*' fzf-preview 'ls --color $realpath'
You can view other configuration options in
fzf-tab
docs. -
As usual - don't forget to source your
.zshrc
:
source ~/.zshrc
⚡️ Aliases
We can also add custom aliases for commands we find ourselves typing regularly.
To add an alias just add an alias
command to your .zshrc
file.
An alias
command looks like this:
alias ${your_alias}="${some_command}"
For example, these are my aliases:
alias yb="yarn build"
alias yba="yarn build:app"
alias ys="yarn start"
alias yt="yarn test"
alias ytw="yarn test:watch"
alias gc-="git checkout -"
alias ..="cd .."
alias ...="cd ../.."
So when I type yb
into the console, it will actually run yarn build
, which I do dozens of times daily.
These are just things I find myself use over and over, so I decided to make an alias for them. You can go wild here!
💻 Custom Scripts
The last section of this guide will be dedicated to some custom scripts I wrote (using my best friend in the entire world - ChatGPT).
I did it because I was missing some functionality, but mostly because I wanted to experiment with bash scripting.
I'm sure that these could be improved, so feel free to comment if you have any suggestions 😬.
grepo - Go to Repo
A simple script used to quickly navigate to a repository. Requires fzf
(see above).
Installation
- Copy the script into your
.zshrc
file. - Change the
repo_dir
variable to the directory in which you keep all your repositories. -
source
your .zshrc file. - Profit!
function grepo() {
local repo_dir=~/{YOUR_REPO_DIR_HERE}
local open_in_editor=false
local pull_latest=false
# Parse flags
while [[ $# -gt 0 ]]; do
case $1 in
-o|--open)
open_in_editor=true
shift
;;
-p|--pull)
pull_latest=true
shift
;;
*)
echo "Unknown option: $1"
return 1
;;
esac
done
# Select repository
local selected_repo=$(find "$repo_dir" -maxdepth 1 -type d | fzf --height=20% --reverse --border --prompt="Select a repo: ")
if [[ -n $selected_repo ]]; then
cd "$selected_repo" || {
echo "❌ Failed to navigate to $selected_repo"
return 1
}
if $pull_latest; then
echo "🔄 Pulling latest changes..."
git pull --ff-only
fi
if $open_in_editor; then
code .
fi
else
echo "⚠️ No valid repository selected"
fi
}
Usage
- Type
grepo
in your terminal. - An interactive
fzf
search box will open. - Search for your repository and click
↵
(enter
) to select it andcd
to it. - (Optional) - you can add the
-p
(or--pull
) and-o
(or--open
) flags to also pull and open the directory in VS Code / Cursor.
Feel free to edit this script, add flags, validations and other functionalities you see fit. Let me know if you add anything cool 😎.
Git Garbage Collection (ggc)
Another simple script used to clean up stale branches after I merge them. It uses git prune
.
Installation is similar to grepo
, just copy the script and paste it in your .zshrc
:
function git_garbage_collection() {
# Check if the current directory is a Git repository
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "Error: This is not a Git repository. Exiting."
return 1
fi
# Fetch updates from the remote and prune stale references
echo "Fetching and pruning stale remote references..."
git fetch --prune > /dev/null 2>&1
# Prune stale remote-tracking branches for the 'origin' remote
echo "Pruning stale remote-tracking branches for 'origin'..."
git remote prune origin > /dev/null 2>&1
echo "Remote pruning complete."
# Find stale local branches, excluding the current branch, and store them in an array
local stale_branches=($(git branch -vv | grep ': gone' | awk '{print $1}' | sed 's/^\* //'))
if [[ ${#stale_branches[@]} -gt 0 ]]; then
echo "The following local branches are no longer tracking a remote:"
for branch in "${stale_branches[@]}"; do
echo "$branch"
done
echo
# Confirm deletion for each branch using a for loop
for branch in "${stale_branches[@]}"; do
echo -n "Force delete '$branch'? [y/N]: "
read -r confirmation
if [[ $confirmation =~ ^[Yy]$ ]]; then
git branch -D "$branch"
else
echo "Skipped '$branch'."
fi
done
else
echo "No stale local branches found."
fi
}
alias ggc="git_garbage_collection"
Usage
- While in some repository - type
ggc
in your terminal. - All of the stale (local and remote) branches will be fetched.
- The script will verify before deleting each of the branches.
Feel free to add a flag to delete all of the branches without needing to confirm each.
Git Branch Switch (gbs)
Another simple script to list all local and remote branches using fzf
.
As before - just copy and paste to your .zshrc
.
function git_branch_switch() {
# Check if the current directory is a Git repository
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "Error: This is not a Git repository. Exiting."
return 1
fi
# Fetch all branches from the remote to ensure up-to-date references
git fetch --all > /dev/null 2>&1
# Combine local branches and valid remote branches
local branch
branch=$(
{
# List local branches
git branch --format="%(refname:short)"
# List remote branches, excluding symbolic refs like "origin/HEAD"
git branch -r --format="%(refname:short)" | grep -v "origin/HEAD"
} | fzf --height=20% --reverse --prompt="Select a branch: "
)
if [[ -n $branch ]]; then
# Strip "remotes/origin/" if a remote branch is selected
git checkout "${branch#remotes/origin/}"
else
echo "No branch selected"
fi
}
# Create a convenient alias
alias gbs="git_branch_switch"
📝 Final Notes
Customizing your .zshrc
can feel intimidating at first, but even small changes can make a big impact on your workflow. Start with what feels useful, and build from there.
Don't worry about making it perfect, just make it yours.
I hope you found this guide helpful 🙏🏼.
Let me know if you have any comments or questions! ✌🏼
Top comments (0)