Nix Tutorial 4 : Nix Derivations: The Core of Building in Nix - wimsio/universities GitHub Wiki

A derivation in Nix is a recipe for building a package or store object. It describes what to build, how to build it, and with which dependencies. The derivation function is how you define these recipes.


📝 Table of Contents

  1. What is a Derivation?

  2. Basic Usage

  3. Key Attributes

  4. Outputs

  5. Passing Data to the Builder

  6. Advanced/Extra Attributes

  7. Content Addressing & Hashing

  8. Import From Derivation (IFD)

  9. Derivation Examples

  10. Further Reading


What is a Derivation? ❓

  • A derivation is a build recipe for the Nix store.
  • It is defined as an attribute set passed to the derivation built-in.
  • Evaluating it creates a .drv file in /nix/store and, once built, the outputs (binaries, libraries, docs, etc).

See the Nix manual: derivations for in-depth theory.


Basic Usage 🔨

derivation {
  name = "hello";
  system = "x86_64-linux";
  builder = "/bin/sh";
  args = [ "-c" "echo Hello, world! > $out" ];
}
  • The result is an attribute set describing outputs, e.g.:

    • /nix/store/<hash>-hello.drv
    • /nix/store/<hash>-hello

Key Attributes 🗝️

Required Attributes

Attribute Type Description Example
name String Name for the derivation "hello"
system String System type (target platform) "x86_64-linux" or builtins.currentSystem
builder Path/String Executable to run for building "/bin/bash" or ./builder.sh

Example

derivation {
  name = "demo";
  system = builtins.currentSystem;
  builder = "/bin/sh";
  args = [ "-c" "echo Hi > $out" ];
}

Optional Attributes

  • args (List of Strings): Arguments passed to the builder.
  • outputs (List of Strings): Which outputs to generate (default: [ "out" ]).
  • Any other attribute: Passed to the builder as an environment variable.

Example:

derivation {
  name = "libexample";
  builder = "/bin/sh";
  args = [ "-c" "touch $lib; touch $dev; touch $doc" ];
  outputs = [ "lib" "dev" "doc" ];
  system = "x86_64-linux";
}

Advanced Attributes

See Advanced Attributes below for power-user settings like allowedReferences, outputHashAlgo, preferLocalBuild, etc.


Outputs 📦

  • Default: a single output named "out".

  • Multiple outputs: e.g., [ "lib" "dev" "doc" ]

    • Each output is available as an attribute: myDrv.lib, myDrv.dev, etc.
    • The first output is the "default" and can be accessed via the top-level variable.

Example:

let
  myDrv = derivation {
    name = "foo";
    outputs = [ "bin" "doc" "out" ];
    ...
  };
in myDrv.doc
  • Outputs become store paths like /nix/store/<hash>-foo-bin, /nix/store/<hash>-foo-doc, etc.

Passing Data to the Builder 📤

  • Strings: Passed unchanged as env vars.
  • Numbers: Converted to strings.
  • Paths: Copied into the store, the env var gets the store path.
  • Lists: Flattened to space-separated strings.
  • true: "1", false/null: empty string.

Big Data: Use passAsFile = [ "myBigString" ]; to pass long data via file path env var (myBigStringPath).


Advanced/Extra Attributes 🚀

Some optional/advanced attributes for special needs:

Attribute Description
exportReferencesGraph Pass closure graphs of dependencies to the builder.
passAsFile Pass env vars via temp files, not the environment (for very long values).
__structuredAttrs Serialize all attributes as JSON file (env: $NIX_ATTRS_JSON_FILE).
allowedReferences List of store paths allowed as runtime refs.
disallowedReferences Store paths not allowed as runtime refs.
preferLocalBuild Prefer local build over remote.
allowSubstitutes If false, disables use of prebuilt binary substitutes.
requiredSystemFeatures Only build on systems with listed features (e.g., [ "kvm" ]).
impureEnvVars Pass selected host env vars to the builder (for fixed-output only).
outputHash*, __contentAddressed Configure advanced content-addressed builds.

See the Nix manual on advanced derivation attributes for the full list.


Content Addressing & Hashing 🔒

  • For fixed-output or content-addressed derivations, use outputHash, outputHashAlgo, and outputHashMode.
  • Supported hash algos: "sha256", "sha512", "blake3", etc.
  • Hash mode: "flat", "nar", "text", "git".

Example:

derivation {
  ...
  outputHash = "abcdef123...";
  outputHashAlgo = "sha256";
  outputHashMode = "flat";
}
  • Needed for reproducibility and trusted builds.

Import From Derivation (IFD) 📥

  • You can use the output of a derivation as an input to functions like import, readFile, etc.
  • This pauses evaluation until the dependency is built (can be slow or problematic in large builds).
  • Control with allow-import-from-derivation setting.

Example:

let
  drv = derivation {
    name = "hello";
    builder = "/bin/sh";
    args = [ "-c" "echo -n hello > $out" ];
    system = builtins.currentSystem;
  };
in "${builtins.readFile drv} world"  # → "hello world"

Illustration: The Nix evaluator will build the drv, then use its output in your expression.


Derivation Examples 🧩

1. Minimal Derivation

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

2. Multi-Output Derivation

derivation {
  name = "multifile";
  outputs = [ "bin" "doc" ];
  builder = "/bin/sh";
  args = [ "-c" "touch $bin; echo docs > $doc" ];
  system = "x86_64-linux";
}

3. Passing Large Data

derivation {
  name = "big";
  builder = "/bin/sh";
  args = [ "-c" "cat $bigPath > $out" ];
  system = "x86_64-linux";
  passAsFile = [ "big" ];
  big = "Very long content...";
}

Further Reading 🔗


Tip: Try inspecting and building derivations with nix repl or nix-instantiate!


⚠️ **GitHub.com Fallback** ⚠️