Hello, I’m just starting to add a second machine to my nascent home manager configuration.
I’ve seen several examples where people have a common.nix
and then host specific host.nix
; however, I have several areas where my common stuff needs to differ only a little bit between hosts, for example:
programs.git {
userName = "foo"; # changes per host for work/personal
userEmail = "foo@foo.com"; # ^
extraConfig = {
core.pager = "delta";
# etc common config
};
};
In this example there are small pieces of the overall config that need to change per host, but the majority is the same. I have several pieces of config that are like this, e.g. my zsh config which sets work specific things in initExtra
and shellAliases
, etc. Duplicating all the common bits in the host.nix
s would lead to the common parts diverging accidentally.
What is the best method for not having to duplicate the common bits but allow each host to have the minor changes needed? Maybe this is where I need to start making my own modules; if that is the right approach is there any decently small examples of this use case I can pull from?
Thanks.
Create your own module(s) where you configure the bits that’s specific.
Alternatively, you can use a global variable to keep track of the machine and then just act based on that. Example:
{
programs.git = {
userName = {
machineA = "Peter Hoeg";
machineB = "James Bond";
}."${config.home.sessionVariables.HOSTNAME}";
extraConfig = {
core.pager = "delta";
};
}; ¤ programs.git = {
}
And then of course you just set home.sessionVariables.HOSTNAME
in the machine specific config file.
Thanks, I went ahead with the module route as it seems like the cleaner solution especially if I deploy to more hosts, but nice to know about the global variable option.
Here is what I ended up with currently:
modules/git.nix
{ config, lib, ... }:
with lib;
let cfg = config.programs.git;
in {
config = mkIf cfg.enable {
programs.git = {
# example global git config
extraConfig = {
url = {
"ssh://git@github.com/" = { insteadOf = "https://github.com/"; };
};
};
};
};
}
host.nix
{ ... }:
{
imports = [ ./modules/git.nix ];
home = {
stateVersion = "22.11";
username = "fortruce";
homeDirectory = "/home/fortruce";
};
programs.git = {
enable = true;
userName = "weasl";
};
}
Two follow-up questions based on this approach with modules:
-
Is there a simple pattern for importing all of my modules rather than explicitly importing them in each host.nix
that uses them? Maybe some way to import them at the flake.nix
level instead?
-
Say I wanted to add additional extraConfig
in my host.nix
that should be merged with the extraConfig
in the git.nix
module. Is there a good pattern for doing that? I guess I could make my own option in git.nix
e.g. extraExtraConfig
and merge it manually, but maybe there’s another way?
Well I guess #2 just works out of the box actually. I’m a bit confused about the order of it resolving modules and merging configs, but it seems that the following just works.
programs.git = {
enable = true;
userName = "weasl";
extraConfig = { test.test = "foo"; };
};
Merged automatically with the extraConfig
in git.nix
– cool!
1 Like
The module option is the cleaner way to do it, but there’s more boiler plate. As it means you need to create some options for the bits that change.
I’ll share some more details over the weekend.
2 Likes