Help using a nixpkgs overlay in a flake

I have a flake called “Custom nixpkgs flake” that creates an overlay of nixpkgs and adds a package named hello-nix to nixpkgs. I have another flake called “local flake” that tries to consume that overlay, and use hello-nix in a devShell. For some reason this isn’t working, and instead is just throwing a sha hash mismatch when there shouldn’t be one.

The “Custom nixpkgs flake” looks like this:

{
  description = "Custom nixpkgs flake";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  };

  outputs =
    { self, nixpkgs,  ... }:
    let
      system = "x86_64-linux";
      pkgs = import nixpkgs {
        inherit system;
      };
    in
    {
      overlays.default = final: prev: {
        hello-nix = pkgs.callPackage ./pkgs/by-name/hello-nix/package.nix { }; 
      };

      packages.${system} = {
        hello-nix = pkgs.callPackage ./pkgs/by-name/hello-nix/package.nix { }; 
      };

    };
}

I have this file in a github repository at github:megaloblasto/custom-nixpkgs. In that same reporepository, in the location ./pkgs/hello-nix/ there is a package.nix file that looks like this:

{ lib
, stdenv
, fetchFromGitHub
, coreutils
, gcc
}:

stdenv.mkDerivation {
  pname = "hello-nix";
  version = "0.1";

  src = fetchFromGitHub {
    owner = "megaloblasto";
    repo = "hello-nix";
    rev = "master";  # You can specify a commit hash or a tag here if needed
    sha256 = "sha256-VP+R+GcvLOd+Hu1n0/zNoMCSVTnZXm44N+KJKQuQlfw=";
  };

  buildInputs = [ coreutils gcc ];

  # Build Phases
  configurePhase = ''
    declare -xp
  '';

  buildPhase = ''
    gcc "$src/hello.c" -o ./hello
  '';

  installPhase = ''
    mkdir -p "$out/bin"
    cp ./hello "$out/bin/"
  '';
}

This points to another github repo at github:megaloblasto/hello-nix/ which has the following hello.c file:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    printf("Hello from megaloblasto \n");
    return 0;
}

Finally, I have another local flake.nix file that looks like this:

{
  description = "local flake";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    custom-nixpkgs.url = "github:megaloblasto/custom-nixpkgs";
  };

  outputs = { self, nixpkgs, custom-nixpkgs, ... }:
      let
        system = "x86_64-linux";
        pkgs = import nixpkgs {
          inherit system;
          overlays = [ custom-nixpkgs.overlays.default ];
        };
      in
        {
          devShells.${system}.default = pkgs.mkShell {
            name = "default";
               
            packages = [
              pkgs.hello-nix
            ];

          };
        };
}

When I run nix develop using this local flake, I get the error:

error: hash mismatch in fixed-output derivation '/nix/store/f6dbmpb4w7m8yyn9yfyd013zx6dcblja-source.drv':
         specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
            got:    sha256-VP+R+GcvLOd+Hu1n0/zNoMCSVTnZXm44N+KJKQuQlfw=

But, as you can see, I did change the sha hash to the appropriate value. Furthermore, if I run nix build .#hello-nix in the “Custom nixpkgs flake”, hello-nix builds flawlessly.

What am I doing wrong here? Why can’t I consume this overlay, and why is it giving me a sha hash mismatch?

You probably forgot to update the “local” flake. Run nix flake lock --update-input custom-nixpkgs.

As an aside:

should probably really be:

overlays.default = final: prev: {
    hello-nix = prev.callPackage ./pkgs/by-name/hello-nix/package.nix { }; 
};
1 Like

Thank you so much. That was exactly it. I thought it had to do with some cache needing to be updated but I had no idea how.

Also thanks for the aside. That was extremely helpful as well.

A slightly more complete answer might be:

  outputs =
    { self, nixpkgs,  ... }:
    let
      system = "x86_64-linux";
      pkgs = import nixpkgs {
        inherit system;
        overlays = [ self.overlays.default ];
      };
    in
    {
      overlays.default = final: prev: {
        hello-nix = prev.callPackage ./pkgs/by-name/hello-nix/package.nix { };
      };

      packages.${system} = {
        inherit (pkgs) hello-nix; 
      };

    };

