Zsh startup is slow because it’s synchronously loading and executing a whole lot of code, and you’re probably not aware of how much.

Let’s see what’s happening.

% zsh -xv
# (lots of output as zsh loads, then your prompt appears)

This command, zsh -xv, is your primary tool. It traces every single line of Zshscript that gets executed during startup, showing you what’s being run and what the values are. You’ll see it printing filenames and commands. The parts that take the longest are the ones you want to focus on.

The most common culprit is an overzealous plugin manager or a plugin that does too much work at startup.

Common Causes and Fixes

  1. Plugin Manager Loading: Frameworks like Oh My Zsh, Prezto, or Antigen can themselves add overhead. Oh My Zsh, in particular, has a default theme and several bundled plugins that are loaded by default.

    • Diagnosis: Look for source commands pointing to your plugin manager’s initialization files (e.g., oh-my-zsh.sh, prezto/init.zsh). The zsh -xv output will show how long these take to execute.
    • Fix: If you’re using Oh My Zsh, edit ~/.zshrc and comment out unnecessary plugins in the plugins=(...) array. For example, if you only need git and zsh-autosuggestions, change it to plugins=(git zsh-autosuggestions). This reduces the number of files sourced and the amount of code executed.
    • Why it works: Fewer plugins mean fewer source commands and less code to parse and run during the critical startup phase.
  2. Heavyweight Plugins: Some plugins, even if individually small, perform expensive operations like scanning directories, making network requests, or running complex shell commands on every startup.

    • Diagnosis: In the zsh -xv output, identify source commands or eval calls for specific plugins that are followed by a long pause before the next line appears. Look for plugins that might be doing file globbing, directory traversal, or external command execution.
    • Fix: Disable the problematic plugin. If it’s from Oh My Zsh, remove it from the plugins=(...) list. If it’s a standalone plugin, comment out its source line in your ~/.zshrc. For example, a plugin that tries to find all Git repositories in your home directory on every startup can be very slow.
    • Why it works: Removing the plugin entirely eliminates the slow operation from the startup sequence.
  3. Conditional Loading Issues: Plugins or custom code that rely on checking conditions (e.g., "am I in a Git repo?") can be slow if the condition check itself is inefficient.

    • Diagnosis: Again, zsh -xv is key. Look for if statements or [[ ... ]] checks that take a long time to evaluate. Sometimes, a plugin might be repeatedly checking the same condition in a loop.
    • Fix: Optimize the condition check. For example, instead of if [[ -d .git ]], you might use a more direct check or ensure the plugin caches the result if possible. If it’s your own code, profile the specific command within the if statement.
    • Why it works: A faster condition check means the conditional code block is entered or skipped more quickly.
  4. Autocompletion Loading: Zsh’s powerful autocompletion system, especially when augmented by plugins like zsh-completions or those that generate completions dynamically, can add significant startup time.

    • Diagnosis: Look for lines related to compinit or compdef in your zsh -xv output. If you see many compdef calls or compinit takes a long time, this is a suspect.
    • Fix: Ensure compinit is called only once, usually near the top of your ~/.zshrc. If you’re using many completion definitions, consider consolidating them or using a tool that pre-compiles completions. For example, rm -f ~/.zcompdump* followed by a fresh zsh session can sometimes help if the cache is corrupted, but the slowness is usually due to what is being completed, not the cache itself.
    • Why it works: Efficiently loading and initializing the completion system reduces the parsing and setup time.
  5. Prompt Theme Complexity: Fancy Zsh themes often involve running commands (like git status) to display information in the prompt. If the theme loads these commands synchronously during startup, it can slow things down.

    • Diagnosis: Observe the zsh -xv output for commands like git status, hg status, or other external command calls that happen before your prompt appears.
    • Fix: Switch to a simpler, faster theme, or modify your current theme to defer expensive operations. Many themes allow you to disable certain prompt elements. For instance, if your theme shows Git branch and status, you might disable the status part.
    • Why it works: Reducing the number of external commands executed to render the prompt directly speeds up initialization.
  6. Antigen/Zgen/etc. Initialization Overhead: If you’re using a plugin manager that itself has a complex initialization process or loads many things lazily, that lazy loading might still be happening on startup.

    • Diagnosis: Use zsh -xv to see the initialization sequence of your specific plugin manager. Look for patterns where the manager sources many files or runs many commands.
    • Fix: Consult your plugin manager’s documentation for performance tips. Some managers allow you to pre-compile or "bundle" plugins, reducing the number of individual source calls. For Antigen, ensuring you’re using antigen bundle and not antigen theme for everything can help, and checking its init.zsh for unnecessary logic.
    • Why it works: Bundling or pre-compiling reduces the dynamic loading overhead by consolidating plugin code into fewer files.

After fixing these, you might find your Zsh starts much faster, but then you’ll likely hit issues with dynamic completion loading if you’ve disabled too much.

Want structured learning?

Take the full Zsh course →