The Purity Paradox: How Nix's Core Principle Collides with Graphics Drivers
#Infrastructure

The Purity Paradox: How Nix's Core Principle Collides with Graphics Drivers

Tech Essays Reporter
4 min read

Nix's fundamental rejection of FHS conventions hits an unavoidable wall with graphics drivers, forcing the system to reintroduce impurity through /run/opengl-driver/lib - a pragmatic compromise that reveals the limits of absolute reproducibility.

When Eelco Dolstra, father of Nix, descended from the mountain tops and enlightened us all, one of the main commandments for Nix was to eschew all uses of the Filesystem Hierarchy Standard (FHS). The FHS is the "find libraries and files by convention" dogma Nix abandons in the pursuit of purity. What if I told you that was a lie? 😑

Nix was explicitly designed to eliminate standard FHS paths (like /usr/lib or /lib64) to guarantee reproducibility. However, graphics drivers represent a hard boundary between user-space and kernel-space. The user-space library (libGL.so) must match the host OS's kernel module and the physical GPU. Nearly all derivations do not bundle libGL.so with them because they have no way of predicting the hardware or host kernel the binary will run on.

What about NixOS? Surely, we know what kernel and drivers we have there!? 🤔 Well, if we modified every derivation to include the correct libGL.so it would cause massive rebuilds for every user and make the NixOS cache effectively useless. To solve this, NixOS & Home Manager introduce an intentional impurity, a global path at /run/opengl-driver/lib where derivations expect to find libGL.so.

We've just re-introduced a convention path à la FHS. 🫠

Unfortunately, that leaves users who use Nix on other Linux distributions in a bad state which is documented in issue#9415, that has been open since 2015. If you tried to install and run any Nix application that requires graphics, you'll be hit with the exact error message Nix was designed to thwart: error while loading shared libraries: libGL.so.1: cannot open shared object file: No such file or directory

There are a couple of workarounds for those of us who use Nix on alternate distributions:

  • nixGL, a runtime script that injects the library via $LD_LIBRARY_PATH
  • Manually hacking $LD_LIBRARY_PATH
  • Creating your own /run/opengl-driver and symlinking it with the drivers from /usr/lib/x86_64-linux-gnu

For those of us though who cling to the beautiful purity of Nix however it feels like a sad but ultimately necessary trade-off. Thou shall not use FHS, unless you really need to.

This fundamental tension reveals something profound about software engineering: the pursuit of absolute purity often collides with practical necessities. The graphics driver problem exposes a hard boundary where reproducibility cannot be achieved without sacrificing usability. Unlike other libraries that can be statically linked or bundled, libGL.so must dynamically match the kernel's graphics subsystem - a constraint imposed by hardware manufacturers and kernel developers, not by Nix's design philosophy.

The /run/opengl-driver/lib compromise is particularly fascinating because it's an admission that some level of convention is necessary for the system to function. It's not just a workaround; it's a recognition that the FHS, despite its flaws, solved certain problems in ways that are still relevant today. The path exists as a global, predictable location precisely because every graphics application needs to find it, and there's no way to encode that knowledge into each individual derivation without creating an explosion of variants.

This impurity creates a strange dichotomy within the Nix ecosystem. NixOS users get a relatively seamless experience where the impurity is managed centrally, while users on other distributions must implement their own solutions. It's a reminder that Nix, despite its aspirations to be a universal solution, still has dependencies on the broader Linux ecosystem that it cannot fully abstract away.

The longevity of issue#9415 (open since 2015) speaks to how fundamental this problem is. It's not a bug to be fixed but a constraint to be worked around. The fact that multiple solutions like nixGL have emerged shows a community adapting to the reality that perfect purity comes at too high a cost.

Perhaps the most important lesson here is that engineering is about trade-offs, not absolutes. Nix's core innovation - treating packages as pure functions of their inputs - remains incredibly powerful. The graphics driver exception doesn't invalidate the entire philosophy; it simply acknowledges that some aspects of computing are inherently impure due to factors outside our control. The kernel-user space boundary, hardware diversity, and proprietary driver requirements create constraints that even the most elegant software design cannot overcome.

In the end, Nix's "lie" about FHS isn't really a lie at all. It's more of a pragmatic acknowledgment that purity is a direction to move toward, not an absolute state to achieve. The system works because it's mostly pure, and the exceptions are well-understood and managed. That's not failure - it's mature engineering recognizing the difference between ideals and reality.

Comments

Loading comments...