Where pkgs is set using the overlay defined in the flake, and it can be used for packages and development environment as well, without making use of callPackage twice.

1 Like

Yes, but be aware of: 1000 instances of nixpkgs

Generally, import nixpkgs is discouraged, the blog post goes into more detail about the nuance with this. Overlays are a bit of an anti-pattern in combination with flakes anyway.

This sounds like you think overlay’s shouldn’t be used with flakes. Is that true?

Depends heavily on project requirements.

Overlays are how you override things in nixpkgs instances, and great when you need to modify deeply nested dependency trees that you want to change across the board of a NixOS deployment or such. Other overlays can also apply first, which means users can change the dependencies of your package with a global override.

They’re however less useful when you just want to publish some packages, or only override a leaf package that isn’t depended on by anything else - they’re total overkill for that, since they require a nixpkgs eval to be able to work. Using the packages output will give you performance benefits and result in a more useful CLI experience. Overlays also depend on the nixpkgs they are being applied to, which means you get no reproducibility guarantee, unlike the packages output.

You can provide both, since users may want to choose which of the benefits they want. But you should probably not use import nixpkgs in the critical path for the packages output because that breaks the benefits of packages and basically just makes it a second overlay output… Which is why I somewhat disagree with @nbp 's suggestion. If you want to DRY that out, you can do that differently, e.g:

outputs =
    { self, nixpkgs,  ... }:
    let
      system = "x86_64-linux";
    in
    {
      overlays.default = final: prev: {
        hello-nix = prev.callPackage ./pkgs/by-name/hello-nix/package.nix { };
      };

      packages.${system} = let
        pkgs = nixpkgs.legacyPackages.${system};
      in
        # YMMV, there's probably a better way
        self.overlays.default pkgs pkgs;

    };

But I think choosing one output depending on the API you want to provide is usually better.

You also should not use overlays for your inputs if you can avoid it, which is the main anti-pattern; flake-parts offers better alternatives.

1 Like

I agree that having multiple Nixpkgs evaluation is bad, and I fully understand the problem.

However, I think that packages and devShell are meant to be used exclusively for command line usage, which we can thus limit to this one instance of Nixpkgs.

Making used of packages within overlays or within a module is bad, because it adds one extra instance of Nixpkgs evaluation.

Any artifact which is meant to be used and composed by another flake should remain independent of the Nixpkgs input.

Calling the overlay explicitly is a bad practice, this is not what overlay are meant for, and this would break the semantic of overlays which are meant to be involved in Nixpkgs fix-point, and this would still require one evaluation of Nixpkgs anyway. Thus you might as well evaluate Nixpkgs with the overlay, as it is meant to be.

1 Like

I’ve provided both packages and overlays in the “custom nixpkgs flake” because it provides a flake that can help with both iterative building of my custom packages (using nix build with the packages attribute) and provide an overlay for other flakes so they can access my custom packages and nixpkgs at the same time (using the overlay attribute).

There are a lot of little things that I want properly packaged in Nix that are of little to no use to other people, hence the need for a custom overlay. For example, I have programs that automatically update my specific waybar configuration, or programs that set up a very specific development environment for work.

That means packages will be exclusively used for command line usage, and only for package building.

That being said, do you still find this to be a design flaw? My understanding is that packages will only be evaluated with nix build ... and overlays will only be evaluated when consumed in another flake, so there will only ever be one Nixpkgs evaluation based on the usage. I could be wrong here.

Secondly, am I understanding you correctly that inherit (pkgs) hello-nix is equivalent to import nixpkgs?

Secondly, am I understanding you correctly that inherit (pkgs) hello-nix is equivalent to import nixpkgs?

inherit (pkgs) hello-nix is literally equivalent to hello-nix = pkgs.hello-nix;.
And nixpkgs.legacyPackages is equivalent to import nixpkgs {}.

Thus, @TLATER example and my example are importing nixpkgs once to evaluate the packages.


edit: nixpkgs.legacyPackages actually evaluates Nixpkgs twice, as it does an import ./. {}, and then calls extend out of the first Nixpkgs evaluation.

1 Like

AIUI the eval cache currently only works on flake attributes, which would mean import nixpkgs {} isn’t quite equivalent.