How do I add a locally defined derivation to a flake?

very simple question. I have a derivation defined in a local file, inside the folder foundationdb/foundationdb.nix, and it’s a call to stdenv.mkDerivation. The code for it is pretty long, so I won’t include it, but this toy derivation gives the same proble:

{ pkgs ? import <nixpkgs> { } }:

pkgs.stdenv.mkDerivation rec {
  pname = "foundationdb";
  version = "1.0";
  src = ./.;
  installPhase = "mkdir -p $out";
}

So I want this to be an input to my dev shell defined in a flake. I’ve tried multiple things: importing the file in the packages attribute directly, adding it as an overlay as below, adding it to inputsFrom, and even as an input to the flake (but then it’d need to be a flake itself, and it’s a mkDerivation, but I thought i’d give it a shot) but nothing works (see the bottom for the error):

{
  description = "The development environment";

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

  outputs = { self, nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachSystem [ "aarch64-darwin" ] (system:
      let
        pkgs = import nixpkgs {
          inherit system;
          overlays = [ (self: super: { fdb = import ./foundationdb/foundationdb.nix { }; }) ];
        };
      in
      {
        devShell = pkgs.mkShell {
          src = [ ./. ];
          packages = with pkgs; [
            fdb
          ];
        };
      });
}

Simply put, it can’t find the file:

error: path '/nix/store/498vvy4jc019rzs8zxl887c3km89p932-source/foundationdb/foundationdb.nix'

This local importing works normally if I use a regular shell.nix.

How are you entering the devshell? I don’t see the same error message as you:

$ nix develop
error: cannot look up '<nixpkgs>' in pure evaluation mode (use '--impure' to override)

Anyway, the most conventional way to load package definition is with callPackage:

let
  pkgs = import nixpkgs { inherit system; };
in
{
  packages.fdb = pkgs.callPackage ./foundationdb/foundationdb.nix { };
  devShell = pkgs.mkShell {
    src = [ ./. ];
    packages = [ self.packages.${system}.fdb ];
  };
}

If you think self.packages.${system}.fdb looks goofy, you can put the definition in the let ... in block

I just do nix develop to try and get into the shell.

I don’t understand your solution… where in the flake is this let block? But in any case, callPackage also doesn’t work. The problem is with how flakes try to find their source files. This doesn’t work:

devShell = pkgs.mkShell {
  src = [ ./. ./foundationdb ];
  packages = with pkgs; [
    (pkgs.callPackage ./foundationdb/foundationdb.nix { })
  ];
};

with the above error of can’t find the source, but this does!!

devShell = pkgs.mkShell {
  src = [ ./. ];
  packages = with pkgs; [
  (pkgs.callPackage ./foundationdb.nix { })
  ];
};

I’ve looked all over in docs, blogs, forum posts and I can’t find the simple cause of this.

By the way, what do you mean by a dev shell? An environment where foundationdb’s output is available on the PATH or an environment from which foundationdb can be built, essentially the environment inside mkDerivation ?

If we assume the latter, I think you could just do devShell = pkgs.fdb
(there’s a cleaner way to do this, but that requires more changes to your code)

Assuming you are using git to track your flake – make sure the file you are trying to source is tracked by git (not necessarily commited, just staged is fine). Flake evaluation copies the code into the store before the actual evaluation happens. If flake is tracked in git – only the git tree is copied.

In your case if you want to use flake-utils to generate boilerplate, you could do something like this. I reformatted the code and added NOTE: comments.

# flake.nix
{
  description = "The development environment";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; # NOTE: enclosed in quotes, URL literals are deprecated
    flake-utils.url = "github:numtide/flake-utils"; # NOTE: Same as above
  };

  outputs =
    {
      self,
      nixpkgs,
      flake-utils,
      ...
    }:
    flake-utils.lib.eachSystem
      [
        "aarch64-darwin"
        "x86_64-linux" # NOTE: My system
      ]
      (
        system:
        let
          pkgs = import nixpkgs {
            inherit system;
            # NOTE: An overlay is not strictly necessary
            # overlays = [ (self: super: { fdb = import ./foundationdb/foundationdb.nix { }; }) ];
          };
        in
        {
          packages.default = pkgs.callPackage ./pkg.nix { };
          devShells.default = pkgs.mkShell {
            packages = [
              self.packages.${system}.default # NOTE: `self` allows referring to the flake itself, dogfooding outputs. I am not sure if `flake-utils` has a better way to address packages output for the same system but this works
            ];
          };
        }
      );
}

# pkg.nix
# { pkgs ? import <nixpkgs> { } }:
{ stdenv, ... }:
stdenv.mkDerivation {
  pname = "foundationdb";
  version = "1.0";
  src = ./.;
  # NOTE: Not a real install script, just an example
  installPhase = ''
    mkdir -p $out/bin
    cat <<EOF > $out/bin/hello
    echo 'Hello world!'
    EOF
    chmod +x $out/bin/hello
  '';

  # NOTE: just so `nix run` works
  meta.mainProgram = "hello";
}

Usage:

❯ which hello
hello not found

❯ nix build .  

❯ ./result/bin/hello 
Hello world!

❯ nix develop .

❯ which hello
/nix/store/9zlq1vpvfmc23kx1glvd4p2m8ik5q1j3-foundationdb-1.0/bin/hello

❯ hello
Hello world!

P.S. for the record – fdb is already packaged, fdbPackages.foundationdb71.

I always forget this (to me, strange) interaction between flakes and git. Thank you so much. Yes fdb is already packaged, but it’s an old version and it doesn’t build on aarch64-darwin; I’m working on packaging it for that.