Nix User's Guide

Draft (Version 0.11)

Eelco Dolstra

Utrecht University
Faculty of Science, Department of Information and Computing Sciences

Table of Contents

1. Introduction
1.1. About Nix
1.2. About us
1.3. About this manual
1.4. License
1.5. More information
2. Quick Start
3. Installation
3.1. Supported platforms
3.2. Obtaining Nix
3.3. Prerequisites
3.4. Building Nix from source
3.5. Installing from RPMs
3.6. Upgrading Nix through Nix
3.7. Security
3.7.1. Single-user mode
3.7.2. Multi-user mode
3.7.2.1. Setting up the build users
3.7.2.2. Nix store/database owned by root
3.7.2.3. Nix store/database not owned by root
3.7.2.4. Restricting access
3.8. Using Nix
4. Package Management
4.1. Basic package management
4.2. Profiles
4.3. Garbage collection
4.3.1. Garbage collector roots
4.4. Channels
4.5. One-click installs
5. Writing Nix Expressions
5.1. A simple Nix expression
5.1.1. The Nix expression
5.1.2. The builder
5.1.3. Composition
5.1.4. Testing
5.1.5. The generic builder
5.2. The Nix expression language
5.2.1. Values
5.2.2. Language constructs
5.2.3. Operators
5.2.4. Derivations
5.2.4.1. Advanced attributes
5.2.5. Built-in functions
5.3. The standard environment
5.3.1. Customising the generic builder
5.3.2. Debugging failed builds
6. Setting up a Build Farm
6.1. Overview
6.2. Setting up distributed builds
A. Command Reference
A.1. Common options
A.2. Common environment variables
A.3. Nix configuration file
A.4. Main commands
A.4.1. nix-env
A.4.2. nix-instantiate
A.4.3. nix-store
A.5. Utilities
A.5.1. nix-build
A.5.2. nix-channel
A.5.3. nix-collect-garbage
A.5.4. nix-copy-closure
A.5.5. nix-hash
A.5.6. nix-install-package
A.5.7. nix-pack-closure
A.5.8. nix-prefetch-url
A.5.9. nix-pull
A.5.10. nix-push
A.5.11. nix-unpack-closure
B. Troubleshooting
B.1. Berkeley DB: “Cannot allocate memory
B.2. Berkeley DB gives weird error messages
B.3. Berkeley DB out of locks
B.4. Collisions in nix-env
B.5. “Too many links” error in the Nix store
C. Bugs / To-Do
D. Glossary
E. Nix Release Notes
E.1. Release 0.11 (December 31, 2007)
E.2. Release 0.10.1 (October 11, 2006)
E.3. Release 0.10 (October 6, 2006)
E.4. Release 0.9.2 (September 21, 2005)
E.5. Release 0.9.1 (September 20, 2005)
E.6. Release 0.9 (September 16, 2005)
E.7. Release 0.8.1 (April 13, 2005)
E.8. Release 0.8 (April 11, 2005)
E.9. Release 0.7 (January 12, 2005)
E.10. Release 0.6 (November 14, 2004)
E.11. Release 0.5 and earlier

List of Figures

4.1. User environments

List of Tables

5.1. Operators

List of Examples

5.1. Nix expression for GNU Hello (default.nix)
5.2. Build script for GNU Hello (builder.sh)
5.3. Composing GNU Hello (all-packages.nix)
5.4. Build script using the generic build functions
5.5. Nix expression for Subversion
5.6. Passing information to a builder using toXML
5.7. XML representation produced by toXML
6.1. Remote machine configuration: remote-systems.conf
A.1. Nix configuration file

Chapter 1. Introduction

1.1. About Nix

Nix is a purely functional package manager. This means that it treats packages like values in purely functional programming languages such as Haskell — they are built by functions that don’t have side-effects, and they never change after they have been built. Nix stores packages in the Nix store, usually the directory /nix/store, where each package has its own unique subdirectory such as

/nix/store/r8vvq9kq18pz08v249h8my6r9vs7s0n3-firefox-2.0.0.1/

where r8vvq9kq… is a unique identifier for the package that captures all its dependencies (it’s a cryptographic hash of the package’s build dependency graph). This enables many powerful features.

Multiple versions

You can have multiple versions or variants of a package installed at the same time. This is especially important when different applications have dependencies on different versions of the same package — it prevents the “DLL hell”. Because of the hashing scheme, different versions of a package end up in different paths in the Nix store, so they don’t interfere with each other.

An important consequence is that operations like upgrading or uninstalling an application cannot break other applications, since these operations never “destructively” update or delete files that are used by other packages.

Complete dependencies

Nix helps you make sure that package dependency specifications are complete. In general, when you’re making a package for a package management system like RPM, you have to specify for each package what its dependencies are, but there are no guarantees that this specification is complete. If you forget a dependency, then the package will build and work correctly on your machine if you have the dependency installed, but not on the end user's machine if it's not there.

Since Nix on the other hand doesn’t install packages in “global” locations like /usr/bin but in package-specific directories, the risk of incomplete dependencies is greatly reduced. This is because tools such as compilers don’t search in per-packages directories such as /nix/store/5lbfaxb722zp…-openssl-0.9.8d/include, so if a package builds correctly on your system, this is because you specified the dependency explicitly.

Runtime dependencies are found by scanning binaries for the hash parts of Nix store paths (such as r8vvq9kq…). This sounds risky, but it works extremely well.

Multi-user support

Starting at version 0.11, Nix has multi-user support. This means that non-privileged users can securely install software. Each user can have a different profile, a set of packages in the Nix store that appear in the user’s PATH. If a user installs a package that another user has already installed previously, the package won’t be built or downloaded a second time. At the same time, it is not possible for one user to inject a Trojan horse into a package that might be used by another user.

Atomic upgrades and rollbacks

Since package management operations never overwrite packages in the Nix store but just add new versions in different paths, they are atomic. So during a package upgrade, there is no time window in which the package has some files from the old version and some files from the new version — which would be bad because a program might well crash if it’s started during that period.

And since package aren’t overwritten, the old versions are still there after an upgrade. This means that you can roll back to the old version:

$ nix-env --upgrade some-packages
$ nix-env --rollback

Garbage collection

When you install a package like this…

$ nix-env --uninstall firefox

the package isn’t deleted from the system right away (after all, you might want to do a rollback, or it might be in the profiles of other users). Instead, unused packages can be deleted safely by running the garbage collector:

$ nix-collect-garbage

This deletes all packages that aren’t in use by any user profile or by a currently running program.

Functional package language

Packages are built from Nix expressions, which is a simple functional language. A Nix expression describes everything that goes into a package build action (a “derivation”): other packages, sources, the build script, environment variables for the build script, etc. Nix tries very hard to ensure that Nix expressions are deterministic: building a Nix expression twice should yield the same result.

Because it’s a functional language, it’s easy to support building variants of a package: turn the Nix expression into a function and call it any number of times with the appropriate arguments. Due to the hashing scheme, variants don’t conflict with each other in the Nix store.

Transparent source/binary deployment

Nix expressions generally describe how to build a package from source, so an installation action like

$ nix-env --install firefox

could cause quite a bit of build activity, as not only Firefox but also all its dependencies (all the way up to the C library and the compiler) would have to built, at least if they are not already in the Nix store. This is a source deployment model. For most users, building from source is not very pleasant as it takes far too long. However, Nix can automatically skip building from source and download a pre-built binary instead if it knows about it. Nix channels provide Nix expressions along with pre-built binaries.

Binary patching

In addition to downloading binaries automatically if they’re available, Nix can download binary deltas that patch an existing package in the Nix store into a new version. This speeds up upgrades.

