Deps
Deps
Deps
Nix: The Package Manager That Refuses to Forget
S2 E2222m · Jun 14, 2026
Inside /nix/store, 32-character hashes guard frozen software that can never break another package—Eelco Dolstra's radical bet that computers should only be in states you explicitly asked for.

Nix: The Package Manager That Refuses to Forget

A Folder Full of Hashes

This is episode twenty-two of What Did I Just Install.

Open a terminal on a machine running NixOS, the Linux distribution we are going to spend some time with today, and look inside a folder called slash nix slash store. What you will see does not look like a normal computer. There are thousands of directories, tens of thousands sometimes, and every single one of them has a name that begins with a wall of gibberish. Thirty-two characters of letters and numbers, then a dash, then something readable like firefox, or python, or openssl. The gibberish is not random. It is a cryptographic hash, a fingerprint computed from every single ingredient that went into building that piece of software. And once that folder is written, it is frozen. Nothing on the system will ever change a byte inside it again.

This is the strangest mainstream idea in software packaging, and it came out of a Dutch university thesis written by a man who decided that the entire industry had been installing software wrong since the beginning. Episode ten traced the install command from the Perl archive through every package manager that followed, and the through-line there was trust. Nix asks a different question entirely. Not who do you trust, but what if your computer could never be in a state you did not explicitly ask for? What if installing one thing could never, ever break another thing? The answer turned out to be beautiful, mathematically pure, and almost impossibly hard to use.

The Two Hells

To understand why anyone would build something this radical, you have to understand the two hells that every developer of a certain age remembers in their bones. The first is dependency hell. You install program A, which needs version one of some shared library. Then you install program B, which needs version two of the same library. Installing B overwrites the library that A needed, and now A is quietly broken. On Windows, this had a specific and dreaded name. It was called DLL hell, after the dynamic link library files that programs shared and constantly clobbered. On Linux, the same disease wore different clothing but killed you just as dead.

The second hell is worse, because it is silent. It is the hell of not being able to go back. You run an update. Something stops working. You have no idea what changed, because the update touched forty files scattered across your entire system, overwriting the old versions in place. There is no undo button. There is no clean record of what your machine looked like an hour ago. You are now an archaeologist excavating your own computer, trying to reconstruct a state that no longer exists anywhere. Anyone who has ever bricked a server with a routine update knows this specific flavor of dread.

The reason both hells exist comes down to one decision that every traditional package manager made without thinking, because it seemed obvious. Software gets installed in place. There is one folder for libraries, one folder for programs, and when you install something new, you copy its files on top of whatever was there before. The system is a shared mutable space, and every install is an act of overwriting. It works, until two things want different versions of the same file. Then someone loses, and usually you do not find out who until something breaks.

Deployment as a Pure Function

Eelco Dolstra was a PhD student at Utrecht University in the Netherlands in the early two thousands, and he was thinking about this problem from a direction almost nobody in the practical software world ever takes. He came from the world of functional programming, where there is a concept called a pure function. A pure function is one that, given the same inputs, always produces exactly the same output, and never changes anything outside itself as a side effect. Add two and three and you get five, today, tomorrow, forever, and nothing else in the universe is disturbed. That is purity. And Dolstra looked at software installation, which is the most impure, side-effect-riddled, state-mangling process imaginable, and he asked a question that sounds almost like a koan. What if building and installing software could be a pure function?

In two thousand six he finished his doctoral thesis. It was titled The Purely Functional Software Deployment Model, and it laid out the whole idea with the patience of a mathematician building a proof. The argument went like this. Take everything that goes into building a package. The source code, the compiler, every library it links against, every build flag, every dependency, all the way down. Feed all of that into a cryptographic hash function, the same kind of fingerprinting math that secures your bank connection. You get back a unique string. Use that string as the name of the folder where the built software lives. And here is the load-bearing sentence from the thesis itself.

