Installing only a single package from `unstable`

@shmu26 You can use Nix Package Versions and https://www.nixhub.io/.

HTH

1 Like

In the simplest case, you can get the hash by going to the GitHub repo and pressing y, then the commit hash will appear in the address bar. You can then paste it into the tarball URL.

What I probably meant back then was setting the sha256 attribute to builtins.fetchTarball, which you can obtain by setting it to the empty string "" and re-building. This is the typical manual procedure suggested in the Nixpkgs manual.

It’s a good idea to explicitly set the derivation name as well, which can be freely chosen. In this particular case my mention of it was probably a fluke though, because builtins.fetchTarball automatically sets that to source, which is perfectly sensible. (There’s an issue with symbolic derivation names, because they are considered for input hashes although they don’t contribute anything to the contents. Setting the name to a constant everywhere is a mitigation against surprising rebuilds.)

Managing remote sources within modules is generally not great though. There are a few patterns one can use for more automation, but I’m not happy with any of them. I’ve written a lengthy rant with the details if you care. tl;dr it needs more work to figure out.

1 Like

Thanks for the great explanation.
I saw something somewhere about using github instead of Tarball, for fetching the packages in such a case.
Do you have anything to say on that?

On the differences between built-in (evaluation time) and Nixpkgs (realisation time) fetchers: Nixpkgs Reference Manual

Briefly, there are two main considerations:

  1. Performance and caching
  2. Structuredness of interfaces

In toy examples I usually use builtins.fetchTarball, but for anything at scale you’ll probably want Nixpkgs fetchers. Another consideration, which for most people will be minor, is bootstrapping: You need to have Nixpkgs to use pkgs.fetchurl and friends, but how do you obtain Nixpkgs in the first place? How much do you want to rely on built-in fetchers and their ephemeral cache? For most practical applications this is not a problem, but at the scale and stakes of Nixpkgs, or any other vital infrastructure, you’ll have to think about that carefully. (In my opinion this is a very much underexposed issue that has not been clearly solved yet.)

1 Like
packageOverrides = pkgs: {
    unstable = import <nixos-unstable> { # pass the nixpkgs config to the unstable alias # to ensure `allowUnfree = true;` is propagated:
      config = config.nixpkgs.config;
    };
  };

I’ve used this in my config for both home manager and config,nix. Posting this, knowing that this is a necropost hoping that i can help someone.

1 Like

Hey I know this is a dead post, but here is a working example for setting an overlay for nixpkgs of a different branch in a flake.

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    nixpkgs-master.url = "github:nixos/nixpkgs";
  };

  outputs = { self, nixpkgs, nixpkgs-master, ... }: {
    nixosConfigurations.example = nixpkgs.lib.nixosSystem {
      modules = [
        {
          nixpkgs.overlays = [
            (final: prev: {
              master = import nixpkgs-master {
                system = prev.system;
                config = prev.config;
              };
            })
          ];
        }
      ];
    };
  };
}

My nixpkgs in my setup follow the unstable branch and I set an overlay for using specific packages from master branch, this can be done the same way for stable or whatever branch you wish to add.
In my full flake.nix it is also imported into the inputs of home-manager so you can use it within home-manager as well.

You can do that, but note that import nixpkgs is an anti-pattern in the flake world. The emerging best practice is to use inputs.nixpkgs-master.legacyPackages.${pkgs.system} after passing it through specialArgs - see second heading here - and not through an overlay. It’s less important for private flakes that basically just contain a nixosConfiguration, but it’s a good habit to get into nonetheless.

To get unfree packages from that you would still need to use import, because flakes have no way to specify configuration at an input level. nixpkgs-unfree exists as a band-aid to fix that, but it doesn’t cover all edge cases, so sometimes you do need to pull out the import nixpkgs, but still, most of the time it can be avoided.

So, since we’re sharing snippets, this is a subtly nicer approach:

# flake.nix
{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    nixpkgs-master.url = "github:nixos/nixpkgs";
    nixpkgs-unfree-master.url = "github:numtide/nixpkgs-unfree";
  };

  outputs = { nixpkgs, ... } @ inputs: {
    nixosConfigurations.example = nixpkgs.lib.nixosSystem {
      modules = [
        ./configuration.nix # let's not do deeply-nested inline modules
      ];
      specialArgs = {
        inherit inputs;
      };
    };
  };
}
# configuration.nix
{ pkgs, inputs, ... }: let
  nixpkgs-unfree-master = inputs.nixpkgs-unfree-master.legacyPackages.${pkgs.system};
in {
  environment.systemPackages = with nixpkgs-unfree-master; [
    # packages here
  ];
}
2 Likes

Those are interesting approaches and a nice read. I will look into it.
The only reason I implemented the overlay in the first place is because a package I need for a course I’m taking was broken on unstable but the fix was already pushed to master.
But does the approach you shared mean that you need to let … in the input both in configuration.nix and home.nix? currently with the overlay and specialArgs and extraSpecialArgs inheriting inputs all I need is to write master.packageName in the normal package sections of the relevant files.

Nah, just wherever you want to use a package from nixpkgs-unfree-master. It’s actually not necessary at all, it’s just restating that as a variable for readability, this works too:

# configuration.nix
{ pkgs, inputs, ... }: {
  environment.systemPackages = [
    inputs.nixpkgs-unfree-master.legacyPackages.${pkgs.system}.some-package-that-has-not-hit-stable-yet
  ];
}

If that’s too verbose for you, you can always change the name at the specialArgs level:

nixosConfigurations.example = nixpkgs.lib.nixosSystem rec {
  # Using `rec` to create this variable for the whole block since you seem
  # to prefer conciseness, but arguably limiting the number of scoped
  # variables with a `let ... in` is better
  system = "x86_64-linux";
  specialArgs = {
    nixpkgs-unfree-master = inputs.nixpkgs-unfree-master.legacyPackages.${system};
  };
};

At which point you can use:

# configuration.nix
{ pkgs, nixpkgs-unfree-master, ... }: {
  environment.systemPackages = [
    nixpkgs-unfree-master.some-package-that-has-not-hit-stable-yet
  ];
}

But this isn’t as popular, because you will likely eventually have other flake inputs with more complex outputs that include modules and such, where you don’t really want to collapse everything down. You can also do a mix of the two, of course.

The overall idea is just to limit what you’re stuffing into overlays for no real reason, because, while they are very powerful, they can cause very hard to understand errors, and tend to increase evaluation cost. Overlays are great for recursively replacing dependencies, using them just to create new attributes is a holdover from the only way you could depend on other projects pre-flakes.

2 Likes

Very comprehensive explanation thank you @TLATER ! Now I finally understood that I can get rid of my overlay as that is the sole reason of the legacyPackages.${pkgs.system}.some-package-that-has-not-hit-stable-yet form.
Had not really grasped that until now also that only special sets such as non-free still need the old form I was never really sure about.