Explaining NixOS to myself at a high-level
Though I’ve been using nixOS on and off since 2019, I realized recently that I have trouble communicating what it’s all about without getting into the weeds. I wanted to write up a short thing explaining at a high-level why and how nixOS is neat in plain-ish terms. Specifically I wanted to make sense of all the serious adjectives it boasts being, ie: functional, reproducible, immutable, and declarative. Here’s my attempt at that!
NixOS: who is she
NixOS is a Linux distribution that fundamentally rethinks how an operating system is built, managed and upgraded. It is unlike the OSes that come before it because it is purely functional, declarative, reproducible and immutable.
This is novel because operating systems as we know them are imperative, mutable systems. We make changes to the system by performing the steps to install packages, run scripts and edit config files. The changes are made in-place, overwriting what was there before and mutating the global state of the system. NixOS rethinks this entire model by taking a functional and declarative approach to system configurations and package management.
NixOS introduces a configuration layer for the OS that is implemented purely functionally1. This allows users to describe the desired end-state of their system using declarative system configs, and these configs are then functionally evaluated into distinct “system generations” that allow for versioning of system builds and other useful features like atomic upgrades and rollbacks. In being purely functional, the resulting system builds are idempotent (or cause no side effects aside from the desired state described) which unlocks immutable system builds as a feature of NixOS. To rephrase, this means that once a system version is built, it cannot be mutated, for example by updating a config file in-place under /etc directory. To make a change, you must describe the change in your config files and rebuild the system as a new system version. The resulting system versions are known and tracked by NixOS and can be switched between easily.
NixOS also takes a novel approach to package management. System changes are applied using the Nix package manager, which is described as a purely functional package manager. Specifically, the system state described in the config files are evaluated purely functionally, meaning there are no side effects or runtime dependencies and the build result (i.e., your resulting operating system) is deterministic. The subsequent build and install steps that apply the system state are technically impure, but are achieved in a reproducible and non-destructive manner through the use of isolated sandboxes and the Nix store (which is the immutable, content-addressable directory of all build outputs of the Nix package manager).
This is why NixOS is described as purely functional, declarative, reproducible and immutable: system configurations are written and evaluated in a purely functional and declarative manner, and applied in a way that achieves immutability and reproducibility.
-
using the purely functional language, the Nix DSL, specialized for building packages and system configs. that’s right fellas, NixOS runs Nix which is also built using Nix 🥲 ↩︎