Hi folks,
for a looong time I wanted to have a way to diff two NixOS configurations at the config-level. I frequently thought about what options would be influenced by making a change to my configuration, for example when trying to bump system.stateVersion or enabling a new service. Today I am happy to announce that this is now possible.
TL;DR:
- This is a tool plus patchset that allows tracking how options depend on each other and how values are calculated by the internal fixpoint iteration
- Blog post with details: Tracking NixOS option values and dependencies
- Diffing tool TUI: GitHub - oddlama/nixos-config-tui: A TUI to browse and diff NixOS configurations on the configuration-level
- Patched branches for nix and nixpkgs
So while this turned out to be not-so-easy™, I finally managed to get it to work properly. It requires a small patch to nix’s evaluation logic, plus some minor changes to the NixOS module system evaluation to use the new primitives. It was important to me that this requires no modifications to any NixOS module, so it works out of the box with any NixOS configuration.
So I’m happy to introduce nixos-config, a utility that allows browsing and diffing configurations in the terminal. The required patches for nix and nixpkgs are contained in the repository and I am also maintaining a branch called thunk-origins-v1 in both my nix and nixpkgs fork with the patches applied. To test this you basically only have to enter a nix shell with the patched nix CLI and add a single line to your configuration to add the tracking information. Instructions are in the repository. I’ve also written a blog post that explains all of this in much more detail.
The terminal utility looks like this:
And here is a graph showing how options of a minimal NixOS configuration depend on each other (only showing options that were actually evaluated):
Of course there’s the awesome nix-diff tool already, but while it can explain what changes in the actual result derivatoin, it cannot tell me why. And this information is currently not accessible in nix, so this required writing some patches.
Oh and before I forget, this is experimental. (i.e. should work with any configuration, but no guarantees). I don’t have much experience with the Nix codebase, and I can’t say with certainty that the patches are not accidentally doing something that you shouldn’t do. If someone experienced could have a look at them, I’d be very glad! Also there are certainly edge cases that I missed, please tell me if you encounter anything odd.

