NixOS releases a new stable version twice a year, in May and November, numbered by year and month (YY.MM) and given an animal codename in alphabetical order. Each recent stable release gets bug fixes and security updates for seven months, which leaves about a month of overlap with the next one. As of 24 October 2026 the current release is NixOS 26.05 "Yarara", released 30 May 2026 and supported until 31 December 2026.
There have been 25 stable releases since 13.10 "Aardvark" in 2013. What sets NixOS apart from every other distribution in this series is not the calendar but the model underneath it: the whole operating system is built from one declarative configuration by the Nix package manager, every build lands in an immutable store path named by a hash of its inputs, and every change you apply produces a new "generation" you can boot back into. This post covers where Nix and NixOS came from, every release with its dates, how channels and nixpkgs branches work, what declarative configuration means in practice, the long story of flakes, how the project handles security and reproducibility, a step by step install, pin, upgrade and rollback routine, and how to turn a Nix closure into an SBOM.
Key takeaways
- Two releases a year, seven months each. The NixOS 25.05, 25.11 and 26.05 announcements each say the release "will receive bugfixes and security updates for seven months": until 31 December 2025, 30 June 2026 and 31 December 2026 respectively.
- Only one stable release is supported right now. 25.11 left support on 30 June 2026, so in October 2026 the supported choices are 26.05 and the rolling
nixos-unstablechannel. The next stable release, 26.11, is already referenced in the 26.05 release notes as the point where the old scripted initrd is removed. - Version numbers are dates, codenames are an alphabet. The release notes appendix runs from 13.10 "Aardvark" to 26.05 "Yarara", one animal per letter.
- Channels are tested pointers into nixpkgs. A channel such as
nixos-26.05only advances after Hydra builds a selection of packages and a set of tests passes, according to the NixOS manual. Small channels likenixos-26.05-smallbuild fewer binaries and so move faster after a security commit. - Every change is a generation you can roll back.
nixos-rebuild switch --rollbackreturns to the previous system configuration, and older generations stay in the boot menu until you garbage collect them. - Flakes are still experimental in the Nix manual. The Nix 2.34 reference manual still lists
flakesas an experimental feature, and nix.dev calls them "an experimental extension format with outstanding issues". NixOS 26.05 addedsystem.nixas a way to pin nixpkgs without channels and without flakes. - Binary substitutes are signed. Nix trusts
cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=by default for the official binary cache, per the nix.conf reference. - A closure is already a dependency graph.
nix path-info --recursivelists every store path a system needs at runtime, and community tools such as sbomnix and bombon turn that graph into CycloneDX or SPDX SBOMs.
What Nix and NixOS are, and where they came from
Nix: a package manager built on a thesis
Nix began as research at Utrecht University. Eelco Dolstra's PhD thesis, The Purely Functional Software Deployment Model, was defended at Utrecht on Wednesday 18 January 2006 under Doaitse Swierstra as promotor and Eelco Visser as copromotor, according to its title page. The first conference paper on the system, "Nix: A Safe and Policy-Free System for Software Deployment" by Dolstra, Merijn de Jonge and Eelco Visser, was presented at LISA XVIII in Atlanta, 14 to 19 November 2004. Its abstract opens by arguing that existing deployment systems "are neither safe nor sufficiently flexible", mainly because they cannot enforce complete dependency specifications.
The core idea in the thesis is to treat software deployment like a pure function. A package build (a "derivation") is described by all of its inputs: source, compiler, libraries, build script, flags, environment. Nix hashes that description and installs the result under a path such as /nix/store/<hash>-openssl-3.x.y. Two builds with different inputs land in different directories, so they never overwrite each other. Nothing is installed into /usr/lib where one package's upgrade can break another. A program finds its dependencies through those exact store paths, which is why the same machine can run two versions of the same library side by side without conflict.
Three consequences follow from that design, and they explain most of what makes NixOS feel different:
- Builds are isolated and explicit. Because each build sees only declared inputs (and builds run in a sandbox by default on Linux), a missing dependency shows up as a build failure rather than as something that happens to work on one developer's laptop.
- Installs and upgrades are atomic. A new version is built in a new store path, then a symlink (a "profile") is switched to point at it. If the build fails, nothing changed. If the result is bad, the old path is still there.
- The runtime dependency graph is recorded. When Nix finishes a build, it scans the outputs for references to other store paths and records them. That record is what lets Nix copy a complete "closure" to another machine, and it is also why Nix makes generating an inventory of components unusually precise.
NixOS: the same model applied to a whole operating system
NixOS takes the Nix model and applies it to the entire system: kernel, initrd, bootloader entries, systemd units, /etc files, users, services and packages. Dolstra, then at Delft University of Technology, and Andres Löh described it in the 2008 ICFP paper "NixOS: A Purely Functional Linux Distribution". The first stable release branch, 13.10 "Aardvark", followed five years later. In NixOS, files such as /etc/ssh/sshd_config are generated from the configuration and live in the Nix store; /etc mostly holds symlinks into a store path for the current system.
The project has since grown far beyond its research origins. The 26.05 announcement credits 2,842 contributors with 59,703 commits since 25.11, and the nixpkgs package collection behind it added 20,442 packages, updated 20,641 and removed 17,532 in that one cycle. The download page lists 26.05 as the current version and offers graphical and minimal ISO images, plus official cloud images such as Amazon machine images named nixos/26.05*.
Nix, nixpkgs and NixOS are three different things
Search results blur these, so it is worth separating them:
| Name | What it is | Where it lives |
|---|---|---|
| Nix | The package manager and build tool, plus the Nix expression language | The nix repository; documented in the Nix reference manual |
| nixpkgs | The package collection and the NixOS module system, written in the Nix language | The nixpkgs repository, with release branches such as release-26.05 |
| NixOS | The Linux distribution built from nixpkgs modules | The nixos/ directory inside nixpkgs, documented in the NixOS manual |
Nix also runs on other Linux distributions and on macOS; NixOS is the case where it owns the boot process and system configuration too. A NixOS release is a branch of nixpkgs, while Nix has its own version numbers (the reference manual cited here is Nix 2.34.9).
Every NixOS release, from 13.10 to 26.05
The table below uses two primary sources. The "Release notes date" column is the date in each heading of the NixOS release notes appendix, which the project writes in mixed formats (some with dots, some with slashes, one with question marks). The "Announced" column is the date of the matching post on the NixOS announcements page. They usually agree within a day or two. For 13.10, 14.04, 14.12, 15.09 and 16.03 the announcement came about a month after the date in the heading; this post reports both rather than guessing why.
| Version | Codename | Release notes date | Announced | Support status (24 Oct 2026) |
|---|---|---|---|---|
| 26.05 | Yarara | 2026.05/30 | 30 May 2026 | Supported until 31 Dec 2026 |
| 25.11 | Xantusia | 2025.11/30 | 30 Nov 2025 | Ended 30 Jun 2026 |
| 25.05 | Warbler | 2025.05/23 | 23 May 2025 | Ended 31 Dec 2025 |
| 24.11 | Vicuña | 2024.11/28 | 30 Nov 2024 | Ended (date not stated in notes) |
| 24.05 | Uakari | 2024.05/31 | 31 May 2024 | Planned to end Dec 2024 |
| 23.11 | Tapir | 2023.11/29 | 29 Nov 2023 | Planned to end Jun 2024 |
| 23.05 | Stoat | 2023.05/31 | 31 May 2023 | Planned to end Dec 2023 |
| 22.11 | Raccoon | 2022.11/30 | 1 Dec 2022 | Planned to end Jun 2023 |
| 22.05 | Quokka | 2022.05/30 | 30 May 2022 | Planned to end Dec 2022 |
| 21.11 | Porcupine | 2021/11/30 | 30 Nov 2021 | Planned to end Jun 2022 |
| 21.05 | Okapi | 2021.05/31 | 1 Jun 2021 | Planned to end Dec 2021 |
| 20.09 | Nightingale | 2020.10/27 | 27 Oct 2020 | Planned to end Jun 2021 |
| 20.03 | Markhor | 2020.04/20 | 20 Apr 2020 | Planned to end Oct 2020 |
| 19.09 | Loris | 2019/10/09 | 9 Oct 2019 | Planned to end Apr 2020 |
| 19.03 | Koi | 2019/04/11 | 10 Apr 2019 | Planned to end Oct 2019 |
| 18.09 | Jellyfish | 2018/10/05 | 6 Oct 2018 | Planned to end Apr 2019 |
| 18.03 | Impala | 2018/04/04 | 4 Apr 2018 | Planned to end Oct 2018 |
| 17.09 | Hummingbird | 2017/09/?? | 2 Oct 2017 | Ended |
| 17.03 | Gorilla | 2017/03/31 | 31 Mar 2017 | Ended |
| 16.09 | Flounder | 2016/09/30 | 3 Oct 2016 | Ended |
| 16.03 | Emu | 2016/03/31 | 1 May 2016 | Ended |
| 15.09 | Dingo | 2015/09/30 | 30 Oct 2015 | Ended |
| 14.12 | Caterpillar | 2014/12/30 | 30 Jan 2015 | Ended |
| 14.04 | Baboon | 2014/04/30 | 30 May 2014 | Ended |
| 13.10 | Aardvark | 2013/10/31 | 1 Dec 2013 | Ended |
The end dates for 25.05, 25.11 and 26.05 are quoted from their release announcements. For 18.03 to 24.05 the release notes themselves state a planned end of support month (for example, the 23.11 notes say "Support is planned until the end of June 2024, handing over to NixOS 24.05"). The notes for 24.11 and for releases before 18.03 fetched for this post do not state an end date, so the table does not guess one. Every release before 26.05 is out of support today.
What the pattern tells you
- The version number is the target month, not a promise. 20.03 shipped in April and 20.09 at the end of October. A version number tells you which cycle a release belongs to; check the announcement for the actual date.
- The schedule moved from March and September to May and November in 2021. RFC 80, started on 28 November 2020, delayed the planned 21.03 to 21.05, extended 20.09 support to June 2021, and set every later release six months apart "following a YY.05 and YY.11 convention". Its motivation was the desktops: GNOME and KDE Plasma both release in September, so a November release gives contributors time to package and stabilise them, where March and September landed just as the versions being stabilised went out of support.
- Support ends one month after the next release. The release notes from 18.03 onward say support is planned until the end of the month after the next release is due, "handing over" to it. 25.05 ended on 31 December 2025, a month after 25.11 shipped on 30 November. 25.11 ended on 30 June 2026, a month after 26.05 shipped on 30 May. That month is the window for moving every machine forward.
Highlights by era, from the release notes
The release notes appendix is the fullest record of how the distribution changed. A selection, quoted or summarised from each release's highlights:
| Release | Notable changes recorded in the release notes |
|---|---|
| 13.10 Aardvark | "the first stable release branch of NixOS" |
| 14.04 Baboon | Installation on UEFI systems supported; systemd 212; systemd user instances started at login |
| 14.12 Caterpillar | systemd 217, Nix 1.8, glibc 2.20, default kernel 3.14 |
| 15.09 Dingo | Haskell packaging redesigned ("Haskell NG"), shipping every package registered on Hackage |
| 16.03 Emu | systemd 229, Linux 4.4, GCC 5.3 (with a C++ ABI change), glibc 2.23; work on bitwise reproducible builds |
| 16.09 Flounder | Closure size reduction: a minimal NixOS container went from about 424 MiB to about 212 MiB |
| 17.03 Gorilla | nixpkgs overlays; glibc 2.25, GCC 5.4.0, systemd 232; default kernel 4.9; Nix 1.11.8; KDE Plasma 5 the default desktop and KDE 4 removed |
| 17.09 Hummingbird | GNOME 3.24, Plasma 5.10; UIDs and GIDs of removed users are remembered and reused |
| 18.03 Impala | aarch64-linux binaries available, but no channel yet |
| 18.09 Jellyfish | Continued effort to bring aarch64-linux to parity with x86_64-linux |
| 19.03 Koi | Pantheon desktop added; default Python 3 is CPython 3.7 |
| 19.09 Loris | Nix 2.3; systemd 239 to 243; GCC 7 to 8; OpenSSL 1.0 to 1.1 |
| 20.03 Markhor | GCC 8.3.0 to 9.2.0; glibc 2.27 to 2.30; Linux 4.19 to 5.4; OpenSSL 1.0.2u to 1.1.1d |
| 24.11 Vicuña | Nix updated to 2.24; significant changes to macOS support |
| 25.05 Warbler | Initial support for the COSMIC desktop (alpha); default kernel 6.6 to 6.12 |
| 25.11 Xantusia | nixos-init, a Rust based init for the systemd initrd without bash; COSMIC beta; FirewallD support |
| 26.05 Yarara | systemd initrd by default; system.nix; default kernel 6.12 to 6.18; dbus-broker by default |
Two threads run through the table. The base toolchain (glibc, GCC, systemd, kernel, OpenSSL) moves forward every release, which is why a NixOS release upgrade rebuilds or re-downloads almost every store path. And the boot path has been steadily rebuilt around systemd, ending in 26.05 with a systemd based initrd and the old scripted stage 1 on its way out.
Recent releases in more detail
The release announcements give a useful snapshot of what changes between versions:
- 25.05 "Warbler" (23 May 2025): GNOME 48, LLVM 19 and GCC 14. 2,857 contributors made 57,054 commits; nixpkgs added 7,840 packages, updated 28,054 and removed 1,694.
- 25.11 "Xantusia" (30 November 2025): GNOME 49, which removes the X11 session, and LLVM 21. 2,742 contributors made 59,430 commits; nixpkgs added 7,002 packages, updated 25,252 and removed 6,338.
- 26.05 "Yarara" (30 May 2026): the initrd (stage 1) is now based on systemd by default, and the old scripted stage 1 is deprecated and scheduled for removal in 26.11. The default kernel moved from 6.12 to 6.18, the default D-Bus implementation switched to
dbus-broker, a newsystem.nixentry point lets you pin nixpkgs withoutnix-channel, the NixOS test driver can usesystemd-nspawncontainers instead of QEMU virtual machines, and 26.05 is the last nixpkgs release to supportx86_64-darwin.
The 26.05 notes carry two upgrade warnings that matter for anyone moving from 25.11. First, with a systemd initrd and LUKS disk encryption, fileSystems."/".device should point at /dev/mapper/<name> to avoid a passphrase prompt timing out, and /dev/root no longer exists. Second, changing the D-Bus implementation is a "switch inhibitor": it needs a reboot rather than a live nixos-rebuild switch.
How channels, branches and the release cycle work
From a commit to a channel
nixpkgs development happens on the master branch. Around each release, release managers cut a branch such as release-26.05 and stabilise it, following the checklist kept in the NixOS release wiki, which describes itself as a record of what previous release managers did rather than fixed rules. After the release only conservative changes are backported to that branch. The release announcements thank the nixpkgs staging team for its staging cycles, the batches in which changes that rebuild many packages are merged.
A channel is a pointer to a specific tested commit on one of those branches. The NixOS manual explains that channels "are updated automatically from NixOS's Git repository after certain tests have passed and a selection of packages has been built successfully", using the nixos/release-combined.nix and nixos/release-small.nix jobsets on Hydra, the project's build farm. If a test fails, the channel stays on the older commit until the failure is fixed. That is why a security fix can be merged into release-26.05 hours before it appears in the nixos-26.05 channel. The channel status page shows each channel's last update time, commit and the Hydra job that gates it.
The channel types
The manual lists three kinds:
- Stable channels, such as
nixos-26.05. These "only get conservative bug fixes and package upgrades". The manual's example is a kernel moving from 4.19.34 to 4.19.38 but not from 4.19 to 4.20. - The unstable channel,
nixos-unstable, which follows the main development branch and "may thus see radical changes between channel updates". The manual says it is not recommended for production systems. - Small channels, such as
nixos-26.05-smallandnixos-unstable-small. They contain the same expressions but fewer prebuilt binaries, so they "get updated faster than the regular channels (for instance, when a critical security patch is committed)". The trade is that more packages may need to be built from source. The manual describes them as intended mostly for servers.
How long a stable release is supported
Two statements in primary sources need to be read together. The NixOS manual says stable channels "are generally maintained until the next stable branch is created". The release announcements for 25.05, 25.11 and 26.05 are more specific: each release "will receive bugfixes and security updates for seven months". In practice the second statement is the one to plan around: a May release is supported to the end of December, a November release to the end of June.
There is no long term support release. If you need a machine that changes less often than every six months, NixOS asks you to absorb a version upgrade twice a year, and in exchange makes the upgrade itself reversible.
Comparing the update models
| Property | NixOS stable channel | NixOS unstable channel | Traditional fixed release distribution |
|---|---|---|---|
| Release cadence | Every six months (May, November) | Continuous | Typically every six months to two years, some with long term releases |
| Support window | Seven months per release | Rolling, fixes land on the branch | Often years, sometimes with paid extensions |
| What updates bring | Backported fixes, minor version bumps | New major versions at any time | Backported fixes, distribution patched versions |
| Gate before users see a change | Hydra builds plus NixOS tests | Hydra builds plus NixOS tests | Distribution build and QA, then the mirror |
| How an upgrade is applied | New system generation built, then switched atomically | Same | Packages unpacked in place, maintainer scripts run |
| Rollback | Select the previous generation in the boot menu or run nixos-rebuild switch --rollback | Same | Needs filesystem snapshots or a backup |
| Configuration drift | Configuration is the source of truth; hand edits to generated files are overwritten | Same | Common; hand edits to /etc persist |
| Pinning a whole system to a commit | Built in (channels at a commit, system.nix or a flake lock) | Same | Usually needs a local mirror or snapshot repository |
What declarative configuration means in practice
configuration.nix
On a NixOS machine, the system is described by /etc/nixos/configuration.nix (or by a flake, or since 26.05 by system.nix). The manual's minimal example looks like this:
{ config, pkgs, ... }:
{
imports = [ ./hardware-configuration.nix ];
boot.loader.systemd-boot.enable = true; # UEFI systems
networking.hostName = "build01";
time.timeZone = "UTC";
services.openssh.enable = true;
services.openssh.settings.PasswordAuthentication = false;
users.users.alice = {
isNormalUser = true;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAA... alice@laptop" ];
};
environment.systemPackages = with pkgs; [ git vim ];
system.stateVersion = "26.05";
}
Every line sets an option. services.openssh.enable = true does not just install the OpenSSH package; the OpenSSH module generates sshd_config, the systemd unit, host key generation and the firewall rule. Remove the line and rebuild, and all of those disappear with it. The full list of options is in Appendix A of the manual and on the options search.
Modules and the merge
A NixOS module is a function that declares options and sets values. The module system collects every module you import plus the hundreds that ship in nixpkgs, and merges the values: lists are concatenated, attribute sets merged, and conflicting single values raise an error unless one side uses a priority helper such as lib.mkForce or lib.mkDefault. This is what lets a team keep a shared base.nix that every host imports, with per host files layered on top.
system.stateVersion is not the release you run
system.stateVersion is one of the most misread options. It records the release the machine was first installed with, so that modules can keep defaults that affect stored data (database formats, data directory layouts) compatible with what is already on disk. The manual's module documentation is full of notes conditioned on it; for example, a service note in the 26.05 manual warns that systems with a stateVersion below 26.05 may need a manual step to avoid a data directory issue. Changing stateVersion does not upgrade NixOS. Leave it at the original value unless a module's documentation tells you how to migrate.
Building, switching and testing
The nixos-rebuild command turns configuration into a running system. The manual describes the main modes:
| Command | What it does | When to use it |
|---|---|---|
nixos-rebuild switch | Build, make it the boot default and activate it now | Normal change |
nixos-rebuild test | Build and activate, but do not make it the boot default | Risky change; a reboot returns to the old system |
nixos-rebuild boot | Build and make it the boot default, but do not activate until reboot | Kernel, initrd or D-Bus changes |
nixos-rebuild build | Build only, leave a result symlink | CI, or checking that a change evaluates and builds |
nixos-rebuild build-vm | Build a QEMU virtual machine of the configuration | Try a change without touching the host |
nixos-rebuild switch --upgrade | Update the channel first, then switch | Applying updates on a channel based system |
nixos-rebuild switch --rollback | Switch back to the previous generation | Undo the last change |
Generations and rollbacks
Each successful switch or boot creates a new system profile link: /nix/var/nix/profiles/system-N-link, pointing at a store path for the complete system. The manual notes that nixos-rebuild switch --rollback "is equivalent to running" that older link's bin/switch-to-configuration switch. The bootloader menu lists every generation that still exists, so even a system that no longer boots can be started from the previous entry.
Rollback covers everything that is part of the system closure: packages, kernel, initrd, generated /etc files and systemd units. It does not cover mutable state such as databases in /var/lib, files in home directories, or data migrations a service ran when it started. The manual's upgrade section warns that some upgrades change a database schema and "cannot be undone easily". Treat rollback as a tool for configuration and package regressions, and keep backups or filesystem snapshots for data.
Old generations keep their store paths alive. nix-collect-garbage --delete-older-than 30d (or nix.gc.automatic = true in configuration) frees the space; afterwards those generations can no longer be selected.
Automatic upgrades
The manual documents system.autoUpgrade.enable = true, which runs a nixos-upgrade.service timer. With allowReboot = false it runs nixos-rebuild switch --upgrade on the current channel; with allowReboot = true it can reboot when the kernel, initrd or kernel modules changed. systemctl list-timers shows when it runs. Automatic upgrades stay within the channel you subscribed to; they never move a machine from 25.11 to 26.05.
Flakes: why they have been experimental for so long
What a flake is
A flake is a directory with a flake.nix that declares inputs (other flakes or source trees, such as nixpkgs at a branch) and outputs (packages, development shells, NixOS configurations). The nix flake reference explains the lock file: Nix "will automatically generate and use a lock file called flake.lock in the flake's directory", a JSON file whose graph mirrors the flake's dependency graph and maps each unlocked input specification to a locked one with an exact revision and content hash.
A minimal NixOS flake looks like this:
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
outputs = { self, nixpkgs }: {
nixosConfigurations.build01 = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [ ./configuration.nix ];
};
};
}
nixos-rebuild switch --flake .#build01 builds that configuration from exactly the nixpkgs revision in flake.lock. nix flake update moves the lock to the current head of nixos-26.05; committing the new lock file is the change record.
Status in 2026
Flakes arrived in Nix 2.4, released on 1 November 2021, whose notes describe them as "a new format to package Nix-based projects" and say they "are currently marked as experimental". As of the Nix 2.34 reference manual, they are still listed on the experimental features page, alongside nix-command, the newer command line. The nix flake manual page opens by warning that the "program is experimental and its interface is subject to change". The nix.dev flakes concept page is blunt: flakes are "an experimental extension format with outstanding issues", their functionality "can generally be achieved without them", and as an experimental feature "flakes can still change". It points out practical limits such as flakes having no parameters, so the target system has to be stated explicitly.
The same page shows how to enable them, either per command with --experimental-features 'nix-command flakes' or permanently with:
nix.settings.experimental-features = [ "nix-command" "flakes" ];
Why so long? The reasons visible in the documentation are design questions rather than bugs: the interface is still subject to change, some of the functionality overlaps with other features (the experimental features page notes that fetchTree, once guarded by the flakes flag, is now being offered on its own as a "release candidate"), and the project has avoided declaring a stable interface it would then have to keep. The practical upshot for teams is simple. Flakes are widely used and the lock file is a sound pinning mechanism, but nothing in the official docs promises the format will not change.
Pinning without flakes: system.nix in 26.05
NixOS 26.05 added a third entry point. The release notes describe system.nix as "an alternative entry point to configuration.nix (and flake.nix) that allows configuring NixOS without using nix-channel". It must evaluate to a NixOS system (or a set of them selected with --attr), and the example fetches a pinned nixpkgs tarball by commit and SHA-256 hash:
# /etc/nixos/system.nix
let
nixpkgs = builtins.fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/<commit>.tar.gz";
sha256 = "<hash from nix-prefetch-url --unpack>";
};
in
import "${nixpkgs}/nixos" {
configuration = ./configuration.nix;
}
The notes suggest curl -I https://channels.nixos.org/nixos-26.05 to find the channel's current commit and nix-prefetch-url --unpack to compute the hash. This gives you the main benefit of a lock file (the whole system is defined by one exact nixpkgs commit) using only stable Nix features.
Choosing a pinning method
| Method | Pins to | Experimental feature needed | Update action | Suits |
|---|---|---|---|---|
nix-channel | Whatever commit the channel had at your last update | No | nix-channel --update or nixos-rebuild switch --upgrade | Single machines, simple setups |
system.nix with fetchTarball | An exact commit and hash in the file | No | Edit commit and hash, rebuild | Teams that want pinning on stable Nix only (26.05 and later) |
Flake with flake.lock | Exact revisions and hashes for every input | Yes (flakes, nix-command) | nix flake update, commit the lock | Fleets managed from one repository, CI built systems |
How NixOS handles security
The security team and where advisories appear
The NixOS security team page lists the official channels: Discourse announcements "on security for major events", the Nixpkgs security tracker "for managing information on vulnerabilities in software distributed through Nixpkgs", a Security Triage Matrix room for triage and coordinating mitigations, a Security Discussions room, GitHub Security Advisories on the nixpkgs, NixOS and Nix repositories, and security labelled GitHub issues. To report a problem privately, the page asks you to email a member of the team.
The point to understand is that most fixes in nixpkgs are package updates or backported patches made by package maintainers, merged into master and backported to the supported release branch, and then delivered when the channel advances. There is no separate "security repository" as on some distributions. The small channels exist precisely so that servers can receive such a fix before the full binary set for the big channel is rebuilt.
Binary cache signing
Most NixOS users never compile most packages; they download prebuilt store paths ("substitutes") from https://cache.nixos.org. Nix only accepts a substitute signed by a key in trusted-public-keys, whose default value in the nix.conf reference is cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=, and require-sigs defaults to true. When you add a private cache, add its key explicitly:
nix.settings.substituters = [ "https://cache.nixos.org" "https://cache.example.internal" ];
nix.settings.trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"cache.example.internal-1:<your public key>"
];
What a signature proves is that the holder of the cache key published that output for that store path. It does not prove the output was built honestly from the source. That is the question reproducibility addresses.
Reproducible builds
The NixOS reproducible builds page states the goal plainly: when building "from the same source on independent infrastructure yields bit-by-bit identical results", that gives confidence the build infrastructure was not compromised. It notes that Nix's deterministic dependency references and sandboxed builds make it "an excellent starting point" but that this alone is not sufficient, because builds can still leak timestamps or other nondeterminism. Problems are tracked in nixpkgs with a reproducible builds issue label, and the cross distribution Reproducible Builds project list includes NixOS with its project board and continuous tests.
You can check a package yourself:
# Rebuild locally and compare with what is already in the store
nix build nixpkgs#hello --rebuild --keep-failed
# The same with the classic command line
nix-build '<nixpkgs>' -A hello --check --keep-failed
As the page warns, two matching builds cannot prove a package is reproducible; you might have been lucky. A mismatch, analysed with a diffing tool such as diffoscope, tells you where nondeterminism comes from. The live post on the supply chain case for reproducible Nix builds goes further into why that matters.
What Nix does not do for you
- It does not tell you a package is vulnerable. Store paths name versions; matching them to advisories is a separate step (see the SBOM section below).
- It does not remove vulnerable code until you rebuild. A fixed package in the channel changes nothing on a machine until
nixos-rebuildruns and, for long running services, the service restarts. A fixed library also means every package linked against it gets a new store path, so the closure diff after an upgrade can be large. - It does not cover old generations. A previous generation still contains the old, vulnerable packages. If you roll back, you roll back to them. Garbage collect generations you would never want to boot.
Step by step: install NixOS, pin nixpkgs, upgrade and roll back
The walkthrough follows the NixOS manual's manual installation on a UEFI machine with one disk. The manual recommends the graphical installer on the graphical ISO for desktop users; the minimal images boot to a command line and use the manual route below, which also shows what the graphical installer does for you.
Step 1: download and verify the ISO
Download the 26.05 minimal or graphical ISO from the download page. The page publishes a SHA-256 checksum next to each image. Verify it before writing to a USB stick:
sha256sum nixos-minimal-26.05.*-x86_64-linux.iso
# compare with the checksum published on nixos.org/download
Step 2: write the ISO to a USB drive
Warning: the next command overwrites the target device completely. Check the device path first.
lsblk -o NAME,SIZE,MODEL,TRAN # identify the USB stick by size, model and "usb" transport
Only when you are certain of the device:
sudo dd if=nixos-minimal-26.05.*-x86_64-linux.iso of=/dev/sdX bs=4M status=progress conv=fsync
Step 3: boot the installer and get online
Boot the stick. The installer logs in automatically as nixos, a user with an empty password, so sudo -i gives a root shell. The manual says the boot process should already have brought up networking (check with ip a), and that Wi-Fi can be configured through NetworkManager, with nmtui working even without a graphical session. Networking is required, because the installer downloads packages from the binary cache.
Step 4: partition and format
Warning: partitioning and formatting erase the target disk. Confirm the disk path before running any of these commands.
lsblk -o NAME,SIZE,MODEL,SERIAL # confirm which disk is the install target
Then, replacing /dev/sda only after you have confirmed it:
parted /dev/sda -- mklabel gpt
parted /dev/sda -- mkpart root ext4 512MB -8GB
parted /dev/sda -- mkpart swap linux-swap -8GB 100%
parted /dev/sda -- mkpart ESP fat32 1MB 512MB
parted /dev/sda -- set 3 esp on
mkfs.ext4 -L nixos /dev/sda1
mkswap -L swap /dev/sda2
mkfs.fat -F 32 -n boot /dev/sda3
mount /dev/disk/by-label/nixos /mnt
mkdir -p /mnt/boot
mount -o umask=077 /dev/disk/by-label/boot /mnt/boot
swapon /dev/sda2
The labels matter: the generated configuration and the systemd initrd in 26.05 both work most reliably with stable paths such as /dev/disk/by-label/nixos rather than /dev/root or bare device names.
Step 5: generate and edit the configuration
nixos-generate-config --root /mnt
nano /mnt/etc/nixos/configuration.nix
nixos-generate-config writes hardware-configuration.nix (file systems, kernel modules for your hardware) and a starting configuration.nix. The manual notes it also accepts --flake to generate a flake.nix if you want a flake based setup. At minimum, enable a bootloader (boot.loader.systemd-boot.enable = true; on UEFI), set a hostname, add your user, and leave system.stateVersion at the value the generator wrote.
Step 6: install and reboot
nixos-install # builds the system, installs the bootloader, asks for a root password
reboot
After the reboot you are on generation 1. Confirm what you are running:
nixos-version # prints the release, revision and codename
sudo nix-channel --list # the installer subscribes you to nixos-26.05
Step 7: pin nixpkgs
Choose one method from the pinning table above. For a fleet, the common choice is to put the configuration in a Git repository and pin with a flake or with system.nix. With system.nix, find the current channel commit:
curl -sI https://channels.nixos.org/nixos-26.05 | grep -i '^location'
# the redirect target names the release and commit
nix-prefetch-url --unpack https://github.com/NixOS/nixpkgs/archive/<commit>.tar.gz
Put the commit and the printed hash in /etc/nixos/system.nix as shown earlier, then build with nixos-rebuild switch. Now the machine only changes when someone edits that file.
Step 8: apply updates within the release
On a channel based machine:
sudo nixos-rebuild switch --upgrade
On a pinned machine, move the pin (new commit and hash, or nix flake update), review the change, and rebuild. Before switching, it is worth seeing what will change:
nixos-rebuild build # creates ./result
nix store diff-closures /run/current-system ./result
nix store diff-closures (part of the experimental nix-command interface) lists package version changes and size differences between the running system and the new build. That list is your change log for the update.
Step 9: upgrade to a new release
When 26.11 ships, the move is a channel or pin change. The manual's route is to point the nixos channel at the new release with nix-channel --add and then run nixos-rebuild switch --upgrade. A more cautious variant builds the new release as the boot default and activates it on reboot:
sudo nix-channel --add https://channels.nixos.org/nixos-26.11 nixos
sudo nixos-rebuild boot --upgrade
sudo reboot
Using boot rather than switch for a release upgrade avoids activating a new init, D-Bus implementation or kernel in a running session, which matters for 26.05's D-Bus switch inhibitor. Read the release notes' "Backward Incompatibilities" section before you start; NixOS turns many of them into evaluation errors, but not all.
Step 10: roll back
If the new generation misbehaves:
sudo nixos-rebuild switch --rollback
# or pick the previous entry in the boot menu at startup
ls -l /nix/var/nix/profiles/system-*-link # list generations
When you are satisfied the new release works, clean up:
sudo nix-collect-garbage --delete-older-than 14d
sudo nixos-rebuild boot # refresh the boot menu to drop deleted generations
How to get an SBOM or dependency list from a Nix closure
Start with what Nix already records
Because Nix records every runtime reference, the full list of store paths a system needs is one command away. The nix path-info manual page includes this example for the running system:
nix path-info --recursive --closure-size /run/current-system | sort -nk2
Other useful forms:
# Every runtime dependency of a package, with sizes
nix path-info --recursive --size --closure-size --human-readable nixpkgs#openssl
# Machine readable output for scripting
nix path-info --recursive --json /run/current-system > closure.json
# Classic command line equivalents
nix-store --query --requisites /run/current-system
nix-store --query --references /run/current-system
# Why does the system depend on this path at all?
nix why-depends /run/current-system nixpkgs#openssl
A store path such as /nix/store/<hash>-openssl-3.x.y gives you a name and version, which is enough to search advisories by hand. It is not yet an SBOM: there is no package URL, no license field and no supplier, and some store paths are not packages at all (generated config files, wrapper scripts).
Community SBOM generators
Two community projects document how they turn Nix closures into standard SBOMs. Describe them from their own READMEs:
- sbomnix. Its README describes it as "a utility that generates SBOMs given a Nix flake reference or store path". By default it covers runtime dependencies, and it can include build time dependencies. Run against a flake reference, it writes
sbom.cdx.json(CycloneDX),sbom.spdx.json(SPDX) andsbom.csv. The same repository includesnixgraphfor dependency graphs and other helper tools. - bombon. Its README describes "Nix CycloneDX Software Bills of Materials". It is used from Nix itself:
bombon.lib.<system>.buildBom pkgs.hello { }builds a derivation whose output is the CycloneDX SBOM, and it has helpers to include vendored dependencies (for example Go modules) that a plain closure walk would miss.
A typical sbomnix run, following its README:
nix run github:tiiuae/sbomnix#sbomnix -- /run/current-system
# writes sbom.cdx.json, sbom.spdx.json and sbom.csv in the current directory
Runtime closure or build closure?
Choose deliberately. The runtime closure is what actually ships and runs, so it is the right scope for "what is deployed". The build closure adds compilers, build tools and fetched sources, which is the right scope for questions about the build pipeline itself. sbomnix's README explains that, unless told otherwise, its tools work with runtime dependencies, and that the target must have been built for the runtime closure to be known, because Nix only records references after a build.
What to do with the SBOM
An SBOM file is useful only if something reads it on a schedule. Store the CycloneDX file next to the build that produced it (one per system generation, or one per image), and check it against vulnerability data each time it changes and periodically between changes. If you already use Safeguard, safeguard scan --sbom sbom.cdx.json reads a CycloneDX file and matches its components against vulnerability databases, writing JSON results under ./output. The fix itself still comes through nixpkgs: an updated channel or a moved pin, followed by a rebuild.
Common mistakes
- Treating
system.stateVersionas the release number. Bumping it does not upgrade anything and can break services whose data on disk predates the new defaults. Upgrade by changing the channel or pin. - Staying on a release after its seven months end. 25.11 stopped receiving fixes on 30 June 2026. A machine still on
nixos-25.11in October 2026 builds fine and gets nothing new. - Using
nixos-unstablefor servers by default. The manual says it is not recommended for production. Use a stable channel, or a small stable channel for servers that need fixes fast. - Assuming rollback restores data. Generations cover the system closure, not
/var/lib, home directories or database schemas a service migrated on start. - Never garbage collecting. Old generations keep vulnerable packages on disk and in the boot menu, and fill the disk. Collect them once a new generation has proven itself.
- Editing generated files in
/etc. They are links into the store. Change the option in configuration; the next rebuild overwrites hand edits. - Updating a flake lock without reading the diff.
nix flake updatecan move nixpkgs across many commits. Runnix store diff-closureson the result before switching. - Adding a binary cache without its key, or setting
require-sigs = false. That accepts unsigned store paths from that cache. Add the cache's public key totrusted-public-keysinstead. - Thinking a channel update has reached the machine. A fix merged to the release branch is not in the channel until Hydra's gate passes, and not on the host until it rebuilds and restarts the affected services.
FAQ
What is the latest version of NixOS?
NixOS 26.05 "Yarara", released on 30 May 2026, is the current stable release as of 24 October 2026. The download page lists it as the current version. The rolling nixos-unstable channel is newer but is not a release.
How long is a NixOS release supported?
Recent releases receive bug fixes and security updates for seven months: a May release until 31 December and a November release until 30 June of the following year. The 26.05 announcement gives 31 December 2026 as its end date.
When does NixOS 25.11 reach end of life?
It already has. The 25.11 announcement said it would be supported until 30 June 2026. Move 25.11 machines to the nixos-26.05 channel.
When is the next NixOS release?
Releases ship in May and November. The 26.05 release notes refer to 26.11 as the release that removes the scripted initrd, so the next stable release is 26.11, due in November 2026 if the usual schedule holds. Its codename has not been confirmed in the sources used here.
Does NixOS have a long term support release?
No. Every stable release is supported for about seven months. The NixOS approach to stability is pinning and rollback rather than a long support window.
What is the difference between nixos-26.05 and nixos-26.05-small?
They track the same branch, but the small channel builds fewer binary packages, so it advances faster after a fix is committed. You may build more from source. The manual recommends small channels mainly for servers.
Are Nix flakes still experimental?
Yes, according to the Nix 2.34 reference manual, which lists flakes among experimental features, and nix.dev, which calls flakes "an experimental extension format with outstanding issues". They are widely used, but you must enable them explicitly.
How do I roll back a NixOS upgrade?
Run sudo nixos-rebuild switch --rollback, or choose the previous generation in the boot menu. This restores packages, kernel and generated configuration, but not application data or database migrations.
How do I upgrade NixOS to a new release?
Point the nixos channel at the new release with nix-channel --add https://channels.nixos.org/nixos-<version> nixos, then run nixos-rebuild boot --upgrade and reboot. With a flake or system.nix, move the nixpkgs pin to the new release branch and rebuild.
How do I generate an SBOM for a NixOS system?
nix path-info --recursive /run/current-system lists the runtime closure. Community tools such as sbomnix and bombon convert a closure or derivation into CycloneDX (and in sbomnix's case also SPDX) files you can feed to other tools.
NixOS gives you an exact list of what a machine runs and a way to change it atomically, but the packages in that list are still open source components that receive vulnerability fixes, and the applications you build on NixOS pull their own dependencies from npm, PyPI, Maven or Go modules on every build. The fixes for nixpkgs packages come from nixpkgs maintainers through the release branches; the dependencies in your own repositories and container images are your team's to track and fix, and that is where the section below applies.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
Safeguard does not manage NixOS hosts, edit configuration.nix for you or patch nixpkgs. It works on the repositories, container images and SBOM files you produce, which on a NixOS build host is where these demos apply.
The first demo sets up the local runner on your own machine, approves it with its device code, then scans from the terminal. On a NixOS workstation or build server, that is the route for scanning the repositories you build there, or a CycloneDX file produced by a community tool such as sbomnix, without sending source code anywhere first.
Click through it at your own pace, or open it full screen.
The second demo is a real Safeguard CLI session: asked to fix a lodash CVE, the assistant reads the finding and advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with your approval, prints a summary and pushes nothing. The same flow applies to a Node.js service developed on NixOS, for example inside a project shell: the vulnerable dependency is in your repository, not in nixpkgs, so the fix is a change you make, test and review yourself.
Click through it at your own pace, or open it full screen.
The third demo connects Claude to the Safeguard MCP server with OAuth and chooses which tools Claude can use. Once your projects and SBOMs are in Safeguard, that connection lets you ask which of them contain a given component and version, which is the question to answer when a release such as 25.11 leaves support and you want to know what still depends on its versions.
Click through it at your own pace, or open it full screen.
To try the CLI, download Safeguard and follow the CLI documentation.
Quick check
A server is on the nixos-25.11 channel and upgrades itself automatically every night. Is it getting security fixes in October 2026?
No. The 25.11 announcement gave 30 June 2026 as the end of bug fixes and security updates. The nightly upgrade still runs, but the channel no longer receives fixes. Move the server to nixos-26.05 (or nixos-26.05-small) and rebuild with nixos-rebuild boot --upgrade.
After an upgrade to 26.05 a service fails, and you roll back to the previous generation. Is everything back to how it was?
Only the system closure is. Packages, kernel, initrd and generated configuration return to the previous generation, but data the service migrated on its first start under 26.05 stays migrated. That is why backups or snapshots are still needed for stateful services.
Sources
- NixOS manual (stable)
- NixOS manual, Appendix B: Release Notes
- NixOS announcements
- NixOS 25.05 released
- NixOS 25.11 released
- NixOS 26.05 released
- NixOS download page
- NixOS channel status
- NixOS security team
- Nixpkgs security tracker
- NixOS reproducible builds
- Nix reference manual: experimental features
- Nix reference manual: nix flake
- Nix reference manual: nix path-info
- Nix reference manual: nix.conf
- nix.dev: Flakes
- Eelco Dolstra, The Purely Functional Software Deployment Model (PhD thesis, Utrecht University, 2006)
- Dolstra, de Jonge and Visser, Nix: A Safe and Policy-Free System for Software Deployment (LISA 2004)
- Dolstra and Löh, NixOS: A Purely Functional Linux Distribution (ICFP 2008)
- Nix 2.4 release notes
- NixOS RFC 80: NixOS release schedule
- Nix reference manual: nix store diff-closures
- NixOS release wiki
- sbomnix README
- bombon README
- Reproducible Builds: projects
Related reading: the supply chain case for reproducible Nix builds, Debian release history, Ubuntu release history, Alpine Linux release history and unified kernel images and measured Linux boot.
Last reviewed: 24 October 2026. NixOS support dates follow each release announcement; check nixos.org and status.nixos.org before planning an upgrade.