How to Manage Elixir versions on Mac or Linux — Part 1 of Getting Started with Elixir

Photo of a paper boat in a bottle by Simone Viani on Unsplash

Elixir is a wonderful language. Expressive, productive, scalable, fault-tolerant… it’s pretty darn cool. But how do we manage projects which use different versions?

Want to get started as fast as possible? Do you only need the latest version of Elixir? Then Elixir’s official installation guide is the best place to start :)
For everyone else — if you want to easily switch between different versions of Elixir (and Erlang) for different projects: keep on reading below.

What do you do if one project needs Elixir 1.7 while another needs Elixir 1.3 How do you switch between versions of Elixir and Erlang?

I suppose we could manually uninstall and re-install different versions when moving between projects, but that sounds tedious, unproductive, and downright confusing for all involved. There must be a better way… right?

Enter asdf.

Not that kind of asdf

🎛 asdf makes it easy to switch between versions of your favourite languages

asdf lets us easily install and manage multiple versions of almost any language (Node, Ruby, Elixir, Python, etc.). We can even tell asdf to use different language versions for different projects. Very nice.

So what will we be doing with asdf? In part 1 (that’s this article), we’ll be:

  1. Installing asdf (on Mac & Linux)
  2. Installing the Elixir and Erlang plugins for asdf
  3. Installing older versions of Elixir and Erlang (1.3.4 and 19.3 respectively)
  4. Telling asdf to use Elixir 1.3.4 and Erlang 19.3 globally
  5. Creating a new project using Elixir 1.3.4
  6. Telling asdf to always use Elixir 1.3.4 and Erlang 19.3 for our new project (local scope)

Then in part 2, we’ll be:

  1. Installing Elixir 1.7.4 and Erlang 21.1 (the latest versions at the time of writing)
  2. Telling asdf to use the new versions of Elixir and Erlang as our global default (global scope)

By the end, our system will be set up to use the latest versions of Elixir and Erlang by default (called the global scope) and we’ll have a project that will always use Elixir 1.3.4 (even on other people’s machines if they use asdf!).

But first… we need to install asdf. Let’s get started!

🖥 1: Installing asdf

Installing on a Mac using homebrew

Install asdf using homebrew:

  1. Open up Terminal
  2. Ensure you have the latest version of homebrew:
brew update

If you get a command not found error, install homebrew using the command found here.

3. Now that homebrew is updated, let’s install asdf:

brew install asdf

Now that asdf is installed, we’ve got to add it to our shell path.

To do this, we can use a couple of handy commands to append asdf’s path to our shell config file:

Run the following two commands if you’re using bash:

echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bash_profile
echo -e '\n. $HOME/.asdf/completions/asdf.bash' >> ~/.bash_profile

Or run these commands if you’re using zsh:

echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.zshrc
echo -e '\n. $HOME/.asdf/completions/asdf.bash' >> ~/.zshrc

Or run these commands if you’re using fish:

echo 'source ~/.asdf/asdf.fish' >> ~/.config/fish/config.fish
mkdir -p ~/.config/fish/completions; and cp ~/.asdf/completions/asdf.fish ~/.config/fish/completions

Now just restart your Terminal and you should be done!

Test that it worked by checking your asdf version:

asdf --version

Hopefully, you’ll get back v0.6.2 (or whatever the latest version is).

Done! Skip past the next section (installing asdf on Linux) and move onto the second chapter: installing the Erlang & Elixir plugins for asdf.

Installing asdf on Linux using Git

Sadly we don’t have homebrew on Linux 😢 so we’ll be installing asdf using Git:

  1. Open up Terminal
  2. Check you have Git installed by entering: git --version

If you get a command not found error: download Git and restart your Terminal.

3. Download asdf version 0.6.2:

git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.6.2

Now that asdf is downloaded, we’ve got to add it to our shell path.

If you’re using bash, you can do that with:

echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bashrc
echo -e '\n. $HOME/.asdf/completions/asdf.bash' >> ~/.bashrc

If you’re using zsh or fish, have a look at the end of the Mac section above. It contains the commands needed for appending asdf’s path to your zsh or fish config file.

