How do pass attribute sets correctly when dealing with nix-darwin?

Im currently trying to understand and modify dustinlyons/nixos-config. Im struggling with some details about how to pass the inputs attribute-set correctly to the place I want. The flake.nix looks something like this

# flake.nix
{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05";
    darwin = {
      url = "github:LnL7/nix-darwin/master";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    nixvim.url = "github:dc-tec/nixvim";
  };
  outputs = { self, darwin, nixpkgs, nixvim } @inputs:
  let
    system = "aarch64-darwin";
    pkgs = nixpkgs.legacyPackages.${system};
  in
  {
    # Some more stuff
    darwinConfigurations = {
      machine = darwin.lib.darwinSystem {
        inherit system;
        specialArgs = { inherit inputs; };
        modules = [
          ./hosts/darwin
        ];
      };
    };
    # Some more stuff
   };
}

and host/darwin has a default.nix file that looks something like this

# hosts/darwin/default.nix
{ config, pkgs, ... }:
{
  imports = [
    ../../modules/darwin/home-manager.nix
    # Some more stuff
  ];
  # Some more stuff
}

and modules/darwin/home-manager.nix contains something like this

# modules/darwin/home-manager.nix
{ config, pkgs, lib, home-manager, ... }:
let
  user = "test";
in
{
  # Some more stuff
  home-manager = {
    useGlobalPkgs = true;
    users.${user} = { pkgs, config, lib, ... }: {
      home = {
        enableNixpkgsReleaseCheck = false;
        packages = pkgs.callPackage ./packages.nix { };
        stateVersion = "24.05";
      };
    };
  };
  # Some more stuff
}

and packages.nix

# packages.nix
{ pkgs }:
with pkgs;
[
  dockutil
]

What I want is to change the last file to

 # not yet clear what else is needed...
with pkgs;
[
  dockutil
  inputs.nixvim.packages.aarch64-darwin.default
]

There are two things that confuse me:

  • What exactly is passed when listing modules in this block of code
      darwin.lib.darwinSystem {
        inherit system;
        specialArgs = { inherit inputs; };
        modules = [
          ./hosts/darwin
        ];
      };
  • when calling the import keyword in hosts/darwin/default.nix which arguments are we passing here by default? I read through this article here but I don’t think it answered the question… I also found this, but it seemed to rather explain something related instead of the actual question… In short, is inputs here passed to hosts/darwin/default.nix and can I thus change it just to
# modules/darwin/home-manager.nix
{ config, inputs, pkgs, lib, home-manager, ... }:
let
  user = "test";
in
{
  # Some more stuff
}

and it will correctly pass it?

  • how exactly do you handle inputs with the pkgs.callPackage function? Do I need to pass inputs like this
  home-manager = {
    useGlobalPkgs = true;
    users.${user} = { pkgs, inputs, config, lib, ... }: {
      home = {
        enableNixpkgsReleaseCheck = false;
        packages = pkgs.callPackage ./packages.nix { inputs = inputs; };
        stateVersion = "24.05";
      };
    };
  };

Sorry if the questions are super basic, but Im really struggling with this passing around of attribute sets…

Nix’s module system has 5 automatically generated, automatically injected, and declaration-free parameters: lib, config, options, pkgs, and modulesPath. (modulesPath available only in NixOS)

To passing non-default parameters to sub modules, such as input, home-manager, you’ll need to use specialArgs = { key = value };, where the key will be used for name matching when inject parameters into submodule functions.

More detail:

1 Like

Thanks a lot for the answer! This was super useful.

I have one more question. If I pass specialArgs = {inherit inputs;} like this

darwinConfigurations = {
      machine = darwin.lib.darwinSystem {
        inherit system;
        specialArgs = { inherit inputs; };
        modules = [
          ./my_module
        ];
      };
    };

then I can do something like this in my_module

{
  config,
  pkgs,
  inputs, 
  ...
}:
{ 
  # more code
}

This worked great and I was able to use inputs, but I don’t understand how I can pass inputs to other submodules that I import into my_module.nix, i.e.

{
  config,
  pkgs,
  inputs, 
  ...
}:
{ 
  imports = [
    ./my_submodule_a
    ./my_submodule_b
  ];
}

where my_submodule_a looks something like this

{config, pkgs, lib, inputs, ...} : 
{
   # Some code using the above....
} 

I’ve read this here but it does not really explain how the arguments are passed…

Your my_module.nix, my_submodule_a & my_submodule_b all works the same, they all can use the inputs passed by specialArgs.

Hmm, Im not able to use it in a submodule, so I must be doing something else wrong…

Thanks a lot for the answers and the help!