A Beginner’s Guide to the Fundamentals

Basic concepts, components, modules, use cases, and the mental model behind declarative Linux

NixOS for Beginners

  1. Part 1 — The Mental Model Behind Declarative LinuxYou are here
  2. Part 2 — The Nix Store, Derivations, Closures, and Builds
  3. Part 3 — The Nix Language, Nixpkgs, Modules, and Options -> Coming

The one-sentence version

NixOS is a Linux distribution where the intended state of the operating system is described as code, built from precisely identified inputs, and activated as a versioned system generation that can be reproduced, inspected, and rolled back.

Why NixOS feels strange at first – and why that is useful

Most Linux distributions teach you to manage a machine by changing it. You install packages, edit configuration files, enable services, remove packages, upgrade components, and gradually turn a fresh machine into “your” machine.

NixOS asks you to think about the same job differently. Instead of treating the machine as a history of commands, you describe the state you want. Nix evaluates that description, determines what must exist, builds or downloads those objects, and activates a new system configuration.

That distinction sounds small, but it changes almost everything: package management, upgrades, rollbacks, development environments, server configuration, reproducibility, and even the way you reason about troubleshooting.

A useful beginner mental model

Traditional Linux is often “configure this computer.” NixOS is closer to “compile the description of this computer.” The result is still a normal Linux system, but much more of its state is produced from a declarative model.

Where NixOS came from: history and motivation

NixOS did not begin as an attempt to make “yet another Linux distribution.” Its roots are in a research problem: how can software be deployed so that the result is complete, predictable, isolated from unrelated changes, and possible to reproduce or roll back? That question led to Nix first, and then to NixOS.

The problem Nix was designed to attack

Traditional package management is mostly imperative. Installing or upgrading software changes shared directories and global machine state in place. Over time, the result can depend on the exact history of commands that happened to that machine. A package may accidentally rely on something that was already installed, an upgrade can overwrite files another component expects, and recreating the same environment elsewhere can become surprisingly difficult.

  • Hidden dependencies can make software work on one machine and fail on a clean one.
  • Different versions of the same dependency can collide when they must share global filesystem locations.
  • Upgrades can destructively replace the previous working state, making rollback difficult.
  • A machine can slowly become “special” because its real configuration is the accumulated history of manual changes.

Nix: applying functional-programming ideas to deployment

Around 2003, Eelco Dolstra and collaborators at Utrecht University began developing Nix as a research project. The key idea was to treat software deployment more like evaluation in a purely functional language: build outputs should be derived from declared inputs, and once produced they should not be modified in place. Nix combines that model with content-address-like, hash-qualified store paths so that different dependency graphs can coexist safely.

Dolstra’s 2006 PhD thesis described the goal as correct software deployment: deployments should be complete and should not interfere with one another. The design produced several consequences that now feel characteristic of Nix: side-by-side versions, explicit dependency closures, atomic changes, rollback, source/binary transparency, and reproducible configuration as a first-class objective.

PeriodWhat happened
Around 2003Nix begins as a research project at Utrecht University, exploring a purely functional model for reliable software deployment.
2006Eelco Dolstra defends his PhD thesis, The Purely Functional Software Deployment Model, formalizing the central ideas behind Nix.
2007–2009Early NixOS work extends the model from packages to a complete Linux system; research papers describe a distribution whose system configuration is built from declarative Nix specifications.
2013 onwardNixOS matures into a community-developed Linux distribution. The ecosystem grows around Nixpkgs, build infrastructure, binary caches, modules, and increasingly large production and developer use cases.

From a package manager to an operating system

Nix solved the package-deployment problem, but the same question existed one level higher: what about the operating system itself? A conventional Linux server is not only a collection of packages. It also has kernels, boot configuration, users, services, generated configuration files, firewall rules, scheduled jobs, and many other pieces of system state.

NixOS grew from the idea that these pieces could also be described and built declaratively. Instead of using Nix only to install packages, NixOS uses Nix to construct a whole system configuration. A change produces a new system generation rather than destructively rewriting the previous one. That is why NixOS features such as atomic upgrades and rollbacks are not unrelated conveniences; they are direct consequences of the original deployment model.

Why this history matters to a beginner

Many of NixOS’s unusual choices make more sense once you know what problem it was trying to solve. The /nix/store is not strange for the sake of being strange. Hash-qualified paths help isolate dependency graphs. Immutable build outputs make previous results dependable. Declarative modules reduce the importance of manual machine history. Generations preserve older system states. Binary caches let an exact build result be reused instead of reconstructed differently on every machine.

The unifying motivation is simple: make software and system deployment behave less like an accumulation of fragile mutations and more like a controlled, reviewable, repeatable build.