Now just restart your Terminal and you should be done!

Let’s test that it worked by updating asdf:

asdf update

Hopefully, that’ll return something like Updated asdf to release v0.6.2 (or whatever the latest version is.

If not, check you’re using the right shell and have followed the previous steps correctly. If you can’t figure it out after some googling, post a comment down below and I’ll do my best to help out.

Since we’ve installed asdf manually using Git, we should install some packages (as recommended by asdf) to make sure we’re not missing any plugin dependencies.

If you’re on Ubuntu 16 or above, you can do that with:

sudo apt install automake autoconf libreadline-dev libncurses-dev libssl-dev libyaml-dev libxslt-dev libffi-dev libtool unixodbc-dev

Or if you’re on Fedora, run this:

sudo yum install automake autoconf readline-devel ncurses-devel openssl-devel libyaml-devel libxslt-devel libffi-devel libtool unixODBC-devel

Next up, let’s install Elixir and Erlang using asdf.

🔌 2: Installing the Erlang & Elixir plugins for asdf

But Daniel, why do I need Erlang if I just want to use Elixir?

Great question. Elixir is built on Erlang and therefore Elixir code is run inside Erlang’s BEAM VM (Virtual Machine). So we’ll need Erlang if we want to compile and run Elixir code.

Different versions of Elixir require different versions of Erlang (you can find a handy table of which versions are compatible on this page). So we can’t just download one version of Erlang and be done with it. Instead, we’ll use asdf to manage our versions of both Erlang and Elixir.

A table of Erlang & Elixir version compatibilities, as of 4 Jan 2019

But first, asdf needs to understand how to use Elixir and Erlang. To do this, we need to install a couple of plugins:

  1. Open up Terminal
  2. Install the Erlang plugin:
asdf plugin-add erlang

3. Install the Elixir plugin:

asdf plugin-add elixir

Done! Now that asdf knows how to manage Erlang and Elixir, we can start installing them.

🕸 3: Installing Elixir 1.3.4 and Erlang 19.3 (the older versions)

Sooo why Elixir 1.3.4? It’s an old version and that number seems oddly specific… 🤔

The answer’s pretty simple: it’s the version of Elixir that Stephen Grider uses in his (fantastic) Elixir & Phoenix Udemy course.

When starting the course, I found that getting started with Elixir was a bit of a struggle. What version of Erlang do I need for Elixir 1.3? How will I switch between versions? What tool should I use to do that? So this is the article I wish I’d had when I started the course :)

According to the table above (found on this page), Elixir 1.3 requires Erlang 18 or 19.

  1. So let’s first install Erlang 19.3:
asdf install erlang 19.3

That’ll probably take a while… ⏳

2. When that’s done, let’s install Elixir 1.3.4:

asdf install elixir 1.3.4

3. Now let’s check that they installed correctly:

asdf list

Now we should get a list of all versions of all languages that we’ve installed with asdf:

elixir
1.3.4
erlang
19.3

Perfect.

Now try running elixir -v in Terminal. Why doesn’t it work?

So far we’ve installed asdf, installed the Elixir and Erlang plugins for asdf, and installed Elixir 1.3.4 and Erlang 19.3… but we haven’t actually told asdf what versions of Elixir & Erlang to use.

What if we installed ten different versions of Elixir? How would asdf know which one to use?

So next, we’ll explicitly tell asdf which versions of Elixir and Erlang to use.

🌍 4: Telling asdf what versions of Erlang & Elixir to use globally

We’ve just installed Elixir 1.3.4, but right now asdf doesn’t know what version we want to use. Let’s fix that:

  1. Open up Terminal
  2. Tell asdf to use Erlang 19.3 and Elixir 1.3.4 globally:
asdf global erlang 19.3
asdf global elixir 1.3.4
What have we just done there?

We’ve told asdf that we want to use Erlang 19.3 and Elixir 1.3.4 by default (globally). That’s what the global part of the command is doing.

Any time we run an Elixir or Erlang command, asdf will look for a .tool-versions file in our current directory. If that file doesn’t specify an Elixir or Erlang version (or if the file doesn’t exist at all), asdf will use our global default. Right now, our global defaults are set to: Erlang 19.3 and Elixir 1.3.4.

