Installing multiple packages from unstable channel in configuration.nix

I just did my first install to see what NixOS is like and its great, but i would like to install multiple packages from the unstable channel on system install using the configuration file and i cant seem to understand how or find a solution for this.

As side questions:

  1. Would using the unstable release of NixOS allow me to do this?
    Like, does it use unstable by default and i could just get them by just normally adding them to the config?

  2. Is there a way to get the unstable channel using the config without having to do it beforehands from the terminal?

Please do your best to explain it to me like i am a 2 year old since this is how i feel. Thank you so very much!

This is definitely possible, but many ways lead to Rome. To understand this it’s important to first understand what NixOS releases and channels actually are.

I’m assuming some understanding of git here, but in case you lack that, “branches” are just different versions of the same project. You can treat them kind of like releases, since they get updated over time but retain their names, and you need to occasionally pull in the latest changes if you use them.

When you use NixOS, you are fundamentally always building some commit of https://github.com/nixos/nixpkgs. Nixpkgs also has two important branches at any point, one being the latest “stable” branch, currently nixos-21.11, the other being the “unstable” branch, nixos-unstable.

The nix-channel command basically exists to manage cloning nixpkgs, controlling the branch and commit and making it available to your configuration.nix. It doesn’t clone the branch directly though, instead NixOS uses “channels”, which refer to the latest “verified” commit of the associated branch. This is so that you can always have a version of the branch that actually has all the packages pre-built - if you rely on checking out branches directly you may catch Hydra with only some of the packages built, after all.

So, rephrasing what you want to do, you want to use both the stable and the unstable channel in your nixos config, that is, ask nix-channel to clone both (verified commits on) the branches, and make them available to your configuration.nix, and subsequently you probably want to know how to actually access both so you can mix and match.

Let’s see about getting both branches managed by nix-channel first. By default, most systems will have nixos-21.11 as their only channel - you can see which you have set using sudo nix-channel --list.

As an aside, note that your user may have a separate set of channels - it’s worth being acutely aware of this, because nix commands invoked without sudo will use and manipulate your user’s channels, which you need to update and manage separately. If they fall out of sync, you may have issues with GUI applications, servers on localhost and suchlike.

To add a channel to your root channel list, use for example:

sudo nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs-unstable

If you’d previously had a channel entry for stable, you should now have entries for both nixpkgs-unstable and nixpkgs in your sudo nix-channel --list. sudo nix-channel --update will now also update both of them.

So far so good, what you now need to understand is how nix-channel actually makes these channels available to your configuration.nix. This part of the nix pills explains this very well, but in a nutshell, there is an environment variable called NIX_PATH. Whenever you write something like <nixpkgs>, nix will look at that environment variable, look for the definition of nixpkgs in it, and substitute the path defined there. The channel aliases are all defined in this variable, and point to the checkout of the nixpkgs repository that nix-channel created.

So, with the channel we configured earlier, we can write:

import <nixpkgs-unstable> { };

And it will evaluate the unstable version of nixpkgs that your nix-channel command last cloned. That means we can do things like this:

{
  pkgs ? import <nixpkgs> { },
  unstable-pkgs ? import <nixpkgs-unstable> { }
}: {
  environment.systemPackages = [
    # Better stick to stable for GUI packages, graphics drivers
    # don't like mixing.
    pkgs.firefox
    # This *should* work OK though.
    unstable-pkgs.nano
  ];
}

And there we go, we’re mixing and matching between stable and unstable. If you’re curious about that ? stuff, remember that nix modules are ultimately functions, and you define their argument list. ? sets a default value if an argument isn’t given, and we use that here. By default, nixos-rebuild will make sure that the pkgs argument is set to whatever nixpkgs in NIX_PATH is set to already, I just like making that explicit for illustration here.

You might also wonder what version of nixpkgs the modules actually come from. By default, again, this is whatever nixpkgs in NIX_PATH points to. Mixing and matching modules is quite a bit harder than packages.

I’ve also hidden my answer to your first question in here; just setting the nixpkgs channel to the URL we used for nixpkgs-unstable will make your system use everything from the unstable branch. Lots of people do this, and it’s quite usable, but expect breakage every once in a while. The stable branch is more, well, stable, but you have big updates every 6 months that may cause a lot of issues at once, and need explicit upgrading. It’s a trade-off :slight_smile: Personally, I use stable, and occasionally pick a few packages from unstable when I really need them, but I do so rarely because this also means installing a lot of different versions of the same libraries, which eats disk space.

As for your second question, you might complain that this doesn’t seem very declarative. We’ll need to add these channels to our system before we install our configuration, and while it’s still better than all the imperativeness in traditional distros, it’s not great. This is fundamentally the problem that flakes intend to solve. They throw the concept of channels out of the window and just let you clone and manage nixpkgs branches directly, with tooling to support that. I’d recommend figuring them out if you truly want to solve declarative system configuration.

There is probably an alternative way through making a custom NixOS ISO, or manipulating the nixos-install command or such, but I find flakes a much better solution to the problem.

18 Likes

Just wow! Thank you for this great explanation!