Nix development
- Most projects should contain a nix flake in
flake.nixto provide devshell development environments, package builds, and OCI container image builds - Verify builds with
nix flake checkandnix build
Flakes and modules
- Use flakes for all nix projects, not channels
- Use hercules-ci/flake-parts to structure flake.nix files modularly where relevant
- package: nix/modules/{devshell,containers,packages,overrides}.nix
- Use nixos-unified for system configurations and autoWire for module discovery
- system: modules/{home,darwin,nixos,flake-parts}/
Best Practices
- Follow nixpkgs naming conventions and style
- Use
inputs.*.follows = "nixpkgs"to minimize flake input duplication - Place system-level config in modules/darwin/ or modules/nixos/
- Place user-level config in modules/home/all/ (cross-platform) or darwin-only.nix/linux-only.nix
- Use home-manager.sharedModules for platform-specific home configuration
Shell scripts and writeShellApplication
pkgs.writeShellApplication runs shellcheck during its checkPhase.
nix build --dry-run evaluates the derivation graph but does not execute build phases, so it will not catch shellcheck errors.
Run shellcheck <file> directly on shell scripts before committing.
This is faster than a full nix build and catches the same class of errors that checkPhase would surface.
A full nix build (without --dry-run) of the relevant derivation remains the definitive verification, as it executes checkPhase with the exact shellcheck configuration the derivation specifies.
Nix Code Style
- Format with
nix fmt - Use explicit function arguments, not
withstatements - Prefer
inherit (x) y z;overinherit y z; - Use
lib.mkIf,lib.mkMerge,lib.mkDefaultappropriately
