It is possible to extend the regularly passed lib with your own functions by adding those as an overlay along these lines:
{ config, pkgs, ... }:
let
mylibOverlay = self: super: {
lib = super.lib // {
myNewFunction = args: ...; # Your custom function
};
};
in
{
nixpkgs.overlays = [ mylibOverlay ];
}
The module system semantics are quite particular, so it’s not unusual to run into this sort of confusion. Unfortunately the way nixos-rebuild encourages users to think about how modules end up determining the system configuration obscures the actual mechanism, and the NixOS code itself doesn’t necessarily help clarifying how it actually works. The best piece of explanation I’m aware of is @infinisil‘s The Nix Hour: https://m.youtube.com/watch?v=cZjOzOHb2ow&pp=ygUbVGhlIG5peCBob3VycyBtb2R1bGUgc3lzdGVt
That should eventually become a written article, someone just has to sit down and do it.
I tried your suggestion. It works if I use pkgs.lib.myNewFunction but not if I use lib.myNewFunction.
What is the difference between lib and pkgs.lib ?
Ah, that surprised me actually, but as I suspected it’s because how it’s wired up. lib is spliced in at the module system level (independent of NixOS and before any actual modules come into play), but pkgs is added later and set up to actually use overlays configured via module. See here how exactly it’s done, and especially that it doesn’t touch lib: https://github.com/NixOS/nixpkgs/blob/432b9bd6208071be5035efa7e275f906f252861c/nixos/modules/misc/nixpkgs.nix
You would need to also add this to specialArgs when calling nixos, in order for this to work well.
When using classic nix, this is problematic, since you cannot easily control the call to the nixos entry point, as it’s made by nixos-rebuild. With flakes, you can pass this into the usual nixosSystem function.
This has nothing to do with classic Nix or flakes, it’s just that nixos-rebuild happened to do it Wrong™ before flakes (by obscuring the actual invocation of evalModules with two magical layers of indirection and lots of impurity), and somewhat less wrong with flakes. All it really needs to do is build an expression you point it to and then run the resulting activate script on the target machine. There are some devilish details such as Nix version migrations, but it really doesn’t need to be as obfuscated as it is now.