Nix Packages collection

We provide a large set of Nix expressions containing hundreds of existing Unix packages, the Nix Packages collection (Nixpkgs).

Service deployment

Nix can be used not only for rolling out packages, but also complete configurations of services. This is done by treating all the static bits of a service (such as software packages, configuration files, control scripts, static web pages, etc.) as “packages” that can be built by Nix expressions. As a result, all the features above apply to services as well: for instance, you can roll back a web server configuration if a configuration change turns out to be undesirable, you can easily have multiple instances of a service (e.g., a test and production server), and because the whole service is built in a purely functional way from a Nix expression, it is repeatable so you can easily reproduce the service on another machine.

Portability

Nix should run on most Unix systems, including Linux, FreeBSD and Mac OS X. It is also supported on Windows using Cygwin.

NixOS

NixOS is a Linux distribution based on Nix. It uses Nix not just for package management but also to manage the system configuration (e.g., to build configuration files in /etc). This means, among other things, that it’s possible to easily roll back the entire configuration of the system to an earlier state. Also, users can install software without root privileges. For more information and downloads, see the NixOS homepage.

1.2. About us

Nix was developed at the Department of Information and Computing Sciences, Utrecht University by the TraCE project. The project is funded by the Software Engineering Research Program Jacquard to improve the support for variability in software systems.

1.3. About this manual

This manual tells you how to install and use Nix and how to write Nix expressions for software not already in the Nix Packages collection. It also discusses some advanced topics, such as setting up a Nix-based build farm.

1.4. License

Nix is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. Nix is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

1.5. More information

Some background information on Nix can be found in a number of papers. The ICSE 2004 paper Imposing a Memory Management Discipline on Software Deployment discusses the hashing mechanism used to ensure reliable dependency identification and non-interference between different versions and variants of packages. The LISA 2004 paper Nix: A Safe and Policy-Free System for Software Deployment gives a more general discussion of Nix from a system-administration perspective. The CBSE 2005 paper Efficient Upgrading in a Purely Functional Component Deployment Model is about transparent patch deployment in Nix. The SCM-12 paper Service Configuration Management shows how services (e.g., web servers) can be deployed and managed through Nix. A short overview of NixOS is given in the HotOS XI paper Purely Functional System Configuration Management. The Nix homepage has an up-to-date list of Nix-related papers.

Nix is the subject of Eelco Dolstra’s PhD thesis The Purely Functional Software Deployment Model, which contains most of the papers listed above.

Nix has a homepage at http://nix.cs.uu.nl/.

Chapter 2. Quick Start

This chapter is for impatient people who don't like reading documentation. For more in-depth information you are kindly referred to the following chapters.

  1. Download a source tarball or RPM from http://nix.cs.uu.nl/. Build source distributions using the regular sequence:

    $ tar xvfj nix-version.tar.bz2
    $ ./configure
    $ make
    $ make install (as root)

    This will install Nix in /nix. You shouldn't change the prefix if at all possible since that will make it impossible to use pre-built binaries from the Nixpkgs channel and other channels. Alternatively, you could grab an RPM if you're on an RPM-based system. You should also add /nix/etc/profile.d/nix.sh to your ~/.bashrc (or some other login file).

  2. Subscribe to the Nix Packages channel.

    $ nix-channel --add \
        http://nix.cs.uu.nl/dist/nix/channels-v3/nixpkgs-unstable

  3. Download the latest Nix expressions available in the channel.

    $ nix-channel --update

    Note that this in itself doesn't download any packages, it just downloads the Nix expressions that build them and stores them somewhere (under ~/.nix-defexpr, in case you're curious). Also, it registers the fact that pre-built binaries are available remotely.

  4. See what installable packages are currently available in the channel:

    $ nix-env -qa ’*’ (mind the quotes!)
    docbook-xml-4.2
    firefox-1.0pre-PR-0.10.1
    hello-2.1.1
    libxslt-1.1.0
    ...

  5. Install some packages from the channel:

    $ nix-env -i hello firefox ... 

    This should download pre-built packages; it should not build them locally (if it does, something went wrong).

  6. Test that they work:

    $ which hello
    /home/eelco/.nix-profile/bin/hello
    $ hello
    Hello, world!
    $ firefox
    (read Slashdot or something)

  7. Uninstall a package:

    $ nix-env -e hello

  8. To keep up-to-date with the channel, do:

    $ nix-channel --update
    $ nix-env -u '*'

    The latter command will upgrade each installed package for which there is a “newer” version (as determined by comparing the version numbers).

  9. You can also install specific packages directly from your web browser. For instance, you can go to http://nix.cs.uu.nl/dist/nix/nixpkgs-unstable-latest/ and click on any link for the individual packages for your platform. Associate application/nix-package with the program /nix/bin/nix-install-package. A window should appear asking you whether it’s okay to install the package. Say Y. The package and all its dependencies will be installed.

  10. If you're unhappy with the result of a nix-env action (e.g., an upgraded package turned out not to work properly), you can go back:

    $ nix-env --rollback

  11. You should periodically run the Nix garbage collector to get rid of unused packages, since uninstalls or upgrades don't actually delete them:

    $ nix-collect-garbage -d

Chapter 3. Installation

3.1. Supported platforms

Nix is currently supported on the following platforms:

  • Linux (particularly on x86, x86_64, and PowerPC).

  • Mac OS X, both on Intel and PowerPC.

  • FreeBSD (only tested on Intel).

  • Windows through Cygwin.

    Warning

    On Cygwin, Nix must be installed on an NTFS partition. It will not work correctly on a FAT partition.

Nix is pretty portable, so it should work on most other Unix platforms as well.

3.2. Obtaining Nix

The easiest way to obtain Nix is to download a source distribution. RPMs for Red Hat, SuSE, and Fedora Core are also available.

Alternatively, the most recent sources of Nix can be obtained from its Subversion repository. For example, the following command will check out the latest revision into a directory called nix:

$ svn checkout https://svn.cs.uu.nl:12443/repos/trace/nix/trunk nix

Likewise, specific releases can be obtained from the tags directory of the repository. If you don't have Subversion, you can also download an automatically generated compressed tar-file of the head revision of the trunk.

3.3. Prerequisites

The following prerequisites only apply when you build from source. Binary releases (e.g., RPMs) have no prerequisites.

A fairly recent version of GCC/G++ is required. Version 2.95 and higher should work.

To build this manual and the man-pages you need the xmllint and xsltproc programs, which are part of the libxml2 and libxslt packages, respectively. You also need the DocBook XSL stylesheets and optionally the DocBook 5.0 RELAX NG schemas. Note that these are only required if you modify the manual sources or when you are building from the Subversion repository.

To build the parser, very recent versions of Bison and Flex are required. (This is because Nix needs GLR support in Bison and reentrancy support in Flex.) For Bison, you need version 2.3 or higher (1.875 does not work), which can be obtained from the GNU FTP server. For Flex, you need version 2.5.33, which is available on SourceForge. Slightly older versions may also work, but ancient versions like the ubiquitous 2.5.4a won't. Note that these are only required if you modify the parser or when you are building from the Subversion repository.

Nix uses Sleepycat's Berkeley DB, CWI's ATerm library and the bzip2 compressor (including the bzip2 library). These are included in the Nix source distribution. If you build from the Subversion repository, you must download them yourself and place them in the externals/ directory. See externals/Makefile.am for the precise URLs of these packages. Alternatively, if you already have them installed, you can use configure's --with-bdb, --with-aterm and --with-bzip2 options to point to their respective locations. Note that Berkeley DB must be version 4.5; other versions may not have compatible database formats.

3.4. Building Nix from source

