NixOS 23.05 changes the defaults behind a declarative system
NixOS 23.05 updates core packages while changing boot metadata and NSS lookup dispatch. Those changes explain why declaring a system and activating a running machine are separate operations.
A declarative configuration does not freeze the meaning of every option indefinitely. Changing the package collection can change the implementation behind a default, the behavior of a service module, or how the running system enters a new generation. NixOS 23.05 makes several of those distinctions visible in the core operating system.
The May 31 release notes name the release Stoat. The notes preserved at the release tag describe a default kernel update from Linux 5.15 to 6.1 and a Nix update from 2.11 to 2.13. They also document changes that affect how the resulting configuration becomes a running machine.
I value NixOS because it makes intended state explicit and keeps configuration close to the inputs used to build it. A release like this is a reminder to read defaults as versioned decisions. The same declaration evaluated against a different release can intentionally produce a different system.
A boot description becomes an artifact
The release enables boot.bootspec.enable by default. Each system and specialization gains a boot.json document in its top-level output. The notes connect this to the merged bootspec proposal and identify advanced boot arrangements, including Secure Boot, as a motivation.
The bootspec module in 23.05 explains the concrete representation. Its versioned org.nixos.bootspec.v1 object describes the system platform, kernel path, and kernel parameters. It also supplies a label derived from the system release and kernel version.
When an initial ramdisk is enabled, the module adds its path and the program used to append initial-ramdisk secrets. Later generation code injects the system's top-level path and init path. This is a machine-readable description of the built system's boot components, with fields corresponding to actual outputs.
That description gives external tooling a defined input. A consumer does not need to infer the kernel and init paths solely from unrelated file conventions. The source explicitly calls the schema a stable API and says changes to its structure or field meanings should go through an RFC.
Generating this document is not equivalent to enabling every boot feature that can use it. The release notes say it helps enable advanced uses. The module supplies metadata and a schema, while a particular boot integration still needs to consume that metadata and implement its own behavior.
This distinction matters for security claims. A boot.json file is evidence that boot information has been generated. Its presence alone does not prove that a machine enforces a particular signature policy. The module's responsibility is describing the generation in a form other tooling can use.
Specializations remain explicit alternatives
The bootspec generator also embeds documents for system specializations under a separate versioned namespace. The source loads each specialization's document and associates it with that specialization's name. A consumer can therefore see the relationship between a main system and its declared variants.
NixOS 23.05 also adds --specialisation to nixos-rebuild for switch and test. The release notes describe this as a way to choose the specialization during those operations. That is an activation-interface change alongside the generated metadata change.
These facilities address different points in the same workflow. The build describes the variants and their boot artifacts. The rebuild command selects which declared alternative to activate. Neither operation requires treating an alternative configuration as an undocumented collection of edits to the running host.
I find that relationship useful because declared alternatives are easier to inspect than a sequence of remembered manual changes. The metadata gives boot consumers structured information, while the command option lets a caller select a named alternative through the supported interface.
A new generation can require a reboot
The release updates systemd from 252 to 253. Its notes recommend using nixos-rebuild boot and rebooting because switching a live system can fail in rare cases involving missing mount units. That recommendation is specific to the transition described by the release.
The practical distinction is between preparing a generation for boot and activating its services immediately on an already running system. A successful evaluation and build establish that the configuration can produce a system output. They do not by themselves establish that replacing live service state has the same preconditions as entering the system through a fresh boot.
This is especially relevant for declarations concerning mount and service relationships. A running service manager has state accumulated under the old generation. Booting constructs that state under the new generation from the beginning. The release's warning concerns the live transition between those arrangements.
The documented recommendation should therefore be read as an activation choice. It is not a statement that the entire declarative model has failed or that every systemd update must use the same procedure. The notes identify the release-specific condition and the operation intended to avoid it.
Another rebuild-interface change removes special treatment of localhost for --target-host and --build-host. To use the local machine, the notes say to omit the relevant option. Existing automation that explicitly supplied that value needs to account for the revised interface, even when its intended target has not changed.
NSS dispatch changes implementation
NixOS 23.05 defaults to nsncd for NSS lookup dispatch. The release describes it as a non-caching implementation in Rust replacing glibc's nscd. This is a change in the service behind name-service lookups, not simply another package added to the available collection.
The NSS dispatcher module makes the choice explicit through services.nscd.enableNsncd, defaulting to true. Its option description calls nsncd compatible with nscd and says it proxies lookups without caching. Selecting the older implementation remains possible.
The release documents the fallback as a configuration declaration:
{
services.nscd.enableNsncd = false;
}
The distinction between disabling the replacement and disabling the whole service matters. Disabling NSS dispatch can effectively disable lookups from non-glibc NSS modules, including systemd's modules, according to the module. Selecting the fallback changes which implementation supplies the service while retaining the service itself.
Source inspection shows implementation-specific service settings too. With nsncd the service uses a notifying startup type, while glibc nscd uses a forking type. Configuration and reload behavior also differ. The module translates one declarative choice into the service definition needed by the chosen implementation.
That is a useful example of the abstraction a NixOS option provides. A configuration can express the intended implementation without duplicating the entire service definition. A release can change the default while preserving an explicit option for an operator who needs the earlier behavior.
Security defaults can affect stored data
The release also builds libxcrypt without algorithms that upstream does not mark strong. The notes identify system login and several services among the consumers of the password-hashing interface. An algorithm's availability therefore matters beyond the package version printed in a release announcement.
Existing password data has a relationship to the algorithms available to verify it. Updating a declaration does not rewrite every stored credential automatically. The notes identify the affected library and consumer classes so that operators can assess that relationship for their configuration.
This belongs alongside the activation and NSS changes because all three expose state outside a package name. A boot transition has running state, lookup dispatch has service semantics, and password verification depends on stored representations. Declarative configuration makes the chosen implementation reproducible without making those external relationships disappear.
The notes also document services whose firewall-opening option changes its default to false. An existing declaration that relied on the old default can therefore produce a different network-access result after an upgrade. Explicitly enabling the option or supplying separate firewall configuration states the intended exposure. This is another case where the release changes the meaning of an omitted setting.
The release's broader package updates remain significant, including glibc 2.37 and desktop updates. Their operational meaning depends on the components a configuration actually uses. A server using the NSS dispatcher has a different relevant transition from a desktop primarily affected by its graphical session packages.
For a configuration maintained as desired state, Stoat provides explicit artifacts and options for several of these changes. Boot metadata describes each generation, the rebuild interface selects activation behavior, and the NSS option identifies the dispatcher implementation. The release notes provide the additional context needed where changing a built generation also changes its relationship with the live machine or persisted data.