There have been more than a few cases where people suggest various tools to manage my dotfiles for me. Nix is one of the more recent ones and it intrigued me after learning a bit more about how it approaches handling its packages. See, everything in Nix is built to be declarative and immutable by design, all the way down to the libraries backing the tools you would use in your day-to-day work. This fancy trick unlocks a lot of really powerful features for you. Now, I’m no expert in Nix and instead this is going to be more a journey that I’ll be documenting here as I learn more about Nix. A coworker of mine told me that when they were learning how to use Nix they started small and familiar with their dotfiles and moved onto other things from there. I’ll be doing exactly that since I can think of nothing more personal and familiar to me than my dotfiles.

Home-manager

So in my exploring of what Nix is I found a tool that explicitly is for managing dotfiles called Home-manager. Installing this tool and running through the Nix Pills to start learning how to write my own Nix files really started to open my eyes to the power of how Nix manages files. My current dotfiles git repo structure is meant to be an overlay on an existing home directory. It’s installation is almost intentionally messy, but a familiar kind of messy because when I say overlay, it isn’t the nice way that docker layers overlay on each other in the overlay2 filesystem. The installation script iterates over every file in the dotfile repo and creates a symlink from your home directory to the repo itself. Sometimes clobbering your existing configurations in the process.

Now how home-manager handles installation is fascinating. Remember how I said that Nix is declarative? Well when you write your configuration for your dotfiles, you are not writing a .vimrc file or a .bashrc file. Nix expects you to define your configurations in Nix and it will build out a .vimrc and .bashrc for you. Each configuration file generated based on what is know in Nix as a derivation or builder. Since everything in Nix is built to be immutable, Nix keeps every version of your generated dotfiles in /nix/store and symlinks to the versions you actually want to use. This makes rolling back to a previous version of your configurations super simple as its just moving some symlinks around. Home-manager acts as a profile manager for these generated configuration files. It sees what you have declared in your own home.nix file and makes sure that what you want exists in your version of home.nix. It then modifies your PATH or symlinks config files into place in your home directory (if it can do so without destroying anything) and you have a configured environment.

Dotfiles are not the only thing that Home-manager knows how to handle. It can also handle packages and with that you can also get the same benefits of Nix’s declarative and immutable powers. Lets take git for instance which I have defined in my home.nix file.

{ config, pkgs, ... }:
{
  # ...
  home.packages = {
    pkgs.git
  }
  # ...
}

A version of the package git is downloaded, built, and stored within /nix/store with a hash, sometimes referencing dependent libraries by their unique hashes within the derivation for git. git is then symlinked into your PATH so that specific version is made available to you. Not only does this allow you to ensure that the same version of a package exists for you down to the libraries that package is dependant on, it also allows you to have different versions of the same package installed simultaneously which other package managers are definitely not good at handling. This may not be a big deal for most, but for developers out there who bounce between multiple projects, this is huge.

Anyhow, there is a lot more to explore here and I’m only at my dotfiles and am getting some use out of it so far. Needless to say, I’m excited to see where this path takes me.