At some point you’ve been there: ran a system update, rebooted, nothing came up. Or you’re installing an app and its dependency conflicts with something already on the system — fix one thing, break another. This is the inevitable end state of classic Linux administration. Every apt upgrade, every pacman -Syu adds another layer of change that becomes progressively harder to track.
NixOS steps in at exactly this point and asks: what if the entire state of your system was defined in a single file?
What Is NixOS?
NixOS is a Linux distribution built on a fundamentally different package management philosophy, originally developed by Eelco Dolstra as part of his PhD research in 2003. Its defining characteristic is a declarative approach rather than the imperative model used by standard distributions.
On a classic distro, managing a system means running a series of commands: install this, remove that, edit a config file. You need separate tooling (Ansible, Chef, manual notes) to track history. On NixOS you declare what the system should look like in a configuration file, and the system assembles itself to match that description.
That distinction sounds small. In practice it changes everything.
Declarative Configuration and the Generation System
The heart of NixOS is /etc/nixos/configuration.nix. Which packages are installed, which services run, users, network settings, desktop environment — all of it is defined here in the Nix language.
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
git
neovim
firefox
htop
];
services.openssh.enable = true;
users.users.oguz = {
isNormalUser = true;
extraGroups = [ "wheel" "docker" ];
};
}
When you want to make a change, you edit the file and run nixos-rebuild switch. The system rebuilds itself to match the new declaration.
Every nixos-rebuild creates a generation — a complete snapshot of the system at that point in time. When something breaks, rolling back is trivial:
# Roll back to the previous generation
nixos-rebuild switch --rollback
# Activate a specific generation
nix-env --switch-generation 42
On servers this is genuinely powerful. If a production update breaks something, you SSH in and roll back to the previous generation — a recovery that takes minutes instead of hours of debugging on a traditional distro.
Old generations naturally consume disk space, so periodic cleanup is worthwhile:
nix-collect-garbage --delete-older-than 30d
This can also be automated in your configuration.
Nix Store and the Hash Mechanism
On NixOS every package lives in its own directory under /nix/store/. That directory name isn’t a plain label — it’s a cryptographic hash representing the package’s exact contents, dependencies, and build parameters:
/nix/store/yw0z7q3z3i3dq2iqqf5wpk3zn2kv1ghw-firefox-124.0/
This design has two important consequences.
First: multiple versions of the same program can coexist on the system simultaneously. Python 3.9 and 3.12 run side by side, completely unaware of each other, without any Flatpak or Docker isolation layer. A quick nix-shell -p python39 drops you into a Python 3.9 environment; exit and the system is clean again.
Second: /nix/store is mounted read-only. You cannot modify an installed package. The smallest change to any package — even a single line — produces a different hash, and the system treats it as an entirely new package.
The security implications are significant. Supply chain attacks typically rely on silently modifying a package’s dependency after it’s been audited. Since the SolarWinds incident in 2020, software supply chain integrity has been a serious concern. On NixOS every file’s hash is recorded, so any post-installation modification is immediately detectable.
There’s another practical benefit: package dependencies are fully isolated. Two applications can use different versions of libssl simultaneously without conflicts. On traditional systems these version mismatches are the root cause of the infamous “dependency hell.”
Nixpkgs: The World’s Largest Package Repository
According to Repology data, Nixpkgs contains over 122,000 packages, making it the largest Linux package repository in the world — ahead of both Debian and Arch, and among the most up-to-date.
The reason comes down to ergonomics: defining a package in Nix requires significantly less code than the equivalent on other distributions. A small number of maintainers can sustain thousands of packages.
NixOS ships two types of channels:
- Stable: Released twice a year, end of May and November. Named by year and month —
25.05means May 2025,25.11means November 2025. Each release receives security updates for roughly seven months. - Unstable: A continuously updated rolling release channel. Because rollback is always available, a significant portion of desktop users prefer this channel despite the name.
NixOS also maintains a binary cache server at cache.nixos.org. When you install a package, the system checks there first; if it finds a cached build it downloads it, otherwise it compiles locally. This concept is called a substituter, and you can configure multiple substituters simultaneously. Services like Cachix or self-hosted tools like Attic let teams share a private binary cache, cutting build times significantly when deploying the same packages across multiple machines.
Nixpkgs also ships hundreds of ready-made modules for services like Nginx, PostgreSQL, and WireGuard. Instead of manually configuring each one:
services.nginx = {
enable = true;
virtualHosts."example.com" = {
enableACME = true;
forceSSL = true;
root = "/var/www/example";
};
};
That’s it. Let’s Encrypt certificate, SSL redirect, service management — all covered in a few lines.
Flakes: Reproducibility Done Right
Early versions of NixOS had a reproducibility gap: when writing configuration.nix you couldn’t pin which exact version of a package you’d get. The system pulled whatever was current in the configured channel. The same configuration file could install different package versions on two different machines or at two different points in time.
Flakes were introduced to close this gap. Today the vast majority of modern NixOS configurations use Flakes.
A flake.nix file explicitly declares your Nixpkgs version and all other dependencies:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
home-manager = {
url = "github:nix-community/home-manager/release-25.05";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { self, nixpkgs, home-manager, ... }: {
nixosConfigurations.mymachine = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [ ./configuration.nix ];
};
};
}
On first run the system generates a flake.lock file that records the exact commit hash of every dependency. Move the configuration to another machine two years from now — the lock file guarantees you get the exact same system.
Flakes also enable ephemeral package execution:
# Try an app without installing it
nix run nixpkgs#cowsay -- "hello"
# Run an app directly from its GitHub repo
nix run github:user/repo
For development environments, devShells replaces the older nix-shell approach:
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [ nodejs python3 postgresql ];
};
nix develop # Enter the project environment; exit leaves no trace
One caveat worth knowing: Flakes were added without going through NixOS’s formal RFC process and are still officially marked “experimental.” In practice everyone uses them — every tutorial, almost every configuration on GitHub — but you still need to opt in:
nix.settings.experimental-features = [ "nix-command" "flakes" ];
Whether to officially stabilize Flakes has been debated for years without resolution. It’s one of those situations where the technical and social tensions have become inseparable.
Home Manager: Dotfile Management, the Nix Way
Home Manager is one of the ecosystem’s essential companion tools. While configuration.nix manages system-wide state, Home Manager owns your user environment.
Neovim config, git settings, shell aliases, terminal tools — all in a single home.nix:
{ config, pkgs, ... }:
{
home.packages = with pkgs; [ ripgrep fd bat eza ];
programs.git = {
enable = true;
userName = "Oguzhan Yilmaz";
userEmail = "oguz@example.com";
extraConfig.core.editor = "nvim";
};
programs.zsh = {
enable = true;
autosuggestion.enable = true;
shellAliases = {
ll = "eza -la";
rebuild = "nixos-rebuild switch --flake .#";
};
};
}
On a new machine: pull your config from GitHub, run one command, and your entire development environment is live.
A key advantage is that Home Manager works outside NixOS too. On macOS or any other Linux distribution, installing just the Nix package manager is enough to use Home Manager. Many people start here before committing to a full NixOS migration — it’s a lower-stakes way to learn Nix’s mental model on familiar ground.
The NixOS Ecosystem
A strong tooling ecosystem has grown around NixOS:
Disko — Brings disk partitioning and filesystem layout into the declarative model. Essential for automated bare-metal installs.
nixos-anywhere — Installs NixOS on any empty server with just SSH access, in a single command. No NixOS image required from your cloud provider.
deploy-rs / Colmena — Manage fleets of servers from a single configuration, with atomic rollbacks.
sops-nix — Stores secrets (API keys, passwords) encrypted inside your configuration, decryptable only on the correct machine. Means you can safely commit your entire config — secrets included — to a public Git repository.
devenv / devbox — A more readable layer on top of Flakes for development environments. Lets team members who don’t know Nix use project shells without needing to understand what’s underneath.
Stylix — Generates a consistent theme for your entire desktop from a single color palette and font definition. Terminal, browser, code editor — all at once.
There’s also nix-darwin, a sibling project for macOS. It can replace Homebrew for system-level package management and integrates with Home Manager. Stable on current hardware including Apple Silicon.
Drawbacks
Being honest about where NixOS creates friction matters.
FHS Incompatibility
Linux has used the Filesystem Hierarchy Standard for decades: libraries live under /lib, executables under /bin. NixOS ignores this — everything is in /nix/store/. Pre-compiled binaries downloaded from the internet, AppImage files, and some closed-source software simply won’t run out of the box.
The standard fix is the nix-ld module:
programs.nix-ld = {
enable = true;
libraries = with pkgs; [ stdenv.cc.cc zlib openssl ];
};
The nix-alien tool can automatically detect and provide missing libraries. Solutions exist, but they’re extra steps that wouldn’t be needed on a conventional distro.
Learning Curve
The Nix language uses lazy evaluation and a syntax unlike anything most developers have worked with before. Error messages aren’t always helpful:
error: value is a set while a list was expected
No line number, no context. Tracking down what triggered it can eat significant time. The community is actively working on better diagnostics — Lix in particular has made this a priority — but the current state is still immature.
Documentation is scattered across the official NixOS wiki, Nixpkgs READMEs, community posts, and dozens of blog articles. The same topic often appears in multiple places with conflicting information. nix.dev is a reasonable starting point, though far from exhaustive.
The 2024 Community Crisis and the Three-Way Split
In 2024 the NixOS community went through a significant fracture. Founder Eelco Dolstra faced mounting criticism over decision-making transparency — including blocking long-time contributors from roles, repeatedly bypassing the RFC process, and handling a sponsorship controversy (a US defense contractor on the NixCon sponsor list) in a way that appeared to benefit his company’s client. An open letter signed by over a hundred contributors called for his resignation. Eelco stepped down from the NixOS Foundation board in May 2024, and most of the moderation team resigned shortly after. A democratic election was held at the end of 2024 to establish a new governance structure with written rules.
The technical fallout split the ecosystem three ways:
- Nix — The original C++ implementation, now under the new NixOS Foundation governance.
- Lix — A community fork that branched off in February 2024, before the crisis peaked. Focuses on a faster evaluation engine and better error messages.
nix-darwinofficially recommends Lix. - Determinate Nix — A fork by Eelco’s company, Determinate Systems. The company’s widely-used installer began shipping Determinate Nix exclusively in early 2026; the community responded by publishing its own installer.
All three share the same ecosystem and are largely interchangeable for day-to-day use. For someone new though, the question of which to choose adds unnecessary complexity on top of an already steep learning curve.
Who Should Use NixOS?
Not the right fit for everyone. Here’s where it genuinely shines:
Developers working across multiple projects. If different projects demand different versions of Node, Python, or Go and you’re tired of managing pyenv, nvm, asdf, and similar tools, Nix’s devShell approach eliminates the problem at the root.
Server administrators. If you manage more than a handful of servers and want consistent state, fast rollbacks after a bad update, and configuration tracked in version control — NixOS with deploy-rs or Colmena is a strong combination.
Teams chasing “works on my machine.” Reproducible project environments via devenv or flake.nix make the discrepancy between developer machines and CI a tractable problem.
Multi-machine personal setups. Desktop, laptop, work machine — same tools, same settings, maintained in one place.
On the other hand, if you’d rather not dig into how your system works at this level, or your time for learning is limited, Ubuntu or Fedora get you productive with far less friction.
For those curious but hesitant about committing: install the Nix package manager on your current distro, set up Home Manager, and use it for dotfile management for a few weeks. If the mental model clicks, install NixOS in a VM. Migrate to it only if you’re convinced.
Conclusion
NixOS represents a genuinely different answer to how Linux systems should be managed. Declarative configuration, real reproducibility, version-isolated packages, and cryptographic integrity checks — these aren’t theoretical features. They make a concrete difference in daily operation.
That said, the learning curve is real. FHS incompatibility is real. The 2024 crisis and the resulting three-way ecosystem split are real.
My take: NixOS makes the most sense for servers first. The ability to rebuild from scratch, roll back atomically, and keep configuration in git — these are “nice to have” on a desktop but genuine operational advantages in production. The 2024 governance reset gave the project a more stable institutional foundation, Nixpkgs still receives hundreds of contributions daily, and the community forums remain active. How the three-way implementation split resolves long-term is an open question, but Nix’s core ideas work the same regardless of which implementation you run.
The number of people who’ve crossed the learning curve and never looked back is telling. It’s worth giving it a few weeks to find out which side of that line you’re on.