Lix 2.95 "Kakigōri" (2026-03-13)
Lix 2.95.1 (2026-03-19)
Fixes
-
fix static builds cl/5385
Static builds using musl were broken in 2.95.0 and should work again now.
Many thanks to eldritch horrors for this.
-
flake config warnings are now printed to stderr lix#1155 cl/5379
The settings listed in a flake-config confirmation prompt are now printed to stderr rather than stdout, which allows
nix print-dev-envto emit valid bash again even in the presence of untrusted settings.Many thanks to lheckemann for this.
Lix 2.95.0 (2026-03-13)
Breaking Changes
-
Deprecate shadowing internal files through the Nix search path lix#998 cl/4632
As Lix uses the path
<nix/fetchurl.nix>for bootstrapping purposes, the ability to shadow it by addingnix=/some/path(or/other/paththat contains anixdirectory) to the search path is not desirable.To alleviate potential issues, Lix now emits a warning when the Nix search path contains potential shadows for internal files, which will be changed to an error in a future release.
The warning can be disabled by enabling the deprecated feature
nix-path-shadow.Many thanks to Tom Hubrecht for this.
-
More deprecated features cl/2092 cl/2310 cl/2311 cl/4638 cl/4652 cl/4764
This release cycle features a new batch of deprecated (anti-)features. You can opt in into the old behavior with
--extra-deprecated-featuresor any equivalent configuration option.broken-string-indentationindented strings (those starting with'') might produce unintended results due to how the whitespace stripping is done. Those cases will now warn the user.broken-string-escape"escaped" characters without a properly defined escape sequence evaluate to "themselves". This is in most cases unintended behaviour, both for writing regexes, and using legacy or uncommon escape sequences like\f. The user will now be warned, if those are present.floating-without-zeroso far, one was able to declare a float using something like.123. This can cause confusion about accessing attributes. Floating point numbers must now always include the leading zero, i.e.0.123rec-set-mergesAttribute sets like{ foo = {}; foo.bar = 42;}implicitly merge at parse time, however if one of them is marked as recursive but not the others then the recursive attribute may get lost (order-dependent). Therefore, merging attrs with mixed-recis now forbidden.rec-set-dynamic-attrsDynamic attributes have weird semantics in the presence of recursive attrsets (they evaluate after the rest of the set). This is now forbidden.or-as-identifieroras an identifier has always been weird since theor(almost-)keyword has been introduced. We are deprecating the backcompat hacks from the early days of Nix in favor of makingora full and proper keyword.tokens-no-whitespaceFunction applications without space around the arguments like0a,0.00.0orfoo"1"2are now forbidden. The same applies to list elements. The primary reason for this deprecation is to remove foot guns around surprising tokenization rules regarding number literals, but this will also free up some syntax for other purposes (e.g.r""strings) for reuse at some point in the future.shadow-internal-symbolshas been expanded to also forbid shadowingnull,trueandfalse.ancient-letdeprecation has been turned into a full parser error instead of a warning.rec-set-overridesdeprecation has been turned into a full parser error instead of a warning.
Many thanks to piegames, rootile (Rutile), and eldritch horrors for this.
-
Move
/root/.cache/nixto/var/cache/nixby default lix#634 cl/4671By default, Lix attempts to locate a cache directory for its operations (such as the narinfo cache) by checking the value of
$XDG_CACHE_DIR.However, since the Nix daemon is a system service, using
$XDG_CACHE_DIRis not typical in this context.To address this, systemd provides a better solution. Specifically, when
CacheDirectory=is set in the[Service]section of a systemd unit, it automatically sets the$CACHE_DIRECTORYenvironment variable and systemd will manage that cache directory for us.Now, our systemd unit includes
CacheDirectory=nix, which sets the$CACHE_DIRECTORYand takes precedence over$XDG_CACHE_DIR.If the daemon is run under user units, systemd will automatically set
$XDG_CACHE_DIR.If neither of these variables is set, Lix falls back to its default behavior. By default, Lix will try to find a cache directory for its various operations (e.g. narinfo cache) by looking into
$XDG_CACHE_DIR.In summary, what was stored in
/root/.cache/nixis now moved to/var/cache/nix/nix.Many thanks to Raito Bezarius for this.
-
Remove
fetch-closureexperimental feature lix#1010 cl/4595The
fetch-closureexperimental feature has been removed.Outside of allowing the user to import closure from binary cache,
fetchClosurealso allowed you to do the following:- rewrite non-CA path to CA
- reject non-CA paths at fetching time
- reject CA paths at fetching time
Some people are using those mechanism to prevent users from having to build any package and force going via the declared cache or as a way to use ancient/old software without paying the evaluation cost of a second nixpkgs.
Both use cases are somewhat of an antipattern in Nix semantics. If the user cannot fetch a program directly via the substituter mechanism and fall back to local build, this is a feature and a misconfiguration. If the user cannot build certain derivations because they are too expensive, the build directives should pass
-j0or similar.As for the second usecase, there's a different way to do it that also allows to have a way to reproduce the paths that are hardcoded in that file, perform
import (fetchurl "https://my-cache/${hashparts storepath}.drv")rather, i.e. an IFD to a possibly well known name. The backend can generate them on the fly or once, and possess stable names.Finally, as for the non-CA → CA features, Lix removed ca-derivations. fetchClosure offers ca-derivations-like features which suffers from similar shortcomings albeit lessened. It only follows that we should deprecate and remove these capabilities.
Many thanks to just1602 for this.
Features
-
nix store add-pathnow supports references cl/5205Lix supports two categories of hashes in store paths: input-addressed and output-addressed.
Currently, in Nix language, there is no way to produce output-addressed paths with references, as fixed-output derivations forbid references. However, the Nix store actually supports references in output-addressed paths. This is very useful for importing build products created outside of Lix that reference dependency store paths since such build products have no associated derivation so don't make any sense to input-address. Previously, output-addressed paths with references could only be created by writing a custom client to the rather-baroque Nix daemon protocol; now it's available in the CLI.
Using
nix store add-path --references-list-json REFS_LIST_FILE SOME_PATHwith a JSON list of string store paths, you can now create such paths with the Lix CLI. They may be consumed from Nix language using something likebuiltins.storePathor the following which also works in pure evaluation mode:# Hack from https://git.lix.systems/lix-project/lix/issues/402#issuecomment-5889 path: builtins.appendContext path { ${path} = { path = true; }; }Many thanks to jade for this.
-
Add
builtins.warnfor emitting warnings from Nix code cl/2248Lix now has a builtin function for emitting warnings. Like
builtins.trace, it takes two arguments: the message to emit, and the expression to return. Unlikebuiltins.trace,builtins.warnrequires the first argument — the message — to be a string. In the future we may extendbuiltins.warnto accept a more structured API.To go along with this, we also have two new config settings:
debugger-on-warn, which, when used with--debugger, makesbuiltins.warnalso function likebuiltins.break.abort-on-warn, which aborts evaluation entirely after the warning is emitted.
Many thanks to Emilia Bopp and Qyriad for this.
-
keep-env-derivationsis now supported for nix3 CLI (nix profile) lix#1095 cl/5332The
keep-env-derivationsfeature is now available fornix profile. This allows users to prevent the garbage collection of derivations used to install a profile, even whenkeep-derivations = false(set totrueby default).Previously,
nix-envsupported this feature, butnix profilenever did. This caused issues when garbage collection removed the associated.drvfiles, which are required, for example, by vulnerability management tools (e.g. vulnix) for proper operation.This issue has now been resolved.
Many thanks to Raito Bezarius for this.
-
Make
log-formata setting cl/4686The
--log-formatCLI option can now be set innix.conf! For example, you can now persistently enable themultiline-with-logslog format added in Lix 2.91 by adding the following to yournix.conf:log-format = multiline-with-logsOr the equivalent in a NixOS configuration:
{ nix.settings.log-format = "multiline-with-logs"; }Many thanks to Qyriad for this.
-
Allow remote builders to be configured using TOML cl/4533
Lix now supports configuring remote builders using a TOML file instead of the old, very cursed and incomprehensible format. This comes with not only a human-understandable file, but also with better messages and error reports on misconfiguration.
A more detailed Documentation can be found on the distributed-builds documentation page.
Many thanks to rootile (Rutile) and Qyriad for this.
-
Emit warnings when encountering IFD with
warn-import-from-derivationnix#13279 cl/3879Instead of only being able to toggle the use of Import from Derivation with
allow-import-from-derivation, Lix is now able to warn users whenever IFD is encountered withwarn-import-from-derivation.Many thanks to Seth Flynn, gustavderdrache, and Eelco Dolstra for this.
Improvements
-
Collect Flakes untrusted settings into one prompt lix#682 cl/2921
When working with Flakes containing untrusted settings, a prompt is shown for each setting, asking whether to vet or approve it. This looks like:
❯ nix flake lock warning: ignoring untrusted flake configuration setting 'allow-dirty', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page) warning: ignoring untrusted flake configuration setting 'sandbox', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page) The following settings require your decision: - allow-dirty = false - sandbox = false Do you want to allow configuration settings to be applied? This may allow the flake to gain root, see the nix.conf manual page (yes for now/Allow always/no/No to all)In Flakes with a large number of settings to approve or reject, this process can become tedious as each option must be handled individually.
To address this, all untrusted settings are now consolidated into a single prompt: allowing for bulk acceptance permanently or not, rejection, or detailed review. For example:
Scrutiny scenario
❯ nix flake lock warning: ignoring untrusted flake configuration setting 'allow-dirty', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page) warning: ignoring untrusted flake configuration setting 'sandbox', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page) The following settings require your decision: - allow-dirty = false - sandbox = false Do you want to allow configuration settings to be applied? This may allow the flake to gain root, see the nix.conf manual page (yes for now/Allow always/no/No to all) n warning: you can set 'accept-flake-config' to 'false' to automatically reject configuration options supplied by flakes Do you want to allow setting 'allow-dirty = false'? (yes for now/Allow always/no for now) y Do you want to allow setting 'sandbox = false'? (yes for now/Allow always/no for now) nReject everything scenario
❯ nix flake lock warning: ignoring untrusted flake configuration setting 'allow-dirty', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page) warning: ignoring untrusted flake configuration setting 'sandbox', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page) The following settings require your decision: - allow-dirty = false - sandbox = false Do you want to allow configuration settings to be applied? This may allow the flake to gain root, see the nix.conf manual page (yes for now/Allow always/no/No to all) N Rejecting all untrusted nix.conf entries warning: you can set 'accept-flake-config' to 'false' to automatically reject configuration options supplied by flakesAccept everything scenario
❯ nix flake lock warning: ignoring untrusted flake configuration setting 'allow-dirty', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page) warning: ignoring untrusted flake configuration setting 'sandbox', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page) The following settings require your decision: - allow-dirty = false - sandbox = false Do you want to allow configuration settings to be applied? This may allow the flake to gain root, see the nix.conf manual page (yes for now/Allow always/no/No to all) yAccept everything PERMANENTLY scenario
Note that accepting everything permanently will authorize these options for any further operations.
The file containing this trust information is usually located in
~/.local/share/nix/trusted-settings.jsonand can be edited manually to revoke this permission until Lix provides a first-class command for this manipulation.❯ nix flake lock warning: ignoring untrusted flake configuration setting 'allow-dirty', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page) warning: ignoring untrusted flake configuration setting 'sandbox', pass '--accept-flake-config' to trust it (may allow the flake to gain root, see the nix.conf manual page) The following settings require your decision: - allow-dirty = false - sandbox = false Do you want to allow configuration settings to be applied? This may allow the flake to gain root, see the nix.conf manual page (yes for now/Allow always/no/No to all) AMany thanks to isabelroses, Raito Bezarius, and eldritch horrors for this.
-
--checkor--rebuildis clearer about a missing path lix#485Previously, when running Lix with --check or --rebuild, failures often surfaced as an unhelpful error:
"some outputs of '...' are not valid, so checking is not possible"
This message could mean two different things:
- The requested output paths don't exist at all, or,
- Some outputs exist but are not known to Lix
Lix cannot reliably distinguish these cases, so it treated them the same.
We've updated the error messages to clarify what Lix can determine: whether any valid outputs (> 0) are present or whether no outputs are available.
When no valid outputs can be found, Lix will now suggest building the derivation normally (without --check or --rebuild) before trying again.
When some valid outputs are present, Lix now reports which ones are valid, shows the full list of known outputs, and also suggests building the derivation normally.
In the future, Lix may automate this recovery step when it knows how to rebuild the paths, but implementing that safely requires more extensive changes to the codebase.
Many thanks to Raito Bezarius for this.
-
nix developno longer ignores the env variableSSL_CERT_FILEcl/5042Running
nix developandnix print-dev-envon shells that define the environment variableSSL_CERT_FILEnow works correctly by exporting that variable inside the built shell.Many thanks to Tom Hubrecht for this.
-
Linux sandbox launch overhead greatly reduced cl/5030 cl/5073 cl/5074
Sandboxed builds are now much cheaper to launch on Linux, with constant management overhead. This will mostly be noticeable when building derivation trees containing many small derivations like nixpkgs'
writeFileorrunCommandwith scripts that exit quickly. In synthetic tests we have seen build times of 3000 small runCommand drop from 80 seconds to 14 seconds, which is the most optimistic case in practice.Many thanks to eldritch horrors for this.
-
mTLS store connections via a plugin cl/3754 cl/3696 cl/3697 cl/3698
To support use cases requiring mutual TLS (mTLS) authentication when connecting to remote Nix stores, e.g. private stores, we have introduced a contributed mTLS plugin extending the Lix store interface.
This design follows an extensibility model which was brought up by a proposal of making Kerberos authentication possible in Lix directly.
This mTLS plugin serves as a concrete example of how store connection mechanisms can be modularized through external plugins, without extending Lix core. This idea can be generalized to integrate automatic certificate renewal or advanced integrations with secrets engine or posture checks.
It enables custom TLS client certificates to be used for authenticating against a remote store that enforces mTLS.
To use the plugin, configure Lix manually by setting in your
nix.conf:plugin-files = /a/path/to/libplugin_mtls_store.soCurrently, this must be done explicitly. In the future, Nixpkgs will provide a mechanism to reference an up-to-date and curated set of plugins automatically.
Making plugins easily consumable outside of Nixpkgs (e.g., from external plugin registries or binary distributions) remains an open question and will require further design.
Contributed plugins come with significantly reduced stability and maintenance guarantees compared to the Lix core. We encourage users who depend on a given plugin to take on maintenance responsibilities and apply for ownership within the Lix mono-repository. These plugins are subject to removal at any time.
Many thanks to Raito Bezarius, eldritch horrors, mic92, vlaci, and nkk0 for this.
-
Add an indication of nix-shell nesting depth lix#826 cl/4657
When in a nix shell (either via a
nix-shellor anix developinvocation), a variableNIX_SHELL_LEVELis exported to indicate the nesting depth of nix shells.Many thanks to Tom Hubrecht for this.
-
nix store deletecan now unlink a GC root before deleting its closure cl/4660Ever build something, and then you want to delete it and whatever dependencies it downloaded? Before you had to resolve the
resultsymlink and copy it, then delete it, thennix store delete --delete-closure --skip-liveon the path you copied. Now you can just pass--unlinkand theresultsymlink itself.Many thanks to Qyriad for this.
-
nix path-infono longer lies to the user about fetching paths lix#323 cl/4866When running
nix path-infowith an installable that is not present in the store, Lix no longer tells the user which paths are missing and that they will be fetched, as the documentation clearly states that this command does not fetch missing paths.Many thanks to Tom Hubrecht for this.
-
Derivations can now be printed in detail in
nix replcl/3842Traditionally derivations printed in the REPL would only print a formatted object representing the path of the derivation file it refers to. This makes inspecting the enhanced derivation attribute sets encountered from
mkDerivationor similar wrappers more difficult. Even the:p/:printcommand would not elaborate attribute sets tagged as a derivation.With this change you can now use
:p/:printto directly inspect a derivation by providing one as the top-level object. Derivation attribute sets will only be printed two levels deep and internal derivation attrsets will remain in unexpanded path form as before.drvAttrswill also be elided as these attributes are already present in the top-level attribute set of the derivation. These heuristics provide a balance between readability and functionality. When the:p/:printis omitted, a bare derivation is printed in the path format as before.Many thanks to Lunaphied for this.
-
Reject
__jsonin structured attributes derivations lix#380 cl/5286In structured attributes derivations,
__jsonis used internally to store the JSON representation of theenvattribute field that users can set.Unfortunately, a user can set
__jsonand enable structured attributes, resulting in a broken derivation from a semantic point of view.As no user can benefit from setting
__jsonand enable structured attributes, we disallow that possibility and throw an error from now on.This is not seen as a breaking change because there's no user code that can benefit from this behavior, hence, it's an improvement to user experience.
Many thanks to Raito Bezarius for this.
-
Shells support
$NIX_LOG_FDnow lix#336 cl/4694 cl/4695Lix's "debugging" shells (
nix3-developandnix-shell) now set the$NIX_LOG_FDenvironment variable.This means that hook logging in stdenv appears while debugging derivations via
nix3-developornix-shell.Many thanks to Raito Bezarius for this.
-
Supplementary groups are now supported for daemon authentication lix#968 cl/5021
macOS, FreeBSD and Linux now support receiving supplementary groups during UNIX domain authentication to a Lix daemon.
This change is particularly beneficial for systemd units with
DynamicUser=truethat need to connect to a Lix daemon, using aSupplementaryGroups=allocated by systemd in the context of the process. This is desirable if you wish to harden Lix clients.Many thanks to Raito Bezarius, Tom Hubrecht, alois31, and eldritch horrors for this.
Fixes
-
Nix shells'
$NIX_BUILD_TOPare shorter lix#1044 cl/4663Following the changes in 2.94.0 to shorten build directory paths, aimed at resolving UNIX domain socket length issues and improving nix-shell, we inadvertently introduced an excessively long path for the
$NIX_BUILD_TOPenvironment variable used by Nix shells (their effective temporary/builddirectory).To fix this, we replaced the
build-top-$HASHdirectory name with simplybuild-top, reducing these paths by at least 30 characters.We also added a test to ensure that Nix shells do not introduce more than 50 extra characters relative to their base directory (e.g.,
/tmpwhen$TMPDIRis not set).Many thanks to Raito Bezarius for this.
-
Fix resolving of symlinks in flake paths lix#106 lix#12286 cl/4783
Flake paths are now canonicalized to resolve symlinks. This ensures that when a flake is accessed via a symlink, paths are resolved relative to the target directory, not the symlink's location.
-
The REPL no longer considers failed loads for
:reloadlix#50 cl/4864 cl/4865 cl/4700 cl/4889The REPL allows "loading" files, flakes, and expressions into the environment, with the commands
:load/:l,:load-flake/:lf, and:add/:arespectively. The results of those stay in the environment as-is even if their sources change, until the:reloadcommand is used. However:reloadwould re-perform all instances of:l/:lf/:a, meaning you would get things like this:nix-repl> :l /tmp/texting.nix error: getting status of '/tmp/texting.nix': No such file or directory # oops, typo. nix-repl> :l /tmp/testing.nix # Do some stuff… nix-repl> :reload error: getting status of '/tmp/texting.nix': No such file or directoryThis is pretty silly, but also incredibly annoying, as it would stop there and not reload the correct files anymore. This effectively meant typoing any of the load commands would make
:reloaduseless for the rest of the entirenix replsession!This has been fixed, so now only successful loads count towards
:reload.Many thanks to Raito Bezarius and Qyriad for this.
-
Consistently use commit hash as rev when locking git inputs cl/4762
Lix will now use commit hashes instead of tag object hashes in the
revfield when fetching git inputs by tag inflake.lockandbuiltins.fetchTreeoutput. Note that this means that Lix may change someflake.lockfiles on re-locking. Oldflake.lockfiles still remain valid.Many thanks to goldstein for this.
Development
-
Functional lang migration lix#856 cl/3213
We have done it! The functional/lang framework has now been fully migrated to functional2/lang. This means: no more
just cleanandjust installmess and whatever because one removed a test. The lang test suite is also getting a face lift, with an improved folder structure and restructuring of many tests.Only the first CL of the chain is provided but there's way more changes associated to this project.
Many thanks to piegames and rootile (Rutile) for this.
Miscellany
-
Warn instead of erroring when the final destination of a transfer changes in-flight lix#1004 cl/4641
Lix will now emit a warning during downloads where the final destination changes suddently mid-transfer instead of throwing an error. This transfer behavior has been known to happen very rarely while fetching from some CDNs.
Many thanks to Tom Hubrecht for this.
-
impersonate-linux-26setting removed cl/5047Linux 3.0 was released 15 years ago. The
impersonate-linux-26setting was added 14 years ago with no mention of it being necessary to build anything, only saying that it improves determinism—which isn't accurate since impersonating Linux 2.6.x still allows the version string to change, and the final component of the version does still change with each Linux release. Since this setting should be no longer necessary in modern systems and workarounds for building old code exist (by using e.g.setarch --uname-2.6to wrap builds) we are removing this setting from Lix.Many thanks to eldritch horrors for this.
-
Default to showing build logs in the new-style (nix3) CLI cl/4674
Lix will now show logs by default, in addition to the progress bar, when invoked through the new-style "nix3" CLI (
nix build, etc)Many thanks to K900 for this.
-
Lix daemons are now fully socket-activated on systemd setups lix#1030
When launched by systemd, Lix no longer uses a persistent daemon process and uses systemd socket activation instead. This is necessary to support the
cgroupsandauto-allocate-uidsfeatures and may improve observability of daemon behavior with common systemd-based monitoring solutions.The old behavior with a single persistent daemon is still available, but disabled by default. It is not possible to enable both a persistent daemon and socket activation, starting one stops the other automatically. Existing installations should not require any changes when they're updated.
Many thanks to eldritch horrors for this.
-
Plugin interfaces have changed (again) lix#359 cl/4933 cl/4934
The
RegisterPrimOpclass used to register builtins has been removed. Plugins must now callPluginPrimOps::addfrom theirnix_plugin_entrywith the same parameters previously passed toRegisterRrimOpto register any new builtins.The
GlobalConfig::Registerhelper class has also been removed. Adding config options to the system is now done withGlobalConfig::registerGlobalConfig; a plugin can add config values by calling this function fromnix_plugin_entry.Many thanks to eldritch horrors for this.