Do flakes also set the system channel?

Does the channel / commit / branch set in a flake also apply to commands such as nix-shell or nix-env? If not how do I set it?

Also, when I set nixpkgs.url to github:nixos/nixpkgs/nixpkgs-22.05-darwin, will rebuilding automatically fetch the latest commit of that branch and will commands like nix-shell automatically use the latest commit or the one that the system was built from when rebuild was last executed?


No, not by default. The “system channel” is in fact just what nixpkgs is set to in NIX_PATH, so we need to set up nix.config.nixPath so that the nixpkgs entry points to the version of nixpkgs provided by our flake. @NobbZ has the most correct implementation of this I’ve seen:

This avoids some pitfalls with using store paths in the nix path, and also sets up the flake registry so nix shell nixpkgs#foo does what you think it does. I honestly think this should be set by default, but we’re not there yet.

It will make any invocation of <nixpkgs> point to the nixpkgs maintained by the flake, which is what most old nix commands use. You can then remove any channels you used with nix-channel (and sudo nix-channel), and all nix commands will still function.

You should probably also use the new commands where possible, though :slight_smile:


I have to admit, that when removing all of roots channels, the handy command-not-found feature will stop to work and throw you an ugly error on an unknown command.

For that to work, roots nixos channel has to stay and kept roughly up to date and that channel has to follow a nixos-* branch that the command-not-found can find its database.

There is an option that would allow you to specify a different location for that DB, though I do not know how to get or build one, as the used DB is different from nix-index.


By accident I found this post again, and I have to add, that I found a solution in the meantime, you can read about this solution in my blog:


Huh, interesting. I’ve not been paying attention to those suggestions, so never noticed.

I think I’m still partial to removing the root channel, simply because it prevents the usual issues of accidentally installing things from channels you’re not expecting, as well as the issue of forgetting to update something you don’t regularly use. Especially so if it will actually have an effect on the running system.

I wonder what it would take to file out edge cases like this and clean up the workflow of making a full system depend on flake inputs upstream. I guess it will be a bit painful for as long as we have both flakes and channels, since the tools that continue to use channels will probably continue to see development that doesn’t test the edge case of what happens if there isn’t a root channel…

I guess for the moment the suggestion should be to switch to nix-index, or turn off the fancy suggestions altogether?

I know that nix-index maintains their own version of the command-not-found script, that would be compatible with their DB, though I have never been able to get that working.

command-not-found is easily fixed.
Add the channel as input

inputs.nixos-channel.url = "";

get the DB out in an overlay

programs_sqlite = runCommandLocal "programs_sqlite" { } ''
  cp ${inputs.nixos-channel}/programs.sqlite $out

change dbPath

programs.command-not-found.dbPath = pkgs.programs_sqlite;

Thanks for this, this helps at least with keeping the DB in a window with my actually used channel.

But is there a way to make sure I use the exact DB for my commit?


All available versions are listed here Channels for NixOS project(s)

Command locations are not changing that often so it is fine to use a slight more out of up to date one.

Is it also possible to extract the channel url from the channel that serves as the flake input?

I do not think flakes really know or care about channels, they just track a branch in a Git repository. And the fact that some branches are updated when channel advances is not really expressible in Git.

But if the flake is set to follow the release-branch, then it should be possible to use sth. like

inputs.nixos-channel.url = ""

(modulo the build number) where the commit-id-part is determined from the lockfile…

Lack of command-not-found behavior has bugged me ever since I deleted my channels, so I made a rather more involved solution which always gets the programs.sqlite associated with the exact commit your input is set to. See the commit to my personal config repo here:

Assuming you follow a ref which corresponds to a channel, I think this should always work, though integrating it into your own config will take some adjustment.


  • my.lib.mkShellScript is a minor convenience wrapper around pkgs.resholve.writeScript. In this case, all it really does is add the interpreter attribute.
  • inputSpecs is calculated from (import (self + "/flake.nix")).inputs with a bit of code that translates url forms to attrset forms. See (EDIT: builtins.parseFlakeRef exists now for this purpose.)
  • hred is not packaged in nixpkgs yet (A shame. It’s the best html/xml data extractor around), but node2nix handles it with no tweaks. Or you could use xq from pkgs.yq to accomplish the same task. EDIT: It’s in nixpkgs now.

do a PR :slight_smile:

that only works if you’re on nixos-unstable or release and do not have any custom commits on top of it.

do a PR :slight_smile:

I probably should. I didn’t at first because I wasn’t familiar enough with nixpkgs’ node stuff, but I could figure it out.

that only works if you’re on nixos-unstable or release and do not have any custom commits on top of it.

Yeah, like I said, “Assuming you follow a ref which corresponds to a channel, I think this should always work.” If that assumption doesn’t hold, you either need to determine a “nearby” commit by whatever means is appropriate for how you consume nixpkgs and adapt this system to that, or you need to generate programs.sqlite yourself.

I’ve flakeified my system following a while ago, and just now noticed that the program I tested with nix-shell -p foo wasn’t the same that was installed when I then added it to my system configuration, and was quite surprised.

So I’m curious whether a single official best practice to tie NIX_PATH to the system’s flake configuration has already emerged? Is it on the way to becoming default (or at least added to the “official” instructions on the wiki)?

I don’t know if this is best practice, but this is what I do:

let nixPath = "/etc/nixPath";

  systemd.tmpfiles.rules = [
    "L+ ${nixPath} - - - - ${pkgs.path}"

  nix = {
    nixPath = [ "nixpkgs=${nixPath}" ];

Instead of using /etc/nixPath, you could of course also just set the NIX_PATH environment variable, but that would require closing terminals in order to pick up the new value, so the on-disk version is more flexible.

EDIT: just to clarify, doing this means that all your regular nix-* tools work as expected with flakes.

1 Like

Thanks @peterhoeg . I confirmed this works for me.

Another alternative that I found in lovesegfault’s dotfiles, is to create a symlink to the outpath.

He creates the symlink for NixOS systems here, and for nix-darwin systems here

Then it’s possible to set the nix.nixPath to the stable link created, which differs slightly between Darwin and Nixos. That’s done here.

I like this slightly more since it works even outside of Nixos, and doesn’t add the dependency on systemd.

I had originally thought to do this as an activationScript, but his approach seems much cleaner.


I think this is very similar to what I do here: ~r-vdp/nixos-config (main): modules/nix.nix - sourcehut git

Which was inspired by the blog post mentioned in the comment.

I think I have a similar problem at Getting older nixpkgs in nix-shell, if system uses nix flakes, does anyone have advice on that as well?