Each component has a name that contains a cryptographic hash of all inputs that contributed to its build process, and the content of a component never changes after it has been built.

Read that twice, because it is the entire revolution in one sentence. The name contains a hash of all the inputs. So if anything changes, even a single compiler flag, you get a different hash, which means a different folder, which means the new thing lives somewhere completely separate from the old thing. They cannot collide. They cannot overwrite each other. Two programs that need two different versions of the same library simply point at two different folders, and both are happy. And the content never changes after it is built. Once it is written, it is frozen forever. Dependency hell, structurally, mathematically, cannot happen here. Not because someone was careful, but because the system makes it impossible.

What the Store Buys You

Dolstra validated this against more than two hundred seventy-eight existing Unix packages, real software, not toy examples, packing them all into this strange immutable store and proving the model held up under the weight of actual programs. The folder where it all lives became slash nix slash store, and the package manager that built and managed it he called Nix.

Now watch what falls out of this design almost for free, because this is the part that makes Nix users evangelical. If every package lives in its own immutable folder addressed by a hash, then your whole system is just a set of pointers to specific folders in the store. Upgrading is not overwriting anything. It is building the new versions into new folders, then flipping a single pointer to say, from now on, use these. The old folders are still sitting right there, untouched. So rolling back is not a heroic recovery operation. It is flipping the pointer back. The thesis called these atomic upgrades and rollbacks, and on NixOS this became almost magical. Your entire operating system, kernel and all, can be rebuilt from a single configuration file. And if the new configuration is broken, you reboot and pick the previous one from a menu, like loading an earlier save in a video game.

There is a second gift hidden in the hash. Because the name of every folder is computed from its inputs, two people on opposite sides of the planet who build the same package from the same recipe get the exact same hash. Bit for bit identical. Reproducibility, the holy grail that episode ten kept circling around, stops being an aspiration and becomes a property of the math. Your build either produces the expected hash or it does not. There is no it works on my machine, because the machine is no longer a variable. The recipe is the machine. This is the same content-addressing instinct that the Git series explored, where a commit is named by the hash of its contents. Nix took that idea and pointed it at an entire operating system.

The Cost of Purity

So if Nix is this elegant, this safe, this reproducible, why is not everyone using it? Why is your laptop almost certainly not running NixOS right now? Here is the honest answer, and it is the heart of the decision story. Dolstra did not just invent a package manager. To make packages into pure functions, he had to invent a whole language to describe them. The Nix language is its own thing, a declarative, purely functional, lazily evaluated, dynamically typed programming language, and those five adjectives are exactly as intimidating in practice as they sound. To package software for Nix, or to configure a NixOS system, you write code in a language that looks like almost nothing else, that nobody learned in school, and whose error messages have made grown engineers weep.

This is the tradeoff at the center of the whole project, and it is the thing worth taking home. Nix chose correctness over approachability, completely and without apology. Every other package manager hides its complexity and lets you install software with one easy command, accepting that the system will occasionally get into a broken state nobody can explain. Nix surfaces all of the complexity, demands that you describe everything explicitly, in a strange language, up front, and in exchange promises that the system can never enter a state you did not ask for. It is the difference between a tool that is easy to start and occasionally betrays you, and a tool that is brutally hard to start and then never lies to you again. Most people, understandably, pick easy. The ones who pick Nix tend to be the kind of people who got burned badly enough, often enough, that they decided they would pay any price in learning curve to never feel that particular pain again.

The community grew slowly and then with surprising intensity, the way these things do. NixOS, the operating system built on top of the package manager, attracted exactly the personality type you would expect. People who run servers that must never drift. People who want their personal laptop and their production cluster to be byte-for-byte the same. Researchers who need an experiment to be reproducible a decade from now. The package collection, called nixpkgs, swelled into one of the largest software repositories in existence. By early twenty twenty-five it held more than a hundred twenty-two thousand packages, with a higher proportion of up-to-date software than any other package repository on earth. A weird academic idea about pure functions had quietly become one of the most complete software catalogs humanity has ever assembled.

