nix-language

(reading-nix-language)=

Nix language basics

The Nix language is designed for conveniently creating and composing derivations – precise descriptions of how contents of existing files are used to derive new files.
It is a domain-specific, purely functional, lazily evaluated, dynamically typed programming language.

:::{admonition} Notable uses of the Nix language
:class: note

  • {term}Nixpkgs

    The largest, most up-to-date software distribution in the world, and written in the Nix language.

  • {term}NixOS

    A Linux distribution that can be configured fully declaratively and is based on Nix and Nixpkgs.

    Its underlying modular configuration system is written in the Nix language, and uses packages from Nixpkgs.
    The operating system environment and services it provides are configured with the Nix language.

:::

You may quickly encounter Nix language expressions that look very complicated.
As with any programming language, the required amount of Nix language code closely matches the complexity of the problem it is supposed to solve, and reflects how well the problem – and its solution – is understood.
Building software is a complex undertaking, and Nix both exposes and allows managing this complexity with the Nix language.

Yet, the Nix language itself has only few basic concepts that will be introduced in this tutorial, and which can be combined arbitrarily.
What may look complicated comes not from the language, but from how it is used.

Overview

This is an introduction to reading the Nix language, for the purpose of following other tutorials and examples.

Using the Nix language in practice entails multiple things:

  • Language: syntax and semantics
  • Libraries: builtins and pkgs.lib
  • Developer tools: testing, debugging, linting, formatting, ...
  • Generic build mechanisms: stdenv.mkDerivation, trivial builders, ...
  • Composition and configuration mechanisms: override, overrideAttrs, overlays, callPackage, ...
  • Ecosystem-specific packaging mechanisms: buildGoModule, buildPythonApplication, ...
  • NixOS module system: config, option, ...

This tutorial only covers the most important language features, briefly discusses libraries, and at the end will direct you to reference material and resources on the other components.

What will you learn?

This tutorial should enable you to read typical Nix language code and understand its structure.
Its goal is to highlight where the Nix language may differ from languages you are used to.

It therefore shows the most common and distinguishing patterns in the Nix language:

:::{important}
This tutorial does not explain all Nix language features in detail and does not go into specifics of syntactical rules.

See the Nix manual for a full language reference.
:::

What do you need?

  • Familiarity with software development
  • Familiarity with Unix shell, to read command line examples
  • A {ref}Nix installation <install-nix> to run the examples

How long does it take?

  • No experience with functional programming: 2 hours
  • Familiar with functional programming: 1 hour
  • Proficient with functional programming: 30 minutes

We recommend to run all examples.
Play with them to validate your assumptions and test what you have learned.
Read detailed explanations if you want to make sure you fully understand the examples.

How to run the examples?

  • A piece of Nix language code is a Nix expression.
  • Evaluating a Nix expression produces a Nix value.
  • The content of a Nix file (file extension .nix) is a Nix expression.

:::{note}
To evaluate means to transform an expression into a value according to the language rules.
:::

This tutorial contains many examples of Nix expressions.
Each one is followed by the expected evaluation result.

The following example is a Nix expression adding two numbers:

:class: expression
1 + 2
:class: value
3

Interactive evaluation

Use nix repl to evaluate Nix expressions interactively (by typing them on the command line):

$ nix repl
Welcome to Nix 2.13.3. Type :? for help.

nix-repl> 1 + 2
3

:::{note}
The Nix language uses lazy evaluation, and nix repl by default only computes values when needed.

Some examples show a fully evaluated data structure for clarity.
If your output does not match the example, try prepending :p to the input expression.

Example:

nix-repl> { a.b.c = 1; }
{ a = { ... }; }

nix-repl> :p { a.b.c = 1; }
{ a = { b = { c = 1; }; }; }

Type :q to exit nix repl.

:::

Evaluating Nix files

Use nix-instantiate --eval to evaluate the expression in a Nix file.

$ echo 1 + 2 > file.nix
$ nix-instantiate --eval file.nix
3

:::{dropdown} Detailed explanation

The first command writes 1 + 2 to a file file.nix in the current directory.
The contents of file.nix are now 1 + 2, which you can check with

$ cat file.nix
1 + 2

The second command runs nix-instantiate with the --eval option on file.nix, which reads the file and evaluates the contained Nix expression.
The resulting value is printed as output.

--eval is required to evaluate the file and do nothing else.
If --eval is omitted, nix-instantiate expects the expression in the given file to evaluate to a special value called a derivation, which we will come back to at the end of this tutorial in .

:::

:::{note}
nix-instantiate --eval will try to read from default.nix if no file name is specified.

$ echo 1 + 2 > default.nix
$ nix-instantiate --eval
3

:::

:::{note}
The Nix language uses lazy evaluation, and nix-instantiate by default only computes values when needed.

Some examples show a fully evaluated data structure for clarity.
If your output does not match the example, try adding the --strict option to nix-instantiate.

Example:

$ echo "{ a.b.c = 1; }" > file.nix
$ nix-instantiate --eval file.nix
{ a = <CODE>; }
$ echo "{ a.b.c = 1; }" > file.nix
$ nix-instantiate --eval --strict file.nix
{ a = { b = { c = 1; }; }; }

:::

Notes on whitespace

White space is used to delimit lexical tokens, where required.
It is otherwise insignificant.

Line breaks, indentation, and additional spaces are for readers' convenience.

The following are equivalent:

:class: expression
let
 x = 1;
 y = 2;
in x + y
:class: value
3
:class: expression
let x=1;y=2;in x+y
:class: value
3

(names-values)=

Names and values

Values in the Nix language can be primitive data types, lists, attribute sets, and functions.

We show examples of primitive data types and lists in the context of attribute sets.
Later in this section we cover special features of character strings: string interpolation, file system paths, and indented strings.
We deal with functions separately.

Attribute sets and let expressions are used to assign names to values.
Assignments are denoted by a single equal sign (=).

Whenever you encounter an equal sign (=) in Nix language code:

  • On its left is the assigned name.
  • On its right is the value, delimited by a semicolon (;).

(attrset)=

Attribute set { ... }

An attribute set is a collection of name-value-pairs, where names must be unique.