derivations
the build instruction at the heart of nix.
“every build is won before it begins”
the build instruction at the heart of nix.
“every build is won before it begins”
the language evaluates expressions and produces values. attribute sets, functions, strings, lists. none of those are packages, and none of them build anything.
a derivation is the value that nix knows how to build. it is an attribute set with a specific shape, and when nix encounters one, it writes a .drv file into the store, computes its hash, and knows exactly what to do with it.
every package in nixpkgs is a derivation. every nix build resolves to one. store paths, references, the language. this is where they meet.
builtins.derivation {
name = "hello";
system = "x86_64-linux";
builder = "/bin/sh";
args = [ "-c" "echo hello > $out" ];
}
builtins.derivation is the bottom of the stack. give it a name, a system, a builder, and nix will write a .drv file and build it. the output lands in /nix/store/{hash}-hello.
nobody uses builtins.derivation directly. it is too raw. you have to set up PATH, provide a compiler, handle source unpacking, configure flags, install into $out. all manually.
stdenv.mkDerivation {
pname = "hello";
version = "1.0";
src = ./src;
buildInputs = [ openssl ];
}
stdenv.mkDerivation wraps the primitive with a standard build environment: a shell, coreutils, a compiler, and a phased build script that handles unpacking, configuring, building, and installing. nearly every package in nixpkgs uses it.
the attribute set you pass to mkDerivation is not the derivation itself. mkDerivation transforms it: it merges your attributes with stdenv's defaults, constructs the builder arguments, resolves dependencies, and calls builtins.derivation underneath.
the .drv file is the serialized build plan that lands in the store. every derivation becomes one.
stdenv and mkDerivation is the standard environment that wraps the primitive and gives you a working build toolchain.
build phases walks through the lifecycle of a standard build: unpack, configure, build, install, fixup. each phase is a shell function you can override.
fixed-output derivations are the exception to the input-addressed model. fetchers need network access, so they hash the output instead.