Nix 2.18 stabilizes deliberate suppression of output references
Nix 2.18 removes the experimental flag from unsafeDiscardReferences. Self-contained images explain why a store hash inside an output does not always name a dependency in the host store.
A filesystem image can contain its own Nix store. Hashes inside that image can name objects in the embedded store rather than objects the host must retain. Scanning the image as though every recognized store reference belonged to the host can therefore record dependencies that do not describe how the image will run.
Nix 2.18 stabilizes the option for deliberately suppressing that scan. The September 20 release notes say unsafeDiscardReferences no longer needs an experimental feature flag. The historical release notes place that change alongside new flake-reference conversion functions. Stabilization concerns availability, while the attribute's purpose and risks remain specific.
I value Nix's dependency accounting because it makes the inputs behind an artifact inspectable. That accounting also needs a way to represent artifacts whose internal references belong to another filesystem context. The image example gives a concrete reason for the otherwise alarming word unsafe in this attribute's name.
Output scanning records a dependency relationship
The advanced-attribute documentation says unsafeDiscardReferences disables scanning an output for runtime dependencies. It works with structured attributes and contains a Boolean setting for each output name. The scope is therefore an identified output, not automatically every result of a build.
The example enables structured attributes and selects the default named output. Its two settings are both needed to express the documented arrangement.
{
__structuredAttrs = true;
unsafeDiscardReferences.out = true;
}
These attributes belong inside a derivation's attribute set. They do not by themselves describe a complete build, and the setting for out does not imply an instruction for every other named output. An author must choose the output whose reference scanning should be suppressed.
The documented motivation is a self-contained filesystem image with an embedded Nix store. References found inside that image concern the store it carries. The host's runtime dependency graph is not necessarily the right place to record them.
This is a representational issue rather than a request to remove text from the image. Disabling a scan changes the dependencies Nix records for the output. It does not rewrite store paths embedded in files or transform an ordinary executable into a self-contained one.
Stable availability does not validate every use
Removing the experimental flag makes the attribute available without that opt-in. It does not establish that suppressing references is safe for arbitrary packages. The attribute still directs Nix to omit information that normally describes runtime dependencies.
For a result that actually needs another path in the host store, discarding that relationship would make the recorded dependency information incomplete. The self-contained image case supplies a reason why the usual scan may not express the desired relationship. An ordinary package with genuine host-store dependencies does not gain that justification merely because the attribute is stable.
The output-specific form is important here. A derivation can produce an image alongside other artifacts whose references still need normal accounting. A per-output decision can represent that difference without requiring one global choice for the entire build.
This is also separate from choosing declared build inputs. The attribute concerns scanning completed outputs for runtime references. It is not an instruction to ignore build prerequisites or obtain undeclared tools from the host. Input declaration and output dependency recording occupy different stages.
I regard this kind of exception as preferable when its mechanism is explicit and narrowly scoped. Purity and dependency tracking have practical boundaries, and an image containing a second filesystem context is one of them. Naming the output and the omitted scan makes the exception available for review.
Flake references gain structured conversion
The release's new builtins.parseFlakeRef converts a URL-like reference into attributes. Its inverse, builtins.flakeRefToString, converts an attribute representation into a reference string. The implementation and embedded documentation show the supported value types and examples.
The documented parsing example includes a repository reference and a subdirectory. Those components become separate attributes in the result.
builtins.parseFlakeRef "github:NixOS/nixpkgs/23.05?dir=lib"
The resulting attributes identify the GitHub source type and repository owner, with the reference name and directory separately represented. Code that needs the directory no longer has to infer it by splitting a URL string using its own incomplete grammar.
The reverse builtin accepts fields with integer, Boolean, or string values. The implementation rejects other value types with an evaluation error. That restriction gives the conversion a concrete input contract and prevents a caller from assuming that an arbitrary nested Nix value can become a valid flake reference.
Both registrations remain guarded by the flakes experimental feature in this version's source. That is a different status from the newly stabilized discard-reference setting. A release can stabilize one mechanism while adding functions within another facility that still has its own opt-in requirements.
Parsing does not select an immutable source
The implementation separates parsing from builtins.getFlake. Parsing turns a reference's spelling into its attributes. Fetching and evaluating a flake involve additional behavior, including restrictions on unlocked inputs in pure evaluation.
That distinction matters to tooling. A program can inspect which owner or repository a reference names without treating the parsed result as proof that the reference resolves to fixed contents. A branch name remains a branch name when represented as an attribute. The conversion preserves the kind of selection the caller supplied, rather than replacing it with an independently resolved revision.
Likewise, converting attributes back into a string does not add a content hash or establish the referenced repository's compatibility. It serializes a supported reference representation. The consumer still decides which source identity is appropriate for the task.
Nix 2.18 therefore improves two different forms of explicit representation. Output authors can state when runtime-reference scanning is inappropriate for a particular artifact. Nix expressions can also convert flake references through the interpreter's parser instead of reconstructing that grammar manually. In both cases, the documented operation is precise enough to distinguish the information it supplies from decisions it leaves to the caller.