Remove duplicates in the nix store

Hi all - I’m relatively new to NixOS and taken the plunge. After some tweaks I’m finding my nix store is growing pretty large.

I deleted all my older generations with sudo nix-collect-garbage -d && nix-collect-garbage -d and then followed up with a nixos-rebuild switch to clear out the boot entries.

However if I run ncdu I see that my nix store still has several duplicates (see screenshot below).

Is this normal to have multiple copies, even if I’ve deleted my old generations?

If not, can you help me understand what I need to do to clear them out?

thanks

You can query for gcroots using this:

As long as that gcroot is “live”, you can’t remove the path in question.

You can check:

nix store optimise

In options: nix.optimise.*

and also: nix.settings.auto-optimise-store = true;

btrfs file system with deduplication (i think there are some options which are really nice in this case for NixOS)

Thank you - the optimise helped a bit. I think it cleared about 8Gb.

However looking at ncdu following I still see several duplicates e.g. qemu.

I ran the nix-store --query option on three of them and got the following below.

So if I read it right - there are several processes (top lines for each output) that seem to be referencing different versions of qemu in the store? I wonder why


❯ sudo nix-store  --query --roots /nix/store/lc26z5hk1z6bf87c3cg55bnb9xmgclz6-qemu-9.2.2

/proc/48410/environ -> /nix/store/lc26z5hk1z6bf87c3cg55bnb9xmgclz6-qemu-9.2.2
/proc/48412/environ -> /nix/store/lc26z5hk1z6bf87c3cg55bnb9xmgclz6-qemu-9.2.2
/run/booted-system -> /nix/store/xrfpimivx06517iyza8qd0zhyxhrlq5h-nixos-system-john-laptop-25.05.20250424.f771eb4
/proc/1845/fd/26 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/2078/fd/30 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/11692/fd/468 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/27984/fd/23 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/40138/fd/35 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/46851/fd/22 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/46851/maps -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/run/current-system -> /nix/store/w1251h2qnnbm263ffgqyqzx55jkfpj5z-nixos-system-john-laptop-25.05.20250424.f771eb4
/nix/var/nix/profiles/system-26-link -> /nix/store/w1251h2qnnbm263ffgqyqzx55jkfpj5z-nixos-system-john-laptop-25.05.20250424.f771eb4
/home/john/.local/state/home-manager/gcroots/current-home -> /nix/store/cacd0djj3mmw4a0s2k911yrv456dm9w4-home-manager-generation
/home/john/.local/state/nix/profiles/home-manager-14-link -> /nix/store/cacd0djj3mmw4a0s2k911yrv456dm9w4-home-manager-generation
/proc/1658/maps -> /nix/store/kakf3x6136wk97vbm41bhjd34fq2kvrp-home-manager-path
/proc/1677/maps -> /nix/store/kakf3x6136wk97vbm41bhjd34fq2kvrp-home-manager-path
/proc/1824/maps -> /nix/store/kakf3x6136wk97vbm41bhjd34fq2kvrp-home-manager-path
/proc/11613/maps -> /nix/store/kakf3x6136wk97vbm41bhjd34fq2kvrp-home-manager-path
/proc/1659/fd/12 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/1676/fd/20 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/1792/fd/23 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/1677/fd/46 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/1824/fd/31 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/11613/fd/49 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/11677/fd/21 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/47067/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/48265/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/1849/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/2005/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/2078/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/39715/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/46936/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/40340/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/29157/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/43785/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/40138/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/41241/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/43149/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/46851/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
❯ sudo nix-store  --query --roots /nix/store/235drl4bkz2nag5p5kwwvldy63gqw15r-qemu-9.2.2