After unpacking or checking out the Nix sources, issue the following commands:

$ ./configure options...
$ make
$ make install

When building from the Subversion repository, these should be preceded by the command:

$ ./bootstrap

The installation path can be specified by passing the --prefix=prefix to configure. The default installation directory is /nix. You can change this to any location you like. You must have write permission to the prefix path.

Warning

It is best not to change the installation prefix from its default, since doing so makes it impossible to use pre-built binaries from the standard Nixpkgs channels.

If you want to rebuilt the documentation, pass the full path to the DocBook RELAX NG schemas and to the DocBook XSL stylesheets using the --with-docbook-rng=path and --with-docbook-xsl=path options.

3.5. Installing from RPMs

RPM packages of Nix can be downloaded from http://nix.cs.uu.nl/. These RPMs should work for most fairly recent releases of SuSE and Red Hat Linux. They have been known to work work on SuSE Linux 8.1 and 9.0, and Red Hat 9.0. In fact, it should work on any RPM-based Linux distribution based on glibc 2.3 or later.

Once downloaded, the RPMs can be installed or upgraded using rpm -U. For example,

$ rpm -U nix-0.5pre664-1.i386.rpm

The RPMs install into the directory /nix. Nix can be uninstalled using rpm -e nix. After this it will be necessary to manually remove the Nix store and other auxiliary data:

$ rm -rf /nix/store
$ rm -rf /nix/var

3.6. Upgrading Nix through Nix

You can install the latest stable version of Nix through Nix itself by subscribing to the channel http://nix.cs.uu.nl/dist/nix/channels-v3/nix-stable, or the latest unstable version by subscribing to the channel http://nix.cs.uu.nl/dist/nix/channels-v3/nix-unstable. You can also do a one-click installation by clicking on the package links at http://nix.cs.uu.nl/dist/nix/.

3.7. Security

Nix has two basic security models. First, it can be used in “single-user mode”, which is similar to what most other package management tools do: there is a single user (typically root) who performs all package management operations. All other users can then use the installed packages, but they cannot perform package management operations themselves.

Alternatively, you can configure Nix in “multi-user mode”. In this model, all users can perform package management operations — for instance, every user can install software without requiring root privileges. Nix ensures that this is secure. For instance, it’s not possible for one user to overwrite a package used by another user with a Trojan horse.

3.7.1. Single-user mode

In single-user mode, all Nix operations that access the database in prefix/var/nix/db or modify the Nix store in prefix/store must be performed under the user ID that owns those directories. This is typically root. (If you install from RPM packages, that’s in fact the default ownership.) However, on single-user machines, it is often convenient to chown those directories to your normal user account so that you don’t have to su to root all the time.

3.7.2. Multi-user mode

To allow a Nix store to be shared safely among multiple users, it is important that users are not able to run builders that modify the Nix store or database in arbitrary ways, or that interfere with builds started by other users. If they could do so, they could install a Trojan horse in some package and compromise the accounts of other users.

To prevent this, the Nix store and database are owned by some privileged user (usually root) and builders are executed under special user accounts (usually named nixbld1, nixbld2, etc.). When a unprivileged user runs a Nix command, actions that operate on the Nix store (such as builds) are forwarded to a Nix daemon running under the owner of the Nix store/database that performs the operation.

Note

Multi-user mode has one important limitation: only root can run nix-pull to register the availability of pre-built binaries. However, those registrations are shared by all users, so they still get the benefit from nix-pulls done by root.

3.7.2.1. Setting up the build users

The build users are the special UIDs under which builds are performed. They should all be members of the build users group (usually called nixbld). This group should have no other members. The build users should not be members of any other group.

Here is a typical /etc/group definition of the build users group with 10 build users:

nixbld:!:30000:nixbld1,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9,nixbld10

In this example the nixbld group has UID 30000, but of course it can be anything that doesn’t collide with an existing group.

Here is the corresponding part of /etc/passwd:

nixbld1:x:30001:65534:Nix build user 1:/var/empty:/noshell
nixbld2:x:30002:65534:Nix build user 2:/var/empty:/noshell
nixbld3:x:30003:65534:Nix build user 3:/var/empty:/noshell
...
nixbld10:x:30010:65534:Nix build user 10:/var/empty:/noshell

The home directory of the build users should not exist or should be an empty directory to which they do not have write access.

The build users should have write access to the Nix store, but they should not have the right to delete files. Thus the Nix store’s group should be the build users group, and it should have the sticky bit turned on (like /tmp):

$ chgrp nixbld /nix/store
$ chmod 1777 /nix/store

Finally, you should tell Nix to use the build users by specifying the build users group in the build-users-group option in the Nix configuration file (/nix/etc/nix/nix.conf):

build-users-group = nixbld

3.7.2.2. Nix store/database owned by root

The simplest setup is to let root own the Nix store and database. I.e.,

$ chown -R root /nix/store /nix/var/nix

The Nix daemon should be started as follows (as root):

$ nix-worker --daemon

You’ll want to put that line somewhere in your system’s boot scripts.

To let unprivileged users use the daemon, they should set the NIX_REMOTE environment variable to daemon. So you should put a line like

export NIX_REMOTE=daemon

into the users’ login scripts.

3.7.2.3. Nix store/database not owned by root

It is also possible to let the Nix store and database be owned by a non-root user, which should be more secure[1]. Typically, this user is a special account called nix, but it can be named anything. It should own the Nix store and database:

$ chown -R root /nix/store /nix/var/nix

and of course nix-worker --daemon should be started under that user, e.g.,

$ su - nix -c "exec /nix/bin/nix-worker --daemon"

There is a catch, though: non-root users cannot start builds under the build user accounts, since the setuid system call is obviously privileged. To allow a non-root Nix daemon to use the build user feature, it calls a setuid-root helper program, nix-setuid-helper. This program is installed in prefix/libexec/nix-setuid-helper. To set the permissions properly (Nix’s make install doesn’t do this, since we don’t want to ship setuid-root programs out-of-the-box):

$ chown root.root /nix/libexec/nix-setuid-helper
$ chmod 4755 /nix/libexec/nix-setuid-helper

(This example assumes that the Nix binaries are installed in /nix.)

Of course, the nix-setuid-helper command should not be usable by just anybody, since then anybody could run commands under the Nix build user accounts. For that reason there is a configuration file /etc/nix-setuid.conf that restricts the use of the helper. This file should be a text file containing precisely two lines, the first being the Nix daemon user and the second being the build users group, e.g.,

nix
nixbld

The setuid-helper barfs if it is called by a user other than the one specified on the first line, or if it is asked to execute a build under a user who is not a member of the group specified on the second line. The file /etc/nix-setuid.conf must be owned by root, and must not be group- or world-writable. The setuid-helper barfs if this is not the case.

3.7.2.4. Restricting access

To limit which users can perform Nix operations, you can use the permissions on the directory /nix/var/nix/daemon-socket. For instance, if you want to restrict the use of Nix to the members of a group called nix-users, do

$ chgrp nix-users /nix/var/nix/daemon-socket
$ chmod ug=rwx,o= /nix/var/nix/daemon-socket

This way, users who are not in the nix-users group cannot connect to the Unix domain socket /nix/var/nix/daemon-socket/socket, so they cannot perform Nix operations.

3.8. Using Nix

To use Nix, some environment variables should be set. In particular, PATH should contain the directories prefix/bin and ~/.nix-profile/bin. The first directory contains the Nix tools themselves, while ~/.nix-profile is a symbolic link to the current user environment (an automatically generated package consisting of symlinks to installed packages). The simplest way to set the required environment variables is to include the file prefix/etc/profile.d/nix.sh in your ~/.bashrc (or similar), like this:

