Flake.lock for a multi host flake

I’m fairly new to nixos and the whole flake system. So far I managed to create a setup for three hosts manged by a single flake with a config folder for each host. My main problem (probably due to a lack of understanding the flake system properly) is that the flake will create a flake.lock in the top directory where the flake itself resides. If I do a nix flake update it will replace that flake.lock and when I commit this to the git repository that holds all the configurations, the flake.lock of the last host doing the update would be the one used for all systems.
Is there a good way to have the flake.lock on a per host basis, especially when I want them to be on different input versions?
I tried to use the nix command switches --reference-lock-file and --output-lock-file but those are not supported by nixos-rebuild or nixos-install.

Am I missing something obvious or is there a way to do this without having multiple branches per host or a symlink to a flake.lock for each host in the main folder?

The flake lock covers all inputs.

In your case is the issue that the different hosts have different inputs? Or that you want to manage the upgrade schedule and pinning individually for each?

  • If you want some on unstable and some on a release branch, you can simply define different inputs for each nixpkgs branch, and use them as/where appropriate.
  • You could also have three inputs, one per host, all following the same nixpkgs branch, and be careful to only update the host-specific input name each time.
  • If you want each to upgrade separately, when you’re ready, then a branch per host isn’t so bad, and you can use it to follow a CI-style strategy: do all changes on a dev branch, including lockfile updates. Then you can test build each host, and merge the changes to a host-specific branch when you’re ready for each to update to the current ‘known-good’ version.

Exactly. Some hosts are SBCs that are out in the field and I need to be carefull when and what I update there. So having an individual lock file for each host was my first preference.
Different inputs are not used by my systems (for now). So it really boils down to an individual update schedule.

Ok, as long as nixos-rebuild and nixos-install don’t support to specify a lock file I guess this is the only viable option that scales well with an increasing number of hosts. Having an input per host would be fine atm. but with more systems down the road I guess the flake would become somewhat bloated.

Thank you for the clarification and your suggestions. This seems to be a point that is often glossed over in all the flake beginner tutorials. But I still hope the nix option flags mentioned above will find their way into the other nix-* commands in the future. Since this would also simplify the CI like git approach.

If you’re scaling to lots of devices, the branch strategy will help - but instead of a branch per host, you can have a branch per “deployment group”. You can arrange devices into those groups however you like: odds/evens, 10% canary/20% early/70% stable, etc etc.

What about having multiple flakes, in different directories, instead of a single flake?

If I scale up to lets say more than 20 hosts I will do that, with my current nix skills a single flake would become unreadable if it manages too many hosts. For the future I will probably create a separate git and flake for each host group (Servers, SBCs, Desktop). I guess this is the easiest solution for me without having to do too much brain acrobatics when an update is due.

Options:

  1. Single repo multiple flakes:
  • hosts/
    • updateGroupA/
      • flake.nix
        • inputs.groupDep
        • outputs.nixosConfigurations.hostA
        • outputs.nixosConfigurations.hostB
    • updateGroupB/
      • flake.nix
        • inputs.groupDep
        • outputs.nixosConfigurations.hostC
        • outputs.nixosConfigurations.hostD
  • Run the update the directory.
  • You won’t need a different git repository.
  1. Multiple repo multiple flakes:
  • same as above but multiple repos instead of directories
  1. Single flake mutiple deps
  • flake.nix
    • inputs.groupADep
    • inputs.groupBDep
    • outputs.nixosConfigurations.hostA = groupADep…
    • outputs.nixosConfigurations.hostB = groupADep…
    • outputs.nixosConfigurations.hostC = groupBDep…
    • outputs.nixosConfigurations.hostD = groupBDep…
  • nix flake lock --update-input groupADep
  1. Abuse the follows of flake input.
  • flake.nix
    • inputs.dep
    • outputs.nixosConfigurations.hostA = dep…
    • outputs.nixosConfigurations.hostB = dep…
    • outputs.nixosConfigurations.hostC = dep…
    • outputs.nixosConfigurations.hostD = dep…
  • hosts/
    • dev/
      • flake.nix
        • inputs.dep
        • inputs.allHosts.src = “./…/…/”;
        • inputs.allHosts.inputs.dep.follows = “dep”;
        • outputs.nixosConfigurations = allHosts.nixosConfigurations
    • stage/
      • flake.nix
        • inputs.dep
        • inputs.allHosts.src = “./…/…/”;
        • inputs.allHosts.inputs.dep.follows = “dep”;
        • outputs.nixosConfigurations = allHosts.nixosConfigurations
    • prod/
      • flake.nix
        • inputs.dep
        • inputs.allHosts.src = “./…/…/”;
        • inputs.allHosts.inputs.dep.follows = “dep”;
        • outputs.nixosConfigurations = allHosts.nixosConfigurations

note: I’m not sure about some syntax but sure the feature exists

Thanks alot!
Option 4 looks intimidating to me atm. Could you provide a few keywords for me so I can read up on this approach? The role of the central flake is to generate the sources for the different host groups?

Is to be your “unstable” version with all your outputs.

But shouldn’t intimidate you.
Is just

  • one flake with all your hosts
  • other flakes the import your main flake
  • in this other flake you override the input
  • and re expose the outputs

Example:

{
  inputs.nixpkgs.url = "github:nixos/nixpkgs/unstable";
  outputs = { self, nixpkgs }: {
    nixosConfigurations.hostA = nixpkgs.lib.nixosSystem {
      modules = [ ./configurations.nix ];
      system  = "x86_64-linux";
    };
}
{
  inputs.allhost.url  = "./../";
  inputs.nixpkgs.url = "github:nixos/nixpkgs/release-23.11";
  inputs.allhosts.inputs.nixpkgs.follows = "nixpkgs";
  outputs = { self, nixpkgs, allhosts }: allhosts;
}

Awesome! Thank you so much for the explanation.