Derivations_explained
Introduction to Nix Derivations

- A derivation in Nix is a fundamental concept that describes how to build a piece of software or a resource (e.g., a package, library, or configuration file). Think of it as a recipe for creating something within the Nix ecosystem. 
- For beginners, the analogy of a cooking recipe is helpful: - Ingredients (Dependencies): What other software or libraries are needed.
- Steps (Build Instructions): The commands to compile, configure, and install.
- Final Dish (Output): The resulting package or resource.
 
- A Nix derivation encapsulates all this information, telling Nix what inputs to use, how to build it, and what the final output should be. 
Creating Derivations in Nix
- The primary way to define packages in Nix is through the - mkDerivationfunction, which is part of the standard environment (- stdenv). While a lower-level- derivationfunction exists for advanced use cases,- mkDerivationsimplifies the process by automatically managing dependencies and the build environment.
- mkDerivation(and- derivation) takes a set of attributes as its argument. At a minimum, you’ll often encounter these essential attributes:- name: A human-readable identifier for the derivation (e.g., “foo”, “hello.txt”). This helps you and Nix refer to the package.
- system: Specifies the target architecture for the build
(e.g., builtins.currentSystemfor your current machine).
- builder: Defines the program that will execute the build instructions
(e.g., bash).
 
Our First Simple Derivation: Understanding the Builder
- To understand how derivations work, let’s create a very basic example using a
bash script as our builder.
Why a Builder Script?
- The builderattribute in a derivation tells Nix how to perform the build steps. A simple and common way to define these steps is with a bash script.
The Challenge with Shebangs in Nix
- In typical Unix-like systems, you might start a bash script with a shebang ( - #!/bin/bashor- #!/usr/bin/env bash) to tell the system how to execute it. However, in Nix derivations, we generally avoid this.
- Reason: Nix builds happen in an isolated environment where the exact path to common tools like - bashisn’t known beforehand (it resides within the Nix store). Hardcoding a path or relying on the system’s- PATHwould break Nix’s stateless property.
The Importance of Statelessness in Nix
- Stateful Systems (Traditional): When you install software traditionally, it often modifies the core system environment directly. This can lead to dependency conflicts and makes rollbacks difficult. 
- Stateless Systems (Nix): Nix takes a different approach. When installing a package, it creates a unique, immutable directory in the Nix store. This means: - No Conflicts: Different versions of the same package can coexist without interfering with each other.
- Reliable Rollback: You can easily switch back to previous versions without affecting system-wide files.
- Reproducibility: Builds are more likely to produce the same result across different machines if they are “pure” (don’t rely on external system state).
 
Our builder Script
- For our first derivation, we’ll create a simple builder.shfile in the current directory:
# builder.sh
declare -xp
echo foo > $out
- The command - declare -xplists exported variables (it’s a bash builtin function).
- Nix needs to know where the final built product (the “cake” in our earlier analogy) should be placed. So, during the derivation process, Nix calculates a unique output path within the Nix store. This path is then made available to our builder script as an environment variable named - $out. The- .drvfile, which is the recipe, contains instructions for the builder, including setting up this- $outvariable. Our builder script will then put the result of its work (in this case, the “foo” file) into this specific- $outdirectory.
- As mentioned earlier we need to find the nix store path to the bash executable, common way to do this is to load Nixpkgs into the repl and check: 
nix-repl> :l <nixpkgs>
Added 3950 variables.
nix-repl> "${bash}"
"/nix/store/ihmkc7z2wqk3bbipfnlh0yjrlfkkgnv6-bash-4.2-p45"
So, with this little trick we are able to refer to bin/bash and create
our derivation:
nix-repl> d = derivation { name = "foo"; builder = "${bash}/bin/bash";
 args = [ ./builder.sh ]; system = builtins.currentSystem; }
nix-repl> :b d
[1 built, 0.0 MiB DL]
this derivation produced the following outputs:
  out -> /nix/store/gczb4qrag22harvv693wwnflqy7lx5pb-foo
- Boom! The contents of - /nix/store/w024zci0x1hh1wj6gjq0jagkc1sgrf5r-foois really foo! We’ve built our first derivation.
- Derivations are the primitive that Nix uses to define packages. “Package” is a loosely defined term, but a derivation is simply the result of calling - builtins.derivation.
Our Second Derivation
The following is a simple hello-drv derivation:
nix-repl> hello-drv = nixpkgs.stdenv.mkDerivation {
            name = "hello.txt";
            unpackPhase = "true";
            installPhase = ''
              echo -n "Hello World!" > $out
            '';
          }
nix-repl> hello-drv
«derivation /nix/store/ad6c51ia15p9arjmvvqkn9fys9sf1kdw-hello.txt.drv»
- Derivations have a .drvsuffix, as you can see the result of callinghello-drvis the nix store path to a derivation.
Links To Articles about Derivations
- Sparky/blog-creatingASuperSimpleDerivation # How to learn Nix