I turn my eyes to Chapter 12, and learn:

A Nix channel is just a URL that points to a place that contains a set of Nix expressions and a manifest.

Neat. What does that mean?

$ cat ~/.nix-channels
https://nixos.org/channels/nixpkgs-unstable nixpkgs

I’ve got the URL. Let’s see what its deal is.

$ curl https://nixos.org/channels/nixpkgs-unstable
Redirecting to https://channels.nixos.org/nixpkgs-unstable

Oh. Weird. Maybe I should update it, and save myself the redirect. That’s a 302 redirect, too – huh. I wonder if this is for some usage analytics thing that’s not set up on the subdomain?

Following that URL gives me another redirect – a 301 this time – to https://releases.nixos.org/nixpkgs/nixpkgs-21.05pre271734.aed173ff970, which is an HTML page.

I’m probably not sending the right Accepts header to get the “real” responses here, am I? This is a dumb way to investigate this.

Anyway, it tells me some commands for editing ~/.nix-channels, which really do not feel necessary. I’ve gotta add GC roots by hand, but you’ll edit a text file for me? Whatever I’m over it.

nix-channel --update is the important command, which we’ve seen before. Oh! And the manual says that it works by downloading this file:


But that file does not seem to exist. I suspect documentation rot.

And that’s the end of the chapter.

Hmm. Okay. I have to say, I didn’t learn a lot from this chapter. I would like to understand what nix-channel --update actually does, though, so I try the man page.

It mentions nix-channel --rollback. I had suspected this existed when I saw the numbered channels-1-link symlink mirroring the profile-1-link type links in /nix/var/nix/profiles/per-user/ian. Could be neat, I guess? There does not seem to be an equivalent --list-channel-generations or whatever, but that’s fine. They’re symlinks! I’m not afraid of moving some symlinks around.

The man page contains this example of a rollback:

$ nix-instantiate --eval -E '(import <nixpkgs> {}).lib.nixpkgsVersion'

$ nix-channel --rollback
switching from generation 483 to 482

$ nix-instantiate --eval -E '(import <nixpkgs> {}).lib.nixpkgsVersion'

This is tickling some ancient memories, and I have so many questions about these lines but I know it will be a massive tangent, so I deliberately hold off.

It explains that channels_root exists for a multi-user installation, and that it links to the channels used by the root user. I don’t know why I have that, though. I don’t think I have a multi-user install. I certainly don’t have a daemon running or anything.

It’s interesting how being in unfamiliar territory makes everything feel so uncertain. It never occurred to me that channels_root referred to “the root user.” I thought root was like… like a GC root. Like a tree root, or something, something for bootstrapping packages. It’s a good example of a name that seems perfectly intuitive when you already know what it is, but is not intuitive if you don’t already know what it means.

Anyway. Moving on.

The man page tells me that I should be looking for nixexprs.tar.xz, not nixexprs.tar.bz2. Aha!

$ curl -L https://nixos.org/channels/nixpkgs-unstable/nixexprs.tar.xz -o nixexprs.tar.xz
$ xz --decompress nixexprs.tar.xz
$ tar xf nixexprs.tar
$ ls

Okay. Now we’re cooking.

Inspecting that directory, it looks like – well, it looks like an exact copy of the Nixpkgs git repository, as it stood at revision aed173ff970. Neat. Okay. So that’s not really magic at all. It downloads the contents, and puts it somewhere. Where?

$ readlink /nix/var/nix/profiles/per-user/ian/channels-1-link

That’s kinda weird. It’s a user environment? Like our profile links were? Huh.

$ tree /nix/store/98kbm9c2p7m8h1mjppvc0sam1vvkpz85-user-environment
├── manifest.nix -> /nix/store/7ql8mcd63f98janzqa70ijpbz5skz48d-env-manifest.nix
└── nixpkgs -> /nix/store/ys2x968psphylqb0gri928km5bny25ww-nixpkgs-21.05pre271444.9816b99e71c/nixpkgs

Definitely doesn’t look like the other user-environments.

I don’t know where manifest.nix came from. And it’s uglified; I can’t read it. But I can confirm that /nix/store/ys2x...99e71c/nixpkgs is in fact a copy of the Nixpkgs repo, just like the one I untarred (though it’s a different git revision than the one I downloaded because I haven’t nix-channel --updated since yesterday).

Okay! So we saw what it did, sort of. And I think we now officially understand ~/.nix-defexpr? How it’s managed; what it does? Why when we type nix-env -iA nixpkgs.hello, it ends up magically looking in the contents of some git repo? It didn’t need to be a git repo at all – any .tar.xz you download on the internet with the right shape could end up supplyin' packages. Good to know.

  • Why does the default install give me https://nixos.org/channels/nixpkgs-unstable which 302s to https://channels.nixos.org/nixpkgs-unstable?
  • What is a manifest.nix?
  • Why is the store object in ~/.nix-defexpr also called a user-environment?