Interpolated relative paths within flake


I’m playing around with a nix flake to hold configurations for multiple systems and am looking for a good layout which allows for a sparse checkout to address information leakage between multiple hosts.

The layout looks roughly like this:

flake.nix  # should auto-detect nixos configs in deployments/
lib/*  # support functions for building the systems
modules/*  # functions which produce nixos modules (get the flake inputs passed as arguments)
machines/*  # functions which produce hardware configurations
deployments/*  # contains the different nixos configs composed from modules/ & machines/

I want to be able to auto-detect the nixos configurations in the deployments directory. I’ve written a small function for this in lib which uses readDir. And this is were the problem begins: At some point I need to interpolate the return values of readDir with deployments/ which causes deployments/ to be copied in the nix store although it is already part of the flake (but nix doesn’t know this) which is already in the nix store at evaluation time. As the nixos configs in deployments/ reference files in e.g. modules/ they use another relative import e.g. ../modules/xyz which fails to resolve because the flake uses the deployments/ from the nix store and then tries to evaluate ../modules/xyz (relative to the path pointing to the nix store) which of course doesn’t exist in the nix store.

Is there some way to work around this? e.g. to tell nix that “hey, the resulting path of the interpolation is still within the flake so you don’t have to copy it to the store”? I tried to use self.outPath of the flake in the nixos config but that sent the evaluation into an infinite loop.

Try using toString instead of interpolation to coerce the path into a string

Thanks for the tip but I had already tried that (sry didn’t mention it). In this case I get the error string ../deployments/xyz does not represent an absolute path. I think the inherent problem is that nix cannot ensure that the resulting path will be restricted to the flake itself. If xyz is the name of the deployment which is read from the directory it cannot ensure that someone doesn’t pass ../../../../foo (which wouldn’t be inside of the flake) to the interpolation/string concatenation

Just wondering if the Extending NixOS flakes article could be a (slightly different) solution to your intention?

Although, my initial guess would be that the outcome is that every “containment” requires its own git repo which could create some additional overhead :thinking:

@don.dfh thanks for the link, I’ve read the article a while ago when I was exploring different options for managing multiple hosts. The the multiple-git-repo issue mentioned by you was also the reason why I didn’t follow this approach.
As I want to restrict which files are transferred to which host I’d probably need quite a few repos. I think the editing & updating workflow would be a little cumbersome. I’ve tried a similar approach before using git branches instead of independent flakes and found that it didn’t work for me, e.g., there’s no easy way to nix flake check all deployments against the newest configurations. Most of these things could probably be solved by additional tooling but I wanted to see how far I can get with vanilla nix & git