I was recently made aware that the nixpkgs manual recommends against using lib.extend
to add custom functions to a config because doing so may cause interoperability conflicts with other modules. While I understand the concern and agree with the intent of the recommendation, I’d like to discuss a potential compromise that would, instead, recommend a best practice when using lib.extend
for custom functions.
In brief, the interoperability conflicts occur when lib.extend
is used to provide a custom function via lib.foo
without the knowledge that another module also relies on a “different” lib.foo
. Instead of using lib.extend
, the recommendation is to add a separate attribute, via specialArgs, that provides the custom function. In this case you would have a custom function provided through someCustomLib.foo
.
Functionally the recommendation above is reasonable, however in practice it is somewhat clunky in cases where both lib
and someCustomLib
are used in a module.
Consider the following rudimentary but real world example:
{
inputs,
lib,
configLib,
config,
pkgs,
...
}:
{
imports = lib.flatten [
inputs.disko.nixosModules.disko
(configLib.relativeToRoot "hosts/common/disks/btrfs-disko.nix")
# ...
My suggestion is that instead of recommending against using lib.extend
altogether, we could suggest a best practice that custom functions specific to a config be provided through lib.custom.foo
so that they are easily distinguished from lib.*
functions and unlikely to cause conflicts.
In my own nix-config flake I recently started to do so using:
lib = nixpkgs.lib.extend (self: super: { custom = import ./lib { inherit (nixpkgs) lib; }; });
Note that this approach also allows lib.custom
to propagate into hm. See: nixos: use `lib` argument instead of `pkgs.lib` by ThinkChaos · Pull Request #3454 · nix-community/home-manager · GitHub
Using this approach the previous example was refactored to:
{
inputs,
lib,
config,
pkgs,
...
}:
{
imports = lib.flatten [
inputs.disko.nixosModules.disko
(lib.custom.relativeToRoot "hosts/common/disks/btrfs-disko.nix")
# ...
Arguably, the difference is subtle and I may just be biased towards what I see as cleaner looking code, however, in modules where lib and a custom lib are used more heavily the result is more pronounced.
I’d like to get some thoughts from others and potentially submit a PR to update the manual or nix.dev whichever makes the most sense for providing best practices.
References:
The recommendation/warning in nixpkgs manual - Nixpkgs Reference Manual
The relevant commit for that section of the manual, which provides additional context for the recommendation -