NixOS — Notes for First-Timers
Contents
NixOS keeps coming up, so I looked into what it actually is. I did not install NixOS in a VM. I installed the Nix package manager on an Ubuntu 24.04 server and went as far as building a NixOS configuration. Versions: NixOS 26.05, Nix 2.35.3.
What it is
A Linux distribution built on top of the Nix package manager.
On a normal distro you install the OS, then add packages and edit files under /etc until the server looks right.
On NixOS you describe the whole system in one file, configuration.nix, and the OS is built from it.
Which packages are installed and which services run is all in that file.
- Nix started around 2003 as Eelco Dolstra’s PhD research
- Two releases a year, May and November, named
year.month - Current release: 26.05 “Yarara” (May 30, 2026). Next: 26.11 “Zokor”
- Each release is supported for seven months. 26.05 runs until December 31, 2026
You can use the Nix package manager without NixOS, on Ubuntu or macOS for example.
How it differs from a normal distro
- Where packages live: Ubuntu uses
/usr/binand/usr/lib. NixOS uses/nix/store/<hash>-<name>-<version> - Configuration: on Ubuntu you edit files under
/etc. On NixOS you editconfiguration.nixand rebuild - Several versions of one package: hard on Ubuntu. On NixOS they just sit side by side
- An upgrade breaks things: on Ubuntu you restore from backup. On NixOS you roll back to the previous generation, also from the boot menu
- Identical servers: Ubuntu needs Ansible or similar. On NixOS the same file gives the same system
Below is what I actually tried.
Install
The usual way is the multi-user (daemon) install.
| |
I was root inside a container, so I used
--no-daemon. As root it fails because thenixbldgroup is missing; addingbuild-users-group =to/etc/nix/nix.confand rerunning fixed it.
The newer commands (nix run, nix shell) and flakes are still experimental and have to be turned on.
| |
Without it:
| |
Packages live in /nix/store
The server already had Python 3.11. I ran 3.12 and 3.13 through Nix.
| |
- Each version gets its own path under
/nix/store, so they never collide - The hash comes from everything that went into the build (source, dependencies, options). Change any of it and the path changes
- The system’s own 3.11 is untouched
The first fetch for Python 3.12 pulled 23 paths (74.7 MB). Python 3.13 shared most of them and needed only one more path (54.1 MB).
Use a tool without installing it
| |
It runs once and leaves nothing on the system. Handy for per-project tools.
Rollback
Every install creates a new generation. I installed hello, then jq.
| |
One step back:
| |
The Nix jq 1.8.2 is gone from the path and Ubuntu’s own jq 1.7 shows up again.
Nothing was deleted. The files are still in /nix/store, so going forward again is instant.
| |
On NixOS this works for the whole OS. Every system change is a generation and stays in the boot menu, so if an update leaves the machine unbootable you pick the previous one. I could not try that part without a real NixOS install.
The whole system in one file
A config with nginx, SSH and one user:
| |
On NixOS you put this in /etc/nixos/configuration.nix and apply it with:
| |
On Ubuntu I can only build it:
| |
- First build: 465 paths fetched (487.5 MB), 270 built, 107 seconds
- Result is 1.2 GB, with kernel 6.18.57
The result folder holds the kernel, the initrd and /etc.
| |
Even the nginx config is not a file in /etc/nginx. It is generated in the store and the service points straight at it:
| |
So you don’t log in and edit config files by hand. You change configuration.nix and rebuild.
Only the change gets rebuilt
I added tmux to the package list and rebuilt. 11 seconds.
| |
Only tmux and the two libraries it needs were added. Everything else was reused.
A typo
I changed enable to enabel:
| |
It fails at build time, before anything is applied. The real error comes after a long stack trace, which is confusing at first.
What is hard at first
The Nix language
The config is written in Nix, its own language. The syntax is small but takes time to get used to, and error messages are long, as above.
Binaries from other distros don’t just run
A normal Linux binary looks for /lib64/ld-linux-x86-64.so.2. Anything built by Nix points into the store instead:
| |
NixOS has no real /lib64 loader. In 26.05 environment.stub-ld.enable is on by default, so you get an explanatory message instead.
To run outside binaries, the usual answer is programs.nix-ld.enable = true. I did not try it.
Disk space
After only these tests /nix/store was 1.1 GB. Old generations keep piling up until you clean them:
| |
Other
- Documentation is spread across the manual, nix.dev and the wiki
- From 26.05 the early boot stage (initrd) is systemd-based by default, so older guides may not match
Trying it
- Full NixOS: ISO from https://nixos.org/download/ (graphical installer or minimal)
- Lower commitment: install just Nix on your current Linux or Mac and start with
nix shell - Intel Macs: 26.05 is the last release with packages built for them
References