Why does overlaying `check` with `nodePackages.prettier` cause a massive rebuild?

Let’s use the following sample flake:

{
  inputs = {
    systems.url = "github:nix-systems/default";
    nixpkgs.url = "nixpkgs/nixos-unstable";
  };

  outputs = inputs:
    let
      eachSystem = f:
        let
          supportedSystems = import inputs.systems;
        in
        inputs.nixpkgs.lib.genAttrs
          supportedSystems
          (system:
            let
              pkgs = (import inputs.nixpkgs) {
                inherit system;
                overlays = [ inputs.self.overlays.default ];
              };
            in
            f pkgs);
    in
    {
      overlays.default = _: prev: {
        check = prev.writeShellApplication {
          name = "breaker";
          text = "echo 'hello'";
        };
      };

      devShells = eachSystem (pkgs: {
        default = pkgs.mkShellNoCC {
          name = "test";

          packages = [ pkgs.nodePackages.prettier ];
        };
      });
    };
}

In one of my project flakes, which has nodePackages.prettier in the development shell packages, I added an overlay for check, which is just a generated script. This was done just like in the example. This would serve as an “alias” of sort in the development shell, where I use it to run nix flake check at the root of the project. This was inspired by the following from flake.nix from the-nix-way/dev-templates. This works great, especially because aliases don’t work when entering the shell through direnv. No issues here.

However, in my project, I noticed that it would cause a massive multi-gigabyte download and rebuild where Nix would build systemd and Python packages, which should have no ties to the development environment. Removing the check overlay, fixed this, where Nix would source what was expected. Re-introducing the overlay for check caused the massive rebuilds and downloads again. If allowed to complete, after a few minutes, the environment did behave as intended, with check correctly being linked to the generated script and PATH appearing normal.

After some fiddling around, I determined that nodePackages.prettier was the culprit. Removing it from the shell packages would not produce the massive builds with the check overlay applied. Re-adding it re-introduced the issue. The example shows the basic needed to reproduce the issue. Either dropping the check overlay or nodePackages.prettier from the shell fixes it.

I realise that the overlay itself is not necessary, as the package can just be declared and built separately and added to the development shell packages directly, rather than through an overlay, whereby a “pure” instance of nixpkgs can be used to source nodePackages.prettier or anything else. Building the check script in packages.<system>.check and adding that to the packages with inputs.self.packages.<system>.check without the use of overlays, allows both it and nodePackages.prettier to be added without triggering the massive build.

However, I figured I’d ask here for educational purposes since I spent a few hours trying to figure out what is going on here to no avail. Some insight from those of you that are more experienced as to what causes this would be great. I’m eager to learn. Many thanks. :slight_smile:

Because it’s an actual package (nixpkgs/pkgs/development/libraries/check/default.nix at 343b0a2225308ff6b8f2a1638f8664bc4bc7037b · NixOS/nixpkgs · GitHub) and overlaying it will cause a rebuild of anything that depends on it (which appears to be 5000+ packages). Hence, I see your example as a massive misuse of overlays.

Yes, I realise that it is unnecessary as I mentioned towards the bottom of the post.

It doesn’t need to be correct. This was just educational to learn about the underlying mechanisms.

The aim here was to get some more insight into what was happening since I am still new to the Nix ecosystem.