How to unchain inodes on NixOS, while getting rid of orphaned packages [Part 2]

15 Jul 2025

2. Running and declaring NixOS garbage-collector routines

├──[ 0. main article ]
╰──[ 1. checking partition stats ]

#A Introduction

As investigated in my previous article, NixOS consumes an increasing amount of the limited metadata storage area of a filesystem with each new build.

For instance, I use NixOS on my regular desktop computers, so I rarely add or remove more than one or two packages in my configuration.nix file before invoking a rebuild process, which then consumes far more space in the metadata area than in the data area

The reason is simple: NixOS release upgrades or full system updates completed by a rebuild produce the latest generation, which installs the latest version of each package and its individual dependencies without removing their previous versions. Those procedures have the potential to double the amount of storage used.

#A.1 The Emergency Fix

✅ NixOS is equipped with its own garbage collector, which can be invoked imperatively whenever needed. This frees inodes instantly in critical situations, such as after a system build fails and reports that no space is left.

╰──Show Emergency Fix

#A.2 The Declarative Approach

✅ Besides the imperative clean-up, it is highly recommended to declare an automated garbage-collection routine in the configuration.nix file in order to prevent any unwanted future shortages of filesystem space.

╰──Show Declarative Fix

#B NixOS Generations for Beginners

Generations in the context of NixOS are originally called build-generations of a distinct profile. Whenever you run nixos-rebuild "switch", it incrementally builds the next generation of your system.

The "switch"-argument causes the system to transition directly to the newly created generation without requiring a reboot:

nixos-rebuild "switch" --use-remote-sudo

Bash --- like in the official NixOS Wiki (seen in November 2025)

A newly created entry at the top of your boot menu refers to the latest generation while preserving the previous ones.

This design guarantees an almost incorruptible operating system. In case of misconfiguration or unwanted results, one can always dive back into a previous generation during the next boot.

In my opinion, this is the most valuable advantage of using NixOS.

Mermaid Diagram of NixOS Profiles
Diagram of NixOS User Environment Profiles

#B.1 How to List All Existing Generations

To keep things simple, I address the system profile only in this article; it is not user‑specific and therefore serves as the public profile for all users on a system. Multiple profiles are possible, e.g., one for each user on multi‑user systems.

sudo nix-env -p /nix/var/nix/profiles/system --list-generations

Bash --- lists all existing generations of the system profile

#C The Garbage-Collector

(Simplified) The garbage collector likely traverses the local nix-store recursively and collects all unlinked packages. These are orphaned nix‑store paths because they are no longer linked to any of the existing generation’s system‑profile trees.

#D How to Clean-Up Your System

#D.1 Removing Legacy Generations Imperatively

As mentioned above, we can free some filesystem space by removing legacy generations of our active profile.

sudo nix-collect-garbage --delete-older-than 14d

Bash --- this removes all generations including their orphaned packages older than 14d

#D.2 Deduplicating Store Dependencies

The nix store optimise operation collects all identical files in your nix-store and replaces each one with a hard link that points to a single original file. This usually frees about 25–30 % of the store. Theoretically, it removes duplicate inodes and the filesystem blocks they were holding pointers to.

⚠️ Attention! This operation is very hungry for resources and may consume a lot of time.

nix store optimise

Bash --- replaces identical files in the store by hard links

#D.2 Results of Self-Experiment

I use btrfs as my filesystem, so I must run this command to plot a summary of the nix-store filesystem statistics:

sudo btrfs filesystem usage /nix/store

Bash --- firstly mentioned in my previous article (you must choose the correct tool depending on your local filesystem)

#Storage statistics I

ℹ️ before the invocation of nix store optimise:

