Disk ran out, how to clean store for some specified projects?

After run some projects, the nix store occupy huge disk space.
For exampe,

├── proj_one
│   ├── shell.nix
├── proj_two
│   ├── shell.nix
├── proj_three
│   ├── shell.nix
├── ... 

and I want to delete ‘proj_one’ and ‘proj_two’ .
then, how to garbage clean files under /nix/store that installed by ‘proj_one’ and ‘proj_two’ ?

You can GC everything that is currently not referenced by any GC route using nix-collect-garbage.

If you also add --delete-older-than= and a timeframe, like 14d, it will also drop system and HM generations older than that.

There is no way to say “delete garbage of this project”, as nix doesn’t have a notion of “projects”, especially not at the garbage level.

In addition, if this doesn’t already clean up enough, to get closer to what you wanted, you can remove some of the roots that might be created by your projects (for example, if you used nix profile for development, or a number of other means).

To help find those, review the output of nix-store --gc --print-roots

Thanks.
Then where should I run nix-collect-garbage command? Without additional parameter, how do it know what can be clean? For example, I still want to keep all those nix store files need by proj_three.

Said I have pull projects into proj_one/proj_two/pwoj_three folder, and have run nix-shell under all these folder. So many file are downloaded into /nix/store. Now execute nix-collect-garbage, what would it clean for me? I would be worry if it clean all? If so, next time I run nix-shell under proj_three, I had to wait long time for them to be downloaded again.

Broadly: it builds a tree of dependencies from the roots printed by the above, which includes profiles, older system generations, running processes and other stuff (mostly symlinks in various nix state directories). When cleaning it then removes everything else not referenced from those roots from the store.

Does every project’s shell.nix will have it own root?

If you register them as roots, say via: nix develop --profile ./profile, yes.

See also:

1 Like

Not by default.

Personally I use nix-direnv which does not only support using flakes, but also adds GC roots to each created shell.

Every once in a while I go through the output of the nix-store --gc --print-roots and delete the roots in the projects that I haven’t worked on recently.

I also do a nix-collect-garbage on a daily schedule via a systemd timer.

As you said we can delete the root before run nix-collect-garbage command, would you please tell how can I get the root file (only one or many?) for given shell.nix?

You can’t, as there is no relationship between a GC root and an arbitrary nix-file. Using the already mentioned nix-direnv, a semi-relationship is created, by co-locating the GC root within a .direnv subfolder, which again is a sibling to the .envrc that controls direnv.

Thanks.
How do you identify which root is the one you unwanted?

Because its in the $PROJECT/.direnv folder.

Thanks. I got it. Really appreciate your help.

@NobbZ
Can I say like this:
By default, the nix-collect-garbage will clean all file for all shell.nix.
So, if we want to keep some projcet’s file ‘live’, we can call nix develop --profile ./profile (or by recourse to nix-direnv ) to put .drv under nix’s gcroots.

nix-collect-garbage is not aware of any shell.nix or any other nix file. It is only aware of GC roots, as created and maintained in /nix/var/nix/gcroots and its children.

nix develop --profile ./profile will create a symlink at ./profile that points at the derivation created by nix develop, and also a symlink in /nix/var/nix/gcroots/auto is created pointing at that profile link.

As soon as either the link in /nix/var/nix/gcroots gets deleted or stale (because you delete the profile link) the GC root gets removed and pathes referenced by it will get removed by the nect GC, unless referenced by another root which is still active.

While this is correct, I think there’s a small missing link required for understanding.

When you run nix-shell in a directory with a shell.nix, nix will download a bunch of files for the packages you specified and put them in the nix store, and use them to create your shell.

Those are considered temporary, though. Nix will not create “garbage collection roots”, which is a fancy way of saying “files that tell nix that a bunch of other files should not be deleted by nix-collect-garbage”.

Next time you call nix-collect-garbage, nix will delete all files that don’t have those roots, which means that yes, the shell is cleaned up, as well as anything else you happen to have installed that doesn’t have a root.

They’re called roots because they function in a tree fashion, where some files depend on others being there, and ultimately end up at a “root”, which if it exists means they should not be removed. But that’s an implementation detail.

You can manually create one of those “garbage collection roots” using the nix profile command, as @NobbZ explains, should you want to keep the files around after all - and delete them later if you want to get rid of them. This is what you need to do if you want to manage something like “projects”.

nixos-rebuild does exactly that for versions of your system, by the way. You don’t want to delete those roots, because that will mean your system will be deleted next time you take out the trash :wink: