Questions on using NixOS desktop with flakes

I’ve successfully switched my NixOS desktop to use flakes, but there were a couple of places where I just guessed. Would love to know the authoritative answers to those questions:

  • How do I upgrade? I used to do nixos-rebuild switch --upgrade before. Am I correct that, while “nixos-rebuild switch” is flake aware, the --upgrade won’t update my lockfile and that I need to run nix flake update manually?
  • Should I doas nix-channel --remove nixos? My understanding is that with flakes the channel mechanism is completely unused, and so [doas] nix-channel --list should be empty.
  • What should I do with hardware-configuration.nix? The file has some ominous warnings about not being suitable for editing by hand, but I think in the nix world it should be manually maintained?
  • How does “configuration is looked up by host name” trick works, if the host name is configured in the config itself? Am I correct that, when installing nixos+flakes on a new machine, the intention is that the first time you switch to the configuration you set the host name manually on the CLI, and then it essentially becomes a fixed-point?


If you want to use the “command not found” feature within nixos, aactually keeping a nixos channel for root which points to a nixos-* would be easiest, as thats where the CNC database is looked up by default.

Alternatively you can speciify programs.command-not-found.dbPath to use another DB which yoou build manually r as part of your update flow. You can not build iit as part of a derivatiion though, as it requires internet access and is also not fixed output.

I keep it aroound for historical reasons and use it to maintain filesystems, everything beyond that is subject to change from my regular base file for that host anyway and just provides some sane defaults.

The attribute and the hostname have to match. Actually you do not need to specify it in the actual module anymorre, as some mmagic makes it inherited from the attribute name. And indeed the error message when they differ is… Confusing.

The intention is, that on first install you prepare yoour flake and then do nixos-install --flake github:you/your-flake#the-hostname and then set the password and then reboot.

Sadly, the last time I tried nixos-install --flake was just broken and did not work correctly and we regularly have questions in the discord that ask about exaactly same issues I experienced. Derivations try to access other derivations and for some reason they are resolved into the installation disk store rather than the installation target store and of course not found in the hosts store…

The usual recommendation is to just nixos-generate a minimal confiiguration, edit it to have nix.package = nixUnstable (or nix_2_4 nowadays) as well nix.extraConfiguration to enable the required experimental feaatures and a minimal network config, install based on that config, reboot, rebuild the system from the prepared flake.


This was true for a good long while. But I coulda swore I saw a PR not too long ago that finally addressed this. Can’t find it atm though unfortunately.

You can. I don’t keep any channels around, but it won’t be detrimental if you do. It would probably be better though to set nix.nixPath = [ "nixpkgs=${nixpkgs}" ] where the expanded nixpkgs in this case is a reference to the nixpkgs flake use to build your system. That way, any commands that reference the NIX_PATH used the same nixpkgs as the rest of your system.

It is fairly simple, nixos-(rebuild|install) accepts a flake fragment pointing to a hostname, e.g .#hostNameFragment. If you don’t pass this fragment, Nix will try to be smart and look at the current system’s hostname, and if it has a nixosConfiguration output with a matching name, it builds it. So, on initial install or if you decide to change your hostname, you’ll just have to pass this fragment on the first rebuild/install.

There isn’t any magic going on here. It’s just standard Nix that is tailored somewhat to your system. You can use it as it, copy parts of it to another file and delete the rest, whatever you want.

As an additional tip, It is also useful to pin nixpkgs in the registry if you are not already. Just makes commands like nix search a lot faster since it doesn’t have to query and pull from github after each ttl expiration. If the name of your nixpkgs flake is nixpkgs verbatim though, then you’ll want to set a fully qualified path to it to avoid an infinite regress, i.e. inputs.nixpkgs.url = github:NixOS/nixpkgs and then set nix.registry.nixpkgs = inputs.nixpkgs.


Aha, i think this is indeed what I need. To spell this more explicitly: in my flake.nix, I have

inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

The corresponding flake.lock pins that to a specific revision. Now, when I run something like nix shell nixpkgs#racket, that actually ignores my flake.lock altogether and uses nixpkgs from master (I think), which bypasses all kinds of caches.

So what I need to do is to somehow teach global nix commands to use my system-wide flake.nix, right?

How do I actually do that though? What “pin nixpkgs in registry” actually means? I skimmed the docs for nix shell and nix flake and didn’t find the answer.

EDIT: found nix registry

Figured pining out, I think. nix registry pin nixpkgs is actually not something I want for this use case. Rather, I need this

My final setup looks like this:

  # Use nixos unstable (aka rolling release).
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

  outputs = { self, nixpkgs }: {
    nixosConfigurations = {
      Ishmael = nixpkgs.lib.nixosSystem {
         system = "x86_64-linux";
         modules = [({ config, pkgs, ... }: {
           nix = {
             # Enable flakes.
             extraOptions = "experimental-features = nix-command flakes";
             # Make sure that stuff like `nix shell nixpkgs#racket` uses the
             # same version of nixpkgs as the rest of the system by pinning. 
             # Check `nix registry list` output to see the effect.
             registry.nixpkgs.flake = nixpkgs;

           # Call my computer Ishmael.
           networking.hostName = "Ishmael";

           # The rest of my old configuration.nix goes here ...