Nix

Also known as: Nix package manager

On this page 7

Nix is a purely functional package manager that installs every package into its own immutable directory under /nix/store, named by a cryptographic hash of all its build inputs. In Linux package management it stands apart from APT, DNF or Pacman: instead of overwriting shared files in /usr, the Nix package manager lets many versions of the same software coexist, makes upgrades atomic and allows a return to any previous state with a single command.

Nix runs on most Linux distributions and on macOS, and it is the foundation of NixOS, a distribution whose entire system configuration is built the same way. The project also maintains Nixpkgs, a very large collection of package definitions that is among the biggest software repositories available for Linux.

How Nix builds and stores packages

Packages in Nix are described in the Nix language, a lazy, purely functional language. A package description evaluates to a derivation: a precise recipe listing source code, compiler, dependencies, build script and environment variables. The hash of that recipe determines the output path, for example /nix/store/ followed by a 32-character hash and the name and version of the package.

Because the path depends on every input, changing any dependency produces a new path rather than modifying an existing one. Builds run in a sandbox without network access and with only declared dependencies visible, which prevents hidden dependencies on whatever happens to be installed on the build machine.

ConceptWhat it isWhy it matters
Nix storeRead-only directory /nix/store holding all packagesPackages never overwrite each other
DerivationComplete build recipe with all inputsDetermines the hash and output path
Binary cacheServer with prebuilt store pathsAvoids compiling locally when the hash matches
Profile and generationsSymlink trees pointing to chosen store pathsAtomic switching and rollback
Garbage collectorRemoves store paths no longer referencedReclaims disk space safely
Core building blocks of Nix

When a matching path exists in a binary cache, Nix downloads it instead of building it, so everyday installation is usually as fast as with conventional package managers. Packages are only compiled locally when they have been modified or are not cached.

Profiles, generations and rollbacks

A user environment in Nix is a profile: a tree of symbolic links into the store. Installing, removing or upgrading software creates a new generation of that profile and then switches one symlink to it. The switch is atomic, so an interrupted upgrade never leaves a half-updated system.

Older generations remain until they are deleted, which makes rollback trivial. On NixOS the same mechanism applies to the whole operating system, and earlier system generations appear as entries in the boot menu, so even a broken kernel or driver update can be undone by choosing the previous entry at startup.

Nix compared with other package managers

Nix shares goals with several tools in the Linux ecosystem but reaches them differently. The table compares it with traditional and container-style approaches.

ApproachInstalls intoMultiple versionsRollbackReproducibility
NixHash-named paths in /nix/storeYes, side by sideBuilt in, atomicStrong by design
APT or DNFShared FHS paths such as /usrRarelyLimited, often by snapshotsDepends on repository state
FlatpakSeparate application bundles with runtimesPartly, by branchSupported for appsGood for desktop apps
Docker imagesLayered container filesystemsYes, per imageBy image tagDepends on how images are built
Nix against neighboring packaging approaches

The decisive difference is that Nix treats a package as a pure function of its inputs. Conventional package managers describe the desired package names and versions, while Nix pins the entire dependency graph down to compilers and libraries.

Everyday use and development environments

Beyond installing software, Nix is widely used to create per-project development environments. A file in the repository lists required compilers, libraries and tools, and one command opens a shell where exactly those versions are available, without touching the rest of the system.

CommandPurpose
nix-shell or nix developEnter a project development environment
nix profile installAdd a package to the user profile
nix-env --rollbackReturn the profile to the previous generation
nixos-rebuild switchBuild and activate a new NixOS configuration
nix-collect-garbage -dDelete old generations and unreferenced store paths
Common Nix commands and their purpose

Flakes add a standard project structure with a lock file that pins exact input revisions, similar to lock files in language package managers. They are widely adopted, although they have long been marked experimental, so teams should agree on whether to use them before building workflows around them.

Limitations and common pitfalls

The main obstacle is the learning curve: the Nix language, derivations and the store model differ from everything most administrators know. Error messages from evaluation can be long and hard to interpret, and documentation is spread across several manuals and community resources.

Precompiled binaries from outside Nix often fail to run because they expect libraries and a dynamic loader at standard FHS paths that do not exist in the same form on NixOS. Workarounds include patching binaries, compatibility layers and FHS-style environments. Disk usage also grows because old generations keep their packages alive, so regular garbage collection is part of normal maintenance.

Understanding it simply

Nix is a way of installing software that never overwrites anything. Each program goes into its own sealed box with a unique label. That label is based on exactly how the program was made.

Because old boxes are kept, you can always go back to how things were yesterday. It is a bit like a word processor with a perfect undo button, but for your whole set of installed programs. Two projects can even use different versions of the same tool without getting in each other’s way.

Applied in practice

A team of six developers maintains a data processing service that needs a specific Python version, a pinned PostgreSQL client library and a particular build of GDAL. New team members used to spend most of their first day setting up their laptops, and the results still differed slightly between machines.

The team adds a Nix flake to the repository that declares all tools and libraries with exact versions. Now a new developer installs Nix, clones the repository and runs nix develop; within about ten minutes, mostly spent downloading from the binary cache, the full environment is ready. The continuous integration server uses the same definition, so the familiar works on my machine problem largely disappears, and a later upgrade is tested on a branch and rolled back with one command when a library change breaks a test.