Skip to content

Instantly share code, notes, and snippets.

@joepie91
Created January 15, 2019 10:20
Show Gist options
  • Save joepie91/9fdaf8244b0a83afcce204e6da127c7d to your computer and use it in GitHub Desktop.
Save joepie91/9fdaf8244b0a83afcce204e6da127c7d to your computer and use it in GitHub Desktop.

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:

  • Deterministic: Building the same thing in Nix with the same configuration always results in the same output. No matter where you build it, what else is installed, or how you've configured your system. If it works in one place, it works everywhere; if it breaks in one place, it breaks everywhere in exactly the same way. Say goodbye to "works on my system".
  • Isolated: Every package has its own fully-declared set of dependencies, that doesn't conflict with any other package on the system. Dependencies are deduplicated where possible, but it's completely possible to have an unlimited amount of different versions of the same dependency, used by different applications - without dependency conflicts.
  • Customizable: All packages can be freely modified, right from within your system configuration, without needing complex custom repository infrastructure or tooling. That includes making patches to dependencies, even for a single application, without affecting anything else on the system! Even packaging your own applications is trivial.
  • End-to-end: 'Packages' aren't just software. Nix can build your system configuration, too, with all of the same guarantees, and it can seamlessly extend to container or even multi-system management - whether it's synchronizing the software on your desktop and your laptop, or managing a large fleet of production servers.
  • No overhead: Best of all, Nix can do all of the above without needing VMs or containers. That means that there's no runtime overhead, and it works absolutely fine in graphical environments like on a desktop or laptop, too! You can use VMs or containers, of course, where you need them - they're just a part of your system configuration.

^^^todo Add 'derived from a single config file' to the list. ^^^

These properties give you a lot of nice features:

  • Reliability: A Nix-based system is much more reliable than what you could get from another Linux distribution (that isn't based on the Nix model). Mystery failures are eliminated, problems are easier to diagnose, and they can be reliably reproduced by people helping you out, even if they are running a totally different system configuration.
  • Rollbacks: Change your kernel settings? Install some experimental drivers or software? No problem. If something breaks, you can just roll back to a previous version of your system - even if your system doesn't boot anymore.
  • Ease of installation: No need to resolve dependency conflicts, or mess around with virtualenv, or pick between two pieces of software that require different conflicting dependencies. Software just works. Even if it's ancient software that requires ancient dependency versions to run that are supported by nothing else, you can make it work without breaking any other software.
  • Easy synchronization: Synchronizing software or system configurations between computers is as simple as copying over your configuration.nix, either manually or through something like Git or even Dropbox. Since the entire system is built from that file, you can apply it to any amount of computers without issues, even if they were running a totally different configuration before.
  • No 'cruft' or 'decay': Because your system state is derived entirely from the configuration you give it, and not from piecemeal "change this, change that" instructions, your system doesn't accumulate 'cruft' over time like you may be used to from other distributions. A 5-year-old NixOS installation will run just as smoothly and reliably as a 2-day-old one, because effectively every configuration change is a (fast) reinstallation.
  • Automated package testing: Because all builds are isolated and deterministic, it's possible to do fully automated package tests, to verify that a package really works as advertised. This is done for the official package set, too.

^^^todo Explain more about NixOS' automated testing setup. ^^^

The properties above are not entirely without tradeoffs - make sure to read the FAQ entry about the tradeoffs 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 'nix-lang' to differentiate it from the package manager, and we'll do the same in this documentation.

nix-lang 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 sometimes even exceeding them - as well as all the bits and pieces for NixOS (explained below).

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.

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 documentation is for 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.

What is Hydra?

Hydra is, more or less, a build server. Unsurprisingly, it uses Nix and nix-lang 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.

FAQ

Some common questions are addressed here.

General

^anchor(tradeoffs)^

Are there any downsides?

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

  • Poor user experience: While the concepts behind Nix are great and could make system management a lot easier, the current generation of Nix tools can still be rather awkward to use. A lot of user experience kinks haven't been quite worked out yet, although this is a problem that's being worked on, and solvable in the long term.

  • Poor documentation: The documentation for Nix and associated tools isn't great yet. This website is a (hopefully successful!) attempt at improving that, but you'll most likely still run into quite a few 'documentation deserts' while using Nix, especially when just getting started. Please do ^todo(file issues)^ about documentation you're missing - it'll help us improve!

  • Incompatibility with other Linux systems: This is a less solvable problem, mostly specific to NixOS. To be able to provide the guarantees that it does, Nix makes some unusual decisions in how it structures your system. This means that, for example, /usr doesn't exist - and neither do many of the other 'well-known locations' that tools and users alike expect.

    This isn't a problem for packaged software, but it means that random 'static Linux binaries' downloaded from the internet won't work on NixOS out of the box. This includes AppImages, and many proprietary games. Some workarounds exist (in the form of steam-run and appimage-run), but it's still not the click-and-run experience that you get on other distributions.

    Similarly, configuration files aren't in a big bucket that you can edit at will - it's not possible to edit configuration files from outside of your Nix configuration, and various other such limitations exist. This isn't necessarily a problem (since you can still modify configuration files through your Nix configuration, for example), but it means you will have to adjust your habits and essentially re-learn a lot of Linux things.

    While work is ongoing on reducing the impact of these differences to end users, NixOS will never work exactly like the distributions you're used to - the model that those distributions use is fundamentally incompatible with the guarantees that Nix provides.

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 (nix-lang)

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

Most languages are one of roughly two types:

  • Declarative: These are languages like JSON, YAML, XML, TOML, and so on. They're typically very simple, only supporting statically specified data or maybe really basic references, without any logic. They're especially suited for serialization, and for cases where you need to extensively inspect the information written in it, like in configuration files.
  • Imperative: These are what you might think of when you hear 'programming language'; Python, C++, JavaScript, Rust, Lua, and so on. They typically specify a sequence of instructions that modify state and might produce output. They're especially suited towards implementing arbitrary logic, like in software, but it's hard to 'inspect' the state of the application.

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.

nix-lang 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment