# My experience with Nix At the beginning of this year, I had read a lot about [Nix](https://nixos.org) and felt pretty confident that this wasn’t something for me. That was, until I did a voicecall with my good friend [Victor](https://glorifiedgluer.com). He was showing me these really neat tricks on how I could use Nix and Nix Flakes to handle configuration files, build software reproducibly and define my own development shell for each project I’m doing - I was blown away. After that call, I immediately started with the (admittedly stupid) thing that every developer does when learning about a new technology. I started moving all my shit over to it: System configuration, package _management_, package _configuration_, etc. - I wanted it all reproducible. In this blog post I will document my experience so far. This is very far from a guide to using Nix, but you might find some useful hints from my mistakes. ## Installing Nix Okay, the first step was to _aquire_ Nix. I use a [Macbook Air M1](https://en.wikipedia.org/wiki/MacBook_Air_(Apple_silicon)), and I quickly discovered that Apple have made this a hastle. After Catalina, [you are not able to write to the root directory of Macs](https://support.apple.com/en-us/HT210650), which meant getting the `/nix` directory up and running required hacky workarounds. Luckily, these are now intergrated into the installer, which made the install very simple. ``` $ sh <(curl -L https://nixos.org/nix/install) ``` did the trick for me. A reboot was needed, but then everything was up and running smoothly. **Nice!** ## Setting up nix-darwin The next step was to get my system built through Nix. This is a pretty wacky concept, but the advantages are incredible. Think of all the times you’ve bought a new computer or needed to do a factory reset. All those preferences you’ve tinkered with to perfection over the years: They do not need to be set up again! A `git clone`, one simple command, most likely a few minutes of building and you have all your apps and software up and running. I started with [this guide](https://github.com/LnL7/nix-darwin#flakes-experimental) and tinkered a bit according to my system: ``` nix { description = "kmaasrud's system"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; darwin.url = "github:lnl7/nix-darwin/master"; darwin.url.nixpkgs.follows = "nixpkgs"; }; outputs = { self, darwin, nixpkgs }: { darwinConfigurations = rec { mba = darwin.lib.darwinSystem { system = "aarch64-darwin"; modules = [ ./configuration.nix ]; }; } }; } ``` I put some simple system configuration in `configuration.nix`, built the flake with ``` $ nix build .#darwinConfigurations.mba.system ``` and was joyful to see everything working. This gave me a symlinked directory named `result`, containing a binary `sw/bin/darwin-rebuild` which I could use to bootstrap the system from the same flake. To my dismay, I was met with an error that said I was missing the `/run` directory. The error message said I needed to include the line `run\tprivate/var/run` in `/etc/synthetic.conf`, which would create the [firmlink](https://derflounder.wordpress.com/2020/01/18/creating-root-level-directories-and-symbolic-links-on-macos-catalina/) I needed. I did this without luck and ended up giving up on the whole debacle after a long night of googling. That following morning - when I could think sensibly again - I had an idea only a genius like me could find: I did a _reboot_… It worked. Okay, 1-0 to Nix, but I had no reason to give up now. `darwin-rebuild switch --flake .` was working, and I was off to the races! The following days, weeks, months, I have been tinkering and my Nix system configuration to the core, and I am nowhere near considering myself done. If you are curious, you can explore my config yourself on [GitHub](https://github.com/kmaasrud/dotfiles). ## Nix in projects The whole system configuration thing is very cool, but I’ve found that the real magic of Nix comes when you start using it in your projects. Nix serves as a very flexible build tool for your software. The builds are done inside a siloed environment, which means you need to declare **all** the dependencies of your build. This is _immensely_ useful! Software is built the same on all computers, which especially makes CI a lot easier. In my project [MDoc](https://github.com/kmaasrud/mdoc), which depends on [Tectonic](https://tectonic-typesetting.github.io/en-US/) (and subsequently [a bunch of C/C++ libraries](https://tectonic-typesetting.github.io/book/latest/howto/build-tectonic/index.html#third-party-dependencies)), I am able to do the build in a shell that has all the required dependencies without actually having to manually install said dependencies. They are listed in the following way: ``` nix buildInputs = with pkgs; [ fontconfig graphite2 harfbuzz icu libpng perl openssl zlib ] ++ lib.optionals stdenv.isDarwin [ ApplicationServices Cocoa ]; ``` Nix uses this list and makes sure these are linkable when building - **so smooth!** As you can see, "software is built the same on all computers" wasn’t an entirely true statement after all, since I need some specific dependencies for Darwin systems. However, when they can be conditionally defined this way, who am I to judge. ## Conclusion Allright, that is a misleading header; My Nix journey has only just begun. What I can say, is that Nix has changed the way I look at software. It would be very hard to go back to the old ways of a mutable system and non-reproducible development environments. I am convinced that Nix is the future - in some way or the other. It just needs a [facelift](https://nixos.wiki/wiki/Nix_command), because there is no way I am accepting `nix-*` type commands.