Concepts

This chapter introduces you to a number of different core concepts in Nix and NixOS, as well as various of the important tools in the ecosystem.

What is Nix?

Nix is a next-generation package and system manager.

Many other package managers suffer from dependency conflict issues, and many systems built on them 'decay' over time, becoming messier, slower, and more prone to crashes over time. Nix does not suffer from these issues, because of a few unique properties:

These properties give you a lot of nice features:

The properties above are not entirely without tradeoffs - make sure to read the section below about the tradeoffs in the FAQ before diving into Nix and NixOS.

What is Nix (the language)?

Confusingly, the name "Nix" is not just used for the package manager, but also for the language that you use to write packages or system configurations. Sometimes, people call it 'nixlang' to differentiate it from the package manager, and we'll do the same in this documentation.

nixlang is a little different from what you might be used to. It's a bit like a declarative language such as JSON, but also a bit like a 'real' programming language, with support for functions and variables (sort of). An excellent step-by-step introduction to the language can be found here - it's a fairly simple language, but because it has some unusual characteristics, you should definitely give that a read.

This language is used throughout Nix, and in all of the tooling surrounding it. It's the language you use for writing package definitions, modifying your system configuration, managing multiple servers, and even for writing package tests. Because it allows creating functions and other abstractions, it can support configuration at any scale, without becoming complex to use for the simple cases.

If you're curious why Nix has its own custom language, and why it doesn't just use something that already exists, have a look in the FAQ.

What is nixpkgs?

You'll often run across the name 'nixpkgs' in this documentation. Nix itself is really just the package manager and build tool - it doesn't come with any software packages, and expects the user to point it at some sort of 'package set'.

That's where nixpkgs comes in - it's the officially maintained package set for Nix, and it's what almost every Nix user uses. It contains a wide selection of software - comparable to what you might find in most Linux distributions, and often even exceeding them - as well as all the bits and pieces for NixOS.

You're not limited to using nixpkgs, of course. It's just selected as a default when you install Nix, and you're free to add other package sets, or write an 'overlay' that extends nixpkgs with additional packages. For example, Mozilla maintains a nixpkgs overlay for their Rust and Firefox projects; and many users maintain Flakes, which can provide their own package sets.

If you're in a more experimental mood, you could even totally remove nixpkgs, and write your own package set from scratch. This is something that most users won't want (or need) to do, though.

What is NixOS?

While Nix can run as a stand-alone package manager on any Linux system, and even on macOS, there's only so much that it can do without control over the rest of the system. NixOS is a Linux distribution that takes the concept of Nix a step further, by making it possible to use Nix for managing your entire system - from software, to services, to kernel settings, to container management, all using the same language.

This wiki is for learning both Nix and NixOS - NixOS-specific sections will be marked as such.

What is NixOps?

Nix (and NixOS) themselves only manage a single machine. If you want to manage multiple machines, especially if they are many servers, you can use a tool like NixOps - it's an 'orchestration tool' like Ansible, Chef, or Puppet, but with the guarantees of Nix. Like all of the other tools, you use nix-lang for specifying your systems.

If you're curious about what NixOS with NixOps does better than other orchestration tools, give this excellent article a read.

NixOps is only one of many deployment tools for Nix and NixOS, and it is mentioned here because it was the first one. If you only need to manage one or a few servers, there are many other options that are often simpler, such as morph. These will likely get their own wiki articles at a later time.

What is Hydra?

Hydra is, more or less, a build server. Unsurprisingly, it uses Nix and nixlang for specifying what to build. It's used to build the binary packages for nixpkgs, for example, as well as for running automated tests to ensure that packages actually work. If you're just using Nix or NixOS as an end user, you probably don't need to care about this.

Because Hydra supports deployment operations after a successful build-and-testing cycle, you could also technically consider it a Continuous Deployment system.

What is a derivation?

You can think of a derivation as a set of build instructions, somewhat similar to how IKEA furniture comes with an assembly manual. The furniture (or package, or configuration file, or...) still needs to be built, but the build instructions (the derivation) have the information on how to do so. Nix takes these instructions, and uses them to create a build result.

Derivations are described using the Nix language (nixlang), and they may build anything - it doesn't need to be a software package! You might have a derivation for every software package that is being a built, and a derivation for your system configuration, and a derivation for each (automatically generated) configuration file for the software on your system, and so on.

Derivations also keep track track of their dependencies; that is, which other derivations are referenced inside of its instructions. Nix needs this information to make sure that everything is built in the correct order, and correctly linked together.