Now let’s test that it worked.

3. Restart your Terminal

4. Check what version of Elixir you’re running:

elixir -v

You should get back a similar output to this:

Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Elixir 1.3.4

Perfect. You’re now ready to get started using Elixir 1.3.4. So let’s test it out by creating a new project.

📂 5: Creating our new project using Elixir 1.3.4

Now we’ll create our new project with Elixir 1.3.4 using the mix new command:

  1. Create a new Elixir project called my_legacy_project (or whatever you want to call it):
mix new my_legacy_project

2. Enter the new my_legacy_project directory:

cd my_legacy_project

3. Check that everything has installed correctly by running the project’s tests:

mix test

You should see something similar to this:

Compiling 1 file (.ex)
Generated my_legacy_project app
.

Finished in 0.03 seconds
1 test, 0 failures

Randomized with seed 123456

If all of your tests passed (all 1 of them haha), then congrats! Our new project is set up.

Creating a project by following the steps above

🏠 6: Telling asdf to always use Elixir 1.3.4 and Erlang 19.3 for our new project (using local scope)

But what would happen if you changed your global Elixir version?

Great question. We’ve created this project with 1.3.4, but what happens if we need to change our global version for a different project? Would we always have to run asdf global elixir <version> when switching projects (and do the same for Erlang too?!?).

That sounds tiresome. Thankfully, we won’t ever have to do that because asdf is pretty smart. We can lock projects to a specific version by using the local keyword in asdf. Let’s run the command ourselves to figure out how it works:

1. Tell asdf to use local Erlang and Elixir versions for this project:

asdf local erlang 19.3
asdf local elixir 1.3.4

So what did we just do? We told asdf to create a file called .tool-versions (this goes in our project file) which keeps track of what language versions a project should use.

What does that .tool-versions file contain?

2. Let’s have a look at the new file that asdf created:

cat .tool-versions

The cat command will output the contents of a file into our Terminal. So we should get back the contents of .tool-versions:

erlang 19.3
elixir 1.3.4

If a project doesn’t have a .tool-versions file, or if a version isn’t specified in this file, asdf will use the global version that you set.

Setting the project’s local version of Erlang & Elixir by following the steps above
But wait, earlier we set our global Elixir version to 1.3.4, right? So does the .tool-versions file we just made even make a difference? We’re still using Elixir 1.3.4 either way!

You’re right. We’re still using Elixir 1.3.4 right now, either way. But now that we’ve locked down our versions with a .tool-versions file, we get a couple of powerful advantages:

  1. We can commit the .tool-versions file to source control (like Git) so other team members will use the same versions as us (if they use asdf)
  2. We know that our project will always be using the correct versions of Elixir & Erlang, even if we change our global versions in the future

But we’re still using Elixir 1.3.4 both locally and globally. Let’s change that in part 2 by installing Elixir 1.7.4 globally!

📜 Summary

Phew. That felt like a lot of commands to just get Elixir up and running. But was it worth it? Let’s have a look at what we’ve just done:

  1. Installed asdf version manager
  2. Installed the Erlang & Elixir plugins for asdf:
asdf plugin-add erlang
asdf plugin-add elixir

3. Installed Erlang 19.3 and Elixir 1.3.4 using asdf:

asdf install erlang 19.3
asdf install elixir 1.3.4

4. Set asdf to use Erlang 19.3 and Elixir 1.3.4 globally:

asdf global erlang 19.3
asdf global elixir 1.3.4

5. Created a new project using Elixir 1.3.4:

mix new my_legacy_project
cd my_legacy_project
mix test

6. Told asdf to always use Elixir 1.3.4 and Erlang 19.3 for our new project:

asdf local erlang 19.3
asdf local elixir 1.3.4

Now we have one item left on the todo list: install Elixir 1.7.4 (and Erlang 21.1) globally.

Click here to learn how to do that in part 2.


  • Found this article helpful? Claps or comments are always appreciated :)
  • Got stuck? Leave a comment; I’ll do my best to help!
  • Have an idea on how this article could be improved? Please let me know in a comment! I’m a big fan of constructive feedback :)