Reference path of locally built package

Hey there,

I’m currently starting to build packages, in order to get a grasp on how to do that and I’ve ran into the following issue…

I have successfully created some nix code that builds a package and I’m now trying to use it with callPackage and then reference the packages path:

{ pkgs, ... }:
let
  gatus = pkgs.callPackage ../../pkgs/gatus {};
in
{

  environment.systemPackages = with pkgs; [
    gatus
  ];
...
  systemd.services.gatus = {
...
    serviceConfig = {
      ExecStart = "GATUS_CONFIG_FILE=/etc/gatos/config.yaml ${pkgs.gatus}/bin/gatus";
      WorkingDirectory = "${pkgs.gatus}/bin/gatus";
    };
...
  };
}

Using this code and running a nixos rebuild-switch I get this error:

$ sudo nixos-rebuild switch 
building Nix...
building the system configuration...
error: attribute 'gatus' missing

       at /etc/nixos/modules/gatus/default.nix:18:63:

           17|     serviceConfig = {
           18|       ExecStart = "GATUS_CONFIG_FILE=/etc/gatos/config.yaml ${pkgs.gatus}/bin/gatus";
             |                                                               ^
           19|       WorkingDirectory = "${pkgs.gatus}/bin/gatus";
       Did you mean one of ats, bats, catfs, gams or gau?
(use '--show-trace' to show detailed location information)

So apparently I can’t reference the package using something like ${pkgs.packagename}. How can I reference it instead…

I didn’t really have any idea how to search for that kind of issue, but I did find nix-index, so I started a nix-shell, ran the indexer and searched for the package, this also didn’t return anything, while searching for other installed packages did…

Can anyone help me please? Thanks in advance!

Let’s think about it logically, knowing that Nix is pure, immutable language. The mere existence of a line like this:

let gatus = pkgs.callPackage ../../pkgs/gatus {}; in ...

does not mean that pkgs.gatus will exist. The pkgs variable will be as it was before you added that line because it’s immutable. So in your service definition, you can simply put "${gatus}/bin/gatus" instead of "${pkgs.gatus}/bin/gatus", because the gatus variable is in scope.

But if you did really want to have it in pkgs, NixOS provides a convenient API for that.

  nixpkgs.overlays = [(final: prev: {
    gatus = final.callPackage ../../pkgs/gatus {};
  })];

Now pkgs.gatus will exist. How NixOS does this is sort of complicated, but the very simplified version is that it uses laziness and a fixed point to both provide your config with pkgs, while extracting the overlays field from your config for use in the definition of pkgs. It’s all very recursive wibbly wobbly, but suffice to say that it does not require mutability or magical things.

In case you’re curious, here’s an incredibly simplified representation of what the code in NixOS sorta kinda looks like to accomplish this. Notice how both definitions utilize the other in a recursive fashion.

let
  pkgs = import nixpkgsPath {
    overlays = configuration.nixpkgs.overlays;
  };
  configuration = import yourConfigPath { pkgs = pkgs; };
in configuration