How to pass unstable to nix modules imported from configuration.nix?

I’m sure I’m missing something obvious (still learning), but reading Module - NixOS Wiki didn’t help me…

I have refactored my configuration.nix to import most specific things like this:

# configuration.nix
{ config, pkgs, ... }:
let
  unstable = import <nixos-unstable> { config = { allowUnfree = true; }; };
in {
  imports = [ 
    ./hardware-configuration.nix 
    ./pkgoverrides.nix
    ./fs.nix 
    ./kernel.nix
    ./xserver.nix
    ./users.nix
    ./custom.nix
    ./conffiles.nix
    ./virtualisation.nix
    "${builtins.fetchTarball "https://github.com/Mic92/envfs/archive/main.tar.gz"}/modules/envfs.nix"
  ] ++ (if builtins.pathExists ./cachix.nix then [ ./cachix.nix ] else []);

and e.g. virtualisation.nix starts with:

# definitions for virtualisation
{ config, pkgs, ... }:

let 
    unstable = import <nixos-unstable> { config = { allowUnfree = true; }; }; # unstable for virtualisation because podman has new fixes
in

{
    virtualisation = {
        podman = {
            enable = true;
            dockerCompat = true;
            # podmanPackage = unstable.podman;
        };
    };
...

But this means in every module where I need unstable I need to define it, though I’d rather just pass it from the importing file (configuration.nix)

However, if I start the imported file with:

{ config, pkgs, unstable, ... }:

this doesn’t work. So how to pass unstable from the importer to the imported file?

And what does ... mean in the parameter list of the module?

In one of your modules you can add unstable to _module.args, like this:

{
  _module.args.unstablePkgs = import <nixos-unstable> { config.allowUnfree = true; };
}

Then you can use unstablePkgs in the other modules argsets. Of course you can use any other name you like.

2 Likes

Thanks, that worked perfectly!

Should I have known this “normally” or is this feature hidden somewhere deep in documentation?
(Just asking because I often find it a challenge to find something in the docs, maybe I’m just searching wrong?)

I guess that the ... in the param list also has to do with this in some way, probably only covers builtins or something though?

_module.args is not documented properly. I am only aware of it, because I am using flakes, and needed some way to pass my inputs through and therefore dug some flake related code, where _module.args was mentioned as a better alternative for the documented but flake specific way of doing it. Sadly this mention was only in a comment.

The ... in the argument set, just means “accept any other argument that is passed in”.

{ foo }: foo would only work if called with an attribute set that contains only foo. { foo, ... }: foo though would be callable with any attribute set that contains at least foo.

1 Like

If you’d like to understand why _module works, this is kind of the entrypoint into that: https://github.com/NixOS/nixpkgs/blob/4e2861e270b534ddb29aac99cd99295339fc0400/nixos/lib/eval-config.nix

And yeah, I also started reading this while learning flakes, they just make it so much more obvious how it all works, so figuring out where to start reading is much easier.

2 Likes