The Home Manager #

The Nix Home Manager is a way to work with Nix in a declarative environment to manage your dotfiles and user environment packages. This can be used on any system running the Nix packagemanager. Personally, I’ve started to dabble around with it a bit after installing the Nix packagemanager in my Alpine installation. Since I’ve already dabbled with Nix on a few systems through NixOS, I already knew the basics of functionally managing packages (or derivations) with the Nix packagemanager. Hence I really quickly got sick of installing packages the imperative way. After looking around for a bit, I found some post mentioning that managing packages in a functional environment outside of NixOS is a bit of a hack. The post referred to some other sources, one of which used a custom meta package and another referred to the Home Manager.

I had messed around with the Nix Home Manager a tiny bit before, but never really gave it a chance to shine as I didn’t really understand it. This time around, I decided to look up some tutorials and see how it worked. When going through the instructions of either tutorial I used, I quickly came to the realisation why I had never really looked at it. Both tutorials took a lot of unnecessary steps according to the author’s will and assumed that everyone following their tutorials had the same preferences as them. I obviously don’t. So here’s my take on installing the Home Manager outside of NixOS.

Actually using Home Manager #

Assuming you’re continuing from my previous article on Nix, the first step is to go to the Home Manager github page and go to the page regarding the standalone installation.

From there, things will be quite self explanatory if you’re used to the (bare) basics of NixOS. Though instead of using /etc/nixos/configuration.nix you’ll be using $HOME/.config/nixpkgs/home.nix by default. A basic Home Manager installation will leave you with a home.nix file with the following content:

{ config, pkgs, ... }:

{
  # Home Manager needs a bit of information about you and the
  # paths it should manage.
  home.username = "$USER";
  home.homeDirectory = "/home/$USER";

  # This value determines the Home Manager release that your
  # configuration is compatible with. This helps avoid breakage
  # when a new Home Manager release introduces backwards
  # incompatible changes.
  #
  # You can update Home Manager without changing this value. See
  # the Home Manager release notes for a list of state version
  # changes in each release.
  home.stateVersion = "22.05";

  # Let Home Manager install and manage itself.
  programs.home-manager.enable = true;
}

After making any changes to your home.nix file, you can apply them with:

home-manager switch

If you first want to see whether you build is going to be successful or not, run:

home-manager build

Installing packages #

To add some packages, you’ll need to add them to the home.packages array. On my Alpine installation I have the following:

...
  home.packages = with pkgs; [
    brave
    vscodium
  ];
...

Notice the with pkgs; section. This prevents you from having to add the pkgs prefix to every package you want to add. I don’t think this is the idiomatic way of adding packages to your configuration, but it allows me to be a bit lazier and it hasn’t caused any breakages yet.

Managing dotfiles and configuration #

Another amazing thing the Home Manager can do is manage your dotfiles. And this in turn can be managed with Git. More on this later.

Git configuration #

For instance, I have it manage my Git config using the git module. To do this, I have the something like the following in my home.nix:

...
  programs.git = {
    enable = true;
    ignores = [ "*.swp" ]; # I don't need to see that I still have a file open in vim
    signing = {
      key = "<gpg-fingerprint>";
      signByDefault = false; # it would probably be better for security to have this be true, but doing so gets annoying really fast
    };
    userEmail = "<user-email>";
    userName = "<user-name>";
    extraConfig = {
      init = {
        defaultBranch = "main";
      };
    };
  };
...

Here’s the list of options supported by the git module.

I strongly recommend digging through the documentation, looking for things that interest you in your current situation and setup.

Integrating existing (dot)files #

The Home Manager can also manage arbitrary (dot)files for you. I have it link my .zshrc into place with the following line:

...
  home.file.".zshrc".source = ./zshrc;
...

This looks for a file called zshrc in the same directory as home.nix. From there, it symlinks it to ~/.zshrc

It can also manage recursive file structures. I have it keep track of my sxiv configuration with the following few lines:

...
  home.file.".config/sxiv" = {
    source = ./sxiv;
    recursive = true;
  };
...

The interesting portion of this snippet is the recursive boolean. Because of this, Home Manager will recreate the directory structure found in ./sxiv in ~/.config/sxiv and symlinks the files found inside into place.

Git integration #

Since all the Home Manager requires is (at least) a single text file to manage your dotfiles and Nix environment packages, it’s really easy to keep track of your configuration using Git. To that end, I have a bare repository on one of my home servers over at /srv/git/nix/<nix-configuration>.git As a remote, I have pointed my repo in $HOME/.config/nixpkgs/ to <server-name>:/srv/git/nix/<nix-configuration>.git. This works over ssh. My $HOME/.ssh/config contains the following lines to make the preceding work:

Host <server-name>
	Hostname <ip-address>
	User git
	Identityfile ~/.ssh/<private-key>
	Port 4242
	IdentitiesOnly yes # this makes using an ssh agent a bit easier when using multiple keys on the same host