Nix Overlays: Add attribute to “lib” and avoid “infinite recursion error”

Published by Philipp Schuster on

The other day, I was about to add an attribute to pkgs.lib using a nixpkgs overlay. There is a small and subtle pitfall when doing so, which made me create this short blog post.

A basic overlay looks like this:

(final: prev: {
  new_attribute = "foobar";

By looking at the architecture diagram, we see that both prev and final refer to what pkgs is, just in different “generations” (or iteration steps) in the evaluation of the final nixpkgs instance. So, when we want to add something to lib, we must add it to prev.lib to follow the intented usage of overlays.

As each nixpkgs instance is recursive in the sense of that pkgs.pkgs.pkgs.pkgs.lib is valid, once must be careful that you merge new functionality with prev.lib and not prev.pkgs.lib. Otherwise, you get an infinite recursion error. (I’m not exactly sure why it happens, but I know how to prevent it – that’s the sublte pitfall I encountered).

So, to properly extend pkgs.lib in an overlay, do the following:

(final: prev: {
  // Caution: This may override existing properties! This only works if
  // you add or entirely replace top-level attributes of `pkgs.lib`.
  lib = prev.lib // {};

If you do it like this, i.e., lib = prev.lib and not lib = prev.pkgs.lib, you get rid of an infinite recursion error and the intented outcome. However, be aware that
{ a = { b = "b";}; } // { a = { c = "c"; }; })
evaluates to
{ a = { c = "c"; }; }.
So if your overlay is not strictly additive to the toplevel attributes of pkgs.lib (or entirely replaces one), you need a deep merge.

Philipp Schuster

Hi, I'm Philipp and interested in Computer Science. I especially like low level development, making ugly things nice, and de-mystify "low level magic".


Leave a Reply

Your email address will not be published. Required fields are marked *