This page is part of my digital garden.

This page might be unfinished or have typos. These pages are meant as part of a public living notebook to be edited over time. For more, visit the page explaining the concept of a digitial garden.

Nix: Language, Nixpkgs, and NixOS

When someone refers to “Nix” they’re referring to one of three things:

  • The functional, lazy langauge with special features for building packages
  • nixpkgs which is the community maintained repo of thousands of lines of Nix code that can build things as complex as the Linux kernel.
  • NixOS which is a Linux distro relying on nixpkgs and is configured and built using Nix.

The langauge Link to heading

Nix is a functional language in C++. It’s syntax is inspired by Haskell, but without all of the types.

Nix is designed with special features to process/output derivations which define some set of inputs to generate some output.

Usually the output is a binary from some code being compiled, but it could be anything. Packages, for instance, also include shared libraries, man pages, and more.

Really, an output is just whatever you generate from some input. It could be the static pages generated by Hugo or other static website generators.

The one complicated part is that for a given set of input files and configuration, which is hashed, that “building” your output using these inputs always results in the same hash for the output. This makes it deterministic and is a key assumption Nix makes when deciding to build something again or not.

Nix, in practice, feels like just writing bash scripts in a weird functional langauge… because it is just bash scripts at some level… but the key thing is that it has tools for dealing with the fact that packages aren’t written to be deterministically compiled.

This series by Ian Henry is currently the most in-depth guide I’ve found which helps explain Nix and NixOS. It documents his experience learning and understanding Nix. The docs and community-maintained wiki help a lot but a lot is left unsaid. Especially the needed trivia needed to be able to read through the source code of Nixpkgs for examples of what/how/why things are done.

Nixpkgs Link to heading

Nixpkgs is a community maintained mono-repo of all kinds of packages which have derivations written for them which you can use with Nix to build those packages and also use them in your own packages. For instance: gcc, libc, python, jupyter, and etc.

Nix “Flakes” Link to heading

Flakes are the newer way of configuring projects using Nix. Much of the Nix ecosystem is still moving to them and they fix a lot of things with how packages and environments are built today.

The latest version of nix you can install via the website supports Flakes already. Before you needed to install nix and then upgrade to the new version and most tutorials will cover that, but it’s not needed anymore. At most, you’ll need to create a ~/.config/nix/nix.conf file to enable the experimental CLI commands and flake support.

What is a flake? Over simplified Link to heading

If a git repo has a flake.nix file then it’s a flake and can be built. Flakes expect to be inside a git repo and ignore any file not tracked by git by-default.

  • If you run nix flake init it’ll use the default template to create a flake in your current directory.
  • nix flake show templates shows you what other templates you can use.

e.g. nix flake init -t templates#simpleContainer.

nix build for instance looks in outputs for defaultPackage.<system>. Flakes allow creating operating system specific changes to how packages are built right inside the flake file. There is a flake called flake-utils which lets you actually loop over all the default systems (like Linux x86, Linux Arm, macOS x86, macOS arm) among other things.

nix develop is the replacement for nix-shell and expects devShell.<system> to be configured otherwise it looks at defaultPackage.<system>.

Jumping ahead a bit: Defining and building a NixOS configuration in a flake is a simple as creating a nixosConfigurtion.<machinename> in the outputs then you using nixos-rebuild build --flake .#<machinename> to build that configuration. You can also build configurations for another machine and switch to it: nixos-rebuild switch --flake .#remotemachine --target-host remote-hostname --build-host localhost

Enable Nix Flakes Link to heading

Depending how you’re using Nix there are a few ways to enable Nix Flakes, but typically you want to set the following configuration variable in your nix.conf (it’s easier to use ~/.config/nix/nix.conf rather than edit the system /etc/nix/nix.conf).

experimental-features = nix-command flakes

If you’re using lnl7/nix-darwin or NixOS there will be options to configure nix like this

({ config, pkgs, ... }: {
    imports = [ ./hardware-configuration.nix ];

    nix.settings.experimental-features = [ "nix-command" "flakes" ];

    # ...
}

If you’re simply using nix + home-manager on a Linux or macOS machine you can create a .config/nix/nix.conf and put the line above into that file.

Configuring Nix for macOS Link to heading


All pages in this Section