~/ ~/documents ~/recommended-reading ~/software ~/pictures github (opens in new tab)

Decoding the Lexicon of Purity

Nix has its own vocabulary, and the terminology can easily overwhelm newcomers. Many terms have precise mathematical, functional, and systems-level meanings that differ from standard Linux jargon.

Declarative

A programming paradigm where you describe what the system should look like (the desired end-state), rather than how to achieve it (a sequence of imperative commands). NixOS is fully declarative: you declare your system configuration, and Nix computes how to configure services, write files, and install packages to match.

Functional

A programming paradigm where programs are constructed by applying and composing pure functions. Nix is a domain-specific, purely functional language: functions are first-class values, variables are immutable (cannot be reassigned), and expressions produce outputs based exclusively on explicit inputs without hidden side effects.

Idempotency

The mathematical and operational property where an action produces the exact same outcome whether executed once or repeated a thousand times. Applying a Nix configuration multiple times leaves the system in the identical target state.

Purity

The invariant that evaluation and build functions depend strictly on explicitly declared inputs and produce zero side effects. In Nix, builds execute in hermetic, network-isolated sandboxes so ambient host state cannot leak into the compiler.

Hermetic Build

A build execution that is completely self-contained and isolated from the host operating system. Only explicitly declared compilers, dependencies, tools, and environment variables are mounted into the sandbox.

FHS (Filesystem Hierarchy Standard)

The traditional directory layout of Unix-like operating systems (defining standard global paths like /bin, /lib, /usr/lib, /var). Nix explicitly rejects the global FHS layout in favor of an isolated, store-based model to prevent dependency collisions and guarantee reproducible environments.

Expression

A piece of code written in the Nix language that evaluates to a value. Because Nix is purely functional, virtually everything is an expression: functions, conditionals, attribute sets, lists, and primitives.

Path

A first-class data type in the Nix language representing a file system path, written without quotes (e.g. ./default.nix or /etc/resolv.conf).

Attribute Set (AttrSet)

A key-value data structure in the Nix language, written with curly braces { name = "value"; }. It is the primary structure used to pass configurations, declare modules, and organize packages.

{
  name = "app";
  version = "1.0.0";
  meta.description = "A Nix attribute set";
}

Recursive Attribute Sets (rec)

A Nix language construct (rec { ... }) allowing attributes within a set to reference siblings. While convenient, rec binds attributes eagerly at definition time rather than supporting open recursion, frequently causing infinite recursion errors or breaking downstream overrides. Modern Nix favors let ... in bindings or finalAttrs.

rec {
  name = "app";
  version = "1.0.0";
  tarball = "${name}-${version}.tar.gz";
}

String Context

Under the hood, Nix strings carry hidden metadata tracking every store path referenced during string evaluation (such as "${pkgs.hello}"). Whenever an interpolated string is passed to a derivation, Nix automatically inspects its string context to include all referenced store paths as build dependencies.

Interpolated String (Antiquotation)

The syntax inside the Nix language ("${expression}") used to evaluate an expression and embed its value directly inside a string. If the expression evaluates to a derivation or path, Nix renders its store path and attaches it to the string’s String Context.

let
  name = "Dominic";
in
"Hello, ${name}!"

Evaluation Time (Eval-time)

The phase where the Nix interpreter reads your Nix code, parses expressions, resolves imports, and evaluates the dependency graph to compute derivations. No compilation or package building occurs during eval-time.

Pure vs Impure Evaluation

REPL (Read-Eval-Print Loop)

An interactive shell (nix repl) for evaluating Nix expressions, exploring package sets, testing helper functions, and inspecting attribute sets in real time.

lib (Nixpkgs Utility Library)

A library bundled inside Nixpkgs containing hundreds of helper functions for data manipulation (lists, strings, attribute sets, filesystem paths) and NixOS module type checking.

The Fixed-Point Pattern (lib.fix)

A functional programming pattern powering open recursion in Nixpkgs. It allows a function’s output to serve as its own input before evaluation finishes, enabling overlays, package overrides, and modular option merging across NixOS.

lib.fix (self: {
  a = 1;
  b = self.a + 2; # evaluates to 3
})

ATerm (Annotated Term)

The internal serialization format used by Nix to represent parsed abstract syntax trees (ASTs) and derivations (.drv files). ATerms implement maximal subterm sharing as Directed Acyclic Graphs (DAGs), ensuring identical expressions share memory and enable constant-time pointer equality checks.

Derivation (.drv)

A build recipe produced during evaluation. It is an immutable text file in /nix/store describing exactly how to build an artifact: source paths, build scripts, compilers, environment variables, dependencies, and target output paths.

derivation {
  name = "simple-example";
  system = "x86_64-linux";
  builder = "/bin/sh";
  args = [ "-c" "echo hello > $out" ];
}

Realisation (Realise / Instantiation)

The build phase where Nix executes the build recipe defined in a .drv file inside an isolated sandbox, compiling the source code and writing the finished artifact to /nix/store.

Stdenv (Standard Environment)

