# Nix Conventions This document records local Nix style and design conventions. Use these conventions when changing this flake. Read this document with `docs/dictionary.md`. ## Names ### Reserve `lib` for `nixpkgs.lib` Use `lib` only for the base `nixpkgs.lib` value. Do not use `lib` for project functions. Use `dotfiles.lib` for library functions passed through module arguments. Use `dotfiles.` for assembly functions passed through module arguments. Avoid: ```nix { lib = dotfilesFunctions; } ``` Use: ```nix { lib = nixpkgs.lib; dotfiles.lib = dotfilesFunctions; } ``` ### Name project function namespaces by role Put pure project functions under `dotfiles.lib`. Put functions that create modules, systems, or assembly values under `dotfiles`. This keeps data-only functions separate from functions that carry flake context. Avoid: ```nix dotfiles.lib.mkHost { hostName = "neogaia"; } ``` Use: ```nix dotfiles.mkHost { hostName = "neogaia"; } ``` ## Function Arguments ### Use closed interfaces for assembly files and library files Use exact function argument patterns for assembly files and library files. The caller owns the argument set for these files. The imported file names each accepted attribute. The imported file rejects stale or accidental extra attributes. Avoid: ```nix { inputs, lib, self, ... }: ``` Use: ```nix { inputs, lib, self, }: ``` ### Pass function arguments explicitly Pass only the values an assembly file or library file needs. Bind `lib` to the base `nixpkgs.lib` value at the call site. Use `inherit` only 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 Files under `hosts/`, `guests/`, and `modules/` return NixOS modules. The NixOS module system owns their argument shape. Name each argument 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 its complete argument set to another function. Name each argument the wrapper uses before `...`. Forward the bound argument set unchanged. Avoid: ```nix { hostName, system ? "x86_64-linux", ... }: mkHost { inherit hostName system; } ``` Use: ```nix args@{ hostName, ... }: mkHost args ``` ## `let` Bindings ### Use `let` for named 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 ``` ### Keep `let` scopes local Place a `let` binding near the expression that needs it. Do not lift a value to a larger scope only for convenience. A larger scope makes the dependency look more important than it is. Avoid: ```nix let hostNames = lib.attrNames hosts; in { names = hostNames; count = lib.length hostNames; } ``` Use: ```nix { names = lib.attrNames hosts; count = lib.length (lib.attrNames hosts); } ``` ## 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 each function 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` 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 functions as public outputs unless an external consumer needs them. Keep internal functions in assembly files or `dotfiles` special arguments. Avoid: ```nix { lib = flakeAssembly; nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts"); } ``` Use: ```nix { nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts"); } ```