Developing with Elixir requires a fair amount of configuration.

You need:

• Erlang
• Elixir
• Hex package manager

And usually you want all these to be locked at a specific version.

There are several solutions out there, the most popular probably being https://github.com/asdf-vm/asdf but for Nix fans, how do we setup a nix-shell and do this the “nix way”?

The Nix community seems to reccomend to nixify your projects, examples exist for

• Ruby https://github.com/nix-community/bundix
• Node https://nixos.wiki/wiki/Node.js
• Elixir https://discourse.nixos.org/t/announcing-mixnix-build-elixir-projects-with-nix/2444

I’ve been using a different pattern with most of my projects to achieve this, and it works for both Ruby, Elixir and many other languages.

The trick is find the env variables that allow us to “isolate” locally the dependency installation, in our example these are MIX_HOME and HEX_HOME.

By setting these two variables to the local directory within the nix-shell we allow mix to install the packages locally instead of trying to add them to the nix-store path (/nix...) that is readonly.

### Summing it up

Here’s the shell.nix file that I use in my elixir projects

with import <nixpkgs> {};
let
# define packages to install with special handling for OSX
basePackages = [
gnumake
gcc
openssl
zlib
libxml2
curl
libiconv
elixir_1_9
glibcLocales
nodejs-12_x
yarn
postgresql
];

inputs = basePackages
++ lib.optional stdenv.isLinux inotify-tools
++ lib.optionals stdenv.isDarwin (with darwin.apple_sdk.frameworks; [
CoreFoundation
CoreServices
]);

# define shell startup command
hooks = ''
# this allows mix to work on the local directory
mkdir -p .nix-mix
mkdir -p .nix-hex
export MIX_HOME=$PWD/.nix-mix export HEX_HOME=$PWD/.nix-hex
export PATH=$MIX_HOME/bin:$PATH
export PATH=$HEX_HOME/bin:$PATH
export LANG=en_US.UTF-8
export ERL_AFLAGS="-kernel shell_history enabled"
'';

in mkShell {
buildInputs = inputs;
shellHook = hooks;
}


save this in your project directory as shell.nix then type nix-shell and you will be in a bash shell that has mix and elixir ready to be used!

https://www.gigalixir.com is one of the simplest ways to deploy Elixir applications. Similarly to Heroku, you subscribe, create hjan account, install the cli and you are off to the races.

The problem is that our nix-shell does not allow us to run pip install gigalixir and install the gigalixir command line utility.

Setting up python in nix requires a little more configuration.

First we need to add Python to our nix-shell and ensure that our python install has the pip package manager, a detailed explaination can be found here https://nixos.wiki/wiki/Python.

In short you can do something like this

  my-python-packages = python-packages: with python-packages; [
pip
setuptools
];

python-with-my-packages = pkgs.python3.withPackages my-python-packages;


Then, like we did for Elixir, we have to force Python to install its stuff locally, we do this by setting PIP_PREFIX and PYTHONPATH;

 alias pip="PIP_PREFIX='$(pwd)/_build/pip_packages' \pip" export PYTHONPATH="$(pwd)/_build/pip_packages/lib/python3.7/site-packages:$PYTHONPATH"  The resulting shell.nix file is then as follows with import <nixpkgs> {}; let my-python-packages = python-packages: with python-packages; [ pip setuptools ]; python-with-my-packages = pkgs.python3.withPackages my-python-packages; # define packages to install with special handling for OSX basePackages = [ gnumake gcc readline openssl zlib libxml2 curl libiconv elixir_1_9 glibcLocales nodejs-12_x yarn postgresql inotify-tools python-with-my-packages ]; inputs = basePackages ++ lib.optional stdenv.isLinux inotify-tools ++ lib.optionals stdenv.isDarwin (with darwin.apple_sdk.frameworks; [ CoreFoundation CoreServices ]); # define shell startup command hooks = '' export PS1='\n$\033[1;32m$[nix-shell:\w]($(git rev-parse --abbrev-ref HEAD))\$$\033[0m$ ' # this allows python to work locally alias pip="PIP_PREFIX='$(pwd)/_build/pip_packages' \pip"
export PYTHONPATH="$(pwd)/_build/pip_packages/lib/python3.7/site-packages:$PYTHONPATH"
unset SOURCE_DATE_EPOCH

# this allows mix to work on the local directory
mkdir -p .nix-mix
mkdir -p .nix-hex
export MIX_HOME=$PWD/.nix-mix export HEX_HOME=$PWD/.nix-hex
export PATH=$MIX_HOME/bin:$PATH
export PATH=$HEX_HOME/bin:$PATH
export LANG=en_US.UTF-8
export PATH=$PATH:$(pwd)/_build/pip_packages/bin
export ERL_AFLAGS="-kernel shell_history enabled"
'';

in mkShell {
buildInputs = inputs;
shellHook = hooks;
}


At this point we can type nix-shell and then pip install gigalixir and we are ready to go!

### Notes:

The full code can be found here in this gist

After publishing this post I found this one that presents a simpler approach and with a shorter shell configuration, I updated my notes above to use mkShell and a nicer syntax that uses lib.optionals to load the MacOS only packages

Another good resource I only found today is here