Huge weekly updates (~10GB) and duplicate packages with different hashes. Help a beginner out! šŸ˜…

Hi everyone! :waving_hand:

I’m relatively new to NixOS and currently running a Flakes + Home Manager setup. I’m absolutely loving the declarative approach so far, but I’ve run into an issue that is completely destroying my bandwidth and SSD.

Every time I do my weekly routine (nix flake update followed by updating both the system and Home Manager), the total update size is massive. I’m talking about ~10GB of downloads and around 28GB unpacked (and yes, this size includes both the system and Home Manager updates combined)!

While investigating, I noticed that Nix is frequently downloading the exact same version of a package but with different hashes. For example, matugen-3.0.0 gets downloaded twice:

  • /nix/store/ks0yggh9nsml5qi2na1ww82cvfqx7c2a-matugen-3.0.0
  • /nix/store/y14wlnb104njx42vnr8s63mhz0qzlsbj-matugen-3.0.0

For some context on my setup:

  • I’m running a hybrid config, mixing nixos-25.11 and nixos-unstable in my flake.nix.
  • I fetch my inputs using Git: git+https://github.com/NixOS/nixpkgs?shallow=1&ref=nixos-25.11
  • I’m using linuxPackages_xanmod.

You can check my full NixOS configuration on my GitHub here: [ GitHub - XiaoXioe/nixos-config Ā· GitHub ]

My questions are:

  1. Is there a flaw in how I’m handling the stable and unstable inputs that causes this dependency tree split (resulting in different hashes for the same app)?
  2. How can I prevent Nix from doing this?
  3. Or is this massive download size just the reality of mixing unstable packages and custom kernels, and I should just move heavy GUI apps to Flatpak via declarative modules?

Any advice, explanations, or pointers to fix my config would be hugely appreciated. Thanks in advance! :folded_hands:

1 Like

Yes, mixing unstable and stable will lead to duplicate packages. If only a single dependency is different, it’s a different package to nix even if the version number is the same.

1 Like

I think @truh is off the mark here. Unstable does mean more churn, and mixing it with stable means more absolute disk space use, but it shouldn’t cause large downloads or rebuilds.

Something is going very wrong, and it’s (probably) not the multi-nixpkgs you depend on. You can test for that by just aliasing the two nixpkgs inputs into one.


You’re also using flake-parts but not even doing the one thing most people use it for (not having to type x86_64-linux once or twice). It looks like you over-engineered without understanding why you’re over-engineering.

It’s hard to spot exactly what’s going wrong because this over-engineering obfuscates what you’re doing, but this kind of thing is a huge indicator of nixpkgs repo imports being done poorly, especially in the context of NixOS (and flake-parts and flakes). Still, nix’ lazyness should save you, so all I can imagine is that somehow you made something really low-level depend on something that updates frequently through an overlay.

I’d recommend bulldozing that flake.nix and rewriting things from scratch without a framework and only for one specific host.

You can attempt hyper-generalizing once you understand what’s going on a bit better, or just don’t generalize at all; Most desktop configurations will not be applied to more than one or two hosts (you seem to have exactly one, given that you’re enumerating exactly one file), what you have looks like it’s extremely overkill and therefore needlessly complex.

Alternatively, try to give us a minimum reproduction scenario, though doing so will likely already show you what you’re doing wrong.

5 Likes

FWIW, one issue with flakes is that every time you make a change to a Git-backed nix config, it must copy the entire source of your config to the nix store instead of using the current Git hash. This only happens when you have uncommitted files in the working dir (you can git add the files to avoid this). This is what ā€œGit tree /etc/nixos is dirtyā€ warning means when you invoke nixos rebuild. Other configuration derivations may rely on the source hash, so you may see things being rebuilt in this circumstances, mostly configuration derivations.

This typically won’t cause double copies of most packages as you’re seeing but it’s worth knowing.

No, it also happens for git repositories with committed files. Every time you make any change to your repo, though only once for each commit or uncommitted change, since the hashes will match if the files are the same. This is ā€œneededā€ for pure eval, and one of the biggest issues with flakes in general.

And yes, it’s unrelated for the specific question asked here.

1 Like

You’re right. I misunderstood what was happening. Cunningham’s law wins again :slight_smile:

2 Likes

Thanks for the blunt feedback @TLATER, you were actually spot on about the poor repo imports and making low-level stuff depend on unstable.

I took a deep dive into my config and found exactly where the ā€œover-engineeringā€ went wrong. The fatal mistake was instantiating a completely independent pkgs-unstable = import inputs.nixpkgs-unstable {} and blindly passing it through specialArgs to over 20 different modules across my system. It was dragging two parallel universes of stdenv, glibc, and rustPlatform into my builds, inflating my system closure size to a massive 30.9 GiB and causing those 10GB weekly downloads.

I didn’t quite bulldoze the entire flake.nix from scratch, but I did a massive architectural cleanup:

  1. Nuked pkgs-unstable from specialArgs entirely: It’s no longer being passed globally to my modules.
  2. Reverted to Stable: Shifted ~90% of my packages (basic CLI tools, security wrappers, GNOME) back to pure stable pkgs.
  3. Quarantined Unstable via Overlay: For the few apps that actually need to be bleeding edge (like gemini-cli or ollama), I set up a proper overlay in flake.nix (pkgs.unstable = import ...) so they are explicitly called via the pkgs namespace without forcing a split in the foundational dependency tree. I also used final.callPackage cherry-picking for specific GUI/Rust apps to build them against my stable foundation.

Thanks for pointing out the bad imports—it forced me to look at how I was injecting dependencies!

1 Like

Those imports are redundant to begin with due to flake-parts and NixOS/home-manager. I do still recommend bulldozing, and learning each module system step by step.

1 Like

This split in the dependency graph is still a thing!

Whether you pass unstable via specialArgs, _mdoule.args or via an overlay, it really doesn’t make a difference.

What probably made the difference was that you indeed yeeted 90% of previous unstable use. You even said you used unstable Gnome…

2 Likes