Nix Language

Nix Language

Introduction

With the Nix package manager, there always comes the Nix programming lanugage. This is a programming language specificly created for the Nix package manager. To launch an interactive repl, run:

$ nix repl
nix-repl> 1 + 2
3
nix-repl>:q
$

The Nix programming language uses lazy evaluation. This means that values only get computed when needed. This is quite useful since it allows for resource efficient recursive functions and other stuff used in functional programming languages. This can be seen in action using something like this:

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

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

Notice how we needed to use the :p to tell Nix that we actually want to see everything and not just the evaluated data structure.

Running/Evaluating Nix files

Until now, we only used the nix repl command to launch an interactive interpreter to get started. We can automate this by creating a file.nix. Please note, that your file can be named differently and doesn't need to be named file.nix:

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

Using the nix-instantiate command with the --eval flag, we can only evaluate the file. If we didn't use that flag, Nix would expect a derivation. What a derivation is, will be explained later. For now, just know that this is the same as running the commands in the nix repl.

In here, we can see the lazy evaluation in action. If we run:

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

You can see, that the output is a bit weird and doesnt really show the actual value, but rather { a = <CODE>; }. To fix this, we can use the --strict flag:

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

Comments

Comments in Nix are declared with #:

{
    string = "hello";
    # This is a comment
}

Data types

In nix, there are various data types. Those include:

Primitive

There are multiple primitive data types in Nix:

myString = "hello";
myInteger = 1;
myFloat = 3.141;
myBool = true;
myNull = null;

List

A list is almost like an array in other languages. In Nix, a list however can contain any type. Also values are not seperated by a , but rather by a whitespace:

myList = [ 1 "two" false ];

Attribute set

An attribute set is a collection of name-value-pairs. A given name must be unique in the set. It is comparable with a json file:

{
    string = "hello";
    integer = 1;
    float = 3.141;
    bool = true;
    null = null;
    list = [ 1 "two" false ];
    attribute-set = {
        a = "hello";
        b = 2;
        c = 2.718;
        d = false;
    };
}

Recursive attribute set

To make an attribute set be able to use its own variables, we need to use the rec { ... } keyword. This allowes the access to those attributes.

rec {
    one = 1;
    two = one + 1;
    three = two + 1;
}

Attribute access

To get a value out of an attribute set, use . and the attribute name:

let
    attribute-set = {
        a = {
            x = 1;
        };
    };
in
attribute-set.a.x

Let ... in ...

This is used for declaring types, which are later reused. Assignments are placed between the let and in keywords. In the following example, a is assigned to 1. After in comes the expression in which the variables are used. a in here refers to a = 1:

let
    a = 1;
    b = 2;
    c = a + b;
in
    a + b + c

Output:

6

with ...; ...

This keyword allows access to attributes without the need to reference the attribute set for each value. This means instead of writing something like attribute-set.nested-attribute-set.value we can use:

let 
    attribute-set = {
        nested-attribute-set = {
            value = 1;
        };
    };
in
with attribute-set.nested-attribute-set; value

Functions

Functions in Nix are defined like this:

let
    myFunction = x: x + 1;
in
myFunction 1

To access values in a attribute set use:

let
    myFunction = x: x.a;
in
myFunction { a = 1; }

Function examples

The following section provides some examples on how to write a function in Nix. Due to the fact that functions only can take one argument in Nix, these examples might be useful.

x: x + 1
x: y: x + y
{ a, b }: a + b
{ a, b ? 0}: a + b
{ a, b, ...}: a + b
{ a, b, ...}@args: a + b + args.c

Builtin functions

Nix comes with many functions out of the box. Those all are implemented in C++ as part of the Nix language interpreter. A full list of all the functions can be found here

Some examples are:

See also

This is just a short guide/wiki entry on how to use the basics of the Nix programming language. A more extensive guide can be found on the official documentation for the Nix ecosystem.