Home-manager installation questions

First let me describe my current NixOS installation, in my configuration.nix I set the NIX_PATH like this:

  nix.nixPath = [
    "nixpkgs=/path/to/my/nixpkgs"
    "nixpkgs-overlays=/path/to/my/overlays"
  ];

because I don’t use channels, and I want to try my own nixpkgs modifications before opening a PR.

I want to achieve something similar with home-manager, but I’m a bit confused because reading the project documentation seems like there are only two options to install it:

  • using channels: I’d like to avoid channels since I don’t use the nix-channel command anymore
  • Install it as NixOS module: In that case, I’ll need to run sudo nixos-rebuild switch to update my user config, while I’d prefer to use the home-manager command

There is also a home-manager package on nixpkgs, but that is not mentioned in the documentation, what is its purpose?

For now, I came with this solution:

  nix.nixPath = [
    "nixpkgs=/path/to/my/nixpkgs"
    "nixpkgs-overlays=/path/to/my/overlays"
    "home-manager=/path/to/my/home-manager"
  ];

users.users.myuser.packages = [
      (pkgs.writeScriptBin "home-manager" ''
        #!${pkgs.bash}/bin/bash
        export HOME_MANAGER_CONFIG=/path/to/my/dotfiles/home.nix
        exec ${pkgs.home-manager}/bin/home-manager "$@"
      '')
    ];
  };

I’m also wrapping the home-manager executable to modify the default home-manager config path. The problem here is that I think that I’m not using my local home-manager checkout, but the once provided by nixpkgs.

One last question, looks like home-manager is doing 2 different things, managing your dotfiles and installing some programs (like with nix-env -i). Is it ok if I install git with environment.systemPackages and then use home-manager to only manage my .gitconfig file? Or is it recommended to not mix systemPackages and home-manager?

Indeed. What you could do is set pam.sessionVariables.HOME_MANAGER_CONFIG in your home-manager configuration. There is a bit of a bootstrap problem though.
Same with the nix.nixPath, that only gets set after the nixos configuration has been switched and after a fresh user session has been created.

Another option is to put that wrapper script into the repository that contains all your nix configuration. This would force you to go to that folder to do the switch but it solves the bootstrap problem.

One last question, looks like home-manager is doing 2 different things, managing your dotfiles and installing some programs (like with nix-env -i ). Is it ok if I install git with environment.systemPackages and then use home-manager to only manage my .gitconfig file? Or is it recommended to not mix systemPackages and home-manager ?

In general, if a program is enabled in home-manager, home-manager tends to also install it in the user profile. If git is also installed on the system level it’s not a problem as it will be shadowed by the one provided by home-manager (because of the ordering in the PATH).

thanks for your answer, I liked the wrapper idea, and end with this solution:

let
  home-manager = { home-manager-path, config-path }:
    (pkgs.callPackage (/. + home-manager-path + "/home-manager") { path = "${home-manager-path}"; }).overrideAttrs (old: {
      nativeBuildInputs = [ pkgs.makeWrapper ];
      buildCommand = ''
        ${old.buildCommand}
        wrapProgram $out/bin/home-manager --set HOME_MANAGER_CONFIG "${config-path}"
      '';
    });

in rec
{
  # ...
  users.users.${mainUser} = {
   # ...
    packages = [
      (home-manager {
        home-manager-path = "/local/checkout/home-manager";
        config-path = "/local/dotfiles/home.nix";
      })
    ];
  };
}

It seems to work as expected, using my local home-manager version.
I notice that setting home-manager on NIX_PATH is useless, because it will be overridden by home-manager script:

https://github.com/rycee/home-manager/blob/6c7a0313673687368a33197e58bc28f4290ec244/home-manager/home-manager#L65-L75

I have one last question, why are you using pam.sessionVariables and not home.sessionVariables or systemd.user.sessionVariables ? I’m not sure which one to use

Mostly cargo-culting from previous configs. Looking at the home-manager modules it seems like home.sessionVariables is the one being used now. Probably the pam-one is only usable on Linux whereas home.sessionVariables seems to be more generic.

1 Like

If you want to rigorously separate system configuration from user configuration - for example to make your user environment portable to machines which you don’t control - you have to install home-manager in the user environment. It is not required to do this with nix-env or using nix-channel. You can also instantiate a nix-shell with the same version of home-manager that will handle your environment.

Let’s say your files live in ~/.config and the entry point to your configuration is ~/.config/home.nix. Then we can define a version of home-manager in sources.nix:

{ pkgs ? import <nixpkgs> {} }:
with pkgs;
{
  home-manager = let
    src = builtins.fetchGit {
      name = "home-manager";
      url = https://github.com/rycee/home-manager;
      ref = "release-20.03";
    };
  # `path` is required for `home-manager` to find its own sources
  in callPackage "${src}/home-manager" { path = "${src}"; };
}

Then you can instantiate your configuration in nix-shell by importing that definition:

$ nix-shell -E \
"with import <nixpkgs> {}; mkShell { buildInputs = [ (callPackage ./sources.nix {}).home-manager ]; }" \
--run "home-manager -f ~/.config/home.nix switch"

Of course your home.nix includes the same home-manager in the environment:

{ pkgs, ... }:
with pkgs;
let
  home-manager = writeShellScriptBin "home-manager" ''
    # `toString` is required to impurely track your configuration instead of copying it to `/nix/store`
    exec ${(callPackage ../home-sources.nix {}).home-manager}/bin/home-manager -f ${toString ./home.nix} $@
  '';
in
{
    home.packages = [ home-manager ];
}

That way you can update home-manager in sources.nix and just run home-manager switch to have it available.

This simplified version uses the system’s nixpkgs, but you could just as well specify one just for that user environment. Don’t forget that home-manager's release number should match that of your nixpkgs, otherwise you may get weird errors due to incompatible package definitions. On my machines I have the nix-shell invocation as part of an installation script, and also parameterize home-manager over different machine-specific configurations.

2 Likes