Elixir Dev Environment With Nix Flakes
In a previous article, I described how to set use Nix and Niv to configure an Elixir dev environment. This setup can be simplified by using Nix flakes instead of Niv.
At the time of writing, Nix flakes are still an experimental feature. If you follow the stable Nix channel, you may need to enable the feature first.
Initialize flake
You can initialize a flake by running:
nix flake init
This will create a flake.nix
file in the current directory.
Inputs
Add this to the generated file.
inputs = {
nixpkgs = { url = "github:NixOS/nixpkgs/nixos-22.11"; };
flake-utils = { url = "github:numtide/flake-utils"; };
};
Here we define nixos-22.11
as package source. You could use nixpkgs-unstable
instead. We also add flake-utils,
which defines a couple of convenience functions for writing flakes.
Outputs
Next, define the dev shell within the outputs.
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
inherit (pkgs.lib) optional optionals;
pkgs = import nixpkgs { inherit system; };
elixir = pkgs.beam.packages.erlang.elixir;
in
with pkgs;
{
devShell = pkgs.mkShell {
buildInputs = [
elixir
elixir_ls
glibcLocales
] ++ optional stdenv.isLinux inotify-tools
++ optional stdenv.isDarwin terminal-notifier
++ optionals stdenv.isDarwin (with darwin.apple_sdk.frameworks; [
CoreFoundation
CoreServices
]);
};
});
To override the Elixir version, replace
elixir = pkgs.beam.packages.erlang.elixir
with:
beamPkg = pkgs.beam.packagesWith pkgs.erlangR25;
elixir = beamPkg.elixir.override {
version = "1.14.0";
sha256 = "NJQ2unK7AeLGfaW/hVXm7yroweEfudKVUa216RUmLJs=";
};
When you update the Elixir version, make sure to update the sha256 value as
well. You can find it in the terminal output by replacing the previous hash with
pkgs.lib.fakeSha256
.
If you also need to override the Erlang version, you can do something like this:
erlang = pkgs.erlangR25.override {
version = "26.0";
sha256 = pkgs.lib.fakeSha256;
};
beamPkg = pkgs.beam.packagesWith erlang;
This is just an example, there is no OTP 26 at the time of writing.
You probably will need more build inputs. For example, you may want to add
postgresql
in order to use psql
and pg_dump
, you may need nodejs-16_x
to
build the frontend assets, you may need to add chromedriver
to run tests with
Wallaby, or you may need imagemagick
for
image processing. Whatever you need, just add it to the buildInputs
of the
devShell
. You can search for packages with:
nix search nixpkgs postgres
Direnv
We used direnv to load the dev environment automatically
when changing the directory to the project folder. We can still do that with
flakes, but instead of use_nix
, we use flake
.
echo "use flake" > .envrc
If you are setting up a new project, don’t forget to add .direnv
to your
.gitignore
file.
echo ".direnv/" >> .gitignore
You’ll need to run direnv allow
once.
direnv allow
If you make changes to the flake, you can reload the environment with:
direnv reload
Updating packages
When you load the environment the first time, a flake.lock
file is created,
which you should commit. You can later update the packages with:
nix flake update --commit-lock-file
What else?
This setup only configures a dev shell environment. You could expand on this and build the application binary with Nix as well. You could even configure a docker image using Nix. I might get back to this in a future article.
Resources
- Flakes documentation
- Getting Started Using Nix Flakes as an Elixir Development Environment
- Rust Environment and Docker Build With Nix Flakes
- Practical Nix Flakes
- Nix Flakes: An Introduction
- Nix Flakes: Packages and How to Use Them
- BEAM languages (Nix docs)