# Nix Conventions This document records local Nix style and design conventions. Use these conventions when changing this flake. ## Names ### Reserve `lib` for `nixpkgs.lib` Use `lib` only for the base `nixpkgs.lib` value. Do not use `lib` for project helper functions. Use `dotfiles.lib` for pure project helpers passed through module arguments. Use `dotfiles.` for project assembly helpers passed through module arguments. Avoid: ```nix { lib = dotfilesHelpers; } ``` Use: ```nix { lib = nixpkgs.lib; dotfiles.lib = dotfilesHelpers; } ``` ## Imports ### Use closed interfaces for helper imports Use exact function argument patterns for helper imports with closed interfaces. A helper import has a closed interface when the caller owns the argument set. The imported file names each accepted attribute. It rejects stale or accidental extra attributes. Avoid: ```nix { inputs, lib, self, ... }: ``` Use: ```nix { inputs, lib, self, }: ``` ### Pass import arguments explicitly Pass only the values an imported helper file needs. Bind `lib` to the base `nixpkgs.lib` value at the call site. Use `inherit` for values that keep the same name. Avoid: ```nix import ./flake inputs ``` Use: ```nix import ./flake { inherit inputs self; lib = nixpkgs.lib; } ``` ### Keep NixOS module interfaces open NixOS modules accept extra arguments because the module system owns their argument shape. Name the arguments the module uses. Keep `...` so the module accepts standard module arguments and special arguments. Avoid: ```nix { config, lib, pkgs, registry, }: ``` Use: ```nix { config, lib, pkgs, registry, ... }: ``` ### Use `@` for forwarding wrappers Use `@` when a wrapper passes the complete argument set to another module function. Name the arguments the wrapper uses before `...`. Forward the bound argument set unchanged. Avoid: ```nix { dotfiles, ... }: dotfiles.guest { name = "sample"; } { inherit dotfiles; } ``` Use: ```nix args@{ dotfiles, ... }: dotfiles.guest { name = "sample"; } args ``` ## `let` Bindings ### Use `let` for important intermediate values Use a `let` binding when it names an important intermediate value. Use a `let` binding when it avoids repeated complex expressions. Do not use a `let` binding only to shorten a standard library call. Avoid: ```nix let inherit (lib) mapAttrs; in mapAttrs f attrs ``` Use: ```nix lib.mapAttrs f attrs ``` ## Standard Library Calls ### Qualify standard library calls in flake assembly Use qualified standard library calls inside flake assembly code. Use `lib.mapAttrs` instead of inheriting `mapAttrs` from `lib`. This keeps the source of helper functions visible. Avoid: ```nix let inherit (lib) mapAttrs; in mapAttrs f attrs ``` Use: ```nix lib.mapAttrs f attrs ``` ## Flake Assembly ### Keep assembly code under `flake/` Keep flake assembly code under `flake/`. Keep `flake.nix` focused on inputs and public outputs. The `outputs` function returns each public output as an attribute. An external flake reads public outputs through `inputs..`. `nix flake show` also displays public outputs. Avoid: ```nix # flake.nix let mkHosts = hostsDir: ...; in { nixosConfigurations = mkHosts (self + "/hosts"); } ``` Use: ```nix # flake.nix let flakeAssembly = import ./flake { inherit inputs self; lib = nixpkgs.lib; }; in { nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts"); } ``` ### Expose only supported flake outputs Use public outputs for the supported interface of this flake. Do not expose assembly helpers as public outputs unless an external consumer needs them. Keep internal helpers in `flake/` or `dotfiles` special arguments. Avoid: ```nix { lib = flakeAssembly; nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts"); } ``` Use: ```nix { nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts"); } ```