The Determinate Nix Installer records how to undo installation
Determinate's Rust installer records host changes in an installation receipt. Its design addresses the stateful setup work that must happen before Nix can manage builds.
Installing Nix requires changes to a machine before Nix can provide its normal build and configuration model. The installer may need to create users and arrange a daemon. On macOS it may also need a root volume. A failure between those operations can leave a machine with some prerequisites present and others missing.
Graham Christensen's February 27 announcement introduces Determinate Systems' alternative installer with that problem in view. Its central design addition is an installation receipt recording what has and has not happened. The new implementation uses Rust, but the receipt explains how the installer intends to handle the consequences of changing a host.
I am interested in Nix because declarative state makes a system easier to describe and rebuild. Installation is an awkward exception to that experience. The software providing the model first needs a working environment, and constructing that environment is itself a sequence of host mutations.
The daemon explains the installation work
The Nix 2.13 multi-user installation documentation explains why installation needs more than a binary. A shared Nix store must stop ordinary users from running builders that arbitrarily modify the store or interfere with other users' builds. Otherwise one user's build activity could compromise packages consumed by another.
The documented arrangement gives the store and database a privileged owner, normally root. Builds run under special build-user accounts. An unprivileged client's store operations go to a daemon running under the owner of the store and database. Those accounts and the daemon are part of the isolation model, not incidental packaging decoration.
This explains why copying nix onto a search path does not establish a multi-user installation. The host also needs identities, ownership, and a service through which clients can request operations. Those prerequisites have to agree with each other before the resulting environment is useful.
The manual also assigns constraints to the build-user group. Build accounts should belong to that group, and it should contain no other members. Such details make installation sensitive to pre-existing host state. A general installer needs to arrange the intended accounts without casually treating unrelated users as disposable.
The announcement identifies the same broader installation burden when it discusses root volumes and service setup. A system can complete one of these operations and fail on another. Calling the whole procedure one installation command does not make its underlying actions atomic.
A receipt connects actions with removal
The new installer stores a JSON receipt under /nix. According to the announcement, it records completed and incomplete installation work and retains the information needed to uninstall. That includes removing objects the installer created and undoing edits to files that must remain.
This difference is concrete for shell configuration. Removing an entire startup file would discard unrelated user settings. An uninstall operation instead needs enough information to remove its own additions while retaining the rest. The announcement describes this as part of the receipt's purpose, alongside deleting installer-created users and groups.
An installation receipt therefore records more than a claim that Nix is installed. It associates the installation with the host changes required to reverse it. The advertised uninstall command uses the retained installer:
/nix/nix-installer uninstall
The announcement says the installer removes itself as part of removal. That makes the retained executable an operational part of the installation, rather than a download that can always be discarded after the first successful run. Its presence gives the user a specific entry point for the reverse operation.
The receipt does not make all host state immutable or prevent subsequent manual edits. The claim made at launch is that the installer records the information it needs to undo its work. That is a narrower and more useful statement than assuming every failed installation automatically becomes indistinguishable from an untouched machine.
Partial progress becomes explicit state
The announcement contrasts the receipt with installations that can leave an intermediate state. Creating a volume successfully does not imply that the appropriate build users were created. A person diagnosing a failure needs to know which operation completed before deciding what remains to be done or undone.
Recording that distinction gives the installer a basis for handling a sequence of actions. It can distinguish an intended action from an accomplished one. That is the relevant design improvement for recovery, even though the announcement does not promise that every possible failure can be rolled back without intervention.
I find this compatible with the reason I like declarative systems. Desired state is useful only if the software can relate it to the state that actually exists. An installation receipt supplies evidence about changes made outside the normal package-build model.
It also makes removal a designed operation. An installer that only knows how to add state leaves users to infer the inverse sequence from documentation or shell history. Keeping that information with the installation reduces the amount of reconstruction required when someone decides to remove it.
Rust changes the implementation constraints
Christensen identifies differences between shell implementations as a maintenance problem in the existing Bash installer. He presents Rust as a way to avoid those shell-specific execution differences and support compiled targets across several systems. The announcement also cites error handling and the implementation libraries used for the command interface and asynchronous work.
Those are the project's stated reasons for its implementation choice. They do not establish that shell programs cannot be tested or that a Rust binary cannot have installation bugs. The architectural advantage described here comes from representing the installer as a structured program with explicit installation state.
The existing official installer is not described as universally broken. The announcement acknowledges that it has worked successfully many times and that Determinate contributors have worked on it. Its case for a fresh implementation concerns maintainability, incomplete-installation behavior, and the lack of built-in removal.
This distinction matters when assessing the alternative. A different implementation language is a means to address specific engineering constraints. The user-visible result needs to be evaluated through the installation and removal behavior the new program offers. Determinate also releases the implementation as a Rust library. The announcement presents that as a way for other installer designs to reuse its logic while choosing their own defaults, without requiring the same user interface.
Defaults also express a policy
The installer enables flakes and the unified command interface by default. The announcement explicitly calls both experimental Nix features. That choice is Determinate's recommended onboarding policy, rather than a claim that the upstream project has stabilized those features.
An installer therefore does more than place files and accounts. It supplies an initial configuration that changes what commands a new user can run without additional setup. Two successful Nix installations can differ in that configuration, even if both provide a working store and daemon.
The documented customization flags address different installation contexts. --no-confirm removes the normal interactive confirmation step for automation. --init none permits installation without an init system such as systemd. The announcement gives containers as a use case for that option.
Those flags change separate aspects of setup. A noninteractive invocation is not automatically an installation without service management. Likewise, omitting an init system does not by itself decide whether a human must confirm the plan. Keeping those controls separate lets an automated environment express its actual requirements.
The announcement also describes supplying extra Nix configuration during installation. Configuration policy remains part of the installer's responsibility, alongside creating the prerequisite host state. A receipt-driven design does not eliminate those choices or make one default suitable for every environment.
Installation remains outside the build model
The supported launch environments include macOS and Linux, with Windows use through WSL2. That phrasing matters because it does not promise a native Windows installation of the same daemon arrangement. The installer also targets CI and virtualized environments where the initial host state can differ considerably.
The Nix manual's multi-user explanation clarifies what those environments must ultimately supply. Clients need a route to the daemon, builders need their dedicated identities, and the store needs controlled ownership. The installer's job is to establish those prerequisites on systems that do not yet have them.
For an automation-oriented user, the receipt is the most consequential part of that job. It ties an installation to a record of its own actions and gives removal a supported command. The February release puts explicit state tracking around the host changes that must precede Nix's ordinary declarative workflow.