What is the established pattern for adding Unstable to Stable default NixOS 26.05

Hi everyone,

What is the established pattern for adding pkgs-unstable (from nixos-unstable) to inputs in (what I assume should be) /etc/nixos/flake.nix and making it callable anywhere when needing to add Unstable packages as nixpkgs — without Overriding regular nixpkgs?

I’ve seen some very experienced Linux people use Overrides to switch package sources.

Cheers

You add nixos-unstable as a separate flake input (I typically call it nixpkgs-unstable) and pass it in as a element of specialArgs to nixosSystem.

For an example, you can look at my configuration (nixos-config/flake.nix at bc4be483319033eaf0056d5c8d6e0039412c7db4 · MaxHearnden/nixos-config · GitHub).

Edit: Whatever is in specialArgs is accessible as a module argument.

2 Likes

I had asked Claude to answer this the other two questions and only just now checked. This is what it said (I never told it I asked questions here but it found them:

The NixOS Discourse posts from three hours ago (cited in results) are almost certainly from this session. The community has not yet answered them. The research provides enough information to address all three questions directly.


Question 3 — The Correct Pattern for Stable vs Unstable Packages

There is a clear, established decision tree. The concern about overrides being bad practice applies only to a specific misuse, not to the feature itself.

Layer 1 — System packages in configuration.nix:

pkgs resolves from whatever nixpkgs the system flake declares. If the system is on 26.05 stable, pkgs.hyprland is the 26.05 version. No additional pattern is needed for packages present in stable.

For packages only in unstable, use _module.args:

{ _module.args.pkgsUnstable = import inputs.nixpkgs-unstable {
    inherit (pkgs.stdenv.hostPlatform) system;
    inherit (config.nixpkgs) config;
  };
}

Then reference pkgsUnstable.somePackage in environment.systemPackages.

Layer 2 — User packages in home.nix:

pkgs resolves from whatever nixpkgs the Home Manager flake declares. Since home-manager init defaults to nixos-unstable, pkgs.somePackage in home.nix is already the unstable version. No additional pattern is needed.

For packages only in stable from Home Manager, the equivalent pattern applies using a pkgsStable argument.

Layer 3 — Packages from their own dedicated flakes:

Packages like Noctalia that are not sourced from nixpkgs channels at all are added as direct flake inputs and referenced via inputs.flake.packages.${system}.default. No channel is involved.

On overrides:

override and overrideAttrs are legitimate Nix primitives used extensively within nixpkgs itself and are not bad practice. What is considered bad practice is importing nixpkgs imperatively inside derivations using import <nixpkgs> {} or builtins.fetchTarball with channel URLs, because these bypass the flake’s reproducibility guarantees. Overlays — which use the same mechanisms — are the established pattern for system-wide package customization and are fully compatible with flakes.

The correct pattern for this specific setup:

Package source Location Pattern
In nixpkgs 26.05 stable configuration.nix pkgs.package
In nixpkgs unstable only configuration.nix pkgsUnstable.package via _module.args
In nixpkgs unstable (HM default) home.nix pkgs.package
In a dedicated flake (Noctalia) Both inputs.flake.packages.${system}.default or flake modules
Hyprland configuration.nix programs.hyprland.enable = true (stable 26.05)
Hyprland user config home.nix wayland.windowManager.hyprland (HM module)

Don’t follow that advice. It commits several anti-patterns. The extended answer is largely distracted by common questions unrelated to your problem, and gives misleading answers to the questions it invents.

@MaxHearnden’s response is correct, even if it doesn’t give you a snippet. If you need more handholding, look for similar questions around here, this is asked weekly. Or at least say so if you don’t understand so we can elaborate.

Christ LLMs are horrifyingly good at starting cargo cults, but I guess what do you expect if nobody thinks about what they do anymore.

3 Likes

Haha yeah when I look at the Claude response it is clearly confused as seen in the layering and the the structure of the answer. The other two answers are better and likely the questions are better, and the scope is smaller.

There is no understanding in the LLMs, it’s primarily word processing. If the Scaffolding and prompt are not well formed, and the source information is not clear the AI suffers the same fate that humans do.

Regarding hand holding — good technical writing is a major deficiency in programming and in IT in general. Good technical writing accelerates task execution and understanding. Good technical writing does not leave gaping holes or make undeclared assumptions both of which are the norm in most forms of general documentation. Why? Because good documentation is HARD. It gets worse if the foundation, the code (in the case of programming and DevOps), is also not clear or poorly written. Or devs have little supports, are time constrained and aren’t trained or interested in technical writing.

Some clear examples of excellent technical writing can be seen in Cisco’s documentation. Clearly written by engineers collaborating with technical writers.

Teaching someone about what we know demands restructuring and reordering to better articulate the knowledge, and a clear understanding of who the audience is. Most writers don’t go far enough because they don’t know to.

Handholding is about doing everything without providing the means to learn and use the document to expand research. So no references or reasoning and, like poorly written documents, no “Why”.

If a document is tasked to articulate a process and drops the reader in only one place and forces them to go ask someone else it has failed. The weakest link syndrome.

I’ve read your answers many times which address failures in documentation that forced people to ask you and others. The world is plagued with bad technical writing and the cost is extreme.

Thanks, good posts from you and Max.

I’ve not seen this before — is it just a more qualified form?

https://channels.nixos.org/nixos-25.11/nixexprs.tar.xz.

Not quite, that’s the official channel source that has gone through the full process and includes the command-not-found database.

Nix got a feature to support tracking tarballs with flakes a year or two ago, which permits using the official channel source rather than GitHub branches again.

The GitHub branches are incomplete, and only get forwarded after the channel tarballs are published. They’re also hosted on GitHub, which causes issues with rate limits and subjects users to GitHub’s whims.

The channel tarballs are simply preferable over the git branches in every way, yet most people don’t even know they exist, so I instruct people to use those whenever possible.

Oh, I don’t mean to say needing hand holding is wrong or anything, that’s perfectly normal. The nix ecosystem’s docs are notoriously awful and as a beginner it can be hard to form snippets from advice.

I’d just prefer you ask me - or find my various posts, like the one you seem to prefer over @MaxHearnden 's answer - instead of trying to get LLMs to teach you.

Training capable humans is IMO the most realistic way to get to a world with good technical writing about our ecosystem, and I dread a world in which everyone contributing docs was trained by whatever that claude answer was, or where LLMs end up being used in lieu of good technical writing, which sadly seems to be where things are going.

3 Likes

Ah, that’s awesome — to use the nixos.org server is definitely preferable, thanks.

I’m surprised the official docs haven’t converted to the direct tarball method.

I agree with all your points and appreciate that you lean towards using abstractions that continue to express the underlying model. Obviously some abstractions should be radically different but often they just move deck chairs around on the titanic.

The Elm language is a great example of keeping abstraction elegant and expressive of the underlying model. Some people prefer to do more though, like use lenses and want more of Haskell’s type system to be in Elm but most like Elm’s straight forward approach. Elm also avoids a lot of math notation and instead uses plain English words which is nice to read albeit adds to the sense of boilerplate.

If you apply the essential philosophy of domain driven design the code can totally express the domain very well, it’s awesome.

I’m very interested in Roc language started by Richard Feldman but inspired by Elm. The compiler is being rewritten in Zig, from the ground up. Check it out.