A shell that opens instantly is the result of knowing where your startup time goes.
Autoloading keeps .zshrc small. Put each function in its own file named after it, in a directory on fpath, and declare it with autoload -Uz name. The file holds only the function body. Nothing is read until the first call. -U disables alias expansion while loading (so your aliases cannot break it) and -z selects zsh-style loading. Most of zsh's bundled features (compinit, vcs_info, zmv) are autoloaded functions.
typeset -U path keeps the path array, which is tied to PATH, free of duplicates; edit path=(dir $path) like any array. The same works for fpath.
To find slow startup, put zmodload zsh/zprof at the very top of .zshrc and zprof at the bottom; it prints which functions took the most time. time zsh -i -c exit measures the total. Usual suspects:
compinitchecking and rebuilding the dump every time: callcompinit -Cwhen the dump is recent,- version-manager init scripts (nvm, pyenv, conda): lazy-load them with a stub function that replaces itself on first use,
- frameworks loading many plugins, and commands like
brew --prefixrun on each start.
zcompile compiles scripts and function directories into .zwc wordcode files that load faster; zsh uses them automatically when they are newer than the source.
Example
# ~/.zshrc, first line:
zmodload zsh/zprof # start profiling
typeset -U path fpath # no duplicate entries
path=(~/.local/bin $path) # tied to $PATH
fpath=(~/.zsh/functions $fpath)
autoload -Uz mkcd # body lives in ~/.zsh/functions/mkcd:
# mkdir -p -- "$1" && cd -- "$1"
nvm() { unfunction nvm; source ~/.nvm/nvm.sh; nvm "$@"; } # lazy-load
autoload -Uz compinit
setopt EXTENDED_GLOB
if [[ -n ~/.zcompdump(#qN.mh+24) ]]; then
compinit # dump older than 24 h: full check
else
compinit -C # recent dump: skip the check
fi
zcompile ~/.zshrc # writes ~/.zshrc.zwc
# last line:
zprof | head -n 15 # functions sorted by time spentRemember
- autoload -Uz name loads ~/fpath/name on first call
- zmodload zsh/zprof + zprof finds slow startup code
- Lazy-load heavy tools and use compinit -C with a fresh dump
Watch out for
- Running
eval "$(slow-tool init)"for several tools on every startup instead of lazy-loading.