Construct a path in configuration.nix

My /etc/nixos/configuration.nix looks like this:

{ config, pkgs, options, ... }:

{
  networking.hostName = "wombat9000"; # Define your hostname.

  imports =
    [ # Include the results of the hardware scan.
      /etc/nixos/hardware-configuration.nix
      /home/amy/dotWombat/nixos/wombat9000.nix
      /home/amy/dotWombat/nixos/python2.nix
      /home/amy/dotWombat/nixos/python3.nix
      /home/amy/dotWombat/nixos/R.nix
      /home/amy/dotWombat/nixos/base.nix
    ];

}

That second import, /home/amy/dotWombat/nixos/wombat9000.nix contains a small bit of machine-specific configuration. I’d like to have the second import depend on the networking.hostname so I only have to change the hostname in one place. But if I try something like this…

/home/amy/dotWombat/nixos/${networking.hostname}.nix

I get an error.

# nixos-rebuild switch --upgrade
unpacking channels...
error: path '/home/amy/dotWombat/nixos/' has a trailing slash
(use '--show-trace' to show detailed location information)
building Nix...
error: path '/home/amy/dotWombat/nixos/' has a trailing slash
(use '--show-trace' to show detailed location information)
building the system configuration...
error: path '/home/amy/dotWombat/nixos/' has a trailing slash
(use '--show-trace' to show detailed location information)

Is there a way to do this?

I don’t know if it’s possible to interpolate a path. Anyway, you can just use a string and convert that to a path. A little less neat but it works:

builtins.toPath "/home/amy/dotWombat/${networking.hostname}.nix"
1 Like

Won’t this cause an infinite recursion? I tried to do a similar thing at some point but afaik, imports are resolved before the configs are merged and thus it is not possible to depend on config values to define the imports. Basically, when doing so, resolving the imports causes the config to be merged which causes the imports to be resolved, which causes the config to be …

I ended up creating a symlink with a fixed name on every server pointing to the file with that server’s machine specific config. And I added a snippet to the activation script to check these symlinks, just in case.

1 Like

You could try refering to config.networking.hostname from within the imported files. Not sure if that works with import paths, but I use it to fill in other fields:

1 Like

You could also do something like

let hostname = "wombat9000"
in
{
  networking.hostName = hostname;

  imports =
    [ # Include the results of the hardware scan.
      /etc/nixos/hardware-configuration.nix
      (/home/amy/dotWombat/nixos + "/${hostname}.nix")
      /home/amy/dotWombat/nixos/python2.nix
      /home/amy/dotWombat/nixos/python3.nix
      /home/amy/dotWombat/nixos/R.nix
      /home/amy/dotWombat/nixos/base.nix
    ];

}
3 Likes

That seemed promising. I tried changing the second import to

builtins.toPath "/home/amy/dotWombat/${networking.hostName}.nix"

and got this error

# nixos-rebuild switch --upgrade
unpacking channels...
error: undefined variable 'networking' at /etc/nixos/configuration.nix:9:46
(use '--show-trace' to show detailed location information)
building Nix...
error: undefined variable 'networking' at /etc/nixos/configuration.nix:9:46
(use '--show-trace' to show detailed location information)
building the system configuration...
error: undefined variable 'networking' at /etc/nixos/configuration.nix:9:46
(use '--show-trace' to show detailed location information)

So then I tried

builtins.toPath "/home/amy/dotWombat/${config.networking.hostName}.nix"

and got this error

# nixos-rebuild switch --upgrade
unpacking channels...
error: 'functionArgs' requires a function, at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/trivial.nix:291:42
(use '--show-trace' to show detailed location information)
building Nix...
error: 'functionArgs' requires a function, at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/trivial.nix:291:42
(use '--show-trace' to show detailed location information)
building the system configuration...
error: 'functionArgs' requires a function, at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/trivial.nix:291:42
(use '--show-trace' to show detailed location information)

Yes, I tried that and I think I got some sort of recursion problem.

I tried changing that second import to

      (/home/amy/dotWombat/nixos + "/${config.networking.hostName}.nix")

and got an infinite recursion error

# nixos-rebuild switch --upgrade
unpacking channels...
error: infinite recursion encountered, at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:62:71
(use '--show-trace' to show detailed location information)
building Nix...
error: infinite recursion encountered, at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:62:71
(use '--show-trace' to show detailed location information)
building the system configuration...
error: infinite recursion encountered, at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:62:71
(use '--show-trace' to show detailed location information)

So it looks like what I’m trying to do just isn’t possible.

The key to @lilyball’s approach is to assign your hostname to a variable using let and then use it to set both the path you want to import and networking.hostName.

In other words: (/home/amy/dotWombat/nixos + "/${config.networking.hostName}.nix") won’t work, but a combination of networking.hostName = hostname and (/home/amy/dotWombat/nixos + "/${hostname}.nix") should be fine.

I ran into the same problem you are and wound up using exactly the approach @lilyball suggests (modulo some variable names) to configure my systems.

2 Likes

That did the trick, thank you for the explanation! For anyone who discovers this thread later, here’s my revised (working) /etc/nixos/configuration.nix.

{ config, pkgs, options, ... }:

let hostname="wombat9000";
in
{
  networking.hostName = hostname;

  imports =
    [ # Include the results of the hardware scan.
      /etc/nixos/hardware-configuration.nix
      (/home/amy/dotWombat/nixos + "/${hostname}.nix")
      /home/amy/dotWombat/nixos/python2.nix
      /home/amy/dotWombat/nixos/python3.nix
      /home/amy/dotWombat/nixos/R.nix
      /home/amy/dotWombat/nixos/base.nix
    ];
}