The default base packaging environment in Nixpkgs. It bundles standard compilers (GCC/Clang), core POSIX/GNU utilities (bash, coreutils, make, sed, grep), and orchestrates the standard phases of building software (unpack, patch, configure, build, check, install).

callPackage

The standard dependency injection mechanism in Nixpkgs. Instead of manually passing every library and tool to a package file, pkgs.callPackage ./file.nix { } automatically inspects the file’s argument list and injects the matching dependencies from the package set.

buildInputs vs nativeBuildInputs

The critical distinction defining where a build dependency is expected to execute:

passthru

An attribute in derivations used to attach helper scripts, tests, or subpackages to a derivation object without affecting its cryptographic build hash.

Multiple Outputs

A packaging pattern that splits a derivation’s build output into separate sub-paths in /nix/store (such as out, bin, lib, dev, man, doc), preventing runtime consumers from pulling in unnecessary build-time headers or documentation.

meta attribute

An attribute set inside a derivation containing informational metadata (licenses, maintainers, homepage, platform compatibility). It does not affect the build hash.

override vs overrideAttrs

The two standard mechanisms for customizing existing Nixpkgs derivations:

# Overriding input arguments
pkgCustom = pkgs.hello.override { stdenv = pkgs.clangStdenv; };

# Overriding derivation build attributes
pkgPatched = pkgs.hello.overrideAttrs (oldAttrs: {
  patches = (oldAttrs.patches or [ ]) ++ [ ./fix.patch ];
});

Source Filtering (cleanSource)

The practice of pruning untracked files (such as .git/, build artifacts, or editor configs) before copying a local directory into /nix/store. Filtering sources prevents trivial file edits from invalidating derivation hashes and causing redundant rebuilds.

stdenv.mkDerivation {
  name = "app";
  src = lib.cleanSource ./.;
}

__structuredAttrs

An advanced derivation setting that serializes all build attributes into a single JSON file ($NIX_ATTRS_JSON_FILE) inside the sandbox. This eliminates POSIX environment variable size limits and supports nested data structures in builder scripts.

allowedReferences / disallowedReferences

Derivation assertions used to enforce strict runtime boundaries:

The Store (/nix/store)

The immutable, read-only directory that houses all packages, derivations, configurations, and dependencies. Every item lives under a unique path prefixed by a cryptographic hash of its inputs.

NAR (Nix Archive)

A deterministic serialization format that packs a file or directory tree into a single contiguous byte stream. Unlike .tar or .zip, NAR guarantees that identical folder contents, timestamps, and permissions always produce the exact same byte-for-byte archive.

NAR Hash (narHash)

The cryptographic hash computed over a path serialized in the NAR format. It is the primary fingerprint Nix uses to identify and verify store objects.

File Hash (Flat Hash)

The raw cryptographic hash of a single file’s contents without NAR framing (equivalent to sha256sum).

Cryptographic Hash

A deterministic hash (typically SHA-256 in base-32 “nix32” or SRI format) used throughout Nix to uniquely identify derivations, verify source archives, and index store paths.

Closure

The complete mathematical closure of a store path: the artifact itself plus the transitive closure of all direct and indirect runtime dependencies required for it to run.

Fixed-Output Derivation (FOD)

A special derivation where the cryptographic hash of the output is declared in advance (e.g. fetchurl, fetchFromGitHub, Cargo/Go dependency fetchers). Because the output hash is pinned, Nix grants the build sandbox network access to download external assets without compromising downstream reproducibility.

pkgs.fetchurl {
  url = "https://example.com/source.tar.gz";
  sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
}

Content-Addressed Derivations (CA Derivations)

An advanced Nix architecture where a derivation’s store path is derived from the cryptographic hash of its built output content rather than its input recipes. This solves the “early cutoff” problem: if a dependency changes but compiles to identical bytecode, downstream packages do not need to be rebuilt.

Garbage Collection (GC)

The process (nix-collect-garbage) of reclaiming disk space by identifying and deleting unreferenced paths in /nix/store. Nix uses a mark-and-sweep algorithm starting from registered GC roots.

GC Root (Garbage Collector Root)

A symlink stored in /nix/var/nix/gcroots that protects a store path and its entire runtime closure from being deleted by the garbage collector.

Profile

A versioned collection of user or system packages maintained as a tree of symlinks. Profiles live in /nix/var/nix/profiles and allow instantaneous atomic updates and rollbacks.

Generation

An immutable snapshot of a profile. Every time you install software or switch a system configuration, a new generation is created, preserving historical generations for rollback.

Impermanence

An architectural pattern where the root filesystem (/) is mounted on temporary storage (tmpfs in RAM) and wiped on every boot. Only explicitly declared paths (e.g., /persist or /home) survive reboots, ensuring state never accumulates silently.

Binary Cache (Cache)

An HTTP server or storage bucket hosting pre-built .nar archives and metadata, allowing machines to substitute pre-compiled binaries instead of compiling from source.

Substituter

A registered binary cache endpoint (e.g., cache.nixos.org). When realising a derivation, Nix queries substituters to fetch matching pre-built outputs before falling back to local compilation.

Narinfo (.narinfo)

A small manifest file downloaded from a binary cache before fetching a package. It details the store path, cache signature, closure references, compression type, and hash of the corresponding .nar file.

Prefetch (nix-prefetch-url)

A utility command used to download a network file, compute its cryptographic hash, and insert it directly into the local store, providing the exact hash needed to write fixed-output derivations.

Cross-Compilation

Building software on a build platform (e.g., x86_64-linux) that executes on a different host platform (e.g., aarch64-linux). The compiler runs natively on the build machine while generating target machine code.

# Cross-compiling a package
pkgsCross = import nixpkgs {
  localSystem = "x86_64-linux";
  crossSystem = "aarch64-linux";
};
armPackage = pkgsCross.hello;

Remote Builder (Builder)

A remote machine configured to accept derivations dispatched over SSH, building packages on behalf of a local machine and returning the built store paths.

Emulated Build (binfmt_misc)

Building non-native binaries locally using user-mode QEMU emulation and the Linux kernel’s binfmt_misc interface (configured via boot.binfmt.emulatedSystems), allowing foreign builds to run without cross-compilers or remote hardware.

Development Shell (devShell)

A transient, reproducible shell environment configured on the fly (via nix develop or nix-shell) containing compilers, tools, and environment variables without installing anything globally.

mkShell

A specialized Nixpkgs helper used to declare development shells. It produces an environment with loaded dependencies and custom shell startup hooks (shellHook).

pkgs.mkShell {
  packages = [ pkgs.rustc pkgs.cargo ];
  shellHook = ''
    echo "Welcome to the Rust dev environment!"
  '';
}

A utility function that merges multiple derivations into a single directory hierarchy using symlinks, creating combined package environments without rebuilding source packages.

autoPatchelfHook (RPATH Patching)

A build hook that inspects pre-compiled ELF binaries and rewrites their dynamic linker interpreter and RPATH library search paths to point directly to /nix/store dependencies, enabling foreign Linux binaries to execute on NixOS.

FHS Environment (buildFHSEnv / envfs)

A sandboxing tool that constructs a virtual Filesystem Hierarchy Standard layout using Linux mount namespaces (chroot/bubblewrap), allowing unpatched proprietary binaries (like Steam or pre-built language toolchains) to run seamlessly.

Package Set (pkgs)

The evaluated attribute set produced by importing Nixpkgs. It contains tens of thousands of derivations, compilers, and library utilities configured for a specific host system.

Nixpkgs

The central Git repository containing the official collection of Nix packages, stdenv build infrastructures, and NixOS modules.

Channel

The legacy rolling-release distribution mechanism for Nixpkgs. Channels are release branches updated only after passing automated test suites.

<nixpkgs> & NIX_PATH

The legacy lookup mechanism that resolves paths based on ambient system environment variables and local channels. Flakes supersede this by replacing <nixpkgs> with explicit, locked inputs.

Flake

The modern packaging and project standard for Nix. A flake.nix file declares explicit, hermetically locked inputs (dependencies) and outputs (packages, modules, devShells, apps).

{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
  outputs = { self, nixpkgs }: {
    packages.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.hello;
  };
}

flake.lock

The JSON lockfile pinning every flake input to an exact cryptographic commit hash and URI, ensuring reproducible evaluations across all machines.

NixOS

A Linux distribution built entirely around the Nix package manager, configured declaratively through modules that generate the kernel, system services, and configuration files.

NixOS Module

A composable configuration file for NixOS. It defines configurable options via options and applies declarative system settings via config.

{ config, lib, pkgs, ... }:

{
  options.myService.enable = lib.mkEnableOption "my service";
  config = lib.mkIf config.myService.enable {
    environment.systemPackages = [ pkgs.curl ];
  };
}

lib.mkIf, lib.mkMerge, lib.mkForce

Module system helpers used to control option precedence and conditionality:

Home Manager

A declarative tool that manages user-level dotfiles, environment variables, and user packages using the Nix module system.

Nix Daemon (nix-daemon)

The privileged background service that manages store paths, builds, and sandboxing in multi-user Nix installations and NixOS.

trusted-users

A privileged group in nix.conf. Trusted users can specify custom binary caches, import unsigned store paths, and alter daemon sandbox policies, making this setting equivalent to root-level access.

IFD (Import from Derivation)

An advanced pattern where the evaluator imports the build output of a derivation back into the evaluation stage as Nix code. While powerful for dynamic code generation, IFD forces evaluation to pause while intermediate builds execute.

The staging Branch & Rebuild Cascades

The Nixpkgs branching strategy used to batch low-level updates (e.g. glibc or gcc) that would otherwise invalidate thousands of package hashes and cause massive rebuild cascades across the ecosystem.

Hydra & OfBorg

The continuous integration and automation engines for Nixpkgs:

Legacy vs Modern Nix CLI (CLI 2.0 / Flakes)

The transition from legacy multi-binary commands (nix-build, nix-shell, nix-env) to the unified, modern nix command suite (nix build, nix develop, nix run, nix flake).