Overall:
    Device size:		 456.52GiB
    Device allocated:		 432.52GiB
    Device unallocated:		  24.00GiB
    Device missing:		     0.00B
    Device slack:		   1.50KiB
    Used:			 303.34GiB
    Free (estimated):		 145.39GiB	(min: 133.39GiB)
    Free (statfs, df):		 145.39GiB
    Data ratio:			      1.00
    Metadata ratio:		      2.00
    Global reserve:		 512.00MiB	(used: 0.00B)
    Multiple profiles:		        no

Data,single: Size:416.50GiB, Used:295.12GiB (70.86%)
   /dev/disk/by-uuid/3095dd1c-cf7e-11f0-b26a-1b1bc8337735	 416.50GiB

Metadata,DUP: Size:8.00GiB, Used:4.11GiB (51.38%)
   /dev/disk/by-uuid/3095dd1c-cf7e-11f0-b26a-1b1bc8337735	  16.00GiB

System,DUP: Size:8.00MiB, Used:64.00KiB (0.78%)
   /dev/disk/by-uuid/3095dd1c-cf7e-11f0-b26a-1b1bc8337735	  16.00MiB

Unallocated:
   /dev/disk/by-uuid/3095dd1c-cf7e-11f0-b26a-1b1bc8337735	  24.00GiB

#Storage Statistics II

ℹ️ right after the invocation

Overall:
    Device size:		 456.52GiB
    Device allocated:		 432.52GiB
    Device unallocated:		  24.00GiB
    Device missing:		     0.00B
    Device slack:		   1.50KiB
    Used:			 293.66GiB
    Free (estimated):		 153.68GiB	(min: 141.68GiB)
    Free (statfs, df):		 153.68GiB
    Data ratio:			      1.00
    Metadata ratio:		      2.00
    Global reserve:		 512.00MiB	(used: 0.00B)
    Multiple profiles:		        no

Data,single: Size:416.50GiB, Used:286.82GiB (68.86%)
   /dev/disk/by-uuid/3095dd1c-cf7e-11f0-b26a-1b1bc8337735	 416.50GiB

Metadata,DUP: Size:8.00GiB, Used:3.42GiB (42.74%)
   /dev/disk/by-uuid/3095dd1c-cf7e-11f0-b26a-1b1bc8337735	  16.00GiB

System,DUP: Size:8.00MiB, Used:64.00KiB (0.78%)
   /dev/disk/by-uuid/3095dd1c-cf7e-11f0-b26a-1b1bc8337735	  16.00MiB

Unallocated:
   /dev/disk/by-uuid/3095dd1c-cf7e-11f0-b26a-1b1bc8337735	  24.00GiB

#Summary

The procedure freed

#E Declaring Garbage-Collector in Configuration.nix

Adding these two lines to the configuration.nix results in automatic garbage collection whenever nixos-rebuild is triggered to build the next generation of your system.

{
	nix.gc.automatic = true;
	nix.gc.options = "--delete-older-than 30d";
}

configuration.nix --- removes all generations older than 30 days during every build

ℹ️ It is also possible to automate the optimization procedure via declaration. Please read the corresponding official NixOS wiki article for further instructions.


/sw-load.js?v=e5ae5a1ed170f4499ac6292e7164b68528c51f6d6518cd75a49e6a6b737831d5728da21fc14dcbc7a91328e53858c6ff7195cc3fc8b25f0feeaef2af151d6686 /favicon.ico?v=1a6495bbd14c74c75aa77e28420ce82a63372b28cd38c952b98403d8d112a9f76589bea299982ca27048215e661245f9d07294bddee7da377aaee76eee70c622 /favicon-16x16.png?v=7267c6f502a03c1e4df9d8136dcc6cd9e67e0b9644941d22ed34e4fe747580f95a65f77a183bb967c1ec60eecd0c298b2670d89a67a647391fb7d1501bcf0982 /favicon-32x32.png?v=5e23bffe691055b88067cbc8d11b96ce2a8dc5e25e49367803766a3cadbcfc7f05a62079bfa558d5e234c6a7455d21fc2960b196bda5cbd591bd4c2dbe67920d /icon-192x192.png?v=3820c1b1e6d755d2b7c2a04a65f0f1feef793b297f7ee995947137ccd8f73ec304457f6ce1df987a9a0a13ed7dacd203225505b832ccd2318b530ae53a55cebc /icon-512x512.png?v=de62ae905479fd813300d286ed1d2fe6bb6f6292623a5d918691642f6dd09a68943c69ed2a95a1820076919e69ff4fda668bb79e610ebc1d3200fedd7f634443 /apple-touch-icon.png?v=4718a090c66653794b3622234784e821a504ee526b6518f20cd10f6b27907566690892339830ede2ef9cb5fedb8a9796f02fb2610de868500c0720c1083013b7 /main.css?v=56a3586628bebba0d5280f2e67a22691fa9e2450e64469ab18fc6d0773692f129ec4694178df261a5efbe4e8c805990ce4a27961d96bf0d54d3a7f9494dcc975 /unstyle.css?v=b14bd48a2efbd463d973763aa3184c69aa02164c0891acacc9eab49ddd275f98f0050b4c31d2093e4671e7abe04f9459a041f0064384a90d97b8ff21b6824825 /langs.css?v=12474958ee314a9fde4704e1f5a032dc632d41f9461faca326ac284297766c4ceb07b45fec7fbc09fa72b0f21dcc64f0c31e64fc2e5e838b1d30f5fe540afd78 /syntax-theme-light.css?v=f6e6c807eb281d55fa88e55276dabcb0d1a72cfa54b432cee2179497d8465a644ad979aaa77323042209cc25179d80f39240e90a0550561dcbca29935cd142ee /syntax-theme-dark.css?v=e7859e08ffe883f85615392635c02b6107cb37848513de49edd3e077eac6509fc782692e34d3fe1de6d3b87bdf8abe24a0e93cead1ac875f03282147cbbe3c27 /sw-style.css?v=a0fa1e87fa2bb3e03d18cefc81ef5c8cfa58c6aa6eea0af223fa155e088bc5af22d32d3ee785ebd3fc26b4c49b70f0bd423f7d592a419a24e6d1e2cb720b7e05 /categories/ /categories/DIY/ /categories/Idea Pool/ /categories/about/ /tags/ /tags/Filesystems/ /tags/Linux/ /tags/NixOS/ /tags/Notebooks/ /tags/content/ /tags/me/ /posts/under_construction/ /diy/ /uebermich/Myself/ /posts/ EMotor_Zeche20121005_132704.jpg?v=2c3609dcaee106dd7878ad118a041d951ae8197788e9a24be8cf4efee34f5c9448a2862ee5dd7c18d265a758d6c939341673ea23e47d5290ff9f769cc4aa4b40 obsidian.png?v=426621284f6d97ca988b7d614555d92b304cc0a3bb55b57f926789eacdbe6bc16e927109d01d634ec23952fb794982d0dfb11603df649ae0a586d2fc982c89aa ffmultra.gif?v=2d5031e4ef808634de742e2338a913cddab4c122d16490791dbf7364b2a659237d65d85c5eb56e08f3185332ec0f4b01af5e94376db4a1a81d5378103aa6bfcc /icon-192x192.png?v=3820c1b1e6d755d2b7c2a04a65f0f1feef793b297f7ee995947137ccd8f73ec304457f6ce1df987a9a0a13ed7dacd203225505b832ccd2318b530ae53a55cebc /glitch.css?v=0b9b7f8691385df5b832251e9cf4c56d68cbcfc98c6e4c27e015f6fb29d2f0c18c358c98c0e7e0a1da9f263d6b355b811e49aac099b70889090912a5040f754a /sitemap.xml /search_index.en.json /search.js /elasticlunr.min.js?v=b9be63b71422cbfde9f14310b397d9a7092f2946bffec11811a831398ace978c1c592e9a578f1fa32041e6c0dde68657fe58d3c30b0eaa758c63c5fd45117336">