Is this overlay correct?

I’ve been having a lot of difficulty grokking overlays. I think I’ve finally figured it out, I just want to confirm my understanding. Does this flake.nix seem correct?

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        devShells.default = import ./shell.nix { inherit pkgs; };
        packages.default = pkgs.callPackage ./yyp.nix {};
    })
    //
    rec {
      overlay = final: prev: {
        yyp = final.callPackage ./yyp.nix {};
      };
      overlays.default = overlay;
    };
}

Full repo here.
One thing I wasn’t entirely sure about was whether I should be using final.callPackage or prev.callPackage. I think because I’m only using stable stdlib stuff it won’t make a difference in this case, is that right?

Looks fine to me, but one nit:

I would recommend not using rec if you can avoid it, it’s prone to causing confusing infinite recursion errors and makes understanding scoping trickier. With flakes you can do instead:

{
  overlay = final: prev: {
    yyp = final.callPackage ./yyp.nix {};
  };
  overlays.default = self.overlay;
}

Besides this, it’s custom to add your own namespace in the overlay so you don’t overwrite a nixpkgs package, not sure if that’s your intention here. Typically doesn’t matter in small ovrlays like this.

I also thought the single outputs like overlay were deprecated in favor of the default attributes. The nix manual still documents both, so maybe I misremember…

Not really.

final is kind of like the flakes’ self - you can use it to refer to things you are defining within your overlay.

prev on the other hand refers to the content of pkgs after the previous overlay was evaluated (overlays are defined in a list, and the order matters).

So, in your case it doesn’t matter, but if you made any changes to callPackage in your overlay, you would need to use final to refer to that changed callPackage, and prev if you wanted an unchanged one.

In practice I almost always use prev, it’s again less prone to confusing recursion errors, and usually I don’t want to use the attributes I’m currently setting - when I do, I use final to make this explicit.

2 Likes

Thanks very much!

Hm, it seems like the schema on the wiki doesn’t mention overlay, I assume you’re right and it’s on the way out.

I’m not sure I understand - suppose I created a yyp namespace and put the yyp package inside it - wouldn’t that overwrite any previously existing yyp in pkgs just as well?

I’ve incorporated the feedback:

diff --git a/flake.nix b/flake.nix
index 3d0806b..50188f8 100644
--- a/flake.nix
+++ b/flake.nix
@@ -14,10 +14,9 @@
         packages.default = pkgs.callPackage ./yyp.nix {};
     })
     //
-    rec {
-      overlay = final: prev: {
-        yyp = final.callPackage ./yyp.nix {};
+    {
+      overlays.default = final: prev: {
+        yyp = prev.callPackage ./yyp.nix {};
       };
-      overlays.default = overlay;
     };
 }

Yes, but think of it as future proofing - say you one day realize you want to add a second package, zyp. If you don’t have a namespace yet, you need to occupy another name in the global namespace if you want to add this package without breaking backwards compatibility with existing users. If you already have a namespace, you just add yyp.zyp.

You’d probably also pick a name that’s less likely to become a package in the future than yyp.

That said, whether you want to do this depends on your exact use case. It’s just custom to do so, and I thought I’d point it out in case you didn’t think of the fact that it is possible.

1 Like

Ah, makes sense. For now I am my only user and don’t anticipate adding any more packages. I’ll think about creating namespace if that starts to change!

1 Like