One flake, multiple systems tracking different releases

Is it possible to define two nixosSystems in a flake which are pinned to different NixOS releases?

Yup, just have two different nixpkgs inputs to your flake, one for each system, and pin those to different versions :slight_smile:

This sounds very easy, but how can I pin this version. I haven’t found any example yet.

You can do explicit pinning by passing the revision in the input URL. If you just want to have e.g. 23.11 for one system and unstable for the other, add both to your inputs and pass the desired one(s) to each system. They will be pinned in you flake.lock and you can update them independently.

An example for what that could look like, from my nixos config: https://github.com/futile/nixos-config/blob/e1c6a21a48bd0ef0ddebd67370b376eb54ff92e2/flake.nix#L4-L47

See how I have some different nixpkgs- inputs, and also see the fish-tide input, which pins to a specific version of the repo.

Also see the official docs for the flake input schema: nix flake - Nix Reference Manual

Looking at your example I would expect your work-host to run nixos-2211 and your home-host to run nixos-2311. This would mean both run two completely different Gnome Versions and Kernel versions without explicitly pin every single package to use this nixos-version.

Is this possible?

Well, currently both run on nixos-unstable, but yeah, I could have them running on different nixos versions, i.e., one could run nixos-23.05 and the other nixos-unstable. It’s very possible, as you can see :slight_smile: You just use two different nixpkgs-versions as inputs, and then use one for one system, and the other one for the other. You can even upgrade the entries in flake.lock individually, i…e, nix flake lock --update-input one-of-the-two-inputs-only will only update one of the inputs.

I still don’t see it. I can only specify one inputs object and inside this object only one nixpkgs. How can I tell lib.nixosSystem to use nixpkgs-unstable for nixos-work and use nixpkgs for nixos-home?

  inputs = {
    nixpkgs = { url = "github:nixos/nixpkgs/nixos-23.05"; };
    nixpkgs-unstable = { url = "github:nixos/nixpkgs/nixos-unstable"; };
  };
  outputs = { self, nixpkgs, nixpkgs-unstable... }@inputs:
    let
      system = "x86_64-linux";
    in
    {
      #### This uses:  nixpkgs. No problem
      nixosConfigurations.nixos-home = nixpkgs.lib.nixosSystem {
        inherit system;
        modules = [
          ./hosts/nixos-home
        ];
      };

      #### This should use:  nixpkgs-unstable... How?
      nixosConfigurations.nixos-work = nixpkgs.lib.nixosSystem {
        inherit system;
        modules = [
          ./hosts/nixos-work
        ];
      };
    };
}
# ...
 nixosConfigurations.nixos-work = nixpkgs-unstable.lib.nixosSystem {
#...
  };
# ...

This does not work. This only calls the lib.nixosSystem function from nixpkgs-unstable in stead of nixpkgs. The work system will still run the version of nixpkgs

1 Like

Ah, yes. You also need to pass the unstable packages to the module system.
You can e.g.

upkgs = import nixpkgs-unstable { inherit system;  };
# ...
modules = [ 
  { nixpkgs.pkgs = upkgs; }
  # .. 
];

or maybe a bit less hacky via specialArgs = {pkgs=upkgs;}

2 Likes

Wait, what? How does nixpkgs-unstable.lib.nixosSystem get a handle on the other nixpkgs input? There are no channels involved, so it should not be able to get arbitrary nixpkgses out of thin air?

Edit: Yeah, it imports the eval-config from the input in question, and uses self.lib to eval. There’s no magic reference to a <nixpkgs> or inputs.nixpkgs or anything - what am I missing?

1 Like

When doing it this way I get the error:

Failed assertions:
       - Your system configures nixpkgs with an externally created instance.
       `nixpkgs.config` options should be passed when creating the instance instead.

But when using nixpkgs.config.pkgs it works!

upkgs = import nixpkgs-unstable { inherit system;  };
# ...
modules = [ 
  { nixpkgs.config.pkgs = upkgs; }
  # .. 
];

This problem was bothering me for months already. I feel I have entered a new NixOS level. Thanks!

Maybe of help for others, here is a complete example:

{
  inputs = {
    nixpkgs = { url = "github:nixos/nixpkgs/nixos-23.11"; };
    nixpkgs-unstable = { url = "github:nixos/nixpkgs/nixos-unstable"; };
  };

  outputs = { self, nixpkgs, nixpkgs-unstable... }@inputs:
  let
    system = "x86_64-linux";
  in
  {
      nixosConfigurations.nixos-home = nixpkgs.lib.nixosSystem {
        modules = [
          ./hosts/nixos-home
        ];
      };

      nixosConfigurations.nixos-work = nixpkgs-unstable.lib.nixosSystem {
        modules = [
          {
            nixpkgs.config.pkgs = import nixpkgs-unstable { inherit system; };
          }
          ./hosts/nixos-work
        ];
      };
    };
  }
}
1 Like

That was also my first thought, but then there is also automatic passing of arguments to modules and nixpkgs somehow being treated as a special name.

Yes, but all of that happens within the module system. At the flake.nix level there should not be automated anything, and if you remame the nixpkgs input to something else the whole system doesn’t break.