source prefix/etc/profile.d/nix.sh


[1] Note however that even when the Nix daemon runs as root, not that much code is executed as root: Nix expression evaluation is performed by the calling (unprivileged) user, and builds are performed under the special build user accounts. So only the code that accesses the database and starts builds is executed as root.

Chapter 4. Package Management

This chapter discusses how to do package management with Nix, i.e., how to obtain, install, upgrade, and erase packages. This is the “user’s” perspective of the Nix system — people who want to create packages should consult Chapter 5, Writing Nix Expressions.

4.1. Basic package management

The main command for package management is nix-env. You can use it to install, upgrade, and erase packages, and to query what packages are installed or are available for installation.

In Nix, different users can have different “views” on the set of installed applications. That is, there might be lots of applications present on the system (possibly in many different versions), but users can have a specific selection of those active — where “active” just means that it appears in a directory in the user’s PATH. Such a view on the set of installed applications is called a user environment, which is just a directory tree consisting of symlinks to the files of the active applications.

Components are installed from a set of Nix expressions that tell Nix how to build those packages, including, if necessary, their dependencies. There is a collection of Nix expressions called the Nix Package collection that contains packages ranging from basic development stuff such as GCC and Glibc, to end-user applications like Mozilla Firefox. (Nix is however not tied to the Nix Package collection; you could write your own Nix expressions based on it, or completely new ones.) You can download the latest version from http://nix.cs.uu.nl/dist/nix.

Assuming that you have downloaded and unpacked a release of Nix Packages, you can view the set of available packages in the release:

$ nix-env -qaf nixpkgs-version '*'
ant-blackdown-1.4.2
aterm-2.2
bash-3.0
binutils-2.15
bison-1.875d
blackdown-1.4.2
bzip2-1.0.2
...

where nixpkgs-version is where you’ve unpacked the release. The flag -q specifies a query operation; -a means that you want to show the “available” (i.e., installable) packages, as opposed to the installed packages; and -f nixpkgs-version specifies the source of the packages. The argument '*' shows all installable packages. (The quotes are necessary to prevent shell expansion.) You can also select specific packages by name:

$ nix-env -qaf nixpkgs-version gcc
gcc-3.4.6
gcc-4.0.3
gcc-4.1.1

It is also possible to see the status of available packages, i.e., whether they are installed into the user environment and/or present in the system:

$ nix-env -qasf nixpkgs-version '*'
...
-PS bash-3.0
--S binutils-2.15
IPS bison-1.875d
...

The first character (I) indicates whether the package is installed in your current user environment. The second (P) indicates whether it is present on your system (in which case installing it into your user environment would be a very quick operation). The last one (S) indicates whether there is a so-called substitute for the package, which is Nix’s mechanism for doing binary deployment. It just means that Nix knows that it can fetch a pre-built package from somewhere (typically a network server) instead of building it locally.

So now that we have a set of Nix expressions we can build the packages contained in them. This is done using nix-env -i. For instance,

$ nix-env -f nixpkgs-version -i subversion

will install the package called subversion (which is, of course, the Subversion version management system).

When you do this for the first time, Nix will start building Subversion and all its dependencies. This will take quite a while — typically an hour or two on modern machines. Fortunately, there is a faster way (so do a Ctrl-C on that install operation!): you just need to tell Nix that pre-built binaries of all those packages are available somewhere. This is done using the nix-pull command, which must be supplied with a URL containing a manifest describing what binaries are available. This URL should correspond to the Nix Packages release that you’re using. For instance, if you obtained a release from http://nix.cs.uu.nl/dist/nix/nixpkgs-0.6pre1554/, then you should do:

$ nix-pull http://nix.cs.uu.nl/dist/nix/nixpkgs-0.6pre1554/MANIFEST

If you then issue the installation command, it should start downloading binaries from nix.cs.uu.nl, instead of building them from source. This might still take a while since all dependencies must be downloaded, but on a reasonably fast connection such as an DSL line it’s on the order of a few minutes.

Naturally, packages can also be uninstalled:

$ nix-env -e subversion

Upgrading to a new version is just as easy. If you have a new release of Nix Packages, you can do:

$ nix-env -f nixpkgs-version -u subversion

This will only upgrade Subversion if there is a “newer” version in the new set of Nix expressions, as defined by some pretty arbitrary rules regarding ordering of version numbers (which generally do what you’d expect of them). To just unconditionally replace Subversion with whatever version is in the Nix expressions, use -i instead of -u; -i will remove whatever version is already installed.

You can also upgrade all packages for which there are newer versions:

$ nix-env -f nixpkgs-version -u '*'

Sometimes it’s useful to be able to ask what nix-env would do, without actually doing it. For instance, to find out what packages would be upgraded by nix-env -u '*', you can do

$ nix-env ... -u '*' --dry-run
(dry run; not doing anything)
upgrading `libxslt-1.1.0' to `libxslt-1.1.10'
upgrading `graphviz-1.10' to `graphviz-1.12'
upgrading `coreutils-5.0' to `coreutils-5.2.1'

If you grow bored of specifying the Nix expressions using -f all the time, you can set a default location:

$ nix-env -I nixpkgs-version

After this you can just say, for instance, nix-env -u '*'.[2]

4.2. Profiles

Profiles and user environments are Nix’s mechanism for implementing the ability to allow different users to have different configurations, and to do atomic upgrades and rollbacks. To understand how they work, it’s useful to know a bit about how Nix works. In Nix, packages are stored in unique locations in the Nix store (typically, /nix/store). For instance, a particular version of the Subversion package might be stored in a directory /nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3/, while another version might be stored in /nix/store/5mq2jcn36ldlmh93yj1n8s9c95pj7c5s-subversion-1.1.2. The long strings prefixed to the directory names are cryptographic hashes[3] of all inputs involved in building the package — sources, dependencies, compiler flags, and so on. So if two packages differ in any way, they end up in different locations in the file system, so they don’t interfere with each other. Figure 4.1, “User environments” shows a part of a typical Nix store.

Figure 4.1. User environments

User environments

Of course, you wouldn’t want to type

$ /nix/store/dpmvp969yhdq...-subversion-1.1.3/bin/svn

every time you want to run Subversion. Of course we could set up the PATH environment variable to include the bin directory of every package we want to use, but this is not very convenient since changing PATH doesn’t take effect for already existing processes. The solution Nix uses is to create directory trees of symlinks to activated packages. These are called user environments and they are packages themselves (though automatically generated by nix-env), so they too reside in the Nix store. For instance, in Figure 4.1, “User environments” the user environment /nix/store/5mq2jcn36ldl...-user-env contains a symlink to just Subversion 1.1.2 (arrows in the figure indicate symlinks). This would be what we would obtain if we had done

$ nix-env -i subversion

on a set of Nix expressions that contained Subversion 1.1.2.

This doesn’t in itself solve the problem, of course; you wouldn’t want to type /nix/store/0c1p5z4kda11...-user-env/bin/svn either. That’s why there are symlinks outside of the store that point to the user environments in the store; for instance, the symlinks default-42-link and default-43-link in the example. These are called generations since every time you perform a nix-env operation, a new user environment is generated based on the current one. For instance, generation 43 was created from generation 42 when we did

$ nix-env -i subversion mozilla

on a set of Nix expressions that contained Mozilla and a new version of Subversion.

Generations are grouped together into profiles so that different users don’t interfere with each other if they don’t want to. For example:

$ ls -l /nix/var/nix/profiles/
...
lrwxrwxrwx  1 eelco ... default-42-link -> /nix/store/0c1p5z4kda11...-user-env
lrwxrwxrwx  1 eelco ... default-43-link -> /nix/store/3aw2pdyx2jfc...-user-env
lrwxrwxrwx  1 eelco ... default -> default-43-link

