Cross-platform flakes, what channel to use for nixpkgs?

At work we use flakes to build and as I’m working my way through moving them to 24.11 I got to wondering if we’re using the channel we should be using.

Some info that might be useful:

  • We almost exclusively build and deploy Docker images, and only for x86_64-linux.
  • We use a mix of languages, the parts written in Haskell are the heaviest users of Nix.
  • Our developers can choose to run Linux or Mac.
  • None of our developers run NixOS; it’s a mix of Fedora, Ubuntu, Arch, … and MacOS.

After reading Which channel branch should I use? I’m wondering how we should write the inputs of our flakes.

Until now we’ve used

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=24.05";
    flake-utils.url = "github:numtide/flake-utils";
  };

which I now realise isn’t that good. We probably should have preferred using a branch instead.

The link above says

  • On Linux (including NixOS and WSL), use nixos-*
  • On macOS/Darwin, use nixpkgs-*-darwin

and adds that

All of these “channel branches” follow the corresponding release-*

So, now that I’m moving the flakes to 24.11, should I use

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=release-24.11";
    flake-utils.url = "github:numtide/flake-utils";
  };

or should I, to increase the likelihood of increasing cache hits when building the local dev shells, make nixpkgs depend on the current system? Something like this (maybe not exactly like this, but hopefully my intention is clear)

  inputs = {
    nixpkgs.url = if builtins.currentSystem == "x86_64-linux" then
      "github:nixos/nixpkgs?ref=nixos-24.11"
    else
      "github:nixos/nixpkgs?ref=nixpkgs-24.11-darwin";
    flake-utils.url = "github:numtide/flake-utils";
  };

Is there a recommendation on this at all? What do others that use Nix in similar ways do?

Your second example won’t work since nix does not permit evaluating anything in the inputs; they must be static, at least to my knowledge.

My suggestion would be to think about what the use cases for these inputs are. What will this stuff actually be used for? Do you need consistency in dev environments? Are the flakes used for nix build? What do the developers actually use and do?

If it’s e.g. just for more convenient setup of dev environments, I’d take both channels and create a macos- and linux-specific devshell, and then make the correct systems use the correct devshells at runtime. That way you get the best UX from the devshell setup, and knowledgeable users can switch to the other shell if there is a need for some reason.

If it’s mostly for builds, I’d base it on the environment that will be deployed to. Here I’d imagine you want what your users develop with to be as close to the target as possible, or at least consistent, so that people don’t run into varied build problems depending on whether they’re developing on Linux or MacOS. The increased build cost is worth the trade-off.

You can of course still offer multiple packages, if exposing the complexity of “well, if it doesn’t build on your mac it likely means the linux packages are broken, use the mac package for now” is acceptable.

Either way, I don’t think there’s an easy rule of thumb here. nixos-24.11 is the easy middle ground, IMO, as that results in well-tested stuff that updates a bit slower. Plus the command-not-found stuff will be accurate if anyone uses that. The darwin side of NixOS is notoriously underfunded, so I’d prefer not to bog everything down by that, but if your developers are by large majority MacOS users, that may be better.

nixpkgs-* is also totally fine, by the way, it just runs fewer tests and doesn’t build the command-not-found cache. You still get the same cache hits as nixos-*. This can sometimes result in buggy software making its way through, but on the whole that’s probably unlikely (and less catastrophic) for your workflows, the extra tests are mostly NixOS-focused.

Do not use the release branches directly, you’ll get entirely unbuilt stuff.

Your current state is pretty terrifying, in any case. You’ll basically have no updates in 6 month intervals.

1 Like

My suggestion would be to think about what the use cases for these inputs are. What will this stuff actually be used for? Do you need consistency in dev environments? Are the flakes used for nix build? What do the developers actually use and do?

I’m not sure what you mean by “consistency” here. Do the nixos-X and nixpkgs-X-darwin branches contains different versions of tools, or just that some packages may be broken on one branch and not the other?

As I tried to explain, the flakes are used for nix build to get the Docker images. nix build is only required to work on Linux. The flakes are also used for nix develop, and that’s where we want flakes that work on both Linux and MacOS, ideally with as little fixing of broken packages as possible by us.

Either way, I don’t think there’s an easy rule of thumb here. nixos-24.11 is the easy middle ground, IMO,

Also on MacOS? So I don’t have to care about the text on Wich channel branch should I use?

if your developers are by large majority MacOS users, that may be better

Well, it’s not that they are a large majority, but given that we let developers choose between Mac and Linux it’d be nice if we could support development on both.

No, they’re both pointing at old commits on release-X, after hydra built them (and ran applicable tests). For example, the former points at 035f8c0853c2977b24ffc4d0a42c74f00b182cd8 and the latter points at 8e39f04b54a435f14b9c1d6a6caede0a0a9825b6. Currently the latter (darwin) happens to be on a more recent commit, but they’re built in parallel, so you can’t guarantee that one will be newer or older than the other.

I do think it’s rare to see a package work on darwin but not on linux, usually it’s the other way round, so using the darwin branch can be “safer” in that sense (and what I’d probably go with).

2 Likes

If you went with both branches, depending on which host OS, the versions would not match, and therefore be “inconsistent”. This might be ok for some use cases.

Given your description, I’d probably use both inputs, use the Linux-focused input for the things done with nix build, probably use the MacOS-focused one for nix develop, and if you do not mind small inconsistencies in specific software versions between the OSes, have something that instead uses a shell built from the Linux-focused input on Linux (e.g. using devenv or whatever).