Decisions
ADR-002: Shell Performance Optimization Strategy
Status: Accepted Date: 2026-02-09 Authors: @sebastienrousseau
Context
Shell startup time directly impacts developer productivity. Every new terminal, tmux pane, or shell command execution incurs this cost. With rich shell configurations (completions, prompts, plugins), startup can easily exceed 1-2 seconds.
Goals:
- Target startup time: <500ms for interactive shells
- Maintain full functionality (completions, syntax highlighting, git info)
- Support both zsh and bash
- Work across macOS and Linux
Decision
Implement a multi-layer performance optimization strategy:
Layer 1: Compilation and Caching
# Compile zsh files to .zwc format
- Compile frequently-sourced files to bytecode
- Cache command output (brew shellenv, mise activate)
- Invalidate cache when source files change
Layer 2: Lazy Loading
Defer loading of heavy components until first use:
# Lazy load completions
- Completions loaded on first command use
- NVM/RVM loaded only when node/ruby commands invoked
- Heavy plugins deferred via zinit's
waitmodifier
Layer 3: Zinit Turbo Mode
- Plugins load asynchronously after prompt
- Critical plugins (syntax highlighting) load synchronously
- Most plugins have 0ms impact on startup
Layer 4: Conditional Loading
# Only load if command exists
&&
# Skip in non-interactive shells
&&
- Platform-specific code guarded by OS detection
- Heavy features opt-in via environment variables
- Non-interactive shells get minimal config
Monitoring
Benchmark script to track startup time:
CI enforces 500ms threshold with warnings.
Consequences
Positive
- Consistent <500ms startup across platforms
- Full functionality preserved
- Easy to add new tools without performance regression
- Clear patterns for contributors to follow
Negative
- First invocation of lazy-loaded commands is slower
- Cache invalidation bugs can cause stale behavior
- Complexity in understanding load order
Neutral
- Profiling required when adding new plugins
- Trade-off between convenience and performance explicit
Measurements
| Configuration | Startup Time |
|---|---|
| Vanilla zsh | ~50ms |
| With oh-my-zsh | ~800ms |
| This approach | ~200-400ms |