How do I add configurable arguments to flakes?

Hi. I’m new to discourse.

I’ve been trying to migrate some of my default.nix and shell.nix files in my projects to use flakes instead. In my old default.nix I have several function arguments that I would set with --arg options to nix-build. These arguments would let me do things like, turn on coverage testing, enable/disable the checkPhase, test out an entirely different haskellPackages set from a different version of ghc, and similar for coqPackages, change from stdenv to clangStdenv, and so forth.

I haven’t been able to find the idiomatic way to replicate these build arguments using flakes.

Thanks for your help.

As far as I can tell, this isn’t possible with flakes. The best thing you can do probably is provide every variant you might be interested in at a different attribute path in the output and then select the one you want on the CLI.

ping to the person who posted this link recently:

I haven’t played with it or anything, but the readme says it does what you want I think.

1 Like

One way to do this is to use an external JSON file. Flakes seem to make this unnecessarily difficult by preventing you from referring to individual files, only flakes, but here’s an example of how to do this:

In your normal flake.nix, add an input with type = "path", like

{
  description = "An example flake";
  inputs = {
    nixpkgs = {
      url = "/home/apoelstra/code/NixOS/nixpkgs/master";
    };
    config = {
      type = "path";
      path = "/home/apoelstra/code/nix-setup/flakes/config";
    };
  };

  outputs = { self, nixpkgs, config }: {
    defaultPackage.x86_64-linux =
      with import nixpkgs { system = "x86_64-linux"; };
      stdenv.mkDerivation {
        name = "hello";
        src = self;
        buildPhase = ''
          gcc -o hello ./hello.c
          echo Done
        '' + (if config.echoTwice then "echo Done2" else "");
        installPhase = "mkdir -p $out/bin; install -t $out/bin hello";
      };
  };
}

(Apologies for the hokey build script here, I took the standard “hello world” example and tweaked it until things worked.)

Then create a new directory ../config/ with the files config.json containing your actual configuration

{
  "echoTwice": true
}

and a flake.nix which just converts the JSON into a flake:

{
  description = "Converts JSON into a flake";
  inputs = {
    nixpkgs = {
      url = "/home/apoelstra/code/NixOS/nixpkgs/master";
    };
  };
  outputs = { self, nixpkgs }: nixpkgs.lib.trivial.importJSON ./config.json;
}

Finally, to change your configuration, you need to update config.json and run nix flake update in your main project to pull the changes in.

I suspect that some part of this could be simplified.

You can avoid most of this indirection if it is possible to have your config.json in the repository that you’re building. For example

{
  description = "JSON Config example";
  inputs = { 
    nixpkgs = { 
      url = "/home/apoelstra/code/NixOS/nixpkgs/master";
    };  
  };  
  outputs = { self, nixpkgs }: (nixpkgs.lib.trivial.importJSON ./config.json) // {
    packages.x86_64-linux.default = (import nixpkgs { system = "x86_64-linux"; }).stdenv.mkDerivation {
        name = "hello";
        src = self;
        buildPhase = "echo Hmm";
        installPhase = ''
          mkdir $out
          cp ${./flake.nix} $out/flake.nix
          cp ${./flake.lock} $out/flake.lock
          cp ${./config.json} $out/config.json
        '';
    };  
  };  
}

Is a complete flake that has access to an arbitrary configuration file (which it copies into its output to help with traceability). If users edit config.json they will get a warning about the git repo being dirty but it will work.