Is using the `./.` directory in flakes still an antipattern?

Is it ok to use ./. in flakes, or should I be using something like builtins.path { path = ./.; name = "mypkg" } instead? I’ve seen it mentioned on nix.dev that this is bad practice. I’m curious if the same applies for something like the following example:

{
  inputs = { ... };
  outputs = { ... }:
    ...
    {
      checks = {
        nixpkgs-fmt = pkgs.runCommand "check-nixpkgs-fmt"
          {
            buildInputs = [ pkgs.nixpkgs-fmt ];
          }
          ''
            mkdir $out
            nixpkgs-fmt --check ${./.}
          '';
      };

      packages.mypkg = naersk-lib.buildPackage {
        pname = "mypkg";
        root = ./.;
      };
    };
}

The linked page says it’s bad because the name given to the path in the nix store isn’t controlled, so the hash differs. This isn’t a problem in nix since it’s always named ...-source anyway. But using ./. is still likely to copy the directory an extra time into the nix store.

{
  outputs = { ... }: {
    foo = "${./.}";
  };
}

$ nix eval .#foo
"/nix/store/blrp8010cjvs8kv4jngvgj3fc6g5rvxc-dnpq4ndp6j41asnl6h5ylnl6hw7vyks3-source"

compared to:

{
  outputs = { self }: {
    foo = "${self}";
  };
}

$ nix eval .#foo
"/nix/store/xy6bd1cch2c36i8y3d4rqa1kqw4zpn6n-source"

Notice the double hash in the name in the first version. Nix copied the flake into the store and eval’d code from there. When it referenced ./., it copied the directory back into the store again.

2 Likes

Oh, so would it be a better idea (performance/space wise) to use self in flakes where I would otherwise use ./.?

I think using ./. (or in general specifying the project root; i.e., ./.. in a subdirectory) is an anti-pattern most of the time. You are specifying each file in the project (or each tracked file in the case of flakes) as a dependency, which is not true most of the time. The derivation will be rebuilt at each file change, and some of that rebuilds will be unnecessary.


Now back to your original question; reproducibility issue mentioned on nix.dev is not valid when using flakes because the directory and each tracked file is moved to Nix store and the evaluation happens on that directory in Nix store. Since Nix uses “source” as the directory name for the directory that the evaluation happens in, regardless of the original directory name, there is no reproducibility issue in this regard.


self is an attribute set that has an attribute named outPath that points to the source directory of the flake in the Nix store as a string with context and the attribute set can be coerced to that value with toString.

./. (assuming that is the project root) refers to the same directory as a Nix path. It can be coerced to string both explicitly or implicitly:

  • You can explicitly call toString to coerce to the path to a string with the same value as self.outPath but without a context.
  • Or, the path can be implicitly coerced to a string with "${./.}". In this case Nix will actually move the directory to another directory and the string will be the path of the new directory and it will have a context.

So, if you explicitly use toString with the Nix path (e.g. ./.) there shouldn’t be any inefficiency compared to using self.outPath. But I don’t think you should use the project root as a derivation source as is because of the reason I described in the first paragraph. You should probably filter the directory with builtins.path, nix-filter, etc.

1 Like