Skip to content
Go back

Improving Zsh Startup Time

I use the same dot files configuration for my zsh setup on my personal and work MacBook. In enterprise environment everything is scanned so it did not surprise me that it takes longer than on my personal laptop. But sometimes taking more than 5 seconds to load a zsh shell instance is crazy. I did some profiling and was managed to reduce the startup time significantly.

Profiling

The first step is to figure out why startup is taking so much time. Zsh has a built in profiler that will show you a table overview of everything that is running during the startup, and how much time it took. Add zmodload zsh/zprof at the top of your .zshrc file and zprof at the bottom:

zmodload zsh/zprof

# ... your zsh config

zprof

Now reload your zsh config, I created an alias for this:

echo "Reloading zsh config..." && exec zsh

You will now see a table output with what is being executed and how much time it took from the total startup time.

Compinit

If you didn’t do the profiling part and searched the internet for tips to improve zsh startup time you will usually find the following recommendations or causes impacting zsh startup time:

In my case the profiler showed that compinit caused for the most delay followed by the plugins and some custom scripts that I load. compinit initializes zsh’s completion system, turning tab into an intelligent assistant that knows how to complete commands, flags, file paths, and arguments. For zsh plugins management I am using zinit which can cache and lazy load plugins and scripts.

I added the following to my .zshrc to precompile and cache compinit:

# Precompile completions and store the result in $ZDOTDIR/.zcompdump
autoload -Uz compinit
if [[ ! -f ${ZDOTDIR:-$HOME}/.zcompdump || ! -s ${ZDOTDIR:-$HOME}/.zcompdump ]]; then
  compinit
else
  compinit -C
fi

There are also solutions that will check the timestamp of .zcompdump and re-compile it automatically but I am fine on doing this manually when I need it. This way I am sure that compinit is never re-compiled unnecessary.

Plugins and scripts caching

I also asked AI to go through my .zshrc and give some recommendations on improving plugins and script loading. It mentioned some adjustments in zinit plugins and snippets that I applied:

# Lazy load plugins using zinit
zinit wait lucid for \
    urbainvaes/fzf-marks \
    Aloxaf/fzf-tab \
    zsh-users/zsh-completions \
    zsh-users/zsh-autosuggestions \
    zsh-users/zsh-history-substring-search \
    zsh-users/zsh-syntax-highlighting

# Load and cache local personal scripts
for file in ~/.zsh/_*.sh; do
    zinit snippet "$file"
done

zinit snippet ~/.fzf.zsh

# Lazy load plugins
zinit wait'0a' lucid atload'eval "$(zoxide init zsh --cmd d)"' for zdharma-continuum/null
zinit wait'0b' lucid atload'eval "$(fnm env --use-on-cd --shell zsh)"' for zdharma-continuum/null

# NOTE: you can update plugins and snippet (caches) using the `zinit update` command

The above changes for compinit, plugins and scripts reduced the (cold) startup time on my work MacBook from 5 seconds to 1 to 2 seconds. It’s still not even close to my personal MacBook at home where the startup time is in milliseconds. But I guess it’s good enough!


 

Next Post
CSS Grid Basics