The Name and the Flake

A quick word on the name, because this series cannot let a name pass unexamined. Nix is short and clean and means, more or less, nothing in particular, though it carries a nice echo. In Dutch and German, niks or nichts means nothing, and there is something fitting in a package manager whose whole promise is that it does nothing destructive, nothing in place, nothing you did not explicitly request. The packages folder is nix store. The operating system is NixOS. The language is Nix. The branding is, appropriately, minimal to the point of absence.

Then there is the flake, which is where the technical story starts bleeding into the human one. For years, one rough edge of Nix was that pulling in external code was loose and underspecified, the kind of thing that quietly undermined the reproducibility the whole system was built to guarantee. So Dolstra designed a new mechanism called flakes, a standard way to package Nix projects with their inputs pinned and locked, hermetic and reproducible by construction. He wrote it up as a formal proposal, the forty-ninth such request for comment in the project, and shipped it in Nix version two point four at the end of twenty twenty-one. Developers loved it. It quickly became the way most people actually used Nix.

And yet, years later, flakes were still officially marked experimental. There was no agreed timeline to bless them as stable. A feature that a huge fraction of the community depended on every single day lived in a permanent state of officially-do-not-rely-on-this. That gap, between what the project said and what people actually did, sounds like a small piece of process bookkeeping. It was not. It was a crack, and the crack ran straight down to the foundation of how the project was governed and who got to decide.

The Company in the Middle

Here is a fact that changes how the rest of the story reads. Eelco Dolstra did not stay a humble academic. Together with a longtime Nix contributor named Graham Christensen, he co-founded a company called Determinate Systems, built to sell Nix to enterprises, to make the thing real engineering teams could deploy with support and confidence. Christensen became the chief executive. Dolstra remained the creator and gravitational center of the open source project and the head of the nonprofit NixOS Foundation that nominally stewarded it. So now the founder of the project, the man whose social authority over Nix was total, also had a commercial company whose business was Nix. The pure function had acquired a profit motive, and the two did not always point the same direction.

For most of its life the project had run on what open source people call a benevolent dictator for life. Not a formal title, just a reality. Dolstra was the founder, so when there was a disagreement, his view tended to win, even on questions where the community had set up teams and a board specifically to make those decisions collectively. For years this was tolerable, because the project was small and the founder was clearly acting in good faith. But the project had grown enormous, and a sprawling volunteer community with a hundred twenty thousand packages and corporate users does not run well on the social gravity of one person. The structure had outgrown the structure.

Save Nix Together

On the twenty-first of April, twenty twenty-four, an open letter appeared at a website with a pointed name, save-nix-together. It was addressed to Eelco Dolstra, and it asked him, directly, to resign from his leadership positions in the project he had created. It was signed by a long list of contributors, the number climbing past a hundred and then toward a hundred sixty. These were not random complainers. Many were the people who had built and maintained the thing for years.

The complaints were not really about code. They were about power. The letter argued that Dolstra repeatedly undermined the decisions of the community teams and the board, despite a charter that was supposed to limit exactly that. He acted, they said, as a benevolent dictator for life through sheer social influence, even where he held no formal authority. The examples were specific and small and damning in their accumulation. Reopening a sponsorship policy that had already been settled, forty-five minutes into a board call. Blocking experienced contributors from becoming reviewers. Obstructing changes that had already been formally approved. The moderation team, exhausted, said they were operating in emergency mode, with contributor retention at an all-time low.

If Eelco Dolstra does not resign, we, the signatories, will switch to and support a fork of the project.

