Why doesn't nix-collect-garbage collect all the garbage?

Just did a fresh nix install on an Ubuntu machine with the Determinate Nix installer. Immediately after installing:

ubuntu@ip-172-31-37-110:~$ du -sh /nix/store/
92M	/nix/store/

That seems a bit heavyweight for just Nix itself, but believable. Let’s play around with an ephemeral nix-shell,

ubuntu@ip-172-31-37-110:~$ nix-shell -p ncdu
[nix-shell:~]$ exit
ubuntu@ip-172-31-37-110:~$ du -sh /nix/store/
852M	/nix/store/

Woo, that’s crazy! Just using a simple CLI brought in 750M. (The static build of ncdu on x86_64 is 611K. That’s a 1227x blowup.) But whatever… an advantage of Nix is that we can easily clean up and get back to a clean slate:

ubuntu@ip-172-31-37-110:~$ nix-collect-garbage
ubuntu@ip-172-31-37-110:~$ nix-collect-garbage -d
ubuntu@ip-172-31-37-110:~$ du -sh /nix/store/
459M	/nix/store/

What? Why aren’t we back to the original 92M /nix/store?

1 Like

Just repeated the test with the official Nix installer, and the numbers are even worse:

  • After Nix install: 473M
  • After nix-shell -p ncdu: 838M
  • After nix-collect-garbage: 836M

What am I missing here?

1 Like

Poking around the /nix/store, it seems that /s2094dggqjwpd54c08hvkwlv2wszdr5x-gcc-13.2.0 is the largest offender at 221M… why is this still sticking around? And why is it necessary at runtime anyways?

(/nix/store/.links is also coming in at a hefty 361M.)

That’s probably nix-shell -p bringing in all of stdenv. It’s not great.

1 Like

(but it is what nix-shell is supposed to do, and other uses are roughly off-label?)

1 Like

From the narrative I get the impression all you did was install, but afaik the optimization operation/settings that create these links aren’t defaults. Are you running optimize after installing? What does your nix config look like? Some settings affect what is and isn’t retained.

Is there any way to prevent nix-shell bring in all of stdenv? I never use nix-shell that way anyways

I mean, there’s mkShellNoCC (Nixpkgs 24.05 manual | Nix & NixOS), but i’d also keep an eye on whether nix-shell is the best way to accomplish whatever you are trying to do.

is there an alternative CLI tool to nix-shell for ephemeral environments for one-off commands?

I don’t mean to be callous or dismissive - there’s lots of legitimate reasons to pay attention to it - but if less than 1GB of disk usage has you concerned, I think you will be fighting with Nix design a lot on this topic. A couple Nixpkgs flake inputs tracked over a month’s time can easily exceed that all by themselves.

Most idiomatic use of Nix is going to be rather disk-hungry, especially relative to mainstream distros.


Yes, understood. But in this case I’m trying to create a minimal disk image to be reused and transferred extensively. Having a minimal footprint is desirable.

Sure. nix shell (i.e., nix shell nixpkgs#ncdu --command ncdu --help) and nix run (nix run nixpkgs#ncdu -- --help).

These obviously aren’t traditional CLI commands, but addressing the ergonomics of use cases like this is a big part of why the newer CLI is being built.

nix-shell isn’t designed for this, so AFAIK you’ll just have to take more control to accomplish this without pulling in more dependencies if that’s an essential requirement for you. (In addition to mkShellNoCC mentioned earlier, you could also probably use something like nix-build '<nixpkgs>' --attr ncdu && ./result/bin/ncdu --help.


This is the kind of reason why I suggested to keep your eye on whether nix-shell is the best way. If you’re building a disk image, how does nix-shell fit in?

1 Like

Thanks! I previously tried switching to nix shell but ran into some issues… time for me to give it another try!

Yes, I am not in fact using nix-shell in the image creation process. I was just using it for debugging purposes and came across this issue/weirdness.

1 Like

I borked a copy-paste in the run example. Edited.

Is garbage collection broken or something?

@abathur’s is the correct answer for the time being, as well as the reference to mkShellNoCC to make shell environments not include the compiler toolchain.

There are two underlying problems:

  1. The differences between nix-shell (and its various modes of operation), nix shell, and nix develop are not thoroughly documented in a visible place. It’s easy to expect the wrong things. The documentation team should probably change that ASAP, but we still have lots of other ongoing, unfinished work.
  2. Shell and build environments are fundamentally a Nixpkgs (or, more generally, downstream of Nix) business, and Nix offering a CLI for them is architecturally unfortunate (it introduces a cyclic dependency), hacky, and contributes to confusion about who’s responsible for what. In fact, Nix maintainers agreed this should be decoupled, implementation welcome.

Side rant: I don’t know how strong the consensus on that issue is, but in my opinion we should make Nix a lot less clever and Nixpkgs more ergonomic. I know there is at least some tension around it, because that would mean dropping quite a few efforts and features that have substantial sunk cost already, but also because it’s tricky to deal with backwards compatibility. A somewhat easy way to start is to nudge learners to think primarily in terms of Nix language expressions, and otherwise work on better documenting and increasing the convenience of APIs for common use cases. Yes, this is against one motivation behind flakes and the new CLI. And while it’s perfectly valid to assume that users will get into the system more quickly if they find familiar interfaces, the only thing this can mimic are traditional package managers — a rather boring special case of what Nix and especially Nixpkgs and NixOS have to offer. Dumb package management (“make this executable available”) can be done with a lot less hassle and a lot more flexibility from out of Nixpkgs itself, which is exactly why nix-shell -p has such a splendid out-of-the-box user experience, until you try doing search or want other versions.