Sometimes I noticed a new shell's startup being really slow. This annoyed me from time to time, so today I decided to try some optimizations.
I measured my startup time in a rather crude way. I'm loading my zsh configuration files like in the following snippet:
I relied on subjective analysis and changed it to the following code:
What this does is print the path to the configuration file, load it and then wait for a return key press to load the next file.
With this, I could start a new shell and see which files are slow to load.
From the measurements I noticed that the slow files were those where I load some tools via homebrew. I load for example
hub that way. I used this approach for my
PATH as well with PHP and the Android SDK.
I then timed an execution of
brew --prefix hub and got the following result:
It takes around 0.15 seconds to load the path prefix for
hub! If you do that a couple of times in your zsh configuration, it sums up to a lot of time.
I then changed all the occurences to the absolute path, as it's mostly just
/usr/local/opt and the package name. It's not as flexible anymore, but that's a small price for a faster shell startup time.
The one other file that loaded slowly was my rbenv initialization. It calls the following snippet:
A bit of googling revealed the
--no-rehash option which prevents an expensive rehashing of ruby and rubygems executables when loading rbenv. You can always rehash later with
So I measured it again, to be sure it helps.
As you can see,
--no-rehash sped it up quite a bit.
As a side-effect, I learned how to measure code blocks in zsh ;-)
With these changes, I decreased my zsh startup time from 1.5s to 0.6s.
It's nice to see that two small changes can speed up an application I use every day.
For more information, you can see my full zsh configuration (along with my other dotfiles) on GitHub.