I recently decided to give Nix a try after seeing various posts about it. It defines itself as "a powerful package manager for Linux and other Unix systems that makes package management reliable and reproducible". There is also NixOS which is a Linux distribution built around Nix which extends the concept beyond just package management.
One of my major drivers was understanding if I could create an environment with pinned versions of various development software. Having consistent development environments can greatly improve developer experience. Removing "But it works on my computer" from the lexicon has long been a desire of the tech industry.
Getting Started
To begin, I installed Nix on my WSL2 instance. The team behind the tool provide install instructions here. I followed along with their "first steps with Nix" guide as well here. This helped demonstrate how it could be used in place of python virtual environments and pip. This leverages the nix-build
command.
While useful, I wanted to see if I could create a more generic environment for someone to build before having the end-to-end application in mind. I discovered the nix-shell
command which was much more in-line with what I was looking for. Remo's Guide on the topic was super helpful with helping me understand the initial configuration required.
From there I was able to drop into a Nix shell with some of the standard tools with my shell.nix
file below by running nix-shell
in the directory where the file was located.
let
pkgs = import <nixpkgs> {};
in
pkgs.stdenv.mkDerivation {
name = "my-env";
buildInputs =
[
pkgs.curl
pkgs.jq
pkgs.git
pkgs.go
pkgs.terraform
pkgs.python310
pkgs.vim
];
}
If you'd like a more detailed breakdown on the formatting of the file, please review the guide mentioned above. While this was a huge step to ensuring consistency I wondered if I could take it a step further and run the shell within a container.
This would bring it more in-line with the remote development feature of VS Code, Github Codespaces, or Git Pod. It also makes it more host operating system agnostic.
Luckily, I did not have to start from scratch as Nix serves their own docker image. I mounted one of my directories and was able to drop into a Nix shell with my configuration file.
This all worked well but I did run into a scenario where I was not getting the expected version of terraform. After some troubleshooting, running nix-channel -- update
inside the container helped refresh the state of available packages.
I made use of nix-env -qaP <search term>
to determine if a package existed and which versions. This site is also useful for that purpose.
Rather than run a bunch of commands just to get into the shell I put together the following docker one-liner.
docker run --rm -it -v /home/ant:/mnt/ant -w /mnt/ant nixos/nix /bin/sh -c "nix-channel --update && nix-shell --command '. /mnt/ant/aliases; return'"
To break down the above, I mount my home directory, move the working directory to mapped directory inside the container, update the nix package cache, and drop into the shell. As the shell loads it also allows for the adding of aliases. This could also be a bashrc file or something similar.
In order for this to work I places my shell.nix
file at the root of my home directory.
With all this configured, access to docker and a copy of the shell.nix
file would be all that's needed to start developing with my tool chain.
Limitations
One item I was not able to get working in the above exercise was using my preferred shell. I use zsh with oh-my-zsh. While the full NixOS supports it, there does not appear to be a way to do so with just Nix.
Nix's documentation was also pretty challenging to navigate. Various blog posts and discussions were much more helpful in pointing me in the right direction.
Conclusion
Overall, I'm intrigued by Nix but think there's definitely room for improvement. There a bunch of features (like flakes) I haven't tried yet and Mitchell Hashimoto's config has given me plenty of ideas of how far the tool can go. While complex, Nix is a very powerful technology.
Being able to define development environments as code similar to other trends (infrastructure, policy, configuration) will help accelerate developers and help them avoid common pitfalls.
Top comments (0)