Speeding Up Oh My Zsh Startup with Lazy Plugin Loading
Learn how to speed up Oh My Zsh startup by lazily loading plugins with the built‑in `omz lazy load` helper, including a step‑by‑step example and trade‑offs.
07 Jun 2026, 08:09 UTC

Problem: Slow shell startup when many Oh My Zsh plugins are enabled
When you enable a dozen or more plugins in Oh My Zsh, each plugin’s init script is sourced synchronously during shell initialization. This can add noticeable latency, especially in environments where shells are started frequently, such as CI containers, terminal tabs, or remote SSH sessions.
Thesis: Using the built‑in lazy‑load helper (`omz lazy load`) defers plugin sourcing until the first command from that plugin is run, cutting startup time while keeping full functionality.
How Oh My Zsh loads plugins by default
Oh My Zsh reads the `plugins` array in `~/.zshrc`. For each entry it sources the corresponding file from `$ZSH/plugins//.plugin.zsh` or `$ZSH/custom/plugins//.plugin.zsh`. All sourcing happens before the first prompt appears, so any side‑effects (PATH changes, option tweaks, completions) are applied immediately.
Lazy‑load mechanism introduced in OMZ v0.13.0
The framework ships a helper function `omz lazy` that wraps the `zsh-defer` pattern. Calling `omz lazy load ` tells Oh My Zsh to create a stub function for each command provided by the plugin. When the stub is invoked, it sources the real plugin file and then re‑executes the original command.
This approach works best for plugins that expose a clear set of commands (e.g., `git`, `docker`, `kubectl`) and do not rely on immediate state changes at load time.
Worked example: deferring the git plugin
- Verify you are running a recent enough version:
omz version # should print v0.13.0 or higher
- Edit `~/.zshrc`. Keep the usual `source $ZSH/oh-my-zsh.sh` line, then add the lazy‑load line after it:
# Standard Oh My Zsh initialization
source $ZSH/oh-my-zsh.sh
# Defer the git plugin until a git command is used
omz lazy load git
- Open a new terminal (or run `exec zsh` to replace the current shell) and measure startup:
time zsh -i -c exit
Record the output; then repeat the measurement after commenting out the `omz lazy load git` line to compare.
- Confirm the plugin still works:
git status # should trigger lazy load and show the repository status
If you add a temporary `echo "git plugin loaded"` at the top of `$ZSH/plugins/git/git.plugin.zsh`, you will see that message only on the first git invocation, not on shell start.
Trade‑off and limitations
- First use of a lazily loaded plugin incurs a small delay while the plugin file is sourced.
- Plugins that modify shell state at load time (e.g., change `$PATH`, set options, define global aliases) may behave incorrectly if deferred, because those changes happen later than expected.
- Not all third‑party plugins are compatible with the lazy‑load helper; you must test each one after enabling lazy loading.
- The helper relies on the plugin exposing distinct command names; plugins that only provide functions or completions without a top‑level command may not benefit.
Practical way to check the result
- Compare startup times with `time zsh -i -c exit` before and after adding the lazy‑load line.
- After the shell is ready, run a command from the lazily loaded plugin and verify it executes without error.
- Optionally add a debug echo to the plugin’s init script to confirm it runs only on first use.
Actionable closing
If you notice your terminal taking a second or more to appear, start by listing the plugins in your `~/.zshrc`. Pick one that provides a clear command (git, docker, npm, etc.) and replace its entry in the `plugins` array with an `omz lazy load` line placed after `source $ZSH/oh-my-zsh.sh`. Measure the startup impact, test the plugin’s core command, and repeat for other plugins as needed. This simple change can shave hundreds of milliseconds off each shell launch while preserving the full feature set you rely on.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.