Avoid repeating home-manager configuration for every host in flake.nix

I’m pretty new to nix and have setup home manager according to this guide: Getting Started with Home Manager | NixOS & Flakes Book. However i have several machines that runs nixos and want to configure them all to use the same home-manager configuration. Currently it looks like this nixos-config/flake.nix at 7733dea1f1f1e5c95104267cbb09365f3f3ff45e · zlepper/nixos-config · GitHub with the home manager configuration repeated for every single host, which seems a bit wasteful.

I have tried moving the configuration out into a let block before the nixosConfiguration blocks like this:

let
      ...
      homeMgr = home-manager.nixosModules.home-manager
      {
        home-manager.useGlobalPkgs = true;
        home-manager.useUserPackages = true;

        home-manager.users.rasmus = import ./home.nix;
        home-manager.extraSpecialArgs = {
          unstable = unstablePkgs;
          writerside = writersidePrPkgs;
        };
      };

  in {
       ...
    nixosConfigurations.home-laptop = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      specialArgs = inputs;
      modules = [
        ./home-laptop.nix
        homeMgr
      ];
    };
  };
}

However when i run that i get this error:

error:
       … while calling the 'seq' builtin

         at /nix/store/9xacbyc7dywnxssdz5xc2nyi7pj0hw3k-source/lib/modules.nix:320:18:

          319|         options = checked options;
          320|         config = checked (removeAttrs config [ "_module" ]);
             |                  ^
          321|         _module = checked (config._module);

       … while evaluating a branch condition

         at /nix/store/9xacbyc7dywnxssdz5xc2nyi7pj0hw3k-source/lib/modules.nix:261:9:

          260|       checkUnmatched =
          261|         if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then
             |         ^
          262|           let

       (stack trace truncated; use '--show-trace' to show the full trace)

       error: function 'anonymous lambda' called without required argument 'config'

       at /nix/store/9613fxrf433y10fz18ccixj4zpmdibzq-source/nixos/default.nix:1:1:

            1| { config, lib, pkgs, utils, ... }:
             | ^
            2|

I assume this has to do with the modules being called in a rather special way that i cannot use in the let block, however i’m a bit lost as to how to proceed from there?

Hey,
you need to write a module, i recommend you follow this wiki entry.
The main thing is that a module consists of a config, option and an optional imports block.
For your case this could look something like this:

# home-manager-module.nix
{ lib, config,  ... }:
with lib;
{
   options.my-option.enable = mkEnableOption "enable home manager with my settings";
   config = mkIf config.my-option.enable {
        home-manager = {
            useGlobalPkgs = true;
            useUserPackages = true;
            # I would put this elsewhere
            # users.rasmus = import ./home.nix;
   };
}
# flake.nix
{
       ...
    nixosConfigurations.home-laptop = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      specialArgs = inputs;
      modules = [
        ./home-laptop.nix
        ./home-manager-module.nix
      ];
    };

# configuration.nix
{
...

  my-option.enable = true
...
}


I hope that was helpful, feel free to ask follow-ups :]

1 Like

Thank you so much for taking the time to reply, it is extremely appreciated :smiley:

I have now tried splitting it out like you suggest (Which is also would i would really like to be my final-endgoal). Current attempt can be seen in this commit: Draft 1 for using home manager from a module · zlepper/nixos-config@f6b5295 · GitHub.

However now i get an error that the option home-manager does not exist:

error:
       … while calling the 'seq' builtin

         at /nix/store/9xacbyc7dywnxssdz5xc2nyi7pj0hw3k-source/lib/modules.nix:320:18:

          319|         options = checked options;
          320|         config = checked (removeAttrs config [ "_module" ]);
             |                  ^
          321|         _module = checked (config._module);

       … while calling the 'throw' builtin

         at /nix/store/9xacbyc7dywnxssdz5xc2nyi7pj0hw3k-source/lib/modules.nix:296:18:

          295|                     ''
          296|             else throw baseMsg
             |                  ^
          297|         else null;

       error: The option `home-manager' does not exist. Definition values:
       - In `/nix/store/bc950b2x0wh3ffv27wwl5cs8sda6if2i-source/home-manager-module.nix':
           {
             _type = "if";
             condition = true;
             content = {
               useGlobalPkgs = true;
           ...

(I have imported the home.nix file directly in the module for now, before i start messing with making it somewhat dynamic, just to only have one thing to be confused about at a time :sweat_smile: )

EDIT: Actually, think i got something working, just a second!

Alright, got it working!

The thing that was “tricking” me here, is that home-manager.nixosModules.home-manager is a nix module, not a function as I originally thought. Then the block after

      {
        home-manager.useGlobalPkgs = true;
        home-manager.useUserPackages = true;

        home-manager.users.rasmus = import ./home.nix;
        home-manager.extraSpecialArgs = {
          unstable = unstablePkgs;
          writerside = writersidePrPkgs;
        };
      };

is also a module, not an argument to that function.

Thus the thing that was missing from @lovirent’s suggestion was just to actually import the home manager module, either in the flake.nix file or in the new home-manager-module.nix file:


{lib, config, unstable, writerside, home-manager, ...}:

{
   imports = [home-manager.nixosModules.home-manager];

   options.use-home-manager.enable = lib.mkEnableOption "enable home manager with my settings";

   config = lib.mkIf config.use-home-manager.enable {
        home-manager = {
            useGlobalPkgs = true;
            useUserPackages = true;
            # I would put this elsewhere
            users.rasmus = import ./home.nix;
            extraSpecialArgs = {
                inherit unstable writerside;
            };
        };
   };
}

Full diff for anyone who comes from the future and need the entire context: Comparing f6b52958e7536b15d146fea846b1d2021b89e9ab..6bcc171d94af2561299324b16a7ee924599f7ce5 · zlepper/nixos-config · GitHub

woopsie,
glad to be of any help tho :slight_smile:

1 Like