How to move Home Manager definition into a separate file

Dear NixOS people,

So far I used Home Manager in the usual way like:

# flake.nix
{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    home-manager.url = "github:nix-community/home-manager";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = inputs@{ nixpkgs, home-manager, ... }: {
    nixosConfigurations = {
      hostname = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          ./configuration.nix

          home-manager.nixosModules.home-manager
          {
            home-manager.useGlobalPkgs = true;
            home-manager.useUserPackages = true;
            home-manager.users.jdoe = import ./myapps.nix;
          }
        ];
      };
    };
  };
}

But I’d like to move it into a separate file like:

# flake.nix
{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    home-manager.url = "github:nix-community/home-manager";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = inputs@{ nixpkgs, home-manager, ... }: {
    nixosConfigurations = {
      hostname = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          ./configuration.nix
          ./home.nix
        ];
      };
    };
  };
}

# home.nix
{ config, ... }:

let
  all-users = map ( ... ) config... ; # using config.... to get user names
in
home-manager.nixosModules.home-manager {
  home-manager.useGlobalPkgs = true;
  home-manager.useUserPackages = true;
  home-manager.users = all-users;
}

So I can get list of users to configure based on values in config and then map over that list.

But I can’t make it work even when a single hardcoded user (without accessing config). Is this possible?

Thank you very much!

Peter

# home.nix
{ config, pkgs, inputs, lib, ... }:

let
  # collect all the created users names that are "normal users"
  userNames = builtins.attrNames (pkgs.lib.attrsets.filterAttrs (user: user.isNormalUser) users.users);
in {
  # import the HM system module *once*
  imports = [ inputs.home-manager.nixosModules.home-manager ];

  # configure HM
  home-manager.useGlobalPkgs = true;
  home-manager.useUserPackages = true;

  # create all the individual HM users if and only if they have an "entrypoint" file under `./home`
  home-manager.users = lib.mkMerge 
    (builtins.map (user:
      lib.mkIf (builtins.pathExists ./home/${user}.nix) {$user.imports = [ ./home/${user}.nix ];}
    ) userNames);
}

Something like this should work for all normal users that also have a home/$user.nix file relative to the home.nix.

This was written on a mobile with split screen and the docs open in the other “window” and is not tested. Therefore no guarantees, but I am happy to help improving that over the next days together with you.

2 Likes

Hello NobbZ!

Created an account to say thank-you for this post as it fixed some of the issues I was having. However I did have one question about your post.

I cannot get the userNames variable to work for me. When I user users.users as input I get an error saying that users is undefined. Then if I user config.users.users I get an infinite loop error. Do you know what might cause that?

Thanks in advance!

Created an account to say thank-you for this post as it fixed some of the issues I was having. However I did have one question about your post.

I cannot get the userNames variable to work for me. When I user users.users as input I get an error saying that users is undefined. Then if I user config.users.users I get an infinite loop error. Do you know what might cause that?

I suspect no one is really watching this thread now; if I were you I would make a new thread and post a link to that new one here :slight_smile: