The earlier discussion of bloat, although IMO mostly going after the wrong targets, got me thinking: what do I consider “bloated” about NixOS as it is today? And the big thing that comes to mind is, the disk space requirements for the store.
Here’s current disk usage on a small server I run using NixOS. Note that / is ephemeral, that’s why it’s not visible here. The total size of the (virtual) disk is 24GB and 4G of it is used as swap.
# df -h | grep \^/dev
Filesystem Size Used Avail Use% Mounted on
/dev/vda5 8.0G 3.5G 4.5G 45% /nix/store
/dev/vda6 12G 1.6G 11G 14% /home
/dev/vda3 704M 253M 452M 36% /var
/dev/vda2 255M 130M 125M 52% /boot
3.5G for the store is, in my opinion, too big. Now this is with a whole bunch of old generations from periodic system updates. After a nix-collect-garbage -d run, though, it only goes down to 2.0G, which is still too big. (In my opinion.)
So how big isn’t too big, in your opinion?
Obviously the space required is going to depend on what the system actually does.
This one is just a web server, serving a mix of static files and PHP scripts. There’s no database, no shell users besides root, and no other major services (however I was forced to install Postfix because nullmailer wasn’t quite capable enough).
I think a machine like this should be able to fit four or five generations of the system profile into one gigabyte. That means a single generation should require no more than about 200MB. Honestly, that still seems a bit on the large side to me, but I am an old fart from the days when a complete installation of Solaris 2.5 fit into less than fifty megs.
Taking 200MB per gen as a target, NixOS 25.11 requires a full order of magnitude more space for this installation. Why?
# cd /nix/store && du -sh * | sort -k1,1rh | head -n15
319M kx2w0vzs6y6dj78azs329l372944f4vx-source
139M 746hvfrby87byzqlpj4jjwhdz89rsh27-linux-6.12.64-modules
104M cdaifv92znxy5ai4sawricjl0p5b9sgf-python3-3.13.11
61M j1scam1h5xmpnsn5ss02nbyhhyc7hwq3-perl-5.40.0
54M yxk9smkrispxlz2ka3gxigvmzhf0fn65-systemd-258.2
47M i6fivbql9nn479sq3s0wiihqjyzizzvm-vim-9.1.1869
44M 0ai16s30fy6br1iamqqyb5pxfckk5bkm-sops-install-secrets-0.0.1
43M 30i9xmq3i3kzvkl532c15xd38823zmhv-caddy-2.10.2
42M 2lalvc104lladjsl0iwbc8592w0p8c7j-git-minimal-2.51.2
39M gf26b8zflmzi6vbhlfqsipykhkrsvagb-icu4c-76.1
38M wr26k9b1ga5ln0w2ppmf6cn0sdnw4m0x-php-8.4.16
38M y6j7ydwz23nj21xqj8x2z96ms6b4iqbg-icu4c-73.2
36M 30sxwq9fvi23blwxqpdahs83pw3hv1dw-initrd-linux-6.12.64
30M wqfs0wh0wp6vdcbbck3wzk5v15qy17m7-glibc-2.40-66
30M y7kk3dj7wlls924zlvpwmm13gskfw1hk-git-2.51.2
There’s probably tweaks I can make on my end to cut this down, e.g. replacing vim with nvi and making sure not to pull in both git and git-minimal; but the biggest pieces of the pie are going to require some work within NixOS and/or nixpkgs if we want them to be smaller.
319M kx2w0vzs6y6dj78azs329l372944f4vx-source
This is the complete source code of nixpkgs. I think this is an example of what this article is getting at: Package managers keep using git as a database, it never works out | Andrew Nesbitt . There oughta be a way for me to pull only the small subset of nixpkgs that is actually relevant to the packages and NixOS modules I am using.
139M 746hvfrby87byzqlpj4jjwhdz89rsh27-linux-6.12.64-modules
I’m already tinkering with custom kernels but what do y’all think of there being a nixpkgs-supplied, minimal, monolithic kernel specifically for use as a VM guest? Almost all the drivers could be turned off.
104M cdaifv92znxy5ai4sawricjl0p5b9sgf-python3-3.13.11
Python is needed by three system components I can’t reasonably get rid of: nixos-rebuild-ng, limine-install, and journalwatch. Almost all of its size (95MB) is lib/python3.13, i.e. the standard library. It should be possible to install this in a more compact form by leveraging zipimport; a zipfile containing all the .pyc files is 17M, and another one with all the .py files is 3.2M. I think it should also be possible to move the .py files to an output that most things don’t depend on.
61M j1scam1h5xmpnsn5ss02nbyhhyc7hwq3-perl-5.40.0
I am not sure what needs this.
# nix why-depends /nix/store/flrcxy9gy89fnvf3h0w3nw62zq0l6zyq-nixos-system-tinka-25.11.20260110.d030887 /nix/store/j1scam1h5xmpnsn5ss02nbyhhyc7hwq3-perl-5.40.0/
/nix/store/flrcxy9gy89fnvf3h0w3nw62zq0l6zyq-nixos-system-tinka-25.11.20260110.d030887
└───/nix/store/swf3hf4h0gdlv2zgxyb79jkn10i2g2py-perl-5.40.0-env
└───/nix/store/j1scam1h5xmpnsn5ss02nbyhhyc7hwq3-perl-5.40.0
Adding --all shows me additional paths through nixos-generate-config and git, which I think I can get rid of, but I do not know why there’s a direct dependency of the system configuration on perl-5.40.0-env.
44M 0ai16s30fy6br1iamqqyb5pxfckk5bkm-sops-install-secrets-0.0.1
43M 30i9xmq3i3kzvkl532c15xd38823zmhv-caddy-2.10.2
These are both programs written in Go, and almost all of the bulk of each package is the binary executable that the program compiles to:
-r-xr-xr-x 2 root root 44M Jan 1 1970 <hash>-sops-install-secrets-0.0.1/bin/sops-install-secrets
-r-xr-xr-x 2 root root 43M Jan 1 1970 <hash>-caddy-2.10.2/bin/caddy
sops-nix is not part of nixpkgs and I’ve reported the issue directly to the package maintainer (The `sops-install-secrets` binary is absurdly large · Issue #892 · Mic92/sops-nix · GitHub); however, caddy is part of nixpkgs, and it appears to me that the root cause of both binaries’ size is that the Go compiler is doing something silly. I don’t know enough about Go to dig into it further but I think someone should.
39M gf26b8zflmzi6vbhlfqsipykhkrsvagb-icu4c-76.1
38M y6j7ydwz23nj21xqj8x2z96ms6b4iqbg-icu4c-73.2
Classic case of “DLL hell”: xfsprogs-6.17.0 was built against icu4c-76.1 and php-intl-8.4.16 was built against icu4c-73.2. There should be an item on the checklist for each NixOS release for someone to go through the dependency tree of all the packages and make sure everything is built with the same version of each major library.