/proc/48463/environ -> /nix/store/235drl4bkz2nag5p5kwwvldy63gqw15r-qemu-9.2.2
/proc/48465/environ -> /nix/store/235drl4bkz2nag5p5kwwvldy63gqw15r-qemu-9.2.2
/run/booted-system -> /nix/store/xrfpimivx06517iyza8qd0zhyxhrlq5h-nixos-system-john-laptop-25.05.20250424.f771eb4
/proc/1845/fd/26 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/2078/fd/30 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/11692/fd/468 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/27984/fd/23 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/40138/fd/35 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/46851/fd/22 -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/proc/46851/maps -> /nix/store/mh2w25cgmyk08861ahqfsbvdasmakmkm-user-environment
/run/current-system -> /nix/store/w1251h2qnnbm263ffgqyqzx55jkfpj5z-nixos-system-john-laptop-25.05.20250424.f771eb4
/nix/var/nix/profiles/system-26-link -> /nix/store/w1251h2qnnbm263ffgqyqzx55jkfpj5z-nixos-system-john-laptop-25.05.20250424.f771eb4
/home/john/.local/state/home-manager/gcroots/current-home -> /nix/store/cacd0djj3mmw4a0s2k911yrv456dm9w4-home-manager-generation
/home/john/.local/state/nix/profiles/home-manager-14-link -> /nix/store/cacd0djj3mmw4a0s2k911yrv456dm9w4-home-manager-generation
/proc/1658/maps -> /nix/store/kakf3x6136wk97vbm41bhjd34fq2kvrp-home-manager-path
/proc/1677/maps -> /nix/store/kakf3x6136wk97vbm41bhjd34fq2kvrp-home-manager-path
/proc/1824/maps -> /nix/store/kakf3x6136wk97vbm41bhjd34fq2kvrp-home-manager-path
/proc/11613/maps -> /nix/store/kakf3x6136wk97vbm41bhjd34fq2kvrp-home-manager-path
/proc/1659/fd/12 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/1676/fd/20 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/1792/fd/23 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/1677/fd/46 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/1824/fd/31 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/11613/fd/49 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/11677/fd/21 -> /nix/store/xnwr5rhrxjk8byqmmn357p2pkjgafkw0-user-environment
/proc/47067/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/48265/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/1849/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/2005/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/2078/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/39715/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/46936/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/40340/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/29157/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/43785/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/40138/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/41241/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/43149/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
/proc/46851/maps -> /nix/store/nmddx96mypyqqq9xa0cki4ab9mqc06ma-home-manager-path
❯ sudo nix-store  --query --roots /nix/store/zdcd3zlvzlp2k5qb4s43nms3ysazkxc5-qemu-9.2.2


/proc/48524/environ -> /nix/store/zdcd3zlvzlp2k5qb4s43nms3ysazkxc5-qemu-9.2.2
/proc/48526/environ -> /nix/store/zdcd3zlvzlp2k5qb4s43nms3ysazkxc5-qemu-9.2.2
/tmp/nh-osPkgJUR/result -> /nix/store/kjf349yggn1475w2v0v50rf0k6kn1s5f-nixos-system-john-laptop-25.05.20250412.2631b0b



current-system is different to booted-system, so that’s two system closures across an upgrade.

There’s also a home-manager closure; if that’s using a different nixpkgs revision than the system closure and you have qemu coming from both, that’s another possible source of additional versions.

The rest is a lot of running processes, probably started at boot before your last upgrade.

You should reboot, then re-run the gc.

3 Likes

You could also check if you have unexpected result symlinks with the output of nix-store --gc --print-roots | grep result or nix-du

You might find one of the tools to summarise and group the output in this thread useful: Show closure size of garbage collector roots - #9 by uep

It helps show which roots are keeping what alive in the store

