Speeding Up My ZSH Shell ⚡
Super quick one I want to document here! I got myself on a side quest, again! No biggie, my ZSH shell was taking ages to load. When I say ages, more like 5+ seconds every time I opened a new terminal, that sort of thing can add up. This is just something I’ve lived with over the years, nothing has prompted this other than me wondering why it’s slow, then searching for how to profile it.
How to profile your ZSH
So, what’s actually slowing things down? Zsh comes with this super
handy profiling tool called zprof. Here’s how to use it:
1# Add this to the TOP of your .zshrc
2zmodload zsh/zprof
3
4# Add this to the BOTTOM of your .zshrc
5zprofThis give a load of output, but it’s a good starting point.
I had no idea this existed so massive shout out to Jacek’s Blog for this tip!
Ok, so what was making my shell slow?
When I ran the profiler, here’s what I found:
11) _omz_source 55.73% # Oh-My-Zsh loading everything
22) compinit 30.76% # Completion system being slow
33) syntax-highlight 14.63% # Making things pretty, but slowSo, Oh-My-Zsh was taking up over half the startup time!
Oh-My-Zsh (55.73% → ~20%)
According to JonLuca’s research, this can cut the load time in half! The auto-updates are nice, but I’d rather do them manually when I want to.
1# Top of .zshrc
2DISABLE_AUTO_UPDATE="true"
3DISABLE_MAGIC_FUNCTIONS="true"
4DISABLE_COMPFIX="true"Fixing the completion system (30.76% → ~10%)
The completion system (compinit) is zsh’s built-in command
completion - it’s what shows possible completions when you hit tab.
This is a neat trick I found. Instead of rebuilding the completion
cache every time, we only do it once a day:
1# Smarter completion initialization
2autoload -Uz compinit
3if [ "$(date +'%j')" != "$(stat -f '%Sm' -t '%j' ~/.zcompdump 2>/dev/null)" ]; then
4 compinit
5else
6 compinit -C
7fiThis comes from a popular GitHub gist - cheers for sharing this one!
Making Spaceship Prompt Faster (22.47% → ~5%)
I love Spaceship prompt (been using it for years!), but it was being a bit of a resource hog. Here’s how to speed it up:
1SPACESHIP_PROMPT_ASYNC=true
2SPACESHIP_PROMPT_ADD_NEWLINE=true
3SPACESHIP_CHAR_SYMBOL="⚡"
4
5# Only load what you actually use
6SPACESHIP_PROMPT_ORDER=(
7 time
8 user
9 dir
10 git
11 line_sep
12 char
13)The Spaceship team actually recommended this approach - only load what you need!
Plugin management
I have very few plugins, here’s how I organize my plugins now:
1plugins=(
2 git
3 zsh-autosuggestions
4 zsh-syntax-highlighting # Always last!
5)The order is super important here! According to the zsh-syntax-highlighting docs, it needs to be last to work properly.
For autosuggestions, I added these performance tweaks:
1ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE="20"
2ZSH_AUTOSUGGEST_USE_ASYNC=1The results? FAST! ⚡
Check this out:
| Component | Before | After |
|---|---|---|
| Oh-My-Zsh | 55.73% | ~20% |
| Completions | 30.76% | ~10% |
| Syntax Highlight | 14.63% | ~8% |
| Total Time | ~5s | ~0.5s |
That’s like a 10x improvement! My terminal now opens in the blink of an eye!
Want to try this yourself?
Add the profiling code (I showed you earlier) to see what’s slow
Try the fixes one at a time - that way you know what’s actually helping
Keep what works for you - everyone’s setup is different!
For the full setup rather than individual fixes, see my updated Zsh configuration. It includes the plugin order and completion settings I ended up using.
Before and after
For comparison here’s a before and after configs:
1# Path to your Oh My Zsh installation.
2export ZSH="$HOME/.oh-my-zsh"
3
4# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
5ZSH_THEME="spaceship"
6
7# spaceship config
8SPACESHIP_PROMPT_ASYNC=false
9SPACESHIP_PROMPT_ADD_NEWLINE="true"
10SPACESHIP_CHAR_SYMBOL="⚡"
11
12# Which plugins would you like to load?
13# Standard plugins can be found in $ZSH/plugins/
14# Custom plugins may be added to $ZSH_CUSTOM/plugins/
15# Example format: plugins=(rails git textmate ruby lighthouse)
16# Add wisely, as too many plugins slow down shell startup.
17plugins=(
18 git
19 zsh-syntax-highlighting
20 zsh-autosuggestions
21)
22
23source $ZSH/oh-my-zsh.sh
24
25# User configuration
26
27# auto suggest
28ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#663399,standout"
29
30#-------- Global Alias {{{
31globalias() {
32 if [[ $LBUFFER =~ '[a-zA-Z0-9]+$' ]]; then
33 zle _expand_alias
34 zle expand-word
35 fi
36 zle self-insert
37}
38zle -N globalias
39bindkey " " globalias # space key to expand globalalias
40# bindkey "^ " magic-space # control-space to bypass completion
41bindkey "^[[Z" magic-space # shift-tab to bypass completion
42bindkey -M isearch " " magic-space # normal space during searches
43. ~/.zsh_aliases
44#}}}
45
46# Start SSH agent if not running
47if [ -z "$SSH_AUTH_SOCK" ]; then
48 eval "$(ssh-agent -s)" > /dev/null
49 ssh-add ~/.ssh/id_github_sign_and_auth 2>/dev/null
50fi
51
52# volta
53export VOLTA_HOME="$HOME/.volta"
54export PATH="$VOLTA_HOME/bin:$PATH"
55# volta end
56
57# bun completions
58#[ -s "/home/scott/.bun/_bun" ] && source "/home/scott/.bun/_bun"
59
60# Turso
61export PATH="$PATH:/home/scott/.turso"With all the optimisations in place, here’s the after config:
1# Performance optimizations
2DISABLE_AUTO_UPDATE="true"
3DISABLE_MAGIC_FUNCTIONS="true"
4DISABLE_COMPFIX="true"
5
6# Cache completions aggressively
7autoload -Uz compinit
8if [ "$(date +'%j')" != "$(stat -f '%Sm' -t '%j' ~/.zcompdump 2>/dev/null)" ]; then
9 compinit
10else
11 compinit -C
12fi
13
14# Oh My Zsh path
15export ZSH="$HOME/.oh-my-zsh"
16
17# Theme config - fixed syntax
18ZSH_THEME="spaceship"
19
20# Spaceship settings (fixed syntax)
21SPACESHIP_PROMPT_ASYNC=true
22SPACESHIP_PROMPT_ADD_NEWLINE=true
23SPACESHIP_CHAR_SYMBOL="⚡"
24
25# Minimal spaceship sections for performance
26SPACESHIP_PROMPT_ORDER=(
27 time
28 user
29 dir
30 git
31 line_sep
32 char
33)
34
35# Carefully ordered plugins (syntax highlighting must be last)
36plugins=(
37 git
38 zsh-autosuggestions
39 zsh-syntax-highlighting
40)
41
42# Source Oh My Zsh
43source $ZSH/oh-my-zsh.sh
44
45# Autosuggest settings
46ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#663399,standout"
47ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE="20"
48ZSH_AUTOSUGGEST_USE_ASYNC=1
49
50# Alias expansion function
51globalias() {
52 if [[ $LBUFFER =~ '[a-zA-Z0-9]+$' ]]; then
53 zle _expand_alias
54 zle expand-word
55 fi
56 zle self-insert
57}
58zle -N globalias
59bindkey " " globalias
60bindkey "^[[Z" magic-space
61bindkey -M isearch " " magic-space
62
63# Lazy load SSH agent
64function _load_ssh_agent() {
65 if [ -z "$SSH_AUTH_SOCK" ]; then
66 eval "$(ssh-agent -s)" > /dev/null
67 ssh-add ~/.ssh/id_github_sign_and_auth 2>/dev/null
68 fi
69}
70autoload -U add-zsh-hook
71add-zsh-hook precmd _load_ssh_agent
72
73# Path configurations
74export VOLTA_HOME="$HOME/.volta"
75PATH="$VOLTA_HOME/bin:$PATH:/home/scott/.turso"
76export PATH
77
78# Source aliases last
79[ -f ~/.zsh_aliases ] && source ~/.zsh_aliasesOther things
As per usual when I do this sort of thing I alway search around for
alternitives, I tried Starship and to be
honest, I’m pretty happy with zsh, what it was for me (when trying it)
is I don’t use cd I’m so used to just entering the directory name I
was pretty put off straight away. 😅
There were other things out there, like:
- Pure prompt (super fast alternative to Spaceship)
- fast-syntax-highlighting (potentially faster than regular syntax highlighting, though the default is pretty quick already!)
- Zinit (a faster alternative to Oh-My-Zsh if you want to try something different)
But, honestly? If you’re happy with your current setup (and I am) and it’s fast enough, stick with it! This was me going on a little side quest because I was curious. My curiosity was rewarded with a much faster shell!
That’s it! Hope this helps if you were having similar issues!
There's a reactions leaderboard you can check out too.
Sign up for the newsletter
Want to keep up to date with what I'm working on?
Join other developers and sign up for the newsletter.
I care about the protection of your data. Read the Privacy Policy for more info.