There is a derivation function in the standard library of Nix, but in practice you will probably never use it. Instead, you will most likely be using mkDerivation, which is a wrapper function in nixpkgs that automatically handles some things for you. This is explained further in the chapter about nixpkgs.

What is the Nix store?

The Nix store is a folder, located at /nix/store by default, that contains every build result from a derivation that Nix has ever generated. These build results stay in the Nix store until they are explicitly garbage-collected. Each entry in the Nix store is prefixed by a hash of the derivation that was used to build - this is how Nix avoids building the same thing more than once, and how it ensures that there is a unique reference to every possible version and variant of a piece of software.

You should not ever need to touch the Nix store manually; it is entirely under the control of Nix. However, Nix does provide several utilities for managing the store, such as nix-collect-garbage.

The high-level workflow of Nix

You can use Nix to build many different things for many different purposes. However, the basic workflow is always the same:

  1. You specify some kind of Nix expression. This can be a simple expression, a whole system configuration, a Morph deployment... anything that is written in Nixlang.
  2. You evaluate that expression, and recursively evaluate everything it references, using Nix. Wherever Nix encounters derivations, it will build them and turn them into the store path of their build result. It then returns the result of the 'top-level' expression you asked it to evaluate.
  3. You apply the result of that expression in some way. For a NixOS configuration that means setting it as the default boot target in the bootloader, for a Morph deployment that means that Morph will send it to the remote server over SSH, for a VM build that means it gives you a link to the generated VM image, and so on.

Importantly, when using NixOS, this same workflow also applies to changing any of your system configuration, and even installing packages! You never "install a package" as a discrete action - rather, you add an item to the list of packages that should exist on your system, and rebuild the configuration using nixos-rebuild.

In that process, Nix will notice that a package is referenced that it doesn't have yet, so it builds or downloads it. Then nixos-rebuild changes the system environment to the new version of your system, where this package is part of the environment. The end result is that the package is now available for you to use.

This is often one of the things that people have the most trouble with, when learning NixOS - unlearning the idea of "installing packages" as a command that you run, and instead thinking of your system configuration as having 'versions' that do or do not have certain packages available. It's a little bit like a version control such as Git.

Isn't that a really limiting workflow?

Yes and no! It's true that this workflow makes some things a bit harder, and that it can take some time to get used to. However, NixOS can do everything that more traditional Linux distributions can do in terms of configuration, and - thanks to this workflow  - can even do some things that they can't do, like going back to past versions of your system, or having virtual environments on the same system that look completely different.

Because every version of the system is itself a build result from a derivation, it can be referenced and managed in the same way that a piece of software might be. Opening a shell that points at a particular environment, generating a virtual machine image out of an environment, it's all possible.

Frequently Asked Questions

General

Are there any downsides?

Yes. Here are some of the most common issues that people run in today:

Should I use Nix?

That depends. Given how different Nix is from 'traditional' package management systems and Linux distributions, it will take quite some time to learn how all of it works.

If you decide to use Nix on another distribution, then you can do this while you continue using your other package manager, so you won't get 'blocked' on not understanding something about Nix yet. However, the benefits you get from Nix will also be limited to just package management.

If you decide to use NixOS, then you can use the full range of system management niceties available - but there won't be an 'escape hatch' when you're not sure how to do something, so this is a somewhat steeper learning curve. You should expect to be figuring things out for at least a week, when taking this route.

It really all comes down to this: you'll have to spend effort upfront to learn about how Nix works, and that can be quite a bit of work. But in the long term you'll get a much more reliable system out of it, and it'll make your life easier. Whether you're willing to make that tradeoff, is up to you.

The Nix language (nixlang)

Why a custom language? Why not use something that already exists?

Most languages are one of roughly two types:

The problem is that Nix needs a little bit of both. It's mostly data-oriented - a system configuration is data, package metadata is data - but it's also about data that's complex enough and sometimes repetitive enough that you want to be able to use logic to produce it.

nixlang is precisely that - a simple and mostly-declarative language with enough abstraction that you can programmatically generate data, but not so much that it becomes difficult to inspect.

One particularly unique aspect of it is that it's lazily-evaluated; that is, instead of executing some logic and storing the result in a variable, you store the logic itself in a variable, and the first time that variable is accessed, the logic is executed and the result remembered for future access. This is what makes it possible to have tens of thousands of packages in a Nix package set, without needing to execute all logic every time you need a single package.