Thanks all - some helpful suggestions. I must admit I’m new so not 100% of what the output is telling me. But wind back a bit. The more I looked at ncdu output after a nix store optimise I realise it has done a lot of linking which, while there remain several copies of the same file (e.g. qemu-9.2.2 they all seem linked so each only only uses a few KB.

So if I ready right thats a win. The total size of my nix store seems to be about 40Gb, which may be normal?

However - I am still curious on some of the results. For reference, I cleaned up using garbage collection command, nix store optimise and then did a rebuild to clean up boot menu options. Then rebooted to ensure clean.

I ran some of the suggested commands:

❯ nix-store --gc --print-roots | grep result
/tmp/nh-osPkgJUR/result -> /nix/store/kjf349yggn1475w2v0v50rf0k6kn1s5f-nixos-system-john-laptop-25.05.20250412.2631b0b

Now I’m not sure what this is telling me exactly. However, when I then ran the suggested script Show closure size of garbage collector roots - #9 by uep

❯ ./closure.sh
  7.4KiB   /nix/store/pc6y12ccrlvmgfbp0rs34cbj8mbsyyvk-flake-registry.json
 20.3GiB   /nix/store/zaxdciv1llr4n2lw4d1lfjdm5bw4swlc-home-manager-generation
 26.7GiB   /nix/store/kjf349yggn1475w2v0v50rf0k6kn1s5f-nixos-system-john-laptop-25.05.20250412.2631b0b
 27.5GiB   /nix/store/hkwiphvp9d8r7hhg1f2758jg08mr2d6c-nixos-system-john-laptop-25.05.20250429.46e634b

Interestingly, there seems to be a reference to a version from 2025-04-12 hanging around. I’m guessing this should have been cleaned up by garbage collection, but for some reason isn’t.

I don’t know the impact of that hanging around but as I’m learning I’m curious why it remains and what I can do to further clean up.

And if it helps, querying that location for what is referencing it got:

❯ sudo nix-store --query --roots  /nix/store/kjf349yggn1475w2v0v50rf0k6kn1s5f-nixos-system-john-laptop-25.05.20250412.2631b0b

/proc/7523/environ -> /nix/store/kjf349yggn1475w2v0v50rf0k6kn1s5f-nixos-system-john-laptop-25.05.20250412.2631b0b
/proc/7525/environ -> /nix/store/kjf349yggn1475w2v0v50rf0k6kn1s5f-nixos-system-john-laptop-25.05.20250412.2631b0b
/tmp/nh-osPkgJUR/result -> /nix/store/kjf349yggn1475w2v0v50rf0k6kn1s5f-nixos-system-john-laptop-25.05.20250412.2631b0b

For a desktop system with a bunch of larger gui things installed, perhaps a few generations kept around? Yeah, not unreasonable:

❯ zfs list -o space rpool/fmrl/nix
NAME            AVAIL   USED  USEDSNAP  USEDDS  USEDREFRESERV  USEDCHILD
rpool/fmrl/nix   345G  47.1G        0B   47.1G             0B         0B

Note that in my case, there is underlying compression and deduplication that isn’t represented in this figure. The actual size of my store doesn’t vary that much with extra generations, even if the logical size does, because a lot of stuff is common even when a package gets a rev or dep bump and thus a new store path. The optimize you ran achieves the same basic result via hardlinking files.

So the first thing to get accustomed to is that keeping a few generations around is a good thing. The overhead is not (necessarily) large, and can be minimised, but it can be worthwhile regardless.

The other part of your question is why, even when you tried, you still had extra generations lying around:

The answer lies in the sequence of operations: garbage collection removes everything that’s not referenced from any of the current roots. You ran garbage collection, then rebooted. I suspect that you had booted from that 04-12 generation, and even after switching to the new generation, it was still referenced by the root at /run/booted-system. If you had rebooted first, or run gc again after, that generation will likely get cleaned up (with -d).

Note that this is desirable… although you have switched to the new generation and probably restarted most services, you haven’t yet booted it. Perhaps the kernel or some of the early startup configuration is bad? It would be unfortunate to gc your only known-bootable generation, in case you need to roll back to it, so it’s kept as a root (as well as there probably still being some elements in use or needed while running).