This repository has been archived on 2026-08-30. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
dotfiles/docs/nix.md

4.7 KiB

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.<name> for assembly functions passed through module arguments.

Avoid:

{
  lib = dotfilesFunctions;
}

Use:

{
  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:

dotfiles.lib.mkHost { hostName = "neogaia"; }

Use:

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:

{
  inputs,
  lib,
  self,
  ...
}:

Use:

{
  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:

import ./flake inputs

Use:

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:

{
  config,
  lib,
  pkgs,
  registry,
}:

Use:

{
  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:

{ hostName, system ? "x86_64-linux", ... }:
mkHost { inherit hostName system; }

Use:

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:

let
  inherit (lib) mapAttrs;
in
mapAttrs f attrs

Use:

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:

let
  hostNames = lib.attrNames hosts;
in
{
  names = hostNames;
  count = lib.length hostNames;
}

Use:

{
  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:

let
  inherit (lib) mapAttrs;
in
mapAttrs f attrs

Use:

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.<name>.<output>. nix flake show displays public outputs.

Avoid:

# flake.nix
let
  mkHosts = hostsDir: ...;
in
{
  nixosConfigurations = mkHosts (self + "/hosts");
}

Use:

# 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:

{
  lib = flakeAssembly;
  nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts");
}

Use:

{
  nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts");
}