Understanding scope of flake inputs in outputs, particularly overlays

I would like help understanding the scope of flake inputs. I generally understand the idea of inputs and outputs, and referencing the inputs within outputs, but I became confused when I tried to create an overlay that did some unusual things with the nixpkgs repo.

Here is my (probably) minimal example, I could reference the “nixpkgs-unstable” input as a path in the outputs.overlays attribute. Why couldn’t I reference it in a file in my repo via import like this: “(import ./packages/rpackages_overlay_flake.nix)”? Is it because import is not just a text substitution?

{
description = “Nix shell for working with R projects”;
inputs = {
nixpkgs-unstable = {
url = “github:NixOS/nixpkgs/nixos-unstable”;
};
};

outputs = {self, nixpkgs-unstable, …}@inputs: {
overlays = {
buildRPackage = final: prev: {
buildRPackage = prev.callPackage (nixpkgs-unstable + “/pkgs/development/r-modules/generic-builder.nix”) {
inherit (final.pkgs) R;
};
};
};

devShells."x86_64-linux" = {
  r-shell = let
    pkgs = import nixpkgs-unstable {
      system = "x86_64-linux";
      overlays = [
        self.overlays.buildRPackage
        (import ./packages/rpackages_overlay_flake.nix)
      ];
    };
    in
      pkgs.mkShell {
        name = "r-shell";
        version = "1";
        buildInputs = (import ./all_packages.nix {pkgs = pkgs;});
    };
  };
};

}

The motivation (skip if you dont care why I did this): The goal was to extend the R package set, and to replace some low level R packages that were out of date in nixpkgs. Overlays are the right tool for this, because the out of date CRAN version is completely replaced by the recent github version, simply adding the updated package to the package set would lead to naming issues or R packages just using the old version. Part of getting that to work was pulling in some nix files from nixpkgs, in particular “/pkgs/development/r-modules/generic-builder.nix”, which is used to make R packages in nixpkgs but never exposed in pkgs. It seemed better to get the code from it’s true source rather than just copying it locally and hoping the file never changed.

1 Like

Is it because import is not just a text substitution?

It’s not a text substitution. import is a normal function that returns the nix expression in the given file. The file you import does not have access to the bindings and arguments at the call site.

If you want to access nixpkgs-unstable in rpackages_overlay_flake.nix you have to explicitly pass it as a function argument:

# rpackages_overlay_flake.nix
{ nixpkgs-unstable }:

final: prev: {
  etc...
}

# flake.nix
overlays = [
  self.overlays.buildRPackage
  (import ./packages/rpackages_overlay_flake.nix {
    inherit nixpkgs-unstable;
  })
];
``
1 Like

Thank you, I see how that works now. I wrap the overlay (final: prev: {etc}) in a function that takes nixpkgs-unstable, and that is how nixpkgs-unstable (or any other flake input) gets into the overlay.