Speeding up pyenv & rbenv using tmux

Note: instructions are in Fish, but concept can be ported to other shells.

  1. In ~/.config/fish/config.fish, add the following:
# pyenv
if status is-login
    pyenv init - --no-rehash fish | source
    and funcsave pyenv
    and sh -c 'command pyenv rehash 2>/dev/null &'

# rbenv
if status is-login
    rbenv init - --no-rehash fish | source
    and funcsave rbenv
    and sh -c 'command rbenv rehash 2>/dev/null &'
  1. Setup your terminal with the following login command (I’m currently using Alacritty).
  program: /usr/local/bin/fish
    - --login
    - -c
    - 'tmux attach || tmux -f ~/.config/tmux/tmux.conf'
  1. In ~/.config/tmux/tmux.conf:
set-option -g default-command "/usr/local/bin/fish"
set-option -g default-shell "/bin/sh"

This instantiates pyenv & rbenv and quickly runs rehash once, when the terminal app launches (i.e., when it’s a login terminal). Then each subsequent session is loaded instantly.

Fish functions can’t be exported, so instead a definition is copied to ~/.config/fish/functions that can be lazy-loaded by child shells. It’s probably only necessary to do this once, but I’ve left it in the init file to avoid having to think about it changing between versions.

On macOS, this requires Fish 3.1 or above since it fixes a bug with paths getting mangled.

🔗Other shells

I only use Fish as a login shell so have no need to do this in other shells, but instructions in zsh should be similar. Just add this to ~/.zprofile:


eval "$(rbenv init - --no-rehash zsh)" &&
    whence -f rbenv >"$AUTOLOAD_FUNC_DIR/rbenv" &&
    (command rbenv rehash 2>/dev/null &)

Then add this to ~/.zshrc:

autoload -Uz rbenv

In Bash this is easier (for better or for worse). Instead of saving the function to a file, just use export -f in ~/.bash_profile:

eval "$(rbenv init - --no-rehash bash)" &&
    export -f rbenv &&
    (command rbenv rehash 2>/dev/null &)

To test that it’s working properly, try using rbenv shell which requires the wrapper function to be defined. The only caveat is that both of these break shell completions, which isn’t the case with Fish since its completions are already included with the shell.