This shows a profile called default. The file default itself is actually a symlink that points to the current generation. When we do a nix-env operation, a new user environment and generation link are created based on the current one, and finally the default symlink is made to point at the new generation. This last step is atomic on Unix, which explains how we can do atomic upgrades. (Note that the building/installing of new packages doesn’t interfere in any way with old packages, since they are stored in different locations in the Nix store.)

If you find that you want to undo a nix-env operation, you can just do

$ nix-env --rollback

which will just make the current generation link point at the previous link. E.g., default would be made to point at default-42-link. You can also switch to a specific generation:

$ nix-env --switch-generation 43

which in this example would roll forward to generation 43 again. You can also see all available generations:

$ nix-env --list-generations

Actually, there is another level of indirection not shown in the figure above. You generally wouldn’t have /nix/var/nix/profiles/some-profile/bin in your PATH. Rather, there is a symlink ~/.nix-profile that points to your current profile. This means that you should put ~/.nix-profile/bin in your PATH (and indeed, that’s what the initialisation script /nix/etc/profile.d/nix.sh does). This makes it easier to switch to a different profile. You can do that using the command nix-env --switch-profile:

$ nix-env --switch-profile /nix/var/nix/profiles/my-profile

$ nix-env --switch-profile /nix/var/nix/profiles/default

These commands switch to the my-profile and default profile, respectively. If the profile doesn’t exist, it will be created automatically. You should be careful about storing a profile in another location than the profiles directory, since otherwise it might not be used as a root of the garbage collector (see section Section 4.3, “Garbage collection”).

All nix-env operations work on the profile pointed to by ~/.nix-profile, but you can override this using the --profile option (abbreviation -p):

$ nix-env -p /nix/var/nix/profiles/other-profile -i subversion

This will not change the ~/.nix-profile symlink.

4.3. Garbage collection

nix-env operations such as upgrades (-u) and uninstall (-e) never actually delete packages from the system. All they do (as shown above) is to create a new user environment that no longer contains symlinks to the “deleted” packages.

Of course, since disk space is not infinite, unused packages should be removed at some point. You can do this by running the Nix garbage collector. It will remove from the Nix store any package not used (directly or indirectly) by any generation of any profile.

Note however that as long as old generations reference a package, it will not be deleted. After all, we wouldn’t be able to do a rollback otherwise. So in order for garbage collection to be effective, you should also delete (some) old generations. Of course, this should only be done if you are certain that you will not need to roll back.

To delete all old (non-current) generations of your current profile:

$ nix-env --delete-generations old

Instead of old you can also specify a list of generations, e.g.,

$ nix-env --delete-generations 10 11 14

After removing appropriate old generations you can run the garbage collector as follows:

$ nix-store --gc

If you are feeling uncertain, you can also first view what files would be deleted:

$ nix-store --gc --print-dead

Likewise, the option --print-live will show the paths that won’t be deleted.

There is also a convenient little utility nix-collect-garbage, which when invoked with the -d (--delete-old) switch deletes all old generations of all profiles in /nix/var/nix/profiles. So

$ nix-collect-garbage -d

is a quick and easy way to clean up your system.

4.3.1. Garbage collector roots

The roots of the garbage collector are all store paths to which there are symlinks in the directory prefix/nix/var/nix/gcroots. For instance, the following command makes the path /nix/store/d718ef...-foo a root of the collector:

$ ln -s /nix/store/d718ef...-foo /nix/var/nix/gcroots/bar

That is, after this command, the garbage collector will not remove /nix/store/d718ef...-foo or any of its dependencies.

Subdirectories of prefix/nix/var/nix/gcroots are also searched for symlinks. Symlinks to non-store paths are followed and searched for roots, but symlinks to non-store paths inside the paths reached in that way are not followed to prevent infinite recursion.

4.4. Channels

If you want to stay up to date with a set of packages, it’s not very convenient to manually download the latest set of Nix expressions for those packages, use nix-pull to register pre-built binaries (if available), and upgrade using nix-env. Fortunately, there’s a better way: Nix channels.

A Nix channel is just a URL that points to a place that contains a set of Nix expressions and a manifest. Using the command nix-channel you can automatically stay up to date with whatever is available at that URL.

You can “subscribe” to a channel using nix-channel --add, e.g.,

$ nix-channel --add http://nix.cs.uu.nl/dist/nix/channels-v3/nixpkgs-unstable

subscribes you to a channel that always contains that latest version of the Nix Packages collection. (Instead of nixpkgs-unstable you could also subscribe to nixpkgs-stable, which should have a higher level of stability, but right now is just outdated.) Subscribing really just means that the URL is added to the file ~/.nix-channels. Right now there is no command to “unsubscribe”; you should just edit that file manually and delete the offending URL.

To obtain the latest Nix expressions available in a channel, do

$ nix-channel --update

This downloads the Nix expressions in every channel (downloaded from url/nixexprs.tar.bz2) and registers any available pre-built binaries in every channel (by nix-pulling url/MANIFEST). It also makes the union of each channel’s Nix expressions the default for nix-env operations. Consequently, you can then say

$ nix-env -u '*'

to upgrade all packages in your profile to the latest versions available in the subscribed channels.

4.5. One-click installs

Often, when you want to install a specific package (e.g., from the Nix Packages collection or from our release server), subscribing to a channel is a bit cumbersome. And channels don’t help you at all if you want to install an older version of a package than the one provided by the current contents of the channel, or a package that has been removed from the channel. That’s when one-click installs come in handy: you can just go to the web page that contains the package, click on it, and it will be installed with all the necessary dependencies.

For instance, you can go to http://nix.cs.uu.nl/dist/nix/nixpkgs-unstable-latest/ — or to any older release of Nix Packages — and click on any link for the individual packages for your platform (say, subversion-1.4.0 for i686-linux). The first time you do this, your browser will ask what to do with application/nix-package files. You should open them with /nix/bin/nix-install-package. This will open a window that asks you to confirm that you want to install the package. When you answer Y, the package and all its dependencies will be installed. This is a binary deployment mechanism — you get packages pre-compiled for the selected platform type.

You can also install application/nix-package files from the command line directly. See Section A.5.6, “nix-install-package” for details.



[2] Setting a default using -I currently clashes with using Nix channels, since nix-channel --update calls nix-env -I to set the default to the Nix expressions it downloaded from the channel, replacing whatever default you had set.

[3] 160-bit truncations of SHA-256 hashes encoded in a base-32 notation, to be precise.

Chapter 5. Writing Nix Expressions

This chapter shows you how to write Nix expressions, which are the things that tell Nix how to build packages. It starts with a simple example (a Nix expression for GNU Hello), and then moves on to a more in-depth look at the Nix expression language.

5.1. A simple Nix expression

This section shows how to add and test the GNU Hello package to the Nix Packages collection. Hello is a program that prints out the text “Hello, world!”.

To add a package to the Nix Packages collection, you generally need to do three things:

  1. Write a Nix expression for the package. This is a file that describes all the inputs involved in building the package, such as dependencies, sources, and so on.

  2. Write a builder. This is a shell script[4] that actually builds the package from the inputs.

  3. Add the package to the file pkgs/top-level/all-packages.nix. The Nix expression written in the first step is a function; it requires other packages in order to build it. In this step you put it all together, i.e., you call the function with the right arguments to build the actual package.

5.1.1. The Nix expression

Example 5.1. Nix expression for GNU Hello (default.nix)

{stdenv, fetchurl, perl}: 1

