Boot entry management

all i know about managing boot entries so far is that you can do nix-collect-garbage and then nixos-rebuilt switch to remove old entries

what i want is:

  • remove one specific entry
  • rename an entry to something nice
  • pin an entry so it’s not deleted with collect-garbage

are there tools for that? or do i just manually modify .conf files in efi/loader/entries ? but then how to “pin” something?

1 Like

for removing the old entries try this:

$ nix-env --list-generations --profile /nix/var/nix/profiles/system
# pick a couple or one to remove
$ nix-env --delete-generations --profile /nix/var/nix/profiles/system 163 164
# or anything older than 5 days
$ nix-env --delete-generations --profile /nix/var/nix/profiles/system 5d

you might need sudo

see this section of manual for more: NixOS 23.05 manual | Nix & NixOS

1 Like

You can achieve this by creating a garbage collector root for it. Just check in /nix/var/nix/profiles/system which generation you want, and create a symlink to it in /nix/var/nix/gcroots. Now this generation will never be garbage collected until you delete that symlink.

Incorrect, see replies below.

I’m not sure if you can just rename generations, but you could try creating a symlink in /nix/var/nix/profiles/system to a numeric generation with a readable name and see if a rebuild makes it appear in the boot entries.

There are other options as well, you can certainly customize the boot.loader.grub or boot.loader.systemd-boot options, depending on which you have enabled. Both support an extraEntries field, check the NixOS options search for more info.

1 Like

“pinning” an entry should prevent it from being garbage collected

thank you, i saw that, but was unsure if i can just create random links in there - i thought it’s for nixos commands to manage

hmmm, not sure what do you mean… i wanted to just change the name of existing entry, it seems that i could just change text in /boot/efi/loader/entries/nixos-generation-1234.conf, but I don’t want to touch such sensitive things without asking around first :slight_smile:

as for new entries - yes, I’ve seen options to control them when generating new one with nixos-rebuilt, but the question is about renaming existing ones

btw, thank you, that’s nice

i also wonder, what is displayed if i do just nix-env --list-generations? are those home-manager profile generations?

what is displayed if i do just nix-env --list-generations? are those home-manager profile generations

that’s a good question and I wish I had a good answer. Might find what you’re looking for in this post. This section of the manual might also provide some insight

This doesn’t work the way you want. When nix deletes old profile generations, it doesn’t check that no other GC root points to them. It just deletes them.

There are two ways to interpret your comment. First, you might mean to create a gcroot that points to the same path that some generation points to. This will keep that path alive, but it won’t keep the generation in the list, so it won’t be in your boot menu.

The other way to interpret your comment is to create a gcroot that points to the generation symlink itself. But this only makes things worse because Nix won’t actually check for the existence of such links when deciding to delete a generation. Now the link you just made is broken and it won’t even keep the path alive.

$ l /nix/var/nix/profiles/per-user/will/foo*
lrwxrwxrwx 1 will users 10 Jun 15 01:51 /nix/var/nix/profiles/per-user/will/foo -> foo-2-link
lrwxrwxrwx 1 will users 60 Jun 15 01:51 /nix/var/nix/profiles/per-user/will/foo-1-link -> /nix/store/0h7fcq8cwk5p7fa3nf39iql368vz5hfx-user-environment
lrwxrwxrwx 1 will users 60 Jun 15 01:51 /nix/var/nix/profiles/per-user/will/foo-2-link -> /nix/store/92hnksqc0mpjm6pfyyzf53lsclk6lzm8-user-environment

$ ln -s /nix/var/nix/profiles/per-user/will/foo-1-link /nix/var/nix/gcroots/per-user/will/foo-pin 

$ nix-collect-garbage --delete-old 
removing old generations of profile /nix/var/nix/profiles/per-user/will/profile
removing old generations of profile /nix/var/nix/profiles/per-user/will/channels
removing old generations of profile /nix/var/nix/profiles/per-user/will/foo
removing profile version 1
finding garbage collector roots...
removing stale link from '/nix/var/nix/gcroots/auto/lp1z7hv5yvq5hh5sc9ix06wmnfhngjcm' to '/nix/var/nix/profiles/per-user/will/foo-1-link'
deleting garbage...

$ l /nix/var/nix/profiles/per-user/will/foo*
lrwxrwxrwx 1 will users 10 Jun 15 01:51 /nix/var/nix/profiles/per-user/will/foo -> foo-2-link
lrwxrwxrwx 1 will users 60 Jun 15 01:51 /nix/var/nix/profiles/per-user/will/foo-2-link -> /nix/store/92hnksqc0mpjm6pfyyzf53lsclk6lzm8-user-environment

The manual is a little subtle on this (emphasis me):

This operation print a list of all the currently existing generations for the active profile.

What this is depends on what user you’re logged in as, but it will generally be whatever the symlink ~/.nix-profile points to. In my case, that’s /nix/var/nix/profiles/per-user/felix/profile/, but you can make it point to any other profile by using nix-env --switch-profile. You can integrate home-manager into your per-user profile, but you don’t have to, you can install packages into it directly using nix-env -if or nix-env -iA.

Oh damn I did not know that. Guess I should’ve tried it before commenting. Sorry @sirphobos for the incorrect information!

NixOS commands generally write their garbage collector roots to /nix/var/nix/gcroots/auto. That directory you indeed shouldn’t mess with manually. But writing a symlink to /nix/var/nix/gcroots is the only way to create a garbage collector root yourself. AFAIK, there’s not even a dedicated command for this in nix.

But as @ElvishJerricco, it doesn’t work as I thought when dealing with profiles :grimacing:

I thought it might be possible to do that by adding an additional link, but I tried it out and it doesn’t work :confused:

You can of course just change the text in one of the entries, but this will get overwritten the next time your run nixos-rebuild, as far as I understand. But I encourage you to try it out, just changing the name of an old generation there is not going to break your system.

Could you maybe post the content of one of those boot entry files? Maybe we can work out something we can put into boot.loader.systemd-boot.extraEntries that will reference your old profile generation directly, that way it will also prevent the old generation from being GCed.

What I meant was that running nixos-rebuild will actually recreate the whole bootloader configuration. Now that I’m looking at the wiki more closely, I’m not 100% sure about that, it might actually only do that for a new entry.

I have read that, and I do understand the concept of user profiles, but I have never in my life used nix-env command before, my whole system and home-manager are built from one system flake. Yet I do see some generations in my user, therefore those were created by something automatically, I assumed it was home-manager’s system module that did that.

tested - yes, those files are recreated on every rebuild

it seems like I need to put the entire .conf entry text there, and it does add an entry.
however, I don’t want to hardcode boot entries to some generations into my system configuration.

I wonder where nixos-rebuild gets the text for boot entries… and i wonder if that place is mutable. Or maybe it’s part of the config, and changing it would change nix store hash, and everything will break
update: i did find the boot.json in the configuration in the store. but changing store contents by hand seems the wrong thing to do

Good on you, that’s really the best way to manage your config on NixOS.

Yeah and potentially won’t even work. boot.json is an immediate representation so that different bootloader generators can install their respective bootloader. So for example, for systemd-boot, the config is generated on the fly in a nix expression via a python script using boot.json.

I didn’t see any options to really modify the behavior of this apart from the aforementioned option.

But, what you could do is use the option system.userActivationScripts to add an additional script that does the changes to the boot entries with sed on every rebuild.