Can anyone help explain to me how I pass values in Nix?

Don’t try to do that in the flake.nix. That way madness lies - if you don’t fully understand the nix language/module system yet, you will never get it to work, and if you do fully understand them, you completely lose separation of concerns and your code becomes a mess.

The style of your config comes from people reading guides on how to use various third party flakes that just show the minimum viable solution with no regards to code quality. I’d recommend a completely different approach.

Rather than this mess:

        modules = [
          ./general
          ./luna/configuration.nix
          home-manager.nixosModules.home-manager
          ({pkgs, myConfig, ... }: {
            home-manager.useGlobalPkgs = true;
            home-manager.useUserPackages = true;
            home-manager.sharedModules = [
              inputs.sops-nix.homeManagerModules.sops
            ];
            home-manager.users.kekkon = import ./general/home.nix;

            # Optionally, use home-manager.extraSpecialArgs to pass
            # arguments to home.nix
            home-manager.extraSpecialArgs = myConfig // {
              extraProfile = ''
                export NIXOS_CONFIG=/home/kekkon/nix-flakes/flake.nix
              '';
            };
          })
          vscode-server.nixosModules.default
          ({config, pkgs, myConfig, ...}: {
            services.atuin.enable = myConfig.enableAtuin or false;
            services.vscode-server.enable = true;
          })
          disko.nixosModules.disko
          sops-nix.nixosModules.sops
          ({...}: {
            nixpkgs.config.allowUnfree = true;
          })
        ];

Split all of that out into your NixOS modules. I’d start by moving the module imports to the imports of general/default.nix. Pass the various flake inputs to the module system with specialArgs so you can do that.

Next, grab the little inline modules you wrote and just expand them into general/default.nix. Ultimately you’ll have something like this:

# general/default.nix
{ inputs, ... }: {
  imports = with inputs; [
    home-manager.nixosModules.home-manager
    vscode-server.nixosModules.default
    disko.nixosModules.disko
    sops-nix.nixosModules.sops
  ];

  nixpkgs.config.allowUnfree = true;

  # home-manager options
  home-manager.useGlobalPkgs = true;
  home-manager.useUserPackages = true;
  home-manager.sharedModules = [
    inputs.sops-nix.homeManagerModules.sops
  ];
  home-manager.users.kekkon = import ./general/home.nix;

  # Optionally, use home-manager.extraSpecialArgs to pass
  # arguments to home.nix
  # This obviously won't work, make it a home-manager module instead
  home-manager.extraSpecialArgs = myConfig // {
    extraProfile = ''
      export NIXOS_CONFIG=/home/kekkon/nix-flakes/flake.nix
    '';
  };

  # vscode options
  services.atuin.enable = myConfig.enableAtuin or false;
  services.vscode-server.enable = true;

  # whatever other options you had in here previously
}

Besides the obvious readability improvements, this also allows you to use the NixOS module systen for DRY purposes. Importing general/default.nix is now enough to enable all those options, you don’t need to repeat them for each nixosConfiguration in your flake.nix.

Break the little subsections into other modules and add them to the general imports as you see fit, I can totally see having a separate module for your home-manager config for example.


After that, if you still want to go with your custom options approach, learn how to write a module for that and write one. You almost have one, but you need to add it to your imports or modules, and I suspect learn a bit about how the imports, options, and config sections and such work.

That said, I’ve personally done that before and found it rather cumbersome in the long run. Learning to use the NixOS module system (and especially lib.mkForce and lib.mkDefault) resulted in much better code quality.

Nowadays I would just write a module that you only add to those configurations which should have that stuff enabled. So your nixosConfigurations eventually looks like this:

nixosConfigurations = {
  luna = nixpkgs.lib.nixosSystem {
    system = "x86_64-linux";
    modules = [
      ./general
      ./general/autin.nix
      ./luna/configuration.nix
    ];
    specialArgs = { inherit inputs; };
  };

  sol = nixpkgs.lib.nixosSystem {
    system = "x86_64-linux";
    modules = [
      ./general
      ./sol/configuration.nix
    ];
    specialArgs = { inherit inputs; };
  };

  titan = nixpkgs.lib.nixosSystem {
    system = "x86_64-linux";
    modules = [
      ./general
      ./general/zellij.nix
      ./titan/configuration.nix
    ];
    specialArgs = { inherit inputs; };
  };
};

I’d even go a step further and only import those modules in the imports of the respective configuration.nixes to make all that completely opaque at the flake.nix level.

9 Likes