stdenv.mkDerivation { 2
  name = "hello-2.1.1"; 3
  builder = ./builder.sh; 4
  src = fetchurl { 5
    url = ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz;
    md5 = "70c9ccf9fac07f762c24f2df2290784d";
  };
  inherit perl; 6
}

Example 5.1, “Nix expression for GNU Hello (default.nix)” shows a Nix expression for GNU Hello. It's actually already in the Nix Packages collection in pkgs/applications/misc/hello/ex-1/default.nix. It is customary to place each package in a separate directory and call the single Nix expression in that directory default.nix. The file has the following elements (referenced from the figure by number):

1

This states that the expression is a function that expects to be called with three arguments: stdenv, fetchurl, and perl. They are needed to build Hello, but we don't know how to build them here; that's why they are function arguments. stdenv is a package that is used by almost all Nix Packages packages; it provides a “standard” environment consisting of the things you would expect in a basic Unix environment: a C/C++ compiler (GCC, to be precise), the Bash shell, fundamental Unix tools such as cp, grep, tar, etc. fetchurl is a function that downloads files. perl is the Perl interpreter.

Nix functions generally have the form {x, y, ..., z}: e where x, y, etc. are the names of the expected arguments, and where e is the body of the function. So here, the entire remainder of the file is the body of the function; when given the required arguments, the body should describe how to build an instance of the Hello package.

2

So we have to build a package. Building something from other stuff is called a derivation in Nix (as opposed to sources, which are built by humans instead of computers). We perform a derivation by calling stdenv.mkDerivation. mkDerivation is a function provided by stdenv that builds a package from a set of attributes. An attribute set is just a list of key/value pairs where each value is an arbitrary Nix expression. They take the general form {name1 = expr1; ... nameN = exprN;}.

3

The attribute name specifies the symbolic name and version of the package. Nix doesn't really care about these things, but they are used by for instance nix-env -q to show a “human-readable” name for packages. This attribute is required by mkDerivation.

4

The attribute builder specifies the builder. This attribute can sometimes be omitted, in which case mkDerivation will fill in a default builder (which does a configure; make; make install, in essence). Hello is sufficiently simple that the default builder would suffice, but in this case, we will show an actual builder for educational purposes. The value ./builder.sh refers to the shell script shown in Example 5.2, “Build script for GNU Hello (builder.sh)”, discussed below.

5

The builder has to know what the sources of the package are. Here, the attribute src is bound to the result of a call to the fetchurl function. Given a URL and an MD5 hash of the expected contents of the file at that URL, this function builds a derivation that downloads the file and checks its hash. So the sources are a dependency that like all other dependencies is built before Hello itself is built.

Instead of src any other name could have been used, and in fact there can be any number of sources (bound to different attributes). However, src is customary, and it's also expected by the default builder (which we don't use in this example).

6

Since the derivation requires Perl, we have to pass the value of the perl function argument to the builder. All attributes in the set are actually passed as environment variables to the builder, so declaring an attribute

perl = perl;

will do the trick: it binds an attribute perl to the function argument which also happens to be called perl. However, it looks a bit silly, so there is a shorter syntax. The inherit keyword causes the specified attributes to be bound to whatever variables with the same name happen to be in scope.

5.1.2. The builder

Example 5.2. Build script for GNU Hello (builder.sh)

source $stdenv/setup 1

PATH=$perl/bin:$PATH 2

tar xvfz $src 3
cd hello-*
./configure --prefix=$out 4
make 5
make install

Example 5.2, “Build script for GNU Hello (builder.sh)” shows the builder referenced from Hello's Nix expression (stored in pkgs/applications/misc/hello/ex-1/builder.sh). The builder can actually be made a lot shorter by using the generic builder functions provided by stdenv, but here we write out the build steps to elucidate what a builder does. It performs the following steps:

1

When Nix runs a builder, it initially completely clears the environment (except for the attributes declared in the derivation). For instance, the PATH variable is empty[5]. This is done to prevent undeclared inputs from being used in the build process. If for example the PATH contained /usr/bin, then you might accidentally use /usr/bin/gcc.

