Switching from pyenv, rbenv, goenv and nvm to asdf
Tags: fish, asdf, pyenv, nvm
Published: 2020-07-20 13:49:27

---
title: Switching from pyenv, rbenv, goenv and nvm to asdf
published: true
date: 2020-07-19 19:57:19 UTC
tags: fish, asdf, pyenv, nvm
canonical_url: https://jinyuz.dev/posts/tips-and-tricks/Switching-from-pyenv,-rbenv,-goenv-and-nvm-to-asdf
---

So, there was a time when I was only developing applications using `Python`. And so I found out about virtual environments.And then after a couple of months, I discovered `pyenv`.

It also came to a time I had to work on multiple projects that uses different versions of `nodejs` and searched something similarso I installed `nvm`.

Then, I was required to work on a `Ruby` project so I installed `rbenv`.

And since `golang` was one of the new shiny objects that kinda got my interest, I went on and installed `goenv`.

Everything was fine until I kinda felt my `config.fish` file got bloated and somehow `nvm` was kinda slowing down my shell startup.

I did do some optimizations such as lazy loading `nvm` and used a `fish` plugin called [fish-nvm](https://github.com/FabioAntunes/fish-nvm).

And then one day, I found out about [asdf-vm](https://google.com).

At first, I was quite hesitant to install it since it would kinda disrupt my work flow with python projects since I heavily use `pyenv virtualenv <version> <name>`.

But I did feel that the benefits of using `asdf-vm` outweighs the cons so I went ahead and proceeded.

# [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#installation)Installation

```
$ git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.7.8
```

`asdf` has a pretty good documentation to be honest. Despite `brew` being my go to package manager, I chose `git` as my installation method.My reason is that `asdf` requires me to add this line in my `config.fish`

```
source (brew --prefix asdf)/asdf.fish
```

and the `brew --prefix adsf` is just too slow compared to just having this

```
source $HOME/.asdf/asdf.fish
```

Next, for the auto completions just run this command in your terminal:

```
$ mkdir -p ~/.config/fish/completions; and cp ~/.asdf/completions/asdf.fish ~/.config/fish/completions
```

Restart your shell so that PATH changes take effect!

You can checkout a more detailed documentation here: [https://asdf-vm.com/#/core-manage-asdf-vm?id=install](https://asdf-vm.com/#/core-manage-asdf-vm?id=install)

Before, my `config.fish` looked something like this:

```
# pyenv
set -gx PYENV_ROOT $HOME/.pyenv
set -gx PYTHON_BUILD_ARIA2_OPTS "-x 10 -k 1M" # Use aria2c when downloading
contains $PYENV_ROOT/bin $fish_user_paths; or set -Ua fish_user_paths $PYENV_ROOT/bin
status --is-interactive; and pyenv init - | source
status --is-interactive; and pyenv virtualenv-init - | source

# goenv
set -gx GOENV_GOPATH_PREFIX $HOME/.go
status --is-interactive; and goenv init - | source

# rbenv
status --is-interactive; and rbenv init - | source

# Set nvm aliases and add to path
set -gx nvm_alias_output $HOME/.node_aliases
contains $nvm_alias_output $fish_user_paths; or set -Ua fish_user_paths $nvm_alias_output
```

After

```
# pyenv (asdf still uses pyenv under the hood)
set -gx PYTHON_BUILD_ARIA2_OPTS "-x 10 -k 1M" # Use aria2c when downloading

# asdf
source $HOME/.asdf/asdf.fish
```

# [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#installing-pyenv-rbenv-goenv-and-nvm-replacements)Installing pyenv, rbenv, goenv, and nvm replacements

Again, most of the things I put here just came from the documentation: [https://asdf-vm.com/#/core-manage-plugins?id=add](https://asdf-vm.com/#/core-manage-plugins?id=add)

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#pyenv-replacement)pyenv replacement

```
$ asdf plugin add python
$ asdf install python latest:3 # At the moment of writing this, it installed 3.8.4
$ asdf global python 3.8.4 # This sets python 3.8.4 as our default python version
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#rbenv-replacement)rbenv replacement

```
$ asdf plugin add ruby
$ asdf install ruby latest # We can omit the version number. Currently installs 2.7.1
$ asdf global ruby 2.7.1
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#goenv-replacement)goenv replacement

```
$ asdf plugin add golang
$ asdf install golang latest # 1.14.6
$ asdf global golang 1.14.6
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#nvm-replacement)nvm replacement

```
$ asdf plugin add nodejs
$ asdf install nodejs 12.18.2
$ asdf global nodejs 12.18.2
```

Using `asdf global` creates a file under your HOME directory called `.tool-versions`

```
$ cat ~/.tool-versions
python 3.8.4
ruby 2.7.1
golang 1.14.6
nodejs 12.18.2
```

This lets `asdf` know which versions to use. And of course, in contrast to `global`,there is also the `local` keyword that creates another `.tool-versions`.This is useful when projects require different version.

```
$ cd ~/project1
$ asdf local python 3.7.5
$ python --version # Uses the python version specified in .tool-versions
3.7.5
$ cd ~/project2
$ python --version # Uses the python version specified in ~/.tool-versions
3.8.4
```

`asdf` has a lot of plugins available. You can check them out here: [https://github.com/asdf-vm/asdf-plugins](https://github.com/asdf-vm/asdf-plugins)

# [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#extras)Extras

In order to accommodate my work flow when I was still using `pyenv virtualenv`,I created a function that behaves quite similar to `pyenv virtualenv`.

```
$ touch ~/.config/fish/functions/venv.fish
```

And paste the following:

```
function venv --argument-names 'python_version' --description 'Create virtualenv named the same as current directory'
  set -l python_bin

  if not test -n "$python_version"
    # Use default python version set by asdf
    set python_bin ($HOME/.asdf/bin/asdf which python)
  else
    set python_bin $ASDF_DIR/installs/python/$python_version/bin/python
  end

  set -l venv_name (basename $PWD | tr . -)

  echo
  if not test -e $python_bin
    echo "Python version `$python_version` is not installed."
    return 1
  end

  echo Creating virtualenv `$venv_name`
  $python_bin -m venv $HOME/.virtualenvs/$venv_name
  source $HOME/.virtualenvs/$venv_name/bin/activate.fish
end
```

Whenever I’m inside a python project, I just need to type `venv` or `venv <python_version>`and it will automatically create a virtualenv under `~/.virtualenvs` using the current directory name.

In order to automatically activate the virtualenv when `cd`ing to a project, do the following:

```
$ touch ~/.config/fish/conf.d/__auto_venv.fish
```

And paste the following:

```
function __auto_venv --on-variable PWD --description "Automatically activate python venv"
  set -l venv_name (basename $PWD | tr . -)

  if test -d $HOME/.virtualenvs/$venv_name
    source $HOME/.virtualenvs/$venv_name/bin/activate.fish
  end
end
```

Cool! Not only did I reduce the lines in my `config.fish`, I could also notice a decreased startup time which is a good thing!

You can also check out my dotfiles in my GitHub repository: [https://github.com/yujinyuz/dotfiles](https://github.com/yujinyuz/dotfiles)

I hope this article helped you! You can leave a comment below and I’ll try to answer them as fast as I can.

Thanks for reading! 🎉