Why do I not have to pass input parameters to certain NixOS-modules?

I often see NixOS-modules, that define an import-set like

{ pkgs, config, lib }:
{
    # Actual module-code

but when those modules are imported in another module, pkgs, config, lib is not passed to it in the import-statement and possibly not even available by the importing module. See the NixOS-Wiki-entry for modules for an example:

hello.nix has an import-set of { lib, pkgs, config, ... }, but there are none of those parameters passed to it, when it’s imported in configuration.nix.

Even more so, the parameters in the import-set of configuration.nix seem not to be fixed. When I call nixos-rebuild switch, I also don’t specify those parameters, so where are they passed to configuration.nix or why is this not necessary?

If there exists documentation on this topic, I would be happy if someone could provide a link.

2 Likes

The module system passes the arguments to the modules.

hello.nix has an import-set of { lib, pkgs, config, … }, but
there are none of those parameters passed to it, when it’s
imported in configuration.nix.

It’s important to note that the imports in a NixOS module is
not an import statement, but a property of the module. I
haven’t looked into it, but I would assume that NixOS iterates
through the list of imported modules and simply calls them with
the same arguments its been called with.

I am not sure where those arguments are instantiated however…
probably somewhere in the nixos part of the nixpkgs repo

hello.nix is in the imports lists, but it isn’t actually imported by configuration.nix. It’s the code that merges all the config files together, applying the priorities expressed by the helpers like mkIf, mkForce and so on, that actually imports the modules.
I’ve only a partial knowledge of how this works but I think it’s important to understand the overall process of the generation of a new (system) configuration.
Tools like nixos-rebuild do evaluate (“instantiate” in Nix lingo) the <nixpkgs/nixos> and create the derivation for the system member of the returned map, usually.
This process locates the main configuration.nix and with the help of nixos/lib/eval-config.nix and lib/modules.nix merges together the configuration, creating that system derivation in the process.
Digging into lib/modules.nix you will find that such arguments are defined as entries in the specia _module.args map, but its definition is scattered and customized as needed (for example the configuration functions of the VMs defined for a test can access a nodes argument that contains the configuration of all of them).

It’s a pity I’m actually unable to tell you precisely all the arguments that are available by default, but maybe you will now dig into the code and tell us! Happy hacking!

1 Like

To dig deeper you may be interested in a more complete explanation of the process of generation and installation that almost any nix-based server configuration management tool uses the do the job, more or less…

2 Likes

Ok, so the module system knows how to handle inputs like pkgs, config and so on, right? Are you aware of a list of inputs, that can be specified in this way?

  • config which is the final value of the resulting configuration after applying all modules.
  • pkgs which represents the set of packages
  • lib which has some helper functions.
  • whatever got specified in any module thorugh _module.args.

In most cases the first 3 are enough to do everything you need. Though especially in flake contexts, it has become quite common to also add all or some of the flakes inputs via _module.args.

2 Likes

Thanks! That’s a great, short explanation :slight_smile:

You might also be interested in a question about import list vs. import function.