Fixing Unified Flakes, Home-Manager + NixOS

I’m trying to get a bit more organized with my flake setup, so I took some inspiration from kradalby’s dotfiles and hammered out a mostly working configuration.

The lingering hangup I found was something like the following:

error: The option `home' does not exist. Definition values:
       - In `/nix/store/8n4fljw8rafsy42gspsqgdga9hcr767b-source/[a relative path from my flake].nix':
           {
             ...
           }

I was at it for hours, commenting out files that I thought were the problem and chasing my tail.

Finally, I came across this fantastic discussion which led me to the solution. @noah kindly pointed a user toward their dotfiles. Lo and behold, after a quick rg users of that repo, I found many of these lovely lines:

modules/common/shell/starship.nix
9:  home-manager.users.${config.user}.programs.starship = {

I then went about changing all of my old plain references from home (without a prefix, which work fine in home-manager alone) to home-manager.users.${config.user}.home and, voila! My configuration is saved.

I should also mention that this goes for other home-manager related things like programs or services.

Huge thank you to noah and all of the other fine folks on this platform. You all make Nix a fun and challenging hobby!

Edit: I spoke too soon!

Now I’m running into this error:

error: attribute 'user' missing
       at /nix/store/ix77vybfp6gk4j31p72sh01xs60bl56l-source/home/vscode.nix:3:24:
            2| {
            3|   home-manager.users.${config.user}.programs.vscode = {
             |                        ^
            4|     enable = true;
       Did you mean users?

Searching for an answer once again…

1 Like

They will have a module like:

{
  options.user = mkOption {
    type = lib.types.string;
  };

  config = {
    user = "jim";
  };
}

somewhere in their config.

I’m not particularly fond of this because that value is effectively supposed to be a constant. If you go down this path, I’d suggest adding your username to _module.args instead of using a config module - at this point you’ve already made the username an argument to the system config, rather than a simple option, no need to dance around it.

So something like:

# flake.nix
lib.nixosSystem {
  specialArgs = {
    inherit inputs;
    username = "jim";
  };
};

# ... OR, if you intend to always use the same username

# configuration.nix
{
  _module.args.username = "jim";
}
# vscode.nix
{ username, ... }: {
  home-manager.users.${username}.programs.vscode.enable = true;
}

I’d like to add that these issues stem from trying to mix home-manager and NixOS modules into one. I’m not sure why so many people are fond of doing this - you’re really muddying the waters between user and system configuration, which isn’t great architecturally. Your system effectively provides an API to your user - by mixing the modules and creating cross-dependencies you tightly couple these, which makes it really hard to change anything about this later (if e.g. you want another user or you want to deploy home-manager standalone), and reduces the barrier for doing stuff your user should have no business doing. It’s also what drives this need for an additional input and that awkward option name split across many modules - you’re effectively making your NixOS configuration require specifying who the sole user is.

2 Likes

Thanks for the quick response!

Your qualms with this approach make a lot of sense. I really appreciate the feedback. Would you recommend splitting the configs then?

(if e.g. you want another user or you want to deploy home-manager standalone)

Coincidentally I got into this because I want to be able to handle my three systems: two non-NixOS systems with home-manager and my NixOS desktop.

Previously I had two separate repos for NixOS and home-manager. I was running a home-manager flake on top of my NixOS system with independent system user and home-manager configs. Now that I write this it sounds like that’s more of a feature of home-manager than a bug.

That’s pretty much what I do, so I can hardly say I wouldn’t recommend it. I don’t think your current setup is workable at all if you intend to deploy home-manager standalone.

I’d suggest putting the two configs in the same flake, though, just in different directories (i.e. a monorepo), so that you don’t need to manage your home-manager config as a flake input.

1 Like

@TLATER is right, here is where I define the user option, and I pass it to my configs with a constant defined in my top-level flake.nix here.

Totally reasonable arguments in favor of splitting up the config, however I chose not to for a few reasons. I think they might be worth mentioning just to provide the other perspective:

  1. I find it annoying to have to run multiple commands/rebuilds to deploy my full system as I would like it to exist. Splitting the code into system vs user breaks the cozy feeling that I get knowing that a single output can reproduce my entire system from beginning to end.
  2. All my machines are single-user devices (other than system users). In my own code, I try not to refactor for complexity that doesn’t exist yet. This won’t apply to everyone, of course!
  3. There are quite a few areas of desktop Linux where my home-manager configs and system configs are tightly coupled. For example, I have a module where I enable the Nautilus file manager and Sushi file previews at the system level while providing the relevant keybindings and xdg settings at the user level. Here’s another example where I replace sudo with doas and add the appropriate sudo alias in my fish shell. While it’s easy enough to split them out, to me that feels more muddled, not less.
  4. I can still use home-manager to apply homeConfigurations that are sourced from the nixosConfigurations directly if I want to apply them on their own (which is rare).

There are many ways to do it — just make sure that it makes sense to you. Use others’ configurations as a starting point but if there’s too much “magic” or abstraction going on then focus on a simple setup that you can understand from the ground up.

2 Likes

Thank you both for your input! I wish I could mark them both as solutions as this is all very valuable.

I will take this all into consideration as I continue to refactor my config layout. Thankfully I was intentional enough to set up my merged configs on a separate branch so I can switch back and forth easily. This has been a fantastic learning experience and I look forward to continuing down this path.

1 Like