Installing Nix
Installing Nix
The rest of this book assumes a working Nix installation with flakes and the nix-command CLI enabled. The boring default is: a multi-user daemon install, flakes on, and nix run nixpkgs#hello succeeding before you write a single expression.
You do not need NixOS yet. Nix the package manager runs on ordinary Linux and on macOS. NixOS (the operating system) comes in the next chapter.
Mental model
Nix is three things that share a name:
| Piece | What it is |
|---|---|
| Nix the tool | The nix binary and the nix-daemon that builds and substitutes store paths |
| The store | /nix/store, a read-only tree of hashed paths |
| NixOS | A Linux distribution whose entire system is a Nix derivation |
This chapter installs the first two. The daemon (multi-user) install is the one that matches production: unprivileged users talk to nix-daemon over a socket; builds run as dedicated nixbld users; the store is owned by root.
Single-user installs (~/.nix-profile only, no daemon) exist. Skip them on a shared workstation. They fight SELinux, they fight /nix permissions, and they do not match the NixOS mental model you will use later.
Flakes are still marked experimental in some docs. On this book’s baseline (Nix 2.35+) they are the boring interface: flake.nix plus flake.lock, no ambient <nixpkgs> channel required.
curl installer
│
▼
/nix created + nix-daemon enabled + your user in the trusted group
│
▼
nix.conf: experimental-features = nix-command flakes
│
▼
nix run nixpkgs#hello → "Hello, world!"
Worked examples
Case 1: Multi-user install on Linux
On a throwaway VM or a Linux workstation you control, run the official multi-user installer. Read the script. Then execute it:
curl -L https://nixos.org/nix/install -o nix-install.sh
less nix-install.sh
sh nix-install.sh --daemonOutput (abbreviated):
installing in multi-user mode...
alright! we're going to call sudo
copying Nix to /nix/store...
providing a `nix` command in your PATH...
setting up the nix-daemon systemd service...
Nix: just installed
Open a new login shell so PATH and NIX_PROFILES are set. Confirm:
nix --version
systemctl is-active nix-daemonOutput:
nix (Nix) 2.35.2
active
The daemon must be active. If it is not, systemctl enable --now nix-daemon and check journalctl -u nix-daemon.
Case 2: Enable flakes in nix.conf
The installer may already have turned flakes on. Check:
nix show-config | grep experimental-featuresIf the line does not include both nix-command and flakes, write them yourself.
On a multi-user install the file is /etc/nix/nix.conf (root). On a single-user leftover it is ~/.config/nix/nix.conf. Prefer the system file:
# /etc/nix/nix.conf
experimental-features = nix-command flakesRestart the daemon so the change is picked up:
sudo systemctl restart nix-daemonnix flake --help must print help, not an “experimental feature disabled” error.
On a multi-user machine the daemon reads /etc/nix/nix.conf. Putting flakes only in ~/.config/nix/nix.conf makes nix flake work in your shell and fail in nix-daemon builds (CI-shaped errors on the laptop). After editing the system file, systemctl restart nix-daemon.
26.05 NixOS ships daemon Nix 2.34. This book’s CLI baseline is 2.35+ (installer, or nix.package on NixOS). nix --version vs nixos-option nix.package — do not assume they match.
Case 3: First substitute from cache.nixos.org
You have not compiled anything. nix run should download a closure:
nix run nixpkgs#helloOutput:
copying path '/nix/store/…-hello-2.12.1' from 'https://cache.nixos.org'...
Hello, world!
If this compiles from source for minutes, your substituters are missing or unsigned. Confirm:
nix show-config | grep substitutershttps://cache.nixos.org must be listed. The matching public key is shipped with Nix; you do not paste it by hand.
Case 4: A pinned flake instead of a floating channel
nix run nixpkgs#hello follows whatever nixpkgs your registry currently points at. That is fine for a smoke test. For desk work, pin.
Save as flake.nix in an empty directory:
# flake.nix
{
description = "Desk smoke test";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in
{
packages.${system}.default = pkgs.hello;
};
}If you are on aarch64, change system to "aarch64-linux" (or "aarch64-darwin" on Apple silicon).
nix flake lock
nix runOutput:
Hello, world!
flake.lock now pins the exact nixpkgs revision. Commit both files. The next machine that clones this directory gets the same hello.
Case 5: macOS (same daemon, different volume)
On macOS the installer creates an APFS volume for /nix (the root filesystem is signed and cannot hold /nix directly). Run the same official script with --daemon. After install:
nix --version
nix run nixpkgs#helloDo not install Nix with Homebrew. Homebrew’s nix package fights the daemon, the volume, and the store layout. One installer, one /nix.
The trap
The trap is curl | sh without reading, then a second installer on top. Mixing the official installer, the Determinate installer, and a distro package (dnf install nix, apt install nix-bin) produces two daemons, two nix.conf files, and a store the next nix-collect-garbage is afraid to touch.
Pick one installer and keep it:
| Situation | Installer |
|---|---|
| Generic Linux VM, this book | Official multi-user (--daemon) |
| Team that already standardised on Determinate | Determinate, and only that |
Fedora with a packaged nix you are required to use |
The distro package, then enable flakes by hand |
If you already have a broken mix:
# last resort: uninstall, then one clean install
sudo systemctl stop nix-daemon
# follow the uninstall steps for whichever installer you actually usedDo not rm -rf /nix while a daemon is running.
A second trap is enabling flakes in ~/.config/nix/nix.conf while the daemon reads /etc/nix/nix.conf. Your shell says flakes are on; nix-build via the daemon says they are not. Put experimental-features in the file the daemon reads.
The boring rule
- Multi-user daemon install. One
/nix. Onenix-daemon. experimental-features = nix-command flakesin the daemon’snix.conf.- Prove the install with
nix run nixpkgs#hellosubstituting fromcache.nixos.org, not compiling. - Pin nixpkgs in a
flake.lockas soon as you keep the directory. - Do not stack installers. Do not install Nix via Homebrew.
Try this
- Run
nix run nixpkgs#cowsay -- "desk online"and confirm the NAR came fromcache.nixos.org(the “copying path … from” line). - In Case 4’s directory, run
nix flake metadataand write down the locked nixpkgs revision. Change nothing, run it on a second machine (or a container with Nix), and confirm the revision matches. - Comment out
experimental-featuresinnix.conf, restart the daemon, and runnix flake show. Restore the line after you have seen the error. - Run
ls -ld /nix /nix/storeand note the owners. The store should not be writable by your ordinary user.