NixOS my new linux distro
Posted in linux on June 1, 2025 by Adrian Wyssmann ‐ 6 min read
Reason for NixOs
Some months ago I got a new Notebook and took the chance to checkout NixOS. I used Archlinux for many years and was very happe. However as DevOps/Platform Engineer I am used to make things reproducible - I use(d) Ansible and Terraform which allows me to create repoducible environments. I even [used Ansible][https://gitlab.com/papanito/devenv] for some aspcets. Then I stumbled upon NixOs which states
Declarative builds and deployments. Nix is a tool that takes a unique approach to package management and system configuration. Learn how to make reproducible, declarative and reliable systems.
Sounds amazing, so let’s give it a try
What is Nix
Nix is actually 3 things
A language or better an expression language
The Nix language is designed for conveniently creating and composing derivations – precise descriptions of how contents of existing files are used to derive new files.
Nix is a powerful package manager for Linux and other Unix systems that makes package management reliable and reproducible.
It offer the lagrest seletion of packages with over 120000 packages and can be used independently on other Linux distributions and macOS.
An operating system
A quick intro to NixOS
Instead of manually installing and configuring software, you define your entire system (packages, services, users, etc.) in a single configuration file (/nixos/configuration.nix
). This allows you to
- Reproduce your system on another machine
- Roll back to previous configurations
- Share setups with others
Every change to the system (like installing a package or updating the OS) is atomic. If something goes wrong, you can roll back to a previous working state with a simple reboot or command. a
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
];
# Omit previous configuration settings...
# Add user 'ryan'
users.users.ryan = {
isNormalUser = true;
description = "ryan";
extraGroups = [ "networkmanager" "wheel" ];
openssh.authorizedKeys.keys = [
# Replace with your own public key
"ssh-ed25519 <some-public-key> ryan@ryan-pc"
];
packages = with pkgs; [
firefox
# thunderbird
];
};
# Enable the OpenSSH daemon.
services.openssh = {
enable = true;
settings = {
X11Forwarding = true;
PermitRootLogin = "no"; # disable root login
PasswordAuthentication = false; # disable password login
};
openFirewall = true;
};
# Omit the rest of the configuration...
}
As you can see it also imports a file called hardware-configuration.nix
, a file that contains hardware-specific settings. It is automatically generated by nixos-generate-config
. It’s a crucial part of the system configuration, providing details about your hardware, such as the kernel, modules, and systemd settings. You typically don’t edit this file directly; it’s meant to be automatically generated and updated as needed. Usually, when you install NixOS for the first time both files are present on the system.
Channels
One important element is nix-channels, the git repository containing all packages and NixOS modules/expressions.
A “channel” is a name for the latest “verified” git commits in Nixpkgs. Each channel has a different definition of what “verified” means. Each time a new git commit is verified, the channel declaring this verification gets updated. Contrary to a user of the git master branch, a channel user will benefit from both verified commits and binary packages from the binary cache. This is what traditionally provides in the Nix language.
Channels can be broadly categorized into stable and unstable channels, and large and small channels. Channels are managed at user-level:
NixOS uses the channels set for the
root
user to update the system-wide configuration; channels set for other users control only the user environment for that user.
So you add a channel with
nix-channel --add https://nixos.org/channels/channel-name nixos
Organize and apply config
Despide you have a configuration.nix
it is best, you split your config in different files, which makes it much more easy to handle. I for instance in my nixos-configuration split it in different modules, so I have the following import statement:
imports = [
./common
./modules
];
While modules
has multiple files
- cloud.nix
- container.nix
- default.nix
- development.nix
- fonts.nix …
Important is the defaults.nix
which ensures, that when you import a folder, all .nix
-files are read:
{ lib, config, pkgs, ... }:
{
imports = [
./cloud.nix
./container.nix
./development.nix
./fonts.nix
./fun.nix
./kde.nix
./gnome.nix
./multimedia.nix
./office.nix
./solokey.nix
./printing.nix
./security.nix
./virt.nix
./wine.nix
];
}
To apply your configuration you run sudo nixos-rebuild switch
while the switch
ensures the configuration is switched. You always can rollback with sudo nixos-rebuild --rollback
or select a previous configuration from the boot menu when you restart your computer. For more details check Nixos-rebuild.
Flakes
Despite marked as experimental feature, flakes is a major development for Nix and indeed widely embraced.
Important
However, it’s important to note that Flakes is still an experimental feature. Some issues persist, and there is a possibility of introducing breaking changes during the stabilization process. The extent of these breaking changes remains uncertain.
Flakes similar something similar like package.json
, to describe the dependencies between Nix packages and how to build projects. It introduce flake.nix
, as well as flake.lock
, akin to package-lock.json
, to lock the versions of dependencies, ensuring project reproducibility.
{
description = "A simple NixOS flake";
inputs = {
# NixOS official package source, here using the nixos-25.05 branch
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
};
outputs = { self, nixpkgs, ... }@inputs: {
# The host with the hostname `my-nixos` will use this configuration
nixosConfigurations.my-nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
];
};
};
}
The flake.nix
has to elements
inputs
: defines all the dependencies of this flake, most commonly thenixpkgs
(instead of the channels on user-level). There can be multiple inputs, incl. other flakes. -outputs
: It is a function that takes the dependencies frominputs
as its parameters, and its return value is an attribute set, which represents the build results of the flake
To apply the configuration, the command is slighty different to the one when using no flakes:
sudo nixos-rebuild switch --flake /path/to/your/flake#your-hostname
For more details on flakes checkout
What else is there?
There are some interesting other elements to nix worth mentioning:
nix-shell
: It creates a temporary shell environment, with specific nix packages. The same can be achieved with the new cli runningnix shell
nix run
: creates an environment with the specified Nix package and directly runs that package within the environment (without installing it into the system environment)nix-env
:nix-env
is a core command-line tool for classic Nix used to manage software packages in the user environment. The command is used to manipulate Nix user environments, in other words to manage software packages in the user environment. Packages installed with nix-env are not automatically recorded in Nix’s declarative configuration and are completely independent of its control, making them challenging to reproduce on other machines. Upgrading packages installed by nix-env is slow and may produce unexpected results because the attribute name where the package was found in nixpkgs is not saved.
Further reading
There is much more amazing things, so I recommend to checkout Introduction to Nix & NixOS for a more detailed introduction to NixOS.