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:
- Plugins
- Compinit
- Nvm
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!