the nix store
content-addressed storage and what makes nix builds reproducible.
content-addressed storage and what makes nix builds reproducible.
most package managers write into shared directories. /usr/lib, /usr/bin, /usr/local. when two packages need different versions of the same dependency, they fight over the same path. one wins. the other breaks, usually silently.
nix does not do this.
run ls /nix/store | head on any nix machine:
$ ls /nix/store | head
0a0igrkhhpbm3kqd2xs3ibqyc5dd0a11-gn-5d0a415.drv
0a0s392pa6709fzmr3s1hk58l7pm1fzl-libxkbcommon-1.11.0.drv
0a0y1r2nhq7gxg00s9hm6h9ncv8qb38f-aws-c-common-0.12.4
0a02vx71hgq46d6kxb2x2cwq4lsv461h-bash-interactive-5.3p3.drv
0a063gj8q7ng0g24zjwd4k2gqfh87kz0-python3.13-appdirs-1.4.4.drv
0a1i4wxza5wpzb3b3g90avk4nzd23wh3-packdir-start
0a1wj3l9iq6ircixbzbj9ygkl3rn9i5d-libglvnd-1.7.0
0a2ms88sl58aq3sfssd912hckmnx2mlm-Net-SMTP-SSL-1.04.tar.gz.drv
flat directory. hash-named paths. no nesting by package, no version subdirectories, no shared lib/ or bin/. you'll see a mix of built package directories (no extension), .drv derivation files, and source archives: the store holds everything nix works with.
each path looks like this:
/nix/store/xhp149abalfmj232yjhgbqaw281ba8np-curl-8.18.0/
32-character hash, then a dash, then name and version. that hash is the entire point.
the hash encodes everything that went into producing the package: the source, every dependency, every build flag, the compiler, environment variables. same inputs, same hash, same path. always.
change a dependency, patch the source, flip a compiler flag. you get a different hash. a different path. the original is untouched.
two apps need different versions of the same library:
both paths exist simultaneously. neither app knows the other is there. no symlinks, no alternatives system, no LD_LIBRARY_PATH juggling.
once a path is written to /nix/store, it is never modified. the store is append-only.
build the same thing again with the same inputs: same hash, same path, already there. nix skips the build entirely. different inputs: new path, old path stays.
there is no state to corrupt. no partial upgrade that leaves things inconsistent. a path either exists and is complete, or it does not exist yet.
store paths goes into how the hash is actually computed: what fields make up a derivation, how SHA-256 becomes a 32-character base-32 string, and what fixed-output derivations are.
the build sandbox covers how nix isolates builds so only the inputs you declared can affect the result.
after those, references and closures shows what nix does with a build output once it lands in the store: scanning for embedded store paths, building closure graphs, and deciding what the garbage collector keeps.