(reading-nix-language)=
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.
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:
builtins
and pkgs.lib
stdenv.mkDerivation
, trivial builders, ...override
, overrideAttrs
, overlays, callPackage
, ...buildGoModule
, buildPythonApplication
, ...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.
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.
:::
Nix installation <install-nix>
to run the examplesWe 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.
.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
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
.
:::
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; }; }; }
:::
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)=
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:
;
).(attrset)=
{ ... }
An attribute set is a collection of name-value-pairs, where names must be unique.