Throwing some Nix in the Mix
Published: 2021-11-29 01:24:57

I recently decided to give [Nix](https://github.com/NixOS/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](https://nixos.org/download.html). I followed along with their "first steps with Nix" guide as well [here](https://nixos.org/guides/dev-environment.html). 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](https://dev.to/monacoremo/how-to-simply-get-your-dependencies-with-nix-2ce1) 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](https://hub.docker.com/r/nixos/nix). 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](https://search.nixos.org/packages) 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](https://nixos.wiki/wiki/Flakes)) I haven't tried yet and Mitchell Hashimoto's [config](https://twitter.com/mitchellh/status/1452721115009191938) 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.