And there was a flashpoint, a specific fight that crystallized everything. Dolstra had pushed to bring on a company called Anduril, a maker of autonomous weapons and military hardware, as a sponsor of the NixCon conference, over real and vocal objection from a community that did not want defense money near their project. To many signatories, this was the conflict of interest made visible. Dolstra ran a Nix company. Defense contractors are exactly the kind of customer a Nix company wants. When someone asked Determinate Systems chief executive Graham Christensen directly about the company's relationships with Anduril, his answer became infamous in the community.

Did you know this category of question is pretty much impossible to answer because NDAs are a thing?

It was meant, presumably, as a deflection. It read, to a furious community, as a confession. Nondisclosure agreements are a thing, yes, and the only reason to invoke them is that there is something to disclose. The line did not calm the storm. It poured fuel on it.

The Fork in the Road

The escalation, from here, was fast. The whole reason this series keeps returning to forks is that a fork is the nuclear option of open source. It is the community saying, we no longer trust you to steer, so we are taking a copy and steering it ourselves. The threat in the letter was not a bluff. On the thirtieth of April, nine days after the letter went up, the NixOS Foundation board announced that Eelco Dolstra had stepped down from the board. The creator of Nix had been pushed out of the governance of Nix by the people who built it alongside him.

But the damage did not heal cleanly, the way these things rarely do. The crisis had already fractured trust beyond a single resignation. A group of some of the most active core developers had decided they did not want to wait and see what the project became. They created a fork of the Nix package manager itself and called it Lix, run by a team that explicitly, pointedly rejected the entire idea of a benevolent dictator for life in favor of distributed, community-led governance. Around the same time, a contributor named Jake Hamilton announced a second fork, a friendly fork of the broader ecosystem called Auxolotl, focused less on changing the technology than on building a radically different community structure from the start.

The project that survived did not go back to one-person rule. In November twenty twenty-four, the Nix community elected a steering committee through an actual vote, four hundred fifty ballots cast, a fifty-six percent turnout, replacing the gravitational pull of a single founder with the messy machinery of representative governance. The benevolent dictator was gone, and in his place was something slower, more bureaucratic, and far harder to capture. Whether it is better is a question the community is still living out in real time.

What the Hash Cannot Hold

So here is the shape of it, the whole arc in one breath. A graduate student in the Netherlands had an idea so pure it was almost mathematical. Make software deployment a pure function. Hash every input. Freeze every output. Build a world where installing one thing can never break another, where you can always roll back, where two strangers building the same recipe get the same bytes. He proved it worked, built an operating system on it, grew one of the largest software catalogs ever assembled, and inspired a community of people who would defend the idea with religious fervor. The technical vision was, by almost any measure, a triumph.

And then the thing the hash could not capture brought it to the edge of breaking. Because you can make software deployment reproducible. You can freeze every byte and pin every input and guarantee that the build will be identical a decade from now. But you cannot hash a human community. You cannot pin trust. You cannot roll back a fight about money and power and whose hand is on the wheel. The same founder whose insistence on purity built something extraordinary turned out to be unable to apply that same letting-go to the project itself, and the structure that ran on his social gravity for two decades finally collapsed under its own weight. The man who taught computers to never hold on to state too tightly could not, in the end, do the same.

The store is still there, on every NixOS machine, thousands of immutable folders named by their hashes, doing exactly what the thesis promised twenty years ago. The packages do not collide. The rollbacks work. The reproducibility is real. The software kept its promises perfectly. It was only the people who turned out to be hard to install cleanly.

You probably do not run NixOS, and that is fine. But you can taste the whole idea in about two minutes without changing your system at all. Install the Nix package manager from nixos dot org, then type nix dash shell, space, dash dash packages, space, and the name of some tool you do not have, say cowsay. Nix will fetch it, drop it into the store under its hash, and open a shell where the command exists. Exit that shell, and the command is gone, but the files are still sitting in slash nix slash store, untouched, ready. Type ls slash nix slash store and scroll through that wall of hashes. Every one is a frozen, reproducible, content-addressed package. That is Eelco Dolstra's thesis, running on your machine.

That was episode twenty-two.