
Motivations
Over two years ago, I made the switch from Windows to Linux, and landed on NixOS primarily for the reliability it provides, as I had previously bricked my computer twice when testing out Ubuntu after changing some system files I probably shouldn't have.
In my journey of learning to use NixOS, I found it pretty hard to find information online, whether in docs or forums, regarding how everything works and how to perform tasks like install a program, update packages. I will say that there's a comprehensive online documentation for Nix and NixOS, but if you're not an adept user, you'll find it hard to understand. On the other-hand, there are many beginner introductions on why you should use NixOS, like this one by No Boilerplate, but I find they never explain enough to actually use it.
The goal of this blog / guide is to explain all of the concepts required to use NixOS practically and hopefully act as a stepping stone for beginners, towards becoming an adept user. If this is the first time you've heard of NixOS, I would recommend watching an introduction video like the one above to get some basic context before proceeding.
What makes NixOS Different?
Nix and NixOS
The first thing you might notice when looking into NixOS is that Nix and NixOS are separate things. The distinction is that Nix is a package manager (as well as a language) like apt or Pacman, that can be installed on any Linux distribution. Whereas NixOS is an operating system that fully leverages the Nix package manager across the entire system.
The Nix package manager is unique, as it installs packages into the /nix/store in isolated, hashed paths so that they never conflict with each other. You can have multiple versions of the same package installed simultaneously with no issues. The same idea follows for dependencies, being able to have multiple versions of the same dependency for different applications without conflict.
Thus making Nix:
- Reproducible - Nix builds packages in isolation from each other.
- Declarative - Nix makes it trivial to share development and build environments.
- Reliable - Nix ensures that installing or upgrading one package cannot break other packages.
Someone on Debian can install Nix and get many of the same benefits for their development workflow without switching their OS. NixOS just takes that philosophy and applies it to the entire system.
NixOS and other operating systems
For example on Debian, packages install to standard locations like /usr/bin/ or /usr/lib/. On NixOS, nothing gets installed there, instead everything lives in the /nix/store under a path like:
/nix/store/abc123...-git-2.43.0/bin/git
The abc123 is a unique hash derived from every input that went into building that package, including source code, compiler, dependencies, build flags, etc... . Any changes would install to a different path. This is what makes NixOS reproducible.
The NixOS Configuration
The Basic Principles
-
Nixpkgs - A community driven repository on GitHub of all packages, modules, options, etc...
-
Channels - Channels are a way of tracking nixpkgs, the repository that contains NixOS packages, modules and options.
nixos-unstableis itself a channel that tracks the latest commits of nixpkgs. Under the hood, channels are just git branches fromnixos-unstable. Stable channels are released twice a year, for example the channel namenixos-24.11was released in November 2024, and so represents a snapshot of nixpkgs slightly before then. After release, the channel continues to receive back-ported bug fixes and security patches. -
Snapshots - As I said, nixpkgs is a GitHub repository, and so it's being committed to constantly. A snapshot is just a specific commit of that repository for a specific channel. Updating your snapshot of the current channel, allows you to receive bug fixes and security patches.
-
Profiles - A profile is a collection of symlinks to the Nix store that defines a particular system or user environment, this includes both packages and configuration. NixOS uses profiles to manage different system configurations. For example, your system profile is what gets rebuilt when you run 'nixos-rebuild switch'. Profiles are versioned, so switching to a previous profile is as simple as selecting it from the boot menu. This is what makes NixOS rollbacks possible.
-
Module options - NixOS configuration is built from modules, each of which provides a set of options. Options are the configurable parameters that control system behaviour. For example,
services.openssh.enablecontrols whether the SSH server is enabled. You can browse all available options at search.nixos.org/options.
How to apply them
Let's say you've just installed NixOS for the first time, and you want to install a package. Chances are you'll find a guide telling you to search the package list here, and then install it with the nix-env command. The use of the nix-env command to install packages permanently modifies your local profile, foregoing many of the benefits that make Nix uniquely powerful, hence this is not recommended.
For simplicity, you only use these two methods to install packages on your system:
- Using nix shell.
- Modifying your NixOS configuration.
Nix Shell
Using the nix-shell command will install a package to the nix store and temporarily add it to your path, allowing execution in the current terminal instance. It can be used as shown here:
nix-shell -p <package name>
This is useful if you wish to temporarily use or test an application without having to update your config.
NixOS Configuration
All NixOS installations come with a configuration.nix file located in /etc/nixos/. Editing this file is the recommended way to install all packages or configure any module options. In the same directory, you may also notice a hardware-configuration.nix, this file is generated upon installation and generally shouldn't be changed manually. You may also notice that hardware-configuration.nix is imported at the top of your configuration.nix, the Nix language allows configurations to be spread across multiple files, so following the same convention that the hardware config used, you can split up your configuration.nix across multiple files if you wish.
To install a package or application to your system, edit the configuration.nix file, locate your environment.systemPackages line, and add your package like so:
environment.systemPackages = with pkgs; [
<package name>
existing-package-1
existing-package-2
existing-package-3
...
];
Note: The with pkgs; part allows you to omit pkgs. before your package names. This means that pkgs.<package name> can just be <package name>.
You can find more information on how the configuration file works here.
Then save the file, and run the following command to rebuild your system, causing the new package to install and your new profile to point to it:
sudo `nixos-rebuild` switch
One of NixOS's most powerful features is rollback. Each rebuild creates a new system generation, and previous generations remain available in your boot menu. If something goes wrong, simply reboot and select the previous generation from the GRUB menu, your system will be exactly as it was before the change.
How do I update?
Once you've got NixOS running, installed some packages and changed your config. You might wonder how packages are updated, and what you have to do to install security patches and bug fixes? I had the same thought and didn't figure it out properly until recently.
I had the long held misconception that packages don't change within the same channel, and so to update, you have to switch to newer channels as they come out. This is not how channels work and not the correct way to update. As explained earlier, your system will have a snapshot of the current channel(s) you're subscribed to. But that snapshot is just a point-in-time view, the channel itself continues to be updated with bug fixes and security patches.
To update your system within the same channel, you first update your local snapshot to the latest version of the channel, then rebuild:
sudo nix-channel --update
sudo nixos-rebuild switch
The first command fetches the latest version of the channels you're subscribed to. The second rebuilds your system with the updated packages. That's it, you now have the latest bug fixes and security patches without switching channels.
Switching to a newer channel (e.g. from nixos-24.11 to nixos-25.05) is a separate operation that should be done deliberately, not as part of routine updates.
Flakes, what and why?
Flakes are a newer approach to managing NixOS configurations that replace channels with explicit, pinned inputs defined in a flake.nix file, typically also in /etc/nixos/. When you run nixos-rebuild with a flake, it reads your flake.nix, which specifies exactly which channel of nixpkgs to use, and a flake.lock file that pins the exact commit hash of each input. If you built your flake for the first time, a flake.lock file will be generated pinning the latest commit hash of your inputs (channels).
The key advantages of flakes over channels are:
- Reproducibility - the
flake.lockfile pins exact versions, so rebuilding on another machine (or months later) produces an identical system. - No channels - flakes don't rely on nix-channels, so there's no ambiguity about which version of nixpkgs your system is tracking.
- Portability - your entire system configuration, including the exact nixpkgs version, is defined in files you can commit to version control and reproduce anywhere.
How to switch your standard nixos system configuration to a flaked one is beyond the scope of this blog, but there are many resources available that explain the process like here or here.
To update your flake inputs to the latest snapshot, run:
sudo nix flake update --flake /etc/nixos
This updates the flake.lock file to point to the latest commits of each input. Then rebuild as usual with sudo nixos-rebuild switch. To switch to a newer channel (e.g. from nixos-24.11 to nixos-25.05), simply change the version input in your flake.nix before running the update command above.
Home Manager, what and why?
Home Manager has significant benefits for single-user systems, and this is one of the most common misconceptions in the NixOS community. The benefit isn't multi-user management, but that it brings the same reproducibility and declarative config that NixOS gives your system, but for your user environment: dotfiles, shell config, application settings (git, neovim, Firefox, etc). Without it, those configs sit outside Nix's control entirely.
For example, instead of a ~/.gitconfig you manually maintain, Home Manager lets you declare it in Nix, being version controlled, reproducible, and rebuild-able on a fresh install. Making home manger certainly worth considering for a single user.
Extras
There are many other ways you can configure a NixOS system to work for you, and it would be a very long blog post if I discussed them all. Instead, here are a few links that a new or current user might find useful:
-
nix-ld - A solution for issues with pre-compiled executables on NixOS. Explainer here and GitHub link here.
-
Direnv - An automatic environment setup utility. Direnv wiki page here and NixOS wiki page here.
-
sops-nix / agenix - Two different projects solving the problem of storing secrets in your configuration. Find sops-nix here and agenix here.
-
disko - Declarative disk partitioning, find it here.
-
nix-index - A utility that helps you find what package provides a given file/library. Don't install it with
nix-envlike it suggests! Add it to your configuration instead :) and find it here.