First, what does “Nix” actually mean?

One of the first sources of confusion is that the word Nix is used for several related things. They are connected, but they are not interchangeable.

NameWhat it isWhy a beginner cares
NixA package manager, build system, store model, command-line tooling, and associated concepts.It is the engine that builds, stores, installs, and manages software and environments.
The Nix languageA small declarative, functional language used to describe packages, configurations, and compositions.You read and write .nix files in this language.
NixpkgsA very large repository of package definitions, libraries, and NixOS modules.It is where most packages and NixOS options come from.
NixOSA Linux distribution built around Nix and the NixOS module system.This is the operating system you install on a machine.
The Nix storeAn immutable store, normally /nix/store, containing packages and other build outputs.It explains side-by-side versions, dependency isolation, and safe rollbacks.
Home ManagerA related community project for declaratively managing user-level files and programs.Useful later for dotfiles and per-user configuration, but not required to learn NixOS.
Nix languageNix / build engineNix storeNixpkgsNixOS

The diagram is deliberately simplified. In practice these pieces interact in several directions, but the flow is enough to orient a new user.

The core philosophy: describe the desired state

NixOS is called declarative because you normally describe properties of the system rather than writing an ordered script of changes.

Imperative thinkingDeclarative thinking
Install OpenSSH. Edit sshd_config. Restart sshd.Set services.openssh.enable = true and define the options you want.
Install PostgreSQL, create service files, tune permissions.Enable the PostgreSQL module and set its declared options.
Remember which packages were installed last year.Read the configuration that defines the intended package set.
Recover by undoing the last set of commands.Select or rebuild a previous known-good generation.

A small NixOS module: it says what should be true, not which shell commands to execute.

{ config, pkgs, … }:
{
  networking.hostName = “nixbox”;
  services.openssh.enable = true;
  environment.systemPackages = with pkgs; [
    git
    vim
    curl
  ];
}

When you run a rebuild, NixOS evaluates the configuration, builds the new system closure, and switches the machine to it. Configuration is still real work; declarative does not mean automatic design. You still decide what the machine should contain and how services should behave.The Nix store: the filesystem idea that makes the rest possible.

The Nix store: the filesystem idea that makes the rest possible

Most software managed by Nix lives in the Nix store. The Nix store is a special directory (/nix/store) where NixOS safely stores all software packages, configuration files, and system components. Store objects have paths that include a hash-like identifier plus a human-readable name. Different builds can therefore coexist without overwriting each other.

Conceptual example – store path hashes are abbreviated here.

/nix/store/abc123…-openssl-3.x/
/nix/store/ghi789…-my-application-1.0/

A package does not need to replace the old version in place. A new version can be placed at a different path. A new system generation can point to the new version while an older generation continue to point to the old one.

  • Unique Hashes: Every file and package name starts with a long cryptographic hash (e.g., /nix/store/12345abcdef…-firefox-100.0). This hash represents the exact recipe and dependencies used to build that specific item.
  • Immutability: Files inside the Nix store are read-only and cannot be changed after they are created. This stops programs from breaking each other or changing unexpectedly. Store paths are treated as immutable build outputs rather than files to edit in place.
  • Isolation: Different dependency graphs can exist side by side.
  • Deduplication/Sharing: Identical files share the same space on your hard drive, which saves storage. Two environments can reference the same store object instead of each keeping a separate copy.
  • Atomic Upgrades: When your system updates, Nix builds the new software in the store alongside the old version, then switches the active system pointer instantly.
  • Rollback: Because old versions stay in the store until you clean them up, you can instantly boot back into a previous system state if an update breaks something. Old generations can continue to reference old store paths until you garbage-collect them.
  • No Garbage Left Behind: An automated “garbage collection” tool safely deletes old packages that your current system configuration no longer uses.

Do not edit /nix/store by hand

If something in the store is wrong, change the source configuration or package definition and build a new result. Treat the store as output, not as your working directory.

Derivations, dependencies, closures, and builds

The term derivation appears frequently in Nix documentation. For a beginner, the most useful definition is: a derivation is a precise build recipe with declared inputs and outputs. Nix uses derivations to know what has to be built and what depends on what.

Source + inputsDerivationBuild / substituteStore output

If an output already exists in a trusted binary cache, Nix can usually download that exact output instead of compiling it locally. This is called substitution. If it does not exist, Nix can build it.

A closure is the complete transitive set of store objects required by something. Your system closure therefore includes the system itself plus all store objects needed at runtime. Thinking in closures is useful because Nix manages dependency graphs rather than just package names.

Why hashes matter

The identity of a store result is derived from relevant build information and dependency relationships. If important inputs change, Nix can produce a distinct path rather than silently mutating the old one.