So the first step is to set up the environment. This is done by calling the setup script of the standard environment. The environment variable stdenv points to the location of the standard environment being used. (It wasn't specified explicitly as an attribute in Example 5.1, “Nix expression for GNU Hello (default.nix)”, but mkDerivation adds it automatically.)

2

Since Hello needs Perl, we have to make sure that Perl is in the PATH. The perl environment variable points to the location of the Perl package (since it was passed in as an attribute to the derivation), so $perl/bin is the directory containing the Perl interpreter.

3

Now we have to unpack the sources. The src attribute was bound to the result of fetching the Hello source tarball from the network, so the src environment variable points to the location in the Nix store to which the tarball was downloaded. After unpacking, we cd to the resulting source directory.

The whole build is performed in a temporary directory created in /tmp, by the way. This directory is removed after the builder finishes, so there is no need to clean up the sources afterwards. Also, the temporary directory is always newly created, so you don't have to worry about files from previous builds interfering with the current build.

4

GNU Hello is a typical Autoconf-based package, so we first have to run its configure script. In Nix every package is stored in a separate location in the Nix store, for instance /nix/store/9a54ba97fb71b65fda531012d0443ce2-hello-2.1.1. Nix computes this path by cryptographically hashing all attributes of the derivation. The path is passed to the builder through the out environment variable. So here we give configure the parameter --prefix=$out to cause Hello to be installed in the expected location.

5

Finally we build Hello (make) and install it into the location specified by out (make install).

If you are wondering about the absence of error checking on the result of various commands called in the builder: this is because the shell script is evaluated with Bash's -e option, which causes the script to be aborted if any command fails without an error check.

5.1.3. Composition

Example 5.3. Composing GNU Hello (all-packages.nix)

...

rec { 1
  
  hello = (import ../applications/misc/hello/ex-1 2) { 3
    inherit fetchurl stdenv perl;
  };

  perl = (import ../development/interpreters/perl) { 4
    inherit fetchurl stdenv;
  };

  fetchurl = (import ../build-support/fetchurl) { 
    inherit stdenv; ...
  };
  
  stdenv = ...;

}

The Nix expression in Example 5.1, “Nix expression for GNU Hello (default.nix)” is a function; it is missing some arguments that have to be filled in somewhere. In the Nix Packages collection this is done in the file pkgs/top-level/all-packages.nix, where all Nix expressions for packages are imported and called with the appropriate arguments. Example 5.3, “Composing GNU Hello (all-packages.nix)” shows some fragments of all-packages.nix.

1

This file defines a set of attributes, all of which are concrete derivations (i.e., not functions). In fact, we define a mutually recursive set of attributes. That is, the attributes can refer to each other. This is precisely what we want since we want to “plug” the various packages into each other.

2

Here we import the Nix expression for GNU Hello. The import operation just loads and returns the specified Nix expression. In fact, we could just have put the contents of Example 5.1, “Nix expression for GNU Hello (default.nix)” in all-packages.nix at this point. That would be completely equivalent, but it would make the file rather bulky.

Note that we refer to ../applications/misc/hello/ex-1, not ../applications/misc/hello/ex-1/default.nix. When you try to import a directory, Nix automatically appends /default.nix to the file name.

3

This is where the actual composition takes place. Here we call the function imported from ../applications/misc/hello/ex-1 with an attribute set containing the things that the function expects, namely fetchurl, stdenv, and perl. We use inherit again to use the attributes defined in the surrounding scope (we could also have written fetchurl = fetchurl;, etc.).

The result of this function call is an actual derivation that can be built by Nix (since when we fill in the arguments of the function, what we get is its body, which is the call to stdenv.mkDerivation in Example 5.1, “Nix expression for GNU Hello (default.nix)”).

4

Likewise, we have to instantiate Perl, fetchurl, and the standard environment.

5.1.4. Testing

You can now try to build Hello. Of course, you could do nix-env -f pkgs/top-level/all-packages.nix -i hello, but you may not want to install a possibly broken package just yet. The best way to test the package is by using the command nix-build, which builds a Nix expression and creates a symlink named result in the current directory:

$ nix-build pkgs/top-level/all-packages.nix -A hello
building path `/nix/store/632d2b22514d...-hello-2.1.1'
hello-2.1.1/
hello-2.1.1/intl/
hello-2.1.1/intl/ChangeLog
...

$ ls -l result
lrwxrwxrwx ... 2006-09-29 10:43 result -> /nix/store/632d2b22514d...-hello-2.1.1

$ ./result/bin/hello
Hello, world!

The -A option selects the hello attribute from all-packages.nix. This is faster than using the symbolic package name specified by the name attribute (which also happens to be hello) and is unambiguous (there can be multiple packages with the symbolic name hello, but there can be only one attribute in a set named hello).

nix-build registers the ./result symlink as a garbage collection root, so unless and until you delete the ./result symlink, the output of the build will be safely kept on your system. You can use nix-build’s -o switch to give the symlink another name.

Nix has a transactional semantics. Once a build finishes successfully, Nix makes a note of this in its database: it registers that the path denoted by out is now “valid”. If you try to build the derivation again, Nix will see that the path is already valid and finish immediately. If a build fails, either because it returns a non-zero exit code, because Nix or the builder are killed, or because the machine crashes, then the output path will not be registered as valid. If you try to build the derivation again, Nix will remove the output path if it exists (e.g., because the builder died half-way through make install) and try again. Note that there is no “negative caching”: Nix doesn't remember that a build failed, and so a failed build can always be repeated. This is because Nix cannot distinguish between permanent failures (e.g., a compiler error due to a syntax error in the source) and transient failures (e.g., a disk full condition).

Nix also performs locking. If you run multiple Nix builds simultaneously, and they try to build the same derivation, the first Nix instance that gets there will perform the build, while the others block (or perform other derivations if available) until the build finishes:

$ nix-build pkgs/top-level/all-packages.nix -A hello
waiting for lock on `/nix/store/0h5b7hp8d4hqfrw8igvx97x1xawrjnac-hello-2.1.1x'

So it is always safe to run multiple instances of Nix in parallel (which isn’t the case with, say, make).

If you have a system with multiple CPUs, you may want to have Nix build different derivations in parallel (insofar as possible). Just pass the option -j N, where N is the maximum number of jobs to be run in parallel, or set. Typically this should be the number of CPUs.

5.1.5. The generic builder

Recall from Example 5.2, “Build script for GNU Hello (builder.sh)” that the builder looked something like this:

PATH=$perl/bin:$PATH
tar xvfz $src
cd hello-*
./configure --prefix=$out
make
make install

The builders for almost all Unix packages look like this — set up some environment variables, unpack the sources, configure, build, and install. For this reason the standard environment provides some Bash functions that automate the build process. A builder using the generic build facilities in shown in Example 5.4, “Build script using the generic build functions”.

Example 5.4. Build script using the generic build functions

buildInputs="$perl" 1

source $stdenv/setup 2

genericBuild 3

1

The buildInputs variable tells setup to use the indicated packages as “inputs”. This means that if a package provides a bin subdirectory, it's added to PATH; if it has a include subdirectory, it's added to GCC's header search path; and so on.[6]

2

The function genericBuild is defined in the file $stdenv/setup.

3

The final step calls the shell function genericBuild, which performs the steps that were done explicitly in Example 5.2, “Build script for GNU Hello (builder.sh)”. The generic builder is smart enough to figure out whether to unpack the sources using gzip, bzip2, etc. It can be customised in many ways; see Section 5.3, “The standard environment”.

Discerning readers will note that the buildInputs could just as well have been set in the Nix expression, like this:

  buildInputs = [perl];

The perl attribute can then be removed, and the builder becomes even shorter:

source $stdenv/setup
genericBuild

In fact, mkDerivation provides a default builder that looks exactly like that, so it is actually possible to omit the builder for Hello entirely.

5.2. The Nix expression language

The Nix expression language is a pure, lazy, functional language. Purity means that operations in the language don't have side-effects (for instance, there is no variable assignment). Laziness means that arguments to functions are evaluated only when they are needed. Functional means that functions are “normal” values that can be passed around and manipulated in interesting ways. The language is not a full-featured, general purpose language. It's main job is to describe packages, compositions of packages, and the variability within packages.

This section presents the various features of the language.

5.2.1. Values

Simple values

Nix has the following basic data types:

  • Strings can be written in three ways.

    The most common way is to enclose the string between double quotes, e.g., "foo bar". Strings can span multiple lines. The special characters " and \ and the character sequence ${ must be escaped by prefixing them with a backslash (\). Newlines, carriage returns and tabs can be written as \n, \r and \t, respectively.

    You can include the result of an expression into a string by enclosing it in ${...}, a feature known as antiquotation. The enclosed expression must evaluate to something that can be coerced into a string (meaning that it must be a string, a path, or a derivation). For instance, rather than writing

    "--with-freetype2-library=" + freetype + "/lib"

    (where freetype is a derivation), you can instead write the more natural

    "--with-freetype2-library=${freetype}/lib"

    The latter is automatically translated to the former. A more complicated example (from the Nix expression for Qt):

    configureFlags = "
      -system-zlib -system-libpng -system-libjpeg
      ${if openglSupport then "-dlopen-opengl
        -L${mesa}/lib -I${mesa}/include
        -L${libXmu}/lib -I${libXmu}/include" else ""}
      ${if threadSupport then "-thread" else "-no-thread"}
    ";

    Note that Nix expressions and strings can be arbitrarily nested; in this case the outer string contains various antiquotations that themselves contain strings (e.g., "-thread"), some of which in turn contain expressions (e.g., ${mesa}).

    The second way to write string literals is as an indented string, which is enclosed between pairs of double single-quotes, like so:

    ''
      This is the first line.
      This is the second line.
        This is the third line.
    ''

    This kind of string literal intelligently strips indentation from the start of each line. To be precise, it strips from each line a number of spaces equal to the minimal indentation of the string as a whole (disregarding the indentation of empty lines). For instance, the first and second line are indented two space, while the third line is indented three spaces. Thus, two spaces are stripped from each line, so the resulting string is

        
    "This is the first line.\nThis is the second line.\n  This is the third line.\n"

    Note that the whitespace and newline following the opening '' is ignored if there is no non-whitespace text on the initial line.

    Antiquotation (${expr}}) is supported in indented strings.

    Since ${ and '' have special meaning in indented strings, you need a way to quote them. ${ can be escaped by prefixing it with '', i.e., ''${. '' can be escaped by prefixing it with ', i.e., '''. Finally, linefeed, carriage-return and tab characters can be writted as ''\n, ''\r, ''\t.

    Indented strings are primarily useful in that they allow multi-line string literals to follow the indentation of the enclosing Nix expression, and that less escaping is typically necessary for strings representing languages such as shell scripts and configuration files because '' is much less common than ". Example:

    stdenv.mkDerivation {
      ...
      postInstall =
        ''
          mkdir $out/bin $out/etc
          cp foo $out/bin
          echo "Hello World" > $out/etc/foo.conf
          ${if enableBar then "cp bar $out/bin" else ""}
        '';
      ...
    }    
    

    Finally, as a convenience, URIs as defined in appendix B of RFC 2396 can be written as is, without quotes. For instance, the string "https://svn.cs.uu.nl:12443/dist/trace/trace-nix-trunk.tar.bz2" can also be written as https://svn.cs.uu.nl:12443/dist/trace/trace-nix-trunk.tar.bz2.

  • Integers, e.g., 123.

  • Paths, e.g., /bin/sh or ./builder.sh. A path must contain at least one slash to be recognised as such; for instance, builder.sh is not a path[7]. If the file name is relative, i.e., if it does not begin with a slash, it is made absolute at parse time relative to the directory of the Nix expression that contained it. For instance, if a Nix expression in /foo/bar/bla.nix refers to ../xyzzy/fnord.nix, the absolutised path is /foo/xyzzy/fnord.nix.

  • Booleans with values true and false.

Lists

Lists are formed by enclosing a whitespace-separated list of values between square brackets. For example,

[ 123 ./foo.nix "abc" (f {x=y;}) ]

defines a list of four elements, the last being the result of a call to the function f. Note that function calls have to be enclosed in parentheses. If they had been omitted, e.g.,

[ 123 ./foo.nix "abc" f {x=y;} ]

the result would be a list of five elements, the fourth one being a function and the fifth being an attribute set.

Attribute sets

Attribute sets are really the core of the language, since ultimately it's all about creating derivations, which are really just sets of attributes to be passed to build scripts.

Attribute sets are just a list of name/value pairs enclosed in curly brackets, where each value is an arbitrary expression terminated by a semicolon. For example:

{ x = 123;
  text = "Hello";
  y = f { bla = 456; };
}

This defines an attribute set with attributes named x, test, y. The order of the attributes is irrelevant. An attribute name may only occur once.

Attributes can be selected from an attribute set using the . operator. For instance,

{ a = "Foo"; b = "Bar"; }.a

evaluates to "Foo".

5.2.2. Language constructs

Recursive attribute sets

Recursive attribute sets are just normal attribute sets, but the attributes can refer to each other. For example,

rec {
  x = y;
  y = 123;
}.x

evaluates to 123. Note that without rec the binding x = y; would refer to the variable y in the surrounding scope, if one exists, and would be invalid if no such variable exists. That is, in a normal (non-recursive) attribute set, attributes are not added to the lexical scope; in a recursive set, they are.

Recursive attribute sets of course introduce the danger of infinite recursion. For example,

rec {
  x = y;
  y = x;
}.x

does not terminate[8].

Let-expressions

A let-expression allows you define local variables for an expression. For instance,

let
  x = "foo";
  y = "bar";
in x + y

evaluates to "foobar".

Note

There is also an obsolete form of let-expression, let { attrs }, which is translated to rec { attrs }.body. That is, the body of the let-expression is the body attribute of the attribute set.

Inheriting attributes

When defining an attribute set it is often convenient to copy variables from the surrounding lexical scope (e.g., when you want to propagate attributes). This can be shortened using the inherit keyword. For instance,

let
  x = 123;
in 
  {
    inherit x;
    y = 456;
  }

evaluates to {x = 123; y = 456;}. (Note that this works because x is added to the lexical scope by the let construct.) It is also possible to inherit attributes from another attribute set. For instance, in this fragment from all-packages.nix,

  graphviz = (import ../tools/graphics/graphviz) {
    inherit fetchurl stdenv libpng libjpeg expat x11 yacc;
    inherit (xlibs) libXaw;
  };

  xlibs = {
    libX11 = ...;
    libXaw = ...;
    ...
  }

  libpng = ...;
  libjpg = ...;
  ...

the attribute set used in the function call to the function defined in ../tools/graphics/graphviz inherits a number of variables from the surrounding scope (fetchurl ... yacc), but also inherits libXaw (the X Athena Widgets) from the xlibs (X11 client-side libraries) attribute set.

Functions

Functions have the following form:

{params}: body

This defines a function that must be called with an attribute set containing the attributes listed in params, which is a comma-separated list of attribute names. Optionally, for each parameter a default value may be specified by writing param ? e, where e is an arbitrary expression. If a parameter has a default, the corresponding attribute may be omitted in function calls.

Note that functions do not have names. If you want to give them a name, you can bind them to an attribute, e.g.,

let concat = {x, y}: x + y;
in concat {x = "foo"; y = "bar";}

It is also possible to define a function that takes a single argument and that does not need to be called with an attribute set as argument. The syntax is

var: body

where var is the name of the argument. It is not possible to define a default. Example:

let negate = x: !x;
    concat = x: y: x + y;
in if negate true then concat "foo" "bar" else ""

Note that concat is a function that takes one arguments and returns a function that takes another argument. This allows partial parameterisation (i.e., only filling some of the arguments of a function); e.g.,

map (concat "foo") ["bar" "bla" "abc"]

evaluates to ["foobar" "foobla" "fooabc"].

Conditionals

Conditionals look like this:

if e1 then e2 else e3

where e1 is an expression that should evaluate to a Boolean value (true or false).

Assertions

Assertions are generally used to check that certain requirements on or between features and dependencies hold. They look like this:

assert e1; e2

where e1 is an expression that should evaluate to a Boolean value. If it evaluates to true, e2 is returned; otherwise expression evaluation is aborted and a backtrace is printed.

Example 5.5. Nix expression for Subversion

{ localServer ? false
, httpServer ? false
, sslSupport ? false
, pythonBindings ? false
, javaSwigBindings ? false
, javahlBindings ? false
, stdenv, fetchurl
, openssl ? null, httpd ? null, db4 ? null, expat, swig ? null, j2sdk ? null
}:

assert localServer -> db4 != null; 1
assert httpServer -> httpd != null && httpd.expat == expat; 2
assert sslSupport -> openssl != null && (httpServer -> httpd.openssl == openssl); 3
assert pythonBindings -> swig != null && swig.pythonSupport;
assert javaSwigBindings -> swig != null && swig.javaSupport;
assert javahlBindings -> j2sdk != null;

stdenv.mkDerivation {
  name = "subversion-1.1.1";
  ...
  openssl = if sslSupport then openssl else null; 4
  ...
}

Example 5.5, “Nix expression for Subversion” show how assertions are used in the Nix expression for Subversion.

1

This assertion states that if Subversion is to have support for local repositories, then Berkeley DB is needed. So if the Subversion function is called with the localServer argument set to true but the db4 argument set to null, then the evaluation fails.

2

This is a more subtle condition: if Subversion is built with Apache (httpServer) support, then the Expat library (an XML library) used by Subversion should be same as the one used by Apache. This is because in this configuration Subversion code ends up being linked with Apache code, and if the Expat libraries do not match, a build- or runtime link error or incompatibility might occur.

2

This assertion says that in order for Subversion to have SSL support (so that it can access https URLs), an OpenSSL library must be passed. Additionally, it says that if Apache support is enabled, then Apache's OpenSSL should match Subversion's. (Note that if Apache support is not enabled, we don't care about Apache's OpenSSL.)

4

The conditional here is not really related to assertions, but is worth pointing out: it ensures that if SSL support is disabled, then the Subversion derivation is not dependent on OpenSSL, even if a non-null value was passed. This prevents an unnecessary rebuild of Subversion if OpenSSL changes.

With-expressions

A with-expression,

with e1; e2

introduces the attribute set e1 into the lexical scope of the expression e2. For instance,

let as = {x = "foo"; y = "bar";};
in with as; x + y

evaluates to "foobar" since the with adds the x and y attributes of as to the lexical scope in the expression x + y. The most common use of with is in conjunction with the import function. E.g.,

with (import ./definitions.nix); ...

makes all attributes defined in the file definitions.nix available as if they were defined